Initial commit
This commit is contained in:
281
pages/common/contactChoose/index.vue
Normal file
281
pages/common/contactChoose/index.vue
Normal file
@@ -0,0 +1,281 @@
|
||||
<template>
|
||||
<view class="contact_choose_container">
|
||||
<custom-nav-bar title="联系人" />
|
||||
|
||||
<view class="search_bar_wrap">
|
||||
<u-search
|
||||
shape="square"
|
||||
placeholder="搜索"
|
||||
:showAction="false"
|
||||
v-model="keyword"
|
||||
/>
|
||||
</view>
|
||||
|
||||
<view class="tab_container">
|
||||
<template v-if="activeTab === 0">
|
||||
<setting-item
|
||||
@click="tabChange(tabs[0].idx)"
|
||||
:title="tabs[0].title"
|
||||
:border="false"
|
||||
/>
|
||||
|
||||
<view class="tab_pane"></view>
|
||||
</template>
|
||||
|
||||
<template v-else>
|
||||
<view class="tab_pane" v-show="activeTab === 1">
|
||||
<choose-index-list
|
||||
@updateCheck="updateCheckedUser"
|
||||
:indexList="getChooseData.indexList"
|
||||
:itemArr="getChooseData.dataList"
|
||||
:checkedIDList="checkedUserIDList"
|
||||
:disabledIDList="disabledUserIDList"
|
||||
:showCheck="true"
|
||||
/>
|
||||
</view>
|
||||
</template>
|
||||
</view>
|
||||
<choose-index-footer
|
||||
:comfirmLoading="comfirmLoading"
|
||||
@removeItem="updateCheckedUserOrGroup"
|
||||
@confirm="confirm"
|
||||
:choosedData="getCheckedInfo"
|
||||
/>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapGetters } from "vuex";
|
||||
import { ContactChooseTypes } from "@/constant";
|
||||
import { formatChooseData, toastWithCallback } from "@/util/common";
|
||||
import IMSDK from "openim-uniapp-polyfill";
|
||||
import CustomNavBar from "@/components/CustomNavBar/index.vue";
|
||||
import UserItem from "@/components/UserItem/index.vue";
|
||||
import ChooseIndexList from "@/components/ChooseIndexList/index.vue";
|
||||
import ChooseIndexFooter from "@/components/ChooseIndexFooter/index.vue";
|
||||
import SettingItem from "@/components/SettingItem/index.vue";
|
||||
|
||||
export default {
|
||||
components: {
|
||||
CustomNavBar,
|
||||
UserItem,
|
||||
ChooseIndexList,
|
||||
ChooseIndexFooter,
|
||||
SettingItem,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
keyword: "",
|
||||
type: ContactChooseTypes.Card,
|
||||
activeTab: 0,
|
||||
groupID: "",
|
||||
checkedUserIDList: [],
|
||||
disabledUserIDList: [],
|
||||
comfirmLoading: false,
|
||||
tabs: [
|
||||
{
|
||||
idx: 1,
|
||||
title: "我的好友",
|
||||
},
|
||||
],
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
...mapGetters([
|
||||
"storeFriendList",
|
||||
"storeCurrentConversation",
|
||||
"storeCurrentUserID",
|
||||
"storeConversationList",
|
||||
]),
|
||||
getChooseData() {
|
||||
if (this.keyword) {
|
||||
return {
|
||||
indexList: ["#"],
|
||||
dataList: [
|
||||
this.storeFriendList.filter(
|
||||
(friend) =>
|
||||
friend.nickname.includes(this.keyword) ||
|
||||
friend.remark.includes(this.keyword)
|
||||
),
|
||||
],
|
||||
};
|
||||
}
|
||||
return formatChooseData(this.storeFriendList);
|
||||
},
|
||||
getCheckedInfo() {
|
||||
const tmpUserIDList = [...this.checkedUserIDList];
|
||||
const checkedFriends = this.storeFriendList.filter((friend) => {
|
||||
const idx = tmpUserIDList.findIndex(
|
||||
(userID) => userID === friend.userID
|
||||
);
|
||||
if (idx > -1) {
|
||||
tmpUserIDList.splice(idx, 1);
|
||||
}
|
||||
return idx > -1;
|
||||
});
|
||||
return [...checkedFriends];
|
||||
},
|
||||
},
|
||||
onLoad(options) {
|
||||
const {
|
||||
groupID,
|
||||
type,
|
||||
checkedUserIDList,
|
||||
} = options;
|
||||
this.type = type;
|
||||
this.groupID = groupID;
|
||||
this.checkedUserIDList = checkedUserIDList
|
||||
? JSON.parse(checkedUserIDList)
|
||||
: [];
|
||||
if (this.type === ContactChooseTypes.Invite) {
|
||||
this.checkDisabledUser();
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
checkDisabledUser() {
|
||||
const friendIDList = this.storeFriendList.map((friend) => friend.userID);
|
||||
IMSDK.asyncApi("getUsersInGroup", IMSDK.uuid(), {
|
||||
groupID: this.groupID,
|
||||
userIDList: friendIDList,
|
||||
}).then(({ data }) => {
|
||||
this.disabledUserIDList = data;
|
||||
});
|
||||
},
|
||||
tabChange(idx) {
|
||||
this.keyword = "";
|
||||
this.activeTab = idx;
|
||||
},
|
||||
updateCheckedUserOrGroup(item) {
|
||||
if (item.userID) {
|
||||
this.updateCheckedUser(item);
|
||||
}
|
||||
},
|
||||
updateCheckedUser({ userID }) {
|
||||
if (this.checkedUserIDList.includes(userID)) {
|
||||
const idx = this.checkedUserIDList.findIndex((item) => item === userID);
|
||||
const tmpArr = [...this.checkedUserIDList];
|
||||
tmpArr.splice(idx, 1);
|
||||
this.checkedUserIDList = [...tmpArr];
|
||||
} else {
|
||||
this.checkedUserIDList = [...this.checkedUserIDList, userID];
|
||||
}
|
||||
},
|
||||
confirm() {
|
||||
if (this.activeTab) {
|
||||
this.activeTab = 0;
|
||||
return;
|
||||
}
|
||||
this.comfirmLoading = true;
|
||||
if (this.type === ContactChooseTypes.GetList) {
|
||||
let pages = getCurrentPages();
|
||||
let prevPage = pages[pages.length - 2];
|
||||
prevPage.$vm.getCheckedUsers(this.getCheckedInfo);
|
||||
this.comfirmLoading = false;
|
||||
|
||||
uni.navigateBack({
|
||||
delta: 1,
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.type === ContactChooseTypes.Invite) {
|
||||
IMSDK.asyncApi(IMSDK.IMMethods.InviteUserToGroup, IMSDK.uuid(), {
|
||||
groupID: this.groupID,
|
||||
reason: "",
|
||||
userIDList: this.getCheckedInfo.map((user) => user.userID),
|
||||
})
|
||||
.then(() => {
|
||||
toastWithCallback("操作成功", () => uni.navigateBack());
|
||||
this.comfirmLoading = false;
|
||||
})
|
||||
.catch(() => toastWithCallback("操作失败"));
|
||||
return;
|
||||
}
|
||||
|
||||
this.comfirmLoading = false;
|
||||
},
|
||||
},
|
||||
onBackPress() {
|
||||
if (this.activeTab) {
|
||||
this.activeTab = 0;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
/deep/.u-popup {
|
||||
flex: none;
|
||||
}
|
||||
.contact_choose_container {
|
||||
height: 100vh;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
.search_bar_wrap {
|
||||
height: 34px;
|
||||
padding: 12px 22px;
|
||||
}
|
||||
|
||||
.tab_container {
|
||||
@include colBox(false);
|
||||
flex: 1;
|
||||
overflow: hidden;
|
||||
|
||||
.setting_item {
|
||||
padding: 32rpx 36rpx;
|
||||
}
|
||||
|
||||
.title {
|
||||
height: 60rpx;
|
||||
display: flex;
|
||||
justify-content: start;
|
||||
align-items: center;
|
||||
// padding: 16rpx 8rpx;
|
||||
background: #f8f9fa;
|
||||
color: #8e9ab0;
|
||||
font-size: 24rpx;
|
||||
}
|
||||
|
||||
.tabs_bar {
|
||||
@include vCenterBox();
|
||||
justify-content: space-evenly;
|
||||
|
||||
.tab_item {
|
||||
@include colBox(false);
|
||||
align-items: center;
|
||||
|
||||
image {
|
||||
width: 50px;
|
||||
height: 50px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.tab_pane {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex: 1;
|
||||
overflow: hidden;
|
||||
|
||||
.member_list {
|
||||
flex: 1;
|
||||
height: 80% !important;
|
||||
/deep/uni-scroll-view {
|
||||
max-height: 100% !important;
|
||||
}
|
||||
}
|
||||
|
||||
.user_list {
|
||||
height: 100% !important;
|
||||
}
|
||||
|
||||
.member_anchor {
|
||||
background-color: #f8f8f8 !important;
|
||||
border: none !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
213
pages/common/createGroup/index.vue
Normal file
213
pages/common/createGroup/index.vue
Normal file
@@ -0,0 +1,213 @@
|
||||
<template>
|
||||
<view class="create_group_container">
|
||||
<custom-nav-bar title="发起群聊" />
|
||||
<u-toast ref="uToast"></u-toast>
|
||||
<view class="main">
|
||||
<view class="group_base_info">
|
||||
<my-avatar
|
||||
@click="chooseImage"
|
||||
:isGroup="true"
|
||||
:src="groupFaceUrl"
|
||||
size="44"
|
||||
/>
|
||||
<u--input
|
||||
placeholder="取个群名称方便后续搜索"
|
||||
border="none"
|
||||
maxlength="16"
|
||||
v-model="groupName"
|
||||
></u--input>
|
||||
</view>
|
||||
|
||||
<view class="member_row" @click="toChooseMember">
|
||||
<view class="desc_title">
|
||||
<text>群成员</text>
|
||||
<text>{{ `${checkedMemberList.length}人` }}</text>
|
||||
</view>
|
||||
<view class="member_list">
|
||||
<view
|
||||
v-for="member in checkedMemberList.slice(0, 5)"
|
||||
:key="member.userID"
|
||||
class="member_item"
|
||||
>
|
||||
<my-avatar :src="member.userID" :desc="member.nickname" size="42" />
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="action_bar">
|
||||
<u-button
|
||||
:loading="createLoading"
|
||||
:disabled="disabledCreate"
|
||||
@click="complateCreate"
|
||||
type="primary"
|
||||
text="完成创建"
|
||||
></u-button>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { ContactChooseTypes } from "@/constant";
|
||||
import IMSDK, {
|
||||
GroupType,
|
||||
IMMethods,
|
||||
SessionType,
|
||||
} from "openim-uniapp-polyfill";
|
||||
import CustomNavBar from "@/components/CustomNavBar/index.vue";
|
||||
import MyAvatar from "@/components/MyAvatar/index.vue";
|
||||
import { navigateToDesignatedConversation } from "@/util/imCommon";
|
||||
import { getPurePath, toastWithCallback } from "@/util/common";
|
||||
export default {
|
||||
components: {
|
||||
CustomNavBar,
|
||||
MyAvatar,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
groupName: "",
|
||||
groupFaceUrl: "",
|
||||
checkedMemberList: [],
|
||||
fileList: [],
|
||||
createLoading: false,
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
disabledCreate() {
|
||||
return !this.groupName || this.checkedMemberList.length === 0;
|
||||
},
|
||||
},
|
||||
onLoad(options) {
|
||||
const { checkedMemberList } = options;
|
||||
this.checkedMemberList = checkedMemberList
|
||||
? JSON.parse(checkedMemberList)
|
||||
: [];
|
||||
},
|
||||
methods: {
|
||||
toChooseMember() {
|
||||
const checkedIDList = this.checkedMemberList.map(
|
||||
(member) => member.userID,
|
||||
);
|
||||
uni.navigateTo({
|
||||
url: `/pages/common/contactChoose/index?type=${
|
||||
ContactChooseTypes.GetList
|
||||
}&checkedUserIDList=${JSON.stringify(checkedIDList)}`,
|
||||
});
|
||||
},
|
||||
complateCreate() {
|
||||
this.createLoading = true;
|
||||
const options = {
|
||||
adminUserIDs: [],
|
||||
memberUserIDs: this.checkedMemberList.map((member) => member.userID),
|
||||
groupInfo: {
|
||||
groupType: GroupType.WorkingGroup,
|
||||
groupName: this.groupName,
|
||||
faceURL: this.groupFaceUrl,
|
||||
},
|
||||
};
|
||||
IMSDK.asyncApi(IMSDK.IMMethods.CreateGroup, IMSDK.uuid(), options)
|
||||
.then(({ data }) => {
|
||||
toastWithCallback("创建成功", () =>
|
||||
navigateToDesignatedConversation(
|
||||
data.groupID,
|
||||
SessionType.WorkingGroup,
|
||||
true,
|
||||
),
|
||||
);
|
||||
})
|
||||
.finally(() => (this.createLoading = false));
|
||||
},
|
||||
getCheckedUsers(list) {
|
||||
this.checkedMemberList = [...list];
|
||||
},
|
||||
chooseImage() {
|
||||
uni.chooseImage({
|
||||
count: 1,
|
||||
sizeType: ["compressed"],
|
||||
success: async ({ tempFilePaths }) => {
|
||||
const path = tempFilePaths[0];
|
||||
const nameIdx = path.lastIndexOf("/") + 1;
|
||||
const typeIdx = path.lastIndexOf(".") + 1;
|
||||
const fileName = path.slice(nameIdx);
|
||||
const fileType = path.slice(typeIdx);
|
||||
|
||||
try {
|
||||
const {
|
||||
data: { url },
|
||||
} = await IMSDK.asyncApi(IMMethods.UploadFile, IMSDK.uuid(), {
|
||||
filepath: getPurePath(tempFilePaths[0]),
|
||||
name: fileName,
|
||||
contentType: fileType,
|
||||
uuid: IMSDK.uuid(),
|
||||
});
|
||||
this.groupFaceUrl = url;
|
||||
} catch (error) {
|
||||
uni.$u.toast("上传失败");
|
||||
}
|
||||
},
|
||||
fail: function (err) {
|
||||
uni.$u.toast("上传失败");
|
||||
},
|
||||
});
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.create_group_container {
|
||||
@include colBox(false);
|
||||
height: 100vh;
|
||||
background-color: #f6f6f6;
|
||||
|
||||
.main {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.group_base_info {
|
||||
@include vCenterBox();
|
||||
padding: 44rpx;
|
||||
background-color: #fff;
|
||||
margin: 36rpx 0;
|
||||
|
||||
.u-input {
|
||||
margin-left: 48rpx;
|
||||
}
|
||||
}
|
||||
|
||||
.member_row {
|
||||
padding: 44rpx;
|
||||
background-color: #fff;
|
||||
color: #999;
|
||||
|
||||
.desc_title {
|
||||
@include vCenterBox();
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.member_list {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
margin-top: 24rpx;
|
||||
|
||||
.member_item {
|
||||
@include colBox(false);
|
||||
align-items: center;
|
||||
margin-right: 12rpx;
|
||||
|
||||
.member_name {
|
||||
@include nomalEllipsis();
|
||||
max-width: 42px;
|
||||
margin-top: 12rpx;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.action_bar {
|
||||
background-color: #fff;
|
||||
padding: 44rpx 44rpx;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
94
pages/common/detailsFileds/index.vue
Normal file
94
pages/common/detailsFileds/index.vue
Normal file
@@ -0,0 +1,94 @@
|
||||
<template>
|
||||
<view class="details_container">
|
||||
<custom-nav-bar title="个人资料" />
|
||||
|
||||
<view class="info_list">
|
||||
<user-info-row-item class="info_item" lable="头像" arrow>
|
||||
<my-avatar
|
||||
:src="sourceInfo.faceURL"
|
||||
:desc="sourceInfo.nickname"
|
||||
size="26"
|
||||
/>
|
||||
</user-info-row-item>
|
||||
<user-info-row-item class="info_item" lable="昵称" arrow>
|
||||
<text class="right_content">{{ sourceInfo.nickname }}</text>
|
||||
</user-info-row-item>
|
||||
<user-info-row-item class="info_item" lable="性别" arrow>
|
||||
<text class="right_content">{{ getGender }}</text>
|
||||
</user-info-row-item>
|
||||
<user-info-row-item class="info_item" lable="生日" arrow>
|
||||
<text class="right_content">{{ getBirthStr }}</text>
|
||||
</user-info-row-item>
|
||||
</view>
|
||||
|
||||
<view class="info_list">
|
||||
<user-info-row-item class="info_item" lable="手机号码" arrow>
|
||||
<text class="right_content">{{ sourceInfo.phoneNumber || "-" }}</text>
|
||||
</user-info-row-item>
|
||||
<user-info-row-item class="info_item" lable="邮箱" arrow>
|
||||
<text class="right_content">{{ sourceInfo.email || "-" }}</text>
|
||||
</user-info-row-item>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import dayjs from "dayjs";
|
||||
import CustomNavBar from "@/components/CustomNavBar/index.vue";
|
||||
import MyAvatar from "@/components/MyAvatar/index.vue";
|
||||
import UserInfoRowItem from "../userCard/components/UserInfoRowItem.vue";
|
||||
export default {
|
||||
components: {
|
||||
CustomNavBar,
|
||||
MyAvatar,
|
||||
UserInfoRowItem,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
sourceInfo: {},
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
getGender() {
|
||||
if (this.sourceInfo.gender === 1) {
|
||||
return "男";
|
||||
}
|
||||
if (this.sourceInfo.gender === 2) {
|
||||
return "女";
|
||||
}
|
||||
return "保密";
|
||||
},
|
||||
getBirthStr() {
|
||||
const birth = this.sourceInfo.birth ?? 0;
|
||||
return dayjs(birth).format("YYYY-MM-DD");
|
||||
},
|
||||
},
|
||||
onLoad(options) {
|
||||
const { sourceInfo } = options;
|
||||
this.sourceInfo = JSON.parse(sourceInfo);
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.details_container {
|
||||
@include colBox(false);
|
||||
height: 100vh;
|
||||
background-color: #f6f6f6;
|
||||
|
||||
.info_list {
|
||||
border-radius: 6px;
|
||||
overflow: hidden;
|
||||
margin: 24rpx;
|
||||
|
||||
.info_item {
|
||||
background-color: #fff;
|
||||
// border-bottom: 1px solid rgba(153, 153, 153, 0.3);
|
||||
|
||||
.right_content {
|
||||
color: #999;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
309
pages/common/groupCard/index.vue
Normal file
309
pages/common/groupCard/index.vue
Normal file
@@ -0,0 +1,309 @@
|
||||
<template>
|
||||
<view class="group_card_container">
|
||||
<custom-nav-bar title="" />
|
||||
<u-toast ref="uToast"></u-toast>
|
||||
|
||||
<view class="main">
|
||||
<view class="base_info">
|
||||
<my-avatar :src="sourceGroupInfo.faceURL" :isGroup="true" size="48" />
|
||||
<view>
|
||||
<view class="group_name">
|
||||
<text>{{ sourceGroupInfo.groupName }}</text>
|
||||
<text v-if="!!sourceGroupInfo.memberCount"
|
||||
>({{ sourceGroupInfo.memberCount }})</text
|
||||
>
|
||||
</view>
|
||||
<view class="create_time">
|
||||
<u-icon name="clock" color="#999" size="14"></u-icon>
|
||||
<text>{{ getCreateTime }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view
|
||||
v-if="!!sourceGroupInfo.memberCount"
|
||||
@click="toMemberList"
|
||||
class="member_row info_row"
|
||||
>
|
||||
<view class="member_desc">
|
||||
<text>群成员</text>
|
||||
<text class="member_count">{{
|
||||
`${sourceGroupInfo.memberCount}人`
|
||||
}}</text>
|
||||
<u-icon name="arrow-right" color="#999" size="18"></u-icon>
|
||||
</view>
|
||||
<view class="member_list">
|
||||
<my-avatar
|
||||
v-for="member in getRenderMemberList"
|
||||
:key="member.userID"
|
||||
class="member_item"
|
||||
size="42"
|
||||
:src="member.faceURL"
|
||||
:desc="member.nickname"
|
||||
></my-avatar>
|
||||
<u-avatar
|
||||
bgColor="#5496EB"
|
||||
icon="more-dot-fill"
|
||||
shape="square"
|
||||
size="42"
|
||||
></u-avatar>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="info_row">
|
||||
<user-info-row-item lable="群ID号" :content="sourceGroupInfo.groupID" />
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="action_row">
|
||||
<u-button type="primary" v-if="!isJoinedGroup" @click="joinGroup"
|
||||
>申请加入该群</u-button
|
||||
>
|
||||
<u-button type="primary" v-else @click="chatingInGroup">发消息</u-button>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { GroupMemberListTypes } from "@/constant";
|
||||
import { navigateToDesignatedConversation } from "@/util/imCommon";
|
||||
import IMSDK, {
|
||||
GroupVerificationType,
|
||||
SessionType,
|
||||
} from "openim-uniapp-polyfill";
|
||||
import dayjs from "dayjs";
|
||||
import MyAvatar from "@/components/MyAvatar/index.vue";
|
||||
import CustomNavBar from "@/components/CustomNavBar/index.vue";
|
||||
import UserInfoRowItem from "../userCard/components/UserInfoRowItem.vue";
|
||||
|
||||
import userIcon from "static/images/contact_my_friend.png";
|
||||
|
||||
export default {
|
||||
components: {
|
||||
CustomNavBar,
|
||||
MyAvatar,
|
||||
UserInfoRowItem,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
sourceID: "",
|
||||
isScan: false,
|
||||
sourceGroupInfo: {},
|
||||
groupMemberList: [],
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
isJoinedGroup() {
|
||||
return (
|
||||
this.$store.getters.storeGroupList.findIndex(
|
||||
(group) => group.groupID === this.sourceID,
|
||||
) !== -1
|
||||
);
|
||||
},
|
||||
getCreateTime() {
|
||||
return dayjs(this.sourceGroupInfo.createTime).format("YYYY-MM-DD");
|
||||
},
|
||||
getRenderMemberList() {
|
||||
if (this.isJoinedGroup) {
|
||||
this.groupMemberList;
|
||||
return this.groupMemberList;
|
||||
}
|
||||
const memberCount = this.sourceGroupInfo.memberCount ?? 0;
|
||||
return new Array(memberCount >= 6 ? 6 : memberCount)
|
||||
.fill(1)
|
||||
.map((item, idx) => ({
|
||||
userID: idx,
|
||||
src: userIcon,
|
||||
}));
|
||||
},
|
||||
},
|
||||
onLoad(options) {
|
||||
const { sourceID, sourceInfo, isScan } = options;
|
||||
this.isScan = !!isScan;
|
||||
if (sourceID) {
|
||||
this.sourceID = sourceID;
|
||||
this.getSourceGroupInfo();
|
||||
} else {
|
||||
const info = JSON.parse(sourceInfo);
|
||||
this.sourceID = info.groupID;
|
||||
this.sourceGroupInfo = {
|
||||
...info,
|
||||
};
|
||||
}
|
||||
this.getGroupMemberList();
|
||||
},
|
||||
methods: {
|
||||
toMemberList() {
|
||||
if (this.isJoinedGroup) {
|
||||
this.$store.dispatch("conversation/getCurrentGroup", this.sourceID);
|
||||
this.$store.dispatch(
|
||||
"conversation/getCurrentMemberInGroup",
|
||||
this.sourceID,
|
||||
);
|
||||
uni.navigateTo({
|
||||
url: `/pages/conversation/groupMemberList/index?type=${GroupMemberListTypes.Preview}&groupID=${this.sourceID}`,
|
||||
});
|
||||
}
|
||||
},
|
||||
joinGroup() {
|
||||
uni.$u.route("/pages/common/sendAddRequest/index", {
|
||||
isGroup: true,
|
||||
sourceID: this.sourceID,
|
||||
isScan: this.isScan,
|
||||
notNeedVerification:
|
||||
this.sourceGroupInfo.needVerification ===
|
||||
GroupVerificationType.AllNot,
|
||||
sessionType: SessionType.WorkingGroup,
|
||||
});
|
||||
},
|
||||
chatingInGroup() {
|
||||
navigateToDesignatedConversation(
|
||||
this.sourceID,
|
||||
SessionType.WorkingGroup,
|
||||
).catch(() => this.showToast("获取会话信息失败"));
|
||||
},
|
||||
async getSourceGroupInfo() {
|
||||
let info = null;
|
||||
if (this.isJoinedGroup) {
|
||||
info = this.$store.getters.storeGroupList.find(
|
||||
(group) => group.groupID === this.sourceID,
|
||||
);
|
||||
} else {
|
||||
try {
|
||||
const { data } = await IMSDK.asyncApi(
|
||||
IMSDK.IMMethods.GetSpecifiedGroupsInfo,
|
||||
IMSDK.uuid(),
|
||||
[this.sourceID],
|
||||
);
|
||||
info = data[0] ?? {};
|
||||
} catch (e) {
|
||||
info = {};
|
||||
}
|
||||
}
|
||||
this.sourceGroupInfo = {
|
||||
...info,
|
||||
};
|
||||
},
|
||||
getGroupMemberList() {
|
||||
if (this.isJoinedGroup) {
|
||||
IMSDK.asyncApi(IMSDK.IMMethods.GetGroupMemberList, IMSDK.uuid(), {
|
||||
groupID: this.sourceID,
|
||||
filter: 0,
|
||||
offset: 0,
|
||||
count: 6,
|
||||
}).then(({ data }) => {
|
||||
this.groupMemberList = [...data];
|
||||
});
|
||||
}
|
||||
},
|
||||
showToast(message) {
|
||||
this.$refs.uToast.show({
|
||||
message,
|
||||
});
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.group_card_container {
|
||||
@include colBox(false);
|
||||
height: 100vh;
|
||||
background-color: #f6f6f6;
|
||||
|
||||
.main {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.base_info {
|
||||
@include vCenterBox();
|
||||
background-color: #fff;
|
||||
padding: 44rpx;
|
||||
margin-bottom: 18rpx;
|
||||
|
||||
.u-avatar {
|
||||
margin-right: 24rpx;
|
||||
}
|
||||
|
||||
.group_name {
|
||||
display: flex;
|
||||
margin-bottom: 12rpx;
|
||||
}
|
||||
|
||||
.create_time {
|
||||
@include vCenterBox();
|
||||
justify-content: center;
|
||||
color: #adadad;
|
||||
font-size: 26rpx;
|
||||
|
||||
.u-icon {
|
||||
margin-right: 12rpx;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.member_row {
|
||||
padding: 24rpx 44rpx;
|
||||
|
||||
.member_desc {
|
||||
margin-bottom: 24rpx;
|
||||
position: relative;
|
||||
|
||||
.member_count {
|
||||
font-size: 28rpx;
|
||||
color: #adadad;
|
||||
margin-left: 24rpx;
|
||||
}
|
||||
|
||||
.u-icon {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.member_list {
|
||||
display: flex;
|
||||
|
||||
.member_item {
|
||||
margin-right: 12rpx;
|
||||
|
||||
&:nth-child(7) {
|
||||
margin-right: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.info_row {
|
||||
background-color: #fff;
|
||||
margin-bottom: 24rpx;
|
||||
|
||||
/deep/ .content {
|
||||
color: #adadad;
|
||||
}
|
||||
}
|
||||
|
||||
.action_row {
|
||||
background-color: #fff;
|
||||
padding: 44rpx 44rpx;
|
||||
}
|
||||
|
||||
.online_state {
|
||||
@include vCenterBox();
|
||||
margin-left: 24rpx;
|
||||
font-size: 24rpx;
|
||||
color: #999;
|
||||
|
||||
.dot {
|
||||
background-color: #10cc64;
|
||||
width: 12rpx;
|
||||
height: 12rpx;
|
||||
border-radius: 50%;
|
||||
margin-right: 12rpx;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
139
pages/common/markOrIDPage/index.vue
Normal file
139
pages/common/markOrIDPage/index.vue
Normal file
@@ -0,0 +1,139 @@
|
||||
<template>
|
||||
<view class="mark_id_container">
|
||||
<custom-nav-bar :title="getTitle">
|
||||
<view class="nav_right_action" slot="more">
|
||||
<text v-show="!loading" @click="saveOrCopy">{{ getConfirmText }}</text>
|
||||
<u-loading-icon v-show="loading" />
|
||||
</view>
|
||||
</custom-nav-bar>
|
||||
|
||||
<view class="content_row">
|
||||
<u-input
|
||||
:disabled="!isRemark && !isSelfNickname"
|
||||
v-model="content"
|
||||
disabledColor="transparent"
|
||||
maxlength="16"
|
||||
placeholder="请输入内容"
|
||||
clearable
|
||||
>
|
||||
</u-input>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import IMSDK from "openim-uniapp-polyfill";
|
||||
|
||||
import CustomNavBar from "@/components/CustomNavBar/index.vue";
|
||||
import { businessInfoUpdate } from "@/api/login";
|
||||
export default {
|
||||
components: {
|
||||
CustomNavBar,
|
||||
},
|
||||
props: {},
|
||||
data() {
|
||||
return {
|
||||
content: "",
|
||||
isRemark: false,
|
||||
isSelfNickname: false,
|
||||
sourceInfo: {},
|
||||
loading: false,
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
getTitle() {
|
||||
if (this.isRemark) {
|
||||
return "设置备注";
|
||||
}
|
||||
if (this.isSelfNickname) {
|
||||
return "我的姓名";
|
||||
}
|
||||
return "ID号";
|
||||
},
|
||||
getConfirmText() {
|
||||
return this.isRemark || this.isSelfNickname ? "保存" : "复制";
|
||||
},
|
||||
},
|
||||
onLoad(options) {
|
||||
const { isRemark, isSelfNickname, sourceInfo } = options;
|
||||
this.sourceInfo = JSON.parse(sourceInfo);
|
||||
this.isRemark = !!isRemark;
|
||||
if (this.isRemark) {
|
||||
this.content = this.sourceInfo.remark;
|
||||
}
|
||||
this.isSelfNickname = !!isSelfNickname;
|
||||
if (this.isSelfNickname) {
|
||||
this.content = this.sourceInfo.nickname;
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
async saveOrCopy() {
|
||||
if (this.isRemark) {
|
||||
this.loading = true;
|
||||
IMSDK.asyncApi(IMSDK.IMMethods.SetFriendRemark, IMSDK.uuid(), {
|
||||
toUserID: this.sourceInfo.userID,
|
||||
remark: this.content,
|
||||
})
|
||||
.then(() => {
|
||||
uni.$u.toast("设置成功");
|
||||
setTimeout(() => uni.navigateBack(), 1000);
|
||||
})
|
||||
.catch((error) => {
|
||||
console.log(error);
|
||||
uni.$u.toast("设置失败");
|
||||
})
|
||||
.finally(() => (this.loading = false));
|
||||
} else if (this.isSelfNickname) {
|
||||
this.loading = true;
|
||||
try {
|
||||
await businessInfoUpdate({
|
||||
userID: this.sourceInfo.userID,
|
||||
nickname: this.content,
|
||||
});
|
||||
await this.$store.dispatch("user/updateBusinessInfo");
|
||||
uni.$u.toast("修改成功");
|
||||
setTimeout(() => uni.navigateBack(), 1000);
|
||||
} catch (e) {
|
||||
console.log(e);
|
||||
uni.$u.toast("修改失败");
|
||||
}
|
||||
this.loading = false;
|
||||
} else {
|
||||
uni.setClipboardData({
|
||||
data: this.sourceInfo.userID,
|
||||
success: () => {
|
||||
uni.hideToast();
|
||||
this.$nextTick(() => {
|
||||
uni.$u.toast("复制成功");
|
||||
});
|
||||
},
|
||||
});
|
||||
}
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.mark_id_container {
|
||||
@include colBox(false);
|
||||
height: 100vh;
|
||||
|
||||
.nav_right_action {
|
||||
margin-right: 36rpx;
|
||||
}
|
||||
|
||||
.content_row {
|
||||
margin-top: 96rpx;
|
||||
margin: 72rpx 44rpx 0;
|
||||
|
||||
.u-input {
|
||||
background-color: #e8eaef;
|
||||
}
|
||||
|
||||
.u-button {
|
||||
height: 60rpx;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
172
pages/common/searchUserOrGroup/index.vue
Normal file
172
pages/common/searchUserOrGroup/index.vue
Normal file
@@ -0,0 +1,172 @@
|
||||
<template>
|
||||
<view class="search_container">
|
||||
<custom-nav-bar :route="false">
|
||||
<view slot="left"> </view>
|
||||
<view class="search_bar" slot="center">
|
||||
<u-search
|
||||
actionText="取消"
|
||||
@change="keywordChange"
|
||||
@custom="cancel"
|
||||
@search="startSearch"
|
||||
shape="square"
|
||||
:placeholder="getPlaceholder"
|
||||
v-model="keyword"
|
||||
/>
|
||||
</view>
|
||||
</custom-nav-bar>
|
||||
|
||||
<view v-show="!empty && !searching" @click="startSearch(keyword)" class="result_row">
|
||||
<image class="icon" :src="getIcon" alt="" />
|
||||
<view class="">
|
||||
<text>查找:</text>
|
||||
<text>{{ keyword }}</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view v-show="searching && !empty" class="result_row result_row_empty">
|
||||
<u-loading-icon></u-loading-icon>
|
||||
</view>
|
||||
|
||||
<view v-show="empty" class="result_row result_row_empty">
|
||||
<text>未搜索到相关结果</text>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import IMSDK from "openim-uniapp-polyfill";
|
||||
import CustomNavBar from "@/components/CustomNavBar/index.vue";
|
||||
|
||||
import searchGroup from "static/images/contact_add_join_group_fill.png";
|
||||
import searchUser from "static/images/contact_add_search_user_fill.png";
|
||||
import { businessSearchUserInfo } from "@/api/login";
|
||||
|
||||
export default {
|
||||
components: {
|
||||
CustomNavBar,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
keyword: "",
|
||||
searching: false,
|
||||
empty: false,
|
||||
isSearchGroup: false,
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
getIcon() {
|
||||
return this.isSearchGroup ? searchGroup : searchUser;
|
||||
},
|
||||
getPlaceholder() {
|
||||
return this.isSearchGroup ? "请输入群聊ID" : "搜索ID或手机号添加好友";
|
||||
},
|
||||
},
|
||||
onLoad(options) {
|
||||
const { isSearchGroup } = options;
|
||||
this.isSearchGroup = JSON.parse(isSearchGroup);
|
||||
},
|
||||
methods: {
|
||||
cancel() {
|
||||
console.log("cancel");
|
||||
uni.navigateBack();
|
||||
},
|
||||
keywordChange() {
|
||||
if (this.empty) {
|
||||
this.empty = !this.empty;
|
||||
}
|
||||
},
|
||||
async startSearch(value) {
|
||||
if (!value) return;
|
||||
this.searching = true;
|
||||
try {
|
||||
if (this.isSearchGroup) {
|
||||
let info = this.$store.getters.storeGroupList.find(
|
||||
(item) => item.groupID === value,
|
||||
);
|
||||
if (!info) {
|
||||
const { data } = await IMSDK.asyncApi(
|
||||
IMSDK.IMMethods.GetSpecifiedGroupsInfo,
|
||||
IMSDK.uuid(),
|
||||
[value],
|
||||
);
|
||||
info = data[0];
|
||||
}
|
||||
if (info) {
|
||||
uni.navigateTo({
|
||||
url: `/pages/common/groupCard/index?sourceInfo=${JSON.stringify(
|
||||
info,
|
||||
)}`,
|
||||
});
|
||||
} else {
|
||||
this.empty = true;
|
||||
}
|
||||
} else {
|
||||
let info = this.$store.getters.storeFriendList.find(
|
||||
(item) => item.userID === value,
|
||||
);
|
||||
if (!info) {
|
||||
const { total, users } = await businessSearchUserInfo(value);
|
||||
if (total > 0) {
|
||||
const { data } = await IMSDK.asyncApi(
|
||||
IMSDK.IMMethods.GetUsersInfo,
|
||||
IMSDK.uuid(),
|
||||
[users[0].userID],
|
||||
);
|
||||
const imData = data[0];
|
||||
|
||||
info = {
|
||||
...imData,
|
||||
...users[0],
|
||||
};
|
||||
}
|
||||
}
|
||||
if (info) {
|
||||
uni.navigateTo({
|
||||
url: `/pages/common/userCard/index?sourceInfo=${JSON.stringify(
|
||||
info,
|
||||
)}`,
|
||||
});
|
||||
} else {
|
||||
this.empty = true;
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
//TODO handle the exception
|
||||
}
|
||||
this.searching = false;
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.search_container {
|
||||
height: 100vh;
|
||||
background-color: #f8f8f8;
|
||||
|
||||
.search_bar {
|
||||
width: 100%;
|
||||
padding: 0 44rpx;
|
||||
}
|
||||
|
||||
.result_row {
|
||||
@include vCenterBox();
|
||||
padding: 24rpx 44rpx;
|
||||
font-size: 28rpx;
|
||||
color: $uni-text-color;
|
||||
background-color: #fff;
|
||||
|
||||
.icon {
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
margin-right: 24rpx;
|
||||
}
|
||||
|
||||
&_empty {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
color: #999;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
125
pages/common/sendAddRequest/index.vue
Normal file
125
pages/common/sendAddRequest/index.vue
Normal file
@@ -0,0 +1,125 @@
|
||||
<template>
|
||||
<view class="request_join_container">
|
||||
<custom-nav-bar :title="isGroup ? '群聊验证' : '好友验证'">
|
||||
<view class="top_right_btn" slot="more">
|
||||
<u-button @click="sendRequest" text="发送" type="primary"></u-button>
|
||||
</view>
|
||||
</custom-nav-bar>
|
||||
|
||||
<text class="title">{{ `发送${isGroup ? "入群" : "好友"}申请` }}</text>
|
||||
|
||||
<view class="input_container">
|
||||
<u--textarea
|
||||
height="120"
|
||||
v-model="reason"
|
||||
border="none"
|
||||
placeholder="请输入内容"
|
||||
maxlength="20"
|
||||
count
|
||||
>
|
||||
</u--textarea>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import IMSDK, { GroupJoinSource } from "openim-uniapp-polyfill";
|
||||
import CustomNavBar from "@/components/CustomNavBar/index.vue";
|
||||
import { navigateToDesignatedConversation } from "@/util/imCommon";
|
||||
|
||||
export default {
|
||||
components: {
|
||||
CustomNavBar,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
reason: "",
|
||||
sourceID: "",
|
||||
isGroup: false,
|
||||
isScan: false,
|
||||
notNeedVerification: false,
|
||||
sessionType: 0,
|
||||
};
|
||||
},
|
||||
onLoad(options) {
|
||||
const { isGroup, sourceID, isScan, notNeedVerification, sessionType } =
|
||||
options;
|
||||
this.isGroup = JSON.parse(isGroup);
|
||||
this.isScan = JSON.parse(isScan);
|
||||
this.sourceID = sourceID;
|
||||
this.notNeedVerification = JSON.parse(notNeedVerification);
|
||||
this.sessionType = sessionType ?? 0;
|
||||
},
|
||||
methods: {
|
||||
sendRequest() {
|
||||
let func;
|
||||
if (this.isGroup) {
|
||||
const joinSource = this.isScan
|
||||
? GroupJoinSource.QrCode
|
||||
: GroupJoinSource.Search;
|
||||
func = IMSDK.asyncApi(IMSDK.IMMethods.JoinGroup, IMSDK.uuid(), {
|
||||
groupID: this.sourceID,
|
||||
reqMsg: this.reason,
|
||||
joinSource,
|
||||
});
|
||||
} else {
|
||||
func = IMSDK.asyncApi(IMSDK.IMMethods.AddFriend, IMSDK.uuid(), {
|
||||
toUserID: this.sourceID,
|
||||
reqMsg: this.reason,
|
||||
});
|
||||
}
|
||||
func
|
||||
.then(() => {
|
||||
uni.$u.toast(this.notNeedVerification ? "你已加入该群" : "发送成功");
|
||||
setTimeout(() => {
|
||||
if (this.notNeedVerification) {
|
||||
navigateToDesignatedConversation(
|
||||
this.sourceID,
|
||||
Number(this.sessionType),
|
||||
).catch(() => this.showToast("获取会话信息失败"));
|
||||
} else {
|
||||
uni.navigateBack();
|
||||
}
|
||||
}, 1000);
|
||||
})
|
||||
.catch((err) => {
|
||||
console.log(err);
|
||||
uni.$u.toast("发送失败");
|
||||
});
|
||||
},
|
||||
showToast(message) {
|
||||
this.$refs.uToast.show({
|
||||
message,
|
||||
});
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.request_join_container {
|
||||
@include colBox(false);
|
||||
height: 100vh;
|
||||
background-color: #f6f6f6;
|
||||
|
||||
.top_right_btn {
|
||||
margin-right: 44rpx;
|
||||
|
||||
.u-button {
|
||||
height: 48rpx;
|
||||
}
|
||||
}
|
||||
|
||||
.title {
|
||||
font-size: 28rpx;
|
||||
color: #999;
|
||||
margin: 24rpx 44rpx;
|
||||
}
|
||||
|
||||
.input_container {
|
||||
/deep/.u-textarea {
|
||||
padding: 24rpx 44rpx !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
51
pages/common/userCard/components/UserInfoRowItem.vue
Normal file
51
pages/common/userCard/components/UserInfoRowItem.vue
Normal file
@@ -0,0 +1,51 @@
|
||||
<template>
|
||||
<view @click="click" class="row_item" :class="{ arrow_right: arrow }">
|
||||
<view class="title">
|
||||
<text>{{ lable }}</text>
|
||||
</view>
|
||||
<view class="content">
|
||||
<text>{{ content }}</text>
|
||||
</view>
|
||||
<slot>
|
||||
<u-icon v-if="arrow" name="arrow-right" color="#999" size="20"></u-icon>
|
||||
</slot>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: "",
|
||||
components: {},
|
||||
props: {
|
||||
lable: String,
|
||||
content: String,
|
||||
arrow: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {};
|
||||
},
|
||||
methods: {
|
||||
click() {
|
||||
this.$emit("click");
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.row_item {
|
||||
@include vCenterBox();
|
||||
padding: 24rpx 44rpx;
|
||||
}
|
||||
|
||||
.title {
|
||||
margin-right: 24rpx;
|
||||
}
|
||||
|
||||
.arrow_right {
|
||||
justify-content: space-between;
|
||||
}
|
||||
</style>
|
||||
298
pages/common/userCard/index.vue
Normal file
298
pages/common/userCard/index.vue
Normal file
@@ -0,0 +1,298 @@
|
||||
<template>
|
||||
<view class="user_card_container">
|
||||
<u-loading-page :loading="isLoading" loading-text="loading..."></u-loading-page>
|
||||
<custom-nav-bar title="" />
|
||||
|
||||
<view v-if="!isLoading" style="flex: 1;display: flex;flex-direction: column;">
|
||||
<view class="base_info">
|
||||
<my-avatar
|
||||
:desc="sourceUserInfo.remark || sourceUserInfo.nickname"
|
||||
:src="sourceUserInfo.faceURL"
|
||||
size="46"
|
||||
/>
|
||||
<view class="user_name">
|
||||
<text class="text">{{ getShowName }}</text>
|
||||
<text class="id" @click="copy(sourceUserInfo.userID)">{{
|
||||
sourceUserInfo.userID
|
||||
}}</text>
|
||||
</view>
|
||||
<view class="add_btn" @click="toAddFriend" v-if="trySendRequest">
|
||||
<u-button type="primary" icon="man-add" text="添加"></u-button>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view v-if="isFriend" class="info_row">
|
||||
<user-info-row-item @click="toMoreInfo" lable="个人资料" arrow />
|
||||
</view>
|
||||
|
||||
<view class="action_row" v-if="!isSelf">
|
||||
<view @click="toDesignatedConversation" class="action_item">
|
||||
<img src="static/images/user_card_message.png" alt="" />
|
||||
<text>发消息</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapGetters } from "vuex";
|
||||
import { navigateToDesignatedConversation } from "@/util/imCommon";
|
||||
import IMSDK, {
|
||||
SessionType,
|
||||
} from "openim-uniapp-polyfill";
|
||||
import MyAvatar from "@/components/MyAvatar/index.vue";
|
||||
import CustomNavBar from "@/components/CustomNavBar/index.vue";
|
||||
import UserInfoRowItem from "./components/UserInfoRowItem.vue";
|
||||
import { businessSearchUserInfo } from "@/api/login";
|
||||
|
||||
export default {
|
||||
components: {
|
||||
CustomNavBar,
|
||||
MyAvatar,
|
||||
UserInfoRowItem,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
isLoading: false,
|
||||
sourceID: "",
|
||||
sourceUserInfo: {},
|
||||
switchLoading: false,
|
||||
showSetRole: false,
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
...mapGetters([
|
||||
"storeFriendList",
|
||||
"storeSelfInfo",
|
||||
]),
|
||||
isFriend() {
|
||||
return (
|
||||
this.storeFriendList.findIndex(
|
||||
(friend) => friend.userID === this.sourceID,
|
||||
) !== -1
|
||||
);
|
||||
},
|
||||
trySendRequest() {
|
||||
return !this.isFriend && !this.isSelf
|
||||
},
|
||||
isSelf() {
|
||||
return this.sourceID === this.storeSelfInfo.userID;
|
||||
},
|
||||
getShowName() {
|
||||
let suffix = "";
|
||||
if (this.sourceUserInfo.remark) {
|
||||
suffix = `(${this.sourceUserInfo.remark})`;
|
||||
}
|
||||
return this.sourceUserInfo.nickname + suffix;
|
||||
},
|
||||
},
|
||||
onLoad(options) {
|
||||
const { sourceID, sourceInfo } = options;
|
||||
if (sourceID) {
|
||||
this.sourceID = sourceID;
|
||||
} else {
|
||||
const info = JSON.parse(sourceInfo);
|
||||
this.sourceID = info.userID;
|
||||
}
|
||||
this.getSourceUserInfo();
|
||||
},
|
||||
methods: {
|
||||
copy(userID) {
|
||||
uni.setClipboardData({
|
||||
showToast: false,
|
||||
data: userID,
|
||||
success: function () {
|
||||
uni.showToast({
|
||||
icon: "none",
|
||||
title: "复制成功",
|
||||
});
|
||||
},
|
||||
});
|
||||
},
|
||||
async getSourceUserInfo() {
|
||||
let info = {};
|
||||
const friendInfo = this.storeFriendList.find((item) => item.userID === this.sourceID);
|
||||
if (friendInfo) {
|
||||
info = { ...friendInfo };
|
||||
}
|
||||
else {
|
||||
const { data } = await IMSDK.asyncApi(
|
||||
IMSDK.IMMethods.GetUsersInfo,
|
||||
IMSDK.uuid(),
|
||||
[this.sourceID],
|
||||
);
|
||||
info = { ...(data[0] ?? {}) };
|
||||
}
|
||||
this.isLoading = true
|
||||
try {
|
||||
const { total, users } = await businessSearchUserInfo(this.sourceID);
|
||||
if (total > 0) {
|
||||
const { data } = await IMSDK.asyncApi(
|
||||
IMSDK.IMMethods.GetUsersInfo,
|
||||
IMSDK.uuid(),
|
||||
[this.sourceID],
|
||||
);
|
||||
const imData = data[0]?.friendInfo ?? data[0]?.publicInfo ?? {};
|
||||
info = {
|
||||
...imData,
|
||||
...users[0],
|
||||
};
|
||||
}
|
||||
} catch (e) {
|
||||
info = {};
|
||||
}
|
||||
this.isLoading = false
|
||||
this.sourceUserInfo = {
|
||||
...info,
|
||||
};
|
||||
},
|
||||
toAddFriend() {
|
||||
uni.$u.route("/pages/common/sendAddRequest/index", {
|
||||
isGroup: false,
|
||||
sourceID: this.sourceID,
|
||||
isScan: false,
|
||||
notNeedVerification: false,
|
||||
});
|
||||
},
|
||||
toDesignatedConversation() {
|
||||
navigateToDesignatedConversation(
|
||||
this.sourceID,
|
||||
SessionType.Single,
|
||||
false,
|
||||
).catch(() => uni.$u.toast("获取会话信息失败"));
|
||||
},
|
||||
toMoreInfo() {
|
||||
uni.navigateTo({
|
||||
url: `/pages/common/userCardMore/index?sourceInfo=${JSON.stringify(
|
||||
this.sourceUserInfo,
|
||||
)}`,
|
||||
});
|
||||
}
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.user_card_container {
|
||||
@include colBox(false);
|
||||
height: 100vh;
|
||||
background-color: #f6f6f6;
|
||||
overflow-y: auto;
|
||||
position: relative;
|
||||
|
||||
.base_info {
|
||||
@include vCenterBox();
|
||||
background-color: #fff;
|
||||
padding: 44rpx;
|
||||
margin-bottom: 18rpx;
|
||||
|
||||
.add_btn {
|
||||
width: 140rpx;
|
||||
height: 60rpx;
|
||||
margin-left: auto;
|
||||
|
||||
.u-button {
|
||||
width: 140rpx;
|
||||
height: 60rpx;
|
||||
}
|
||||
}
|
||||
|
||||
.u-avatar {
|
||||
margin-right: 24rpx;
|
||||
}
|
||||
|
||||
.user_name {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 12rpx;
|
||||
height: 46px;
|
||||
|
||||
.text {
|
||||
@include nomalEllipsis();
|
||||
max-width: 300rpx;
|
||||
}
|
||||
}
|
||||
|
||||
.company {
|
||||
font-size: 28rpx;
|
||||
color: $u-primary;
|
||||
}
|
||||
}
|
||||
|
||||
.info_row {
|
||||
background-color: #fff;
|
||||
margin-bottom: 24rpx;
|
||||
}
|
||||
|
||||
.mute_right {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.company_row {
|
||||
padding: 20rpx 0;
|
||||
|
||||
.desc_title {
|
||||
padding-left: 44rpx;
|
||||
}
|
||||
|
||||
/deep/.title {
|
||||
width: 200rpx;
|
||||
color: #999 !important;
|
||||
}
|
||||
}
|
||||
|
||||
.action_row {
|
||||
@include vCenterBox();
|
||||
align-items: flex-end;
|
||||
justify-content: space-around;
|
||||
margin: 44rpx;
|
||||
flex: 1;
|
||||
|
||||
.action_item {
|
||||
width: 100%;
|
||||
@include colBox(true);
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 22rpx 0;
|
||||
background: $u-primary;
|
||||
color: #fff;
|
||||
border-radius: 12rpx;
|
||||
|
||||
img {
|
||||
margin-right: 16rpx;
|
||||
width: 40rpx;
|
||||
height: 40rpx;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.id {
|
||||
font-size: 24rpx;
|
||||
color: #999;
|
||||
}
|
||||
|
||||
.online_state {
|
||||
@include vCenterBox();
|
||||
margin-left: 24rpx;
|
||||
font-size: 24rpx;
|
||||
color: #999;
|
||||
|
||||
.dot {
|
||||
background-color: #10cc64;
|
||||
width: 12rpx;
|
||||
height: 12rpx;
|
||||
border-radius: 50%;
|
||||
margin-right: 12rpx;
|
||||
}
|
||||
|
||||
.online_str {
|
||||
@include nomalEllipsis();
|
||||
max-width: 280rpx;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
156
pages/common/userCardMore/index.vue
Normal file
156
pages/common/userCardMore/index.vue
Normal file
@@ -0,0 +1,156 @@
|
||||
<template>
|
||||
<view class="user_more_container">
|
||||
<custom-nav-bar title="好友设置" />
|
||||
|
||||
<view class="info_row">
|
||||
<user-info-row-item @click="toMark" lable="设置备注" arrow />
|
||||
<user-info-row-item @click="toMore" lable="个人资料" arrow />
|
||||
</view>
|
||||
|
||||
<view class="info_row">
|
||||
<user-info-row-item lable="加入黑名单" arrow>
|
||||
<u-switch
|
||||
asyncChange
|
||||
:loading="blackLoading"
|
||||
size="20"
|
||||
:value="isBlacked"
|
||||
@change="change"
|
||||
></u-switch>
|
||||
</user-info-row-item>
|
||||
</view>
|
||||
|
||||
<view v-if="isFriend" class="info_row">
|
||||
<u-button
|
||||
@click="() => (showConfirm = true)"
|
||||
type="error"
|
||||
plain
|
||||
text="解除好友关系"
|
||||
></u-button>
|
||||
</view>
|
||||
<u-toast ref="uToast"></u-toast>
|
||||
<u-modal
|
||||
:content="`确定要解除与${sourceInfo.nickname}的好友关系吗?`"
|
||||
asyncClose
|
||||
:show="showConfirm"
|
||||
showCancelButton
|
||||
@confirm="confirmRemove"
|
||||
@cancel="() => (showConfirm = false)"
|
||||
></u-modal>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import IMSDK from "openim-uniapp-polyfill";
|
||||
import CustomNavBar from "@/components/CustomNavBar/index.vue";
|
||||
import UserInfoRowItem from "../userCard/components/UserInfoRowItem.vue";
|
||||
import { ContactChooseTypes } from "@/constant";
|
||||
export default {
|
||||
components: {
|
||||
CustomNavBar,
|
||||
UserInfoRowItem,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
blackLoading: false,
|
||||
sourceInfo: {},
|
||||
showConfirm: false,
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
isFriend() {
|
||||
return (
|
||||
this.$store.getters.storeFriendList.findIndex(
|
||||
(friend) => friend.userID === this.sourceInfo.userID,
|
||||
) !== -1
|
||||
);
|
||||
},
|
||||
isBlacked() {
|
||||
return (
|
||||
this.$store.getters.storeBlackList.findIndex(
|
||||
(black) => black.userID === this.sourceInfo.userID,
|
||||
) !== -1
|
||||
);
|
||||
},
|
||||
},
|
||||
onLoad(options) {
|
||||
const { sourceInfo } = options;
|
||||
this.sourceInfo = JSON.parse(sourceInfo);
|
||||
},
|
||||
methods: {
|
||||
change(isBlack) {
|
||||
this.blackLoading = true;
|
||||
if (isBlack) {
|
||||
IMSDK.asyncApi(IMSDK.IMMethods.AddBlack, IMSDK.uuid(), {
|
||||
toUserID: this.sourceInfo.userID,
|
||||
ex: "",
|
||||
})
|
||||
.catch(() => this.showToast("操作失败"))
|
||||
.finally(() => (this.blackLoading = false));
|
||||
return;
|
||||
}
|
||||
IMSDK.asyncApi(
|
||||
IMSDK.IMMethods.RemoveBlack,
|
||||
IMSDK.uuid(),
|
||||
this.sourceInfo.userID
|
||||
)
|
||||
.catch(() => this.showToast("操作失败"))
|
||||
.finally(() => (this.blackLoading = false));
|
||||
},
|
||||
confirmRemove() {
|
||||
IMSDK.asyncApi(
|
||||
IMSDK.IMMethods.DeleteFriend,
|
||||
IMSDK.uuid(),
|
||||
this.sourceInfo.userID,
|
||||
)
|
||||
.then(() => this.showToast("操作成功"))
|
||||
.catch(() => this.showToast("操作失败"))
|
||||
.finally(() => (this.showConfirm = false));
|
||||
},
|
||||
toMore() {
|
||||
uni.navigateTo({
|
||||
url: `/pages/common/detailsFileds/index?sourceInfo=${JSON.stringify(
|
||||
this.sourceInfo,
|
||||
)}`,
|
||||
});
|
||||
},
|
||||
toMark() {
|
||||
uni.navigateTo({
|
||||
url: `/pages/common/markOrIDPage/index?isRemark=true&sourceInfo=${JSON.stringify(
|
||||
this.sourceInfo,
|
||||
)}`,
|
||||
});
|
||||
},
|
||||
toShare() {
|
||||
uni.navigateTo({
|
||||
url: `/pages/common/contactChoose/index?type=${
|
||||
ContactChooseTypes.ShareCard
|
||||
}&cardInfo=${JSON.stringify(this.sourceInfo)}`,
|
||||
});
|
||||
},
|
||||
showToast(message) {
|
||||
this.$refs.uToast.show({
|
||||
message,
|
||||
});
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.user_more_container {
|
||||
@include colBox(false);
|
||||
height: 100vh;
|
||||
background-color: #f6f6f6;
|
||||
|
||||
.info_row {
|
||||
background-color: #fff;
|
||||
margin: 24rpx;
|
||||
border-radius: 6px;
|
||||
overflow: hidden;
|
||||
|
||||
.u-button {
|
||||
border: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
18
pages/common/webviewWrapper/index.vue
Normal file
18
pages/common/webviewWrapper/index.vue
Normal file
@@ -0,0 +1,18 @@
|
||||
<template>
|
||||
<web-view :src="url"></web-view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
url: "",
|
||||
};
|
||||
},
|
||||
onLoad(options) {
|
||||
this.url = decodeURIComponent(options.url);
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss"></style>
|
||||
Reference in New Issue
Block a user