Initial commit

This commit is contained in:
2025-07-04 16:18:58 +08:00
commit 2cf13f673d
770 changed files with 73394 additions and 0 deletions

View File

@@ -0,0 +1,256 @@
<template>
<view class="page_container">
<custom-nav-bar :title="isGroupApplication ? '群通知' : '好友请求'" />
<view class="application_item">
<view class="base_info_row">
<view class="base_info_left" @click="toSourceDetails">
<my-avatar :src="getSourceFaceURL" :desc="getSourceName" />
<view class="base_info_details">
<text class="nickname">{{ getSourceName }}</text>
</view>
</view>
<u-icon name="arrow-right" size="18" color="#999"></u-icon>
</view>
<view class="request_message">
<view v-if="isGroupApplication" class="title">
<text>申请加入 </text>
<text class="group_name">{{ currentApplication.groupName }}</text>
</view>
<text v-else>{{ `${getSourceName}` }}</text>
<text>{{ currentApplication.reqMsg }}</text>
</view>
</view>
<view class="action_row">
<u-button
:loading="loadingState.accept"
@click="acceptAplication"
type="primary"
:plain="true"
:text="`通过${isGroupApplication ? '入群' : '好友'}申请`"
></u-button>
</view>
<view class="action_row">
<u-button
:loading="loadingState.refuse"
@click="refuseAplication"
type="primary"
:plain="true"
:text="`拒绝${isGroupApplication ? '入群' : '好友'}申请`"
></u-button>
</view>
</view>
</template>
<script>
import { mapGetters } from "vuex";
import IMSDK, { GroupJoinSource } from "openim-uniapp-polyfill";
import CustomNavBar from "@/components/CustomNavBar/index.vue";
import MyAvatar from "@/components/MyAvatar/index.vue";
export default {
components: {
CustomNavBar,
MyAvatar,
},
data() {
return {
currentApplication: {},
isOnline: false,
loadingState: {
accept: false,
refuse: false,
},
};
},
computed: {
...mapGetters(["storeSelfInfo"]),
isGroupApplication() {
return this.currentApplication.groupID !== undefined;
},
getSourceID() {
return (
this.currentApplication.fromUserID ?? this.currentApplication.userID
);
},
getSourceName() {
return (
this.currentApplication.fromNickname ?? this.currentApplication.nickname
);
},
getSourceFaceURL() {
return (
this.currentApplication.fromFaceURL ?? this.currentApplication.faceURL
);
},
},
onLoad(options) {
const { application } = options;
this.currentApplication = JSON.parse(application);
},
methods: {
toSourceDetails() {
uni.navigateTo({
url: `/pages/common/userCard/index?sourceID=${this.getSourceID}`,
});
},
acceptAplication() {
this.loadingState.accept = true;
let func;
if (this.isGroupApplication) {
func = IMSDK.asyncApi(
IMSDK.IMMethods.AcceptGroupApplication,
IMSDK.uuid(),
{
groupID: this.currentApplication.groupID,
fromUserID: this.currentApplication.userID,
handleMsg: "",
},
);
} else {
console.log(this.currentApplication);
func = IMSDK.asyncApi(
IMSDK.IMMethods.AcceptFriendApplication,
IMSDK.uuid(),
{
toUserID: this.currentApplication.fromUserID,
handleMsg: "",
},
);
}
func
.then(() => {
uni.$u.toast("操作成功");
setTimeout(() => uni.navigateBack(), 500);
})
.catch((e) => {
console.log(e);
uni.$u.toast("操作失败");
})
.finally(() => (this.loadingState.accept = false));
},
refuseAplication() {
this.loadingState.refuse = true;
let func;
if (this.isGroupApplication) {
func = IMSDK.asyncApi(
IMSDK.IMMethods.RefuseGroupApplication,
IMSDK.uuid(),
{
groupID: this.currentApplication.groupID,
fromUserID: this.currentApplication.userID,
handleMsg: "",
},
);
} else {
func = IMSDK.asyncApi(
IMSDK.IMMethods.RefuseFriendApplication,
IMSDK.uuid(),
{
toUserID: this.currentApplication.fromUserID,
handleMsg: "",
},
);
}
func
.then(() => {
uni.$u.toast("操作成功");
setTimeout(() => uni.navigateBack(), 250);
})
.catch(() => uni.$u.toast("操作失败"))
.finally(() => (this.loadingState.refuse = false));
},
},
};
</script>
<style lang="scss" scoped>
.page_container {
background-color: #f8f8f8;
.application_item {
padding: 72rpx 44rpx 24rpx;
background-color: #fff;
.base_info_row {
@include btwBox();
.base_info_left {
@include vCenterBox();
}
.base_info_details {
margin-left: 24rpx;
.nickname {
@include nomalEllipsis();
max-width: 600rpx;
}
.online_state {
@include vCenterBox();
flex-direction: row;
font-size: 24rpx;
color: #999;
margin-top: 6rpx;
.dot {
background-color: #10cc64;
width: 12rpx;
height: 12rpx;
border-radius: 50%;
margin-right: 12rpx;
}
}
}
}
.request_message {
background-color: #eee;
margin-top: 48rpx;
padding: 24rpx 36rpx;
border-radius: 12rpx;
font-size: 28rpx;
color: #666;
min-height: 240rpx;
.title {
margin-bottom: 12rpx;
color: $uni-text-color;
.group_name {
@nomalEllipsis();
max-width: 400rpx;
color: $uni-color-primary;
margin-left: 12rpx;
}
}
}
.join_source {
margin-top: 20rpx;
font-size: 24rpx;
color: #666;
text-align: right;
}
}
.action_row {
margin-top: 24rpx;
.u-button {
border: none;
}
&:last-child {
.u-button {
color: #999 !important;
}
}
}
}
</style>

View File

@@ -0,0 +1,246 @@
<template>
<view @click="clickItem" class="application_item">
<my-avatar
:src="getAvatarUrl"
:isGroup="isGroupApplication"
:desc="application[isRecv ? 'fromNickname' : 'toNickname']"
size="42"
/>
<view class="application_item_details">
<view class="content">
<text class="user_name">{{ getShowName }}</text>
<view v-if="isGroupApplication" class="title">
申请加入
<text class="group_name">{{ application.groupName }}</text>
</view>
<text class="req_message">{{ application.reqMsg }}</text>
</view>
<view class="application_action">
<text v-if="showStateStr" class="status_tip">{{ getStateStr }}</text>
<text v-if="showGreet" @tap.stop="greetToUser" class="status_tip greet"
>打招呼</text
>
<button
:loading="accessLoading"
v-if="showAccept"
class="access_btn"
@tap.stop="acceptApplication"
type="primary"
:plain="true"
size="mini"
>
{{ isGroupApplication ? "同意" : "接受" }}
</button>
</view>
<view class="bottom_line"> </view>
</view>
</view>
</template>
<script>
import { navigateToDesignatedConversation } from "@/util/imCommon";
import IMSDK, { SessionType } from "openim-uniapp-polyfill";
import MyAvatar from "@/components/MyAvatar/index.vue";
export default {
name: "ApplicationItem",
components: {
MyAvatar,
},
props: {
application: Object,
isRecv: Boolean,
},
data() {
return {
accessLoading: false,
};
},
computed: {
isGroupApplication() {
return this.application.groupID !== undefined;
},
getShowName() {
if (this.isRecv) {
return this.application[
this.isGroupApplication ? "nickname" : "fromNickname"
];
}
return this.application[
this.isGroupApplication ? "groupName" : "toNickname"
];
},
showGreet() {
return !this.isGroupApplication && this.application.handleResult === 1;
},
showStateStr() {
if (
(this.isRecv && this.application.handleResult === 0) ||
this.showGreet
) {
return false;
}
return true;
},
showAccept() {
return this.application.handleResult === 0 && this.isRecv;
},
getStateStr() {
if (this.application.handleResult === -1) {
return "已拒绝";
}
if (this.application.handleResult === 0) {
return "等待验证";
}
return "已同意";
},
getAvatarUrl() {
if (this.isGroupApplication) {
return this.application.groupFaceURL;
}
return this.application[this.isRecv ? "fromFaceURL" : "toFaceURL"];
},
},
methods: {
clickItem() {
if (this.showAccept) {
uni.navigateTo({
url: `/pages/contact/applicationDetails/index?application=${JSON.stringify(
this.application,
)}`,
});
} else {
let sourceID =
this.application.groupID ??
(this.isRecv
? this.application.fromUserID
: this.application.toUserID);
let cardType = this.isGroupApplication ? "groupCard" : "userCard";
const url = `/pages/common/${cardType}/index?sourceID=${sourceID}`;
uni.navigateTo({
url,
});
}
},
acceptApplication() {
this.accessLoading = true;
let func;
if (this.isGroupApplication) {
func = IMSDK.asyncApi(
IMSDK.IMMethods.AcceptGroupApplication,
IMSDK.uuid(),
{
groupID: this.application.groupID,
fromUserID: this.application.userID,
handleMsg: "",
},
);
} else {
func = IMSDK.asyncApi(
IMSDK.IMMethods.AcceptFriendApplication,
IMSDK.uuid(),
{
toUserID: this.application.fromUserID,
handleMsg: "",
},
);
}
func
.then(() => uni.$u.toast("操作成功"))
.catch(() => uni.$u.toast("操作失败"))
.finally(() => (this.accessLoading = false));
},
greetToUser() {
navigateToDesignatedConversation(
this.application[this.isRecv ? "fromUserID" : "toUserID"],
SessionType.Single,
).catch(() => uni.$u.toast("获取会话信息失败"));
},
},
};
</script>
<style lang="scss" scoped>
.application_item {
// @include vCenterBox();
display: flex;
justify-content: flex-start;
padding: 24rpx 44rpx;
color: $uni-text-color;
background-color: #fff;
&_details {
@include vCenterBox();
margin-left: 24rpx;
width: 100%;
position: relative;
.content {
@include colBox(false);
font-size: 26rpx;
width: 100%;
.user_name {
@include nomalEllipsis();
max-width: 400rpx;
font-size: 28rpx;
color: $uni-text-color;
margin-bottom: 10rpx;
}
.req_message {
@include ellipsisWithLine(2);
max-width: 80%;
color: #999;
}
.title {
margin-bottom: 20rpx;
word-break: break-all;
width: 75%;
.group_name {
margin-left: 12rpx;
color: $uni-color-primary;
}
}
}
.application_action {
position: absolute;
right: 0;
.status_tip {
font-size: 28rpx;
color: #666;
}
.access_btn {
padding: 0 12rpx;
height: 48rpx;
line-height: 48rpx;
}
.greet {
color: #418ae5;
}
}
.bottom_line {
height: 1px;
width: 100%;
background-color: #f0f0f0;
position: absolute;
bottom: -24rpx;
}
}
}
.u-list-item:last-child {
.bottom_line {
height: 0;
}
}
</style>

View File

@@ -0,0 +1,173 @@
<template>
<view class="application_list_container">
<custom-nav-bar :title="isGroupApplication ? '新的群聊' : '新的好友'" />
<view
class="pane_row"
:style="{ transform: `translateX(${isRecv ? '0' : '-100%'})` }"
>
<view class="pane_content">
<u-list v-if="getRecvRenderData.length > 0" class="application_list">
<u-list-item
v-for="application in getRecvRenderData"
:key="
application[!isGroupApplication ? 'fromUserID' : 'userID'] +
application.groupID
"
>
<application-item :isRecv="true" :application="application" />
</u-list-item>
</u-list>
<u-list
v-else-if="getSendRenderData.length > 0"
class="application_list"
>
<u-list-item
v-for="application in getSendRenderData"
:key="application[!isGroupApplication ? 'toUserID' : 'groupID']"
>
<application-item :application="application" />
</u-list-item>
</u-list>
<view v-else class="empty">
<image src="@/static/images/block_empty.png"></image>
<text class="empty_text">暂无数据</text>
</view>
</view>
</view>
</view>
</template>
<script>
import { mapGetters } from "vuex";
import { ContactMenuTypes } from "@/constant";
import CustomNavBar from "@/components/CustomNavBar/index.vue";
import ApplicationItem from "./ApplicationItem.vue";
export default {
components: {
CustomNavBar,
ApplicationItem,
},
data() {
return {
keyword: "",
isRecv: true,
isGroupApplication: false,
};
},
computed: {
...mapGetters([
"storeRecvFriendApplications",
"storeSentFriendApplications",
"storeRecvGroupApplications",
"storeSentGroupApplications",
]),
getRecvRenderData() {
const tmpList = this.isGroupApplication
? this.storeRecvGroupApplications
: this.storeRecvFriendApplications;
tmpList.sort((a, b) => (a.handleResult === 0 ? -1 : 1));
return tmpList.slice(0, 4);
},
getSendRenderData() {
const tmpList = this.isGroupApplication
? this.storeSentGroupApplications
: this.storeSentFriendApplications;
tmpList.sort((a, b) => (a.handleResult === 0 ? -1 : 1));
return tmpList.slice(0, 4);
},
tabList() {
return [
{
name: this.isGroupApplication ? "入群申请" : "好友请求",
},
{
name: "我的请求",
},
];
},
},
onLoad(params) {
const { applicationType } = params;
this.isGroupApplication = applicationType === ContactMenuTypes.NewGroup;
},
methods: {
clickTab({ index }) {
this.isRecv = index === 0;
},
previewAll() {
uni.navigateTo({
url: `/pages/contact/applicationListDetails/index?isGroupApplication=${this.isGroupApplication}&isRecv=${this.isRecv}`,
});
},
toSearch() {
uni.navigateTo({
url: `/pages/common/searchUserOrGroup/index?isSearchGroup=${this.isGroupApplication}`,
});
},
},
};
</script>
<style lang="scss" scoped>
.empty {
@include centerBox();
flex-direction: column;
margin-top: 25vh !important;
&_text {
margin-top: 26rpx;
color: #8e9ab0;
}
image {
width: 237rpx;
height: 244rpx;
}
}
.application_list_container {
@include colBox(false);
height: 100vh;
background-color: #f8f9fa;
overflow-x: hidden;
.search_bar_wrap {
height: 34px;
padding: 12px 22px;
background-color: #fff;
}
.u-tabs {
background-color: #fff;
}
.pane_row {
display: flex;
flex: 1;
transition: all 0.3s ease 0s !important;
background-color: #fff;
margin-top: 20rpx;
.pane_content {
@include colBox(false);
height: 100%;
flex: 0 0 100%;
.pane_title {
font-size: 28rpx;
color: #999;
padding: 12rpx 44rpx;
background-color: #f8f8f8;
}
.application_list {
flex: 1;
height: 100% !important;
}
}
}
.view_all {
background-color: #fff;
padding: 44rpx 44rpx;
}
}
</style>

View File

@@ -0,0 +1,81 @@
<template>
<view class="application_list_container">
<custom-nav-bar :title="getTitle" />
<u-list class="application_list">
<u-list-item
v-for="application in getRenderData"
:key="getKey(application)"
>
<application-item :isRecv="isRecv" :application="application" />
</u-list-item>
</u-list>
</view>
</template>
<script>
import CustomNavBar from "@/components/CustomNavBar/index.vue";
import ApplicationItem from "../applicationList/ApplicationItem.vue";
export default {
components: {
CustomNavBar,
ApplicationItem,
},
data() {
return {
isGroupApplication: false,
isRecv: false,
};
},
computed: {
getRenderData() {
let getterKey = this.isRecv
? "storeRecvFriendApplications"
: "storeSentFriendApplications";
if (this.isGroupApplication) {
getterKey = this.isRecv
? "storeRecvGroupApplications"
: "storeSentGroupApplications";
}
return [...this.$store.getters[getterKey]].sort((a, b) =>
a.handleResult === 0 ? -1 : 1,
);
},
getKey() {
return (application) => {
if (this.isGroupApplication) {
return this.isRecv
? application.userID + application.groupID
: application.groupID;
}
return application[this.isRecv ? "fromUserID" : "toUserID"];
};
},
getTitle() {
if (!this.isRecv) {
return "我的申请";
}
return this.isGroupApplication ? "群通知" : "好友请求";
},
},
onLoad(options) {
const { isGroupApplication, isRecv } = options;
this.isGroupApplication = JSON.parse(isGroupApplication);
this.isRecv = JSON.parse(isRecv);
},
methods: {},
};
</script>
<style lang="scss" scoped>
.application_list_container {
@include colBox(false);
height: 100vh;
background-color: #f8f8f8;
.application_list {
margin-top: 24rpx;
flex: 1;
}
}
</style>

View File

@@ -0,0 +1,74 @@
<template>
<view class="action_item" @click="onClick">
<slot name="icon">
<view class="action_icon">
<image :src="action.icon" mode=""></image>
</view>
</slot>
<view class="action_details">
<text class="title">{{ action.title }}</text>
<text class="desc">{{ action.desc }}</text>
<view class="bottom_line"></view>
</view>
</view>
</template>
<script>
export default {
name: "",
props: {
action: Object,
},
data() {
return {};
},
methods: {
onClick() {
this.$emit("click", this.action);
},
},
};
</script>
<style lang="scss" scoped>
.action_item {
@include vCenterBox();
padding: 24rpx 44rpx;
.action_icon {
width: 30px;
height: 30px;
image {
max-width: 100%;
max-height: 100%;
}
}
.action_details {
@include colBox(false);
margin-left: 48rpx;
width: 100%;
position: relative;
.title {
font-weight: 500;
padding-bottom: 12rpx;
}
.desc {
font-size: 24rpx;
color: #999;
}
.bottom_line {
height: 1px;
width: 100%;
background-color: #f0f0f0;
position: absolute;
bottom: -24rpx;
}
}
}
</style>

View File

@@ -0,0 +1,101 @@
<template>
<view class="contact_add_container">
<custom-nav-bar title="添加" />
<view class="action_row">
<action-item
@click="friendAction(item)"
v-for="item in friendActionMenus"
:action="item"
:key="item.idx"
/>
<action-item
@click="groupAction(item)"
v-for="item in groupActionMenus"
:action="item"
:key="item.idx"
/>
</view>
</view>
</template>
<script>
import CustomNavBar from "@/components/CustomNavBar/index.vue";
import ActionItem from "./ActionItem.vue";
export default {
components: {
CustomNavBar,
ActionItem,
},
data() {
return {
groupActionMenus: [
{
idx: 0,
title: "创建群聊",
desc: "创建群聊全面使用OpenIM",
icon: require("static/images/contact_add_create_group.png"),
},
{
idx: 1,
title: "添加群聊",
desc: "向管理员或团队成员询问ID",
icon: require("static/images/contact_add_join_group.png"),
},
],
friendActionMenus: [
{
idx: 0,
title: "添加好友",
desc: "通过手机号/ID号/搜索添加",
icon: require("static/images/contact_add_search_user.png"),
},
],
};
},
methods: {
groupAction({ idx }) {
if (idx === 0) {
uni.navigateTo({
url: `/pages/common/createGroup/index`,
});
} else {
uni.navigateTo({
url: "/pages/contact/switchJoinGroup/index",
});
}
},
friendAction({ idx }) {
if (!idx) {
uni.navigateTo({
url: "/pages/common/searchUserOrGroup/index?isSearchGroup=false",
});
}
},
},
};
</script>
<style lang="scss" scoped>
.contact_add_container {
height: 100vh;
background-color: #f8f8f8;
.desc_title {
font-size: 24rpx;
color: #999;
padding: 24rpx 44rpx;
}
.action_row {
margin-top: 24rpx;
background-color: #fff;
.action_item:last-child {
.bottom_line {
height: 0;
}
}
}
}
</style>

View File

@@ -0,0 +1,93 @@
<template>
<view class="friend_list_container">
<custom-nav-bar title="我的好友" />
<view class="search_bar_wrap">
<u-search
class="search_bar"
shape="square"
placeholder="搜索"
:showAction="false"
disabled
/>
</view>
<choose-index-list
v-if="getIndexData.dataList.length > 0"
@itemClick="userClick"
:height="`${listHeight}px`"
:indexList="getIndexData.indexList"
:itemArr="getIndexData.dataList"
/>
<u-empty v-else mode="list" />
</view>
</template>
<script>
import { mapGetters } from "vuex";
import { formatChooseData } from "@/util/common";
import CustomNavBar from "@/components/CustomNavBar/index.vue";
import ChooseIndexList from "@/components/ChooseIndexList/index.vue";
export default {
components: {
CustomNavBar,
ChooseIndexList,
},
data() {
return {
keyword: "",
listHeight: 0,
};
},
computed: {
...mapGetters(["storeFriendList"]),
getIndexData() {
return formatChooseData(this.storeFriendList);
},
},
mounted() {
this.getListHeight();
},
methods: {
userClick(friend) {
uni.navigateTo({
url: `/pages/common/userCard/index?sourceID=${friend.userID}`,
});
},
async getListHeight() {
const windowInfo = uni.getWindowInfo();
const data = await this.getEl(".search_bar_wrap");
const searchBarHeight = Number(data.height.toFixed());
this.listHeight =
windowInfo.windowHeight -
windowInfo.statusBarHeight -
44 -
searchBarHeight;
},
getEl(el) {
return new Promise((resolve) => {
const query = uni.createSelectorQuery().in(this);
query
.select(el)
.boundingClientRect((data) => {
// 存在data且存在宽和高视为渲染完毕
resolve(data);
})
.exec();
});
},
},
};
</script>
<style lang="scss" scoped>
.friend_list_container {
.search_bar_wrap {
height: 34px;
padding: 12px 22px;
}
.u-empty {
margin-top: 25vh !important;
}
}
</style>

View File

@@ -0,0 +1,55 @@
<template>
<view @click="toGroupCard" class="group_item">
<my-avatar :src="groupInfo.faceURL" :isGroup="true" size="42" />
<view class="group_info">
<text class="group_name">{{ groupInfo.groupName }}</text>
<view class="group_details">
<text>{{ `${groupInfo.memberCount}` }}</text>
</view>
</view>
</view>
</template>
<script>
import MyAvatar from "@/components/MyAvatar/index.vue";
export default {
name: "",
components: {
MyAvatar,
},
props: {
groupInfo: Object,
},
data() {
return {};
},
methods: {
toGroupCard() {
uni.navigateTo({
url: `/pages/common/groupCard/index?sourceID=${this.groupInfo.groupID}`,
});
},
},
};
</script>
<style lang="scss" scoped>
.group_item {
@include vCenterBox();
padding: 24rpx 44rpx;
.group_info {
margin-left: 24rpx;
.group_name {
@include nomalEllipsis() max-width: 400rpx;
}
.group_details {
font-size: 28rpx;
color: #999;
margin-top: 8rpx;
}
}
}
</style>

View File

@@ -0,0 +1,157 @@
<template>
<view class="group_list_container">
<custom-nav-bar title="我的群组">
</custom-nav-bar>
<view class="search_bar_wrap">
<u-search
class="search_bar"
shape="square"
placeholder="搜索"
disabled
:showAction="false"
/>
</view>
<u-tabs :scrollable="false" :list="tabList" @click="clickTab"></u-tabs>
<view
class="pane_row"
:style="{ transform: `translateX(${isMyCreate ? '0' : '-100%'})` }"
>
<view class="pane_content">
<u-list
v-if="getMyCreateGroupList.length > 0"
class="group_list"
:height="`${getListHeight}px`"
>
<u-list-item
v-for="group in getMyCreateGroupList"
:key="group.groupID"
>
<group-item :groupInfo="group" />
</u-list-item>
</u-list>
<u-empty v-else mode="list" />
</view>
<view class="pane_content">
<u-list
v-if="getMyJoinedGroupList.length > 0"
class="group_list"
:height="`${getListHeight}px`"
>
<u-list-item
v-for="group in getMyJoinedGroupList"
:key="group.groupID"
>
<group-item :groupInfo="group" />
</u-list-item>
</u-list>
<u-empty v-else mode="list" />
</view>
</view>
</view>
</template>
<script>
import { mapGetters } from "vuex";
import CustomNavBar from "@/components/CustomNavBar/index.vue";
import GroupItem from "./GroupItem.vue";
export default {
components: {
CustomNavBar,
GroupItem,
},
data() {
return {
keyword: "",
tabList: [
{
name: "我创建的",
},
{
name: "我加入的",
},
],
isMyCreate: true,
};
},
computed: {
...mapGetters(["storeGroupList", "storeCurrentUserID"]),
getMyCreateGroupList() {
return this.storeGroupList.filter(
(group) => group.ownerUserID === this.storeCurrentUserID,
);
},
getListHeight() {
const statusBar = uni.getWindowInfo().statusBarHeight;
const searchBar = 58;
const tabAndNavBar = 44 * 2;
const titleBar = 32;
return (
uni.getWindowInfo().safeArea.height -
statusBar -
searchBar -
tabAndNavBar -
titleBar
);
},
getMyJoinedGroupList() {
// console.log(this.storeGroupList.filter(group => group.ownerUserID !== this.storeCurrentUserID));
return this.storeGroupList.filter(
(group) => group.ownerUserID !== this.storeCurrentUserID,
);
},
},
mounted() {},
methods: {
clickTab({ index }) {
this.isMyCreate = index === 0;
},
toCreateGroup() {
uni.navigateTo({
url: `/pages/common/createGroup/index`,
});
}
},
};
</script>
<style lang="scss" scoped>
.group_list_container {
@include colBox(false);
height: 100vh;
overflow: hidden;
.nav_right_action {
padding-right: 44rpx;
}
.search_bar_wrap {
height: 34px;
padding: 12px 22px;
}
.pane_row {
display: flex;
flex: 1;
transition: all 0.3s ease 0s !important;
border-top: 2rpx solid #e8eaef;
// overflow-x: hidden;
.pane_content {
@include colBox(false);
height: 100%;
flex: 0 0 100%;
.pane_title {
font-size: 14px;
color: #999;
padding: 6px 22px;
background-color: #f8f8f8;
}
}
}
}
</style>

View File

@@ -0,0 +1,151 @@
<template>
<view class="">
<view class="menu_list">
<view
@click="menuClick(item)"
v-for="item in getMenus"
:key="item.idx"
class="menu_list_item"
>
<image class="menu_icon" :src="item.icon" mode=""></image>
<view class="item_content">
<text class="title">
{{ item.title }}
</text>
<view class="icon">
<u-icon name="arrow-right" color="#999" size="18" />
</view>
</view>
</view>
</view>
<view class="menu_list">
<view
@click="menuClick(item)"
v-for="item in getFriendsMenus"
:key="item.idx"
class="menu_list_item"
>
<image class="menu_icon" :src="item.icon" mode=""></image>
<view class="item_content">
<text class="title">
{{ item.title }}
</text>
<view class="icon">
<u-icon name="arrow-right" color="#999" size="18" />
</view>
</view>
</view>
</view>
</view>
</template>
<script>
import { mapGetters } from "vuex";
import { ContactMenuTypes } from "@/constant";
export default {
name: "",
props: {},
data() {
return {};
},
computed: {
getMenus() {
return [
{
idx: 0,
type: ContactMenuTypes.NewFriend,
title: "新的好友",
icon: require("static/images/contact_new_friend.png"),
},
{
idx: 1,
type: ContactMenuTypes.NewGroup,
title: "新的群组",
icon: require("static/images/contact_new_group.png"),
},
];
},
getFriendsMenus() {
return [
{
idx: 2,
type: ContactMenuTypes.MyFriend,
title: "我的好友",
icon: require("static/images/contact_my_friend.png"),
badge: 0,
},
{
idx: 3,
type: ContactMenuTypes.MyGroup,
title: "我的群组",
icon: require("static/images/contact_my_group.png"),
badge: 0,
},
];
},
},
methods: {
menuClick({ type }) {
switch (type) {
case ContactMenuTypes.NewFriend:
case ContactMenuTypes.NewGroup:
uni.navigateTo({
url: `/pages/contact/applicationList/index?applicationType=${type}`,
});
break;
case ContactMenuTypes.MyFriend:
uni.navigateTo({
url: "/pages/contact/friendList/index",
});
break;
case ContactMenuTypes.MyGroup:
uni.navigateTo({
url: "/pages/contact/groupList/index",
});
break;
default:
break;
}
},
},
};
</script>
<style lang="scss" scoped>
.menu_list {
margin-bottom: 24rpx;
background-color: #fff;
&_item {
@include vCenterBox();
margin: 0 44rpx;
padding: 24rpx 0;
color: #0c1c33;
.menu_icon {
width: 42px;
min-width: 42px;
height: 42px;
min-height: 42px;
}
.item_content {
@include btwBox();
margin-left: 24rpx;
width: 100%;
position: relative;
.icon {
display: flex;
.u-badge {
width: fit-content;
padding: 8rpx 12rpx;
line-height: 18rpx;
}
}
}
}
}
</style>

View File

@@ -0,0 +1,87 @@
<template>
<view class="contact_container">
<custom-nav-bar>
<view class="contact_title" slot="left">
<text>通讯录</text>
</view>
<view class="contact_action" slot="more">
<view @click="contactAddClick" class="search_icon">
<image src="@/static/images/common_add.png" alt="" srcset="" />
</view>
</view>
</custom-nav-bar>
<contact-menus />
</view>
</template>
<script>
import CustomNavBar from "@/components/CustomNavBar/index.vue";
import ContactMenus from "./components/ContactMenus.vue";
import UserItem from "@/components/UserItem/index.vue";
export default {
components: {
CustomNavBar,
ContactMenus,
UserItem,
},
data() {
return {
frequentContacts: [],
};
},
methods: {
contactAddClick() {
uni.navigateTo({
url: "/pages/contact/contactAdd/index",
});
},
userClick(item) {
uni.navigateTo({
url: `/pages/common/userCard/index?sourceID=${item.userID}`,
});
},
},
};
</script>
<style lang="scss" scoped>
.contact_container {
@include colBox(false);
height: 100vh;
background-color: #f6f6f6;
.contact_title {
padding-left: 44rpx;
font-size: 40rpx;
font-weight: 600;
color: #0c1c33;
}
.contact_action {
padding-right: 36rpx;
display: flex;
.search_icon {
margin: 0 16rpx;
image {
width: 56rpx;
height: 56rpx;
}
}
}
.list_title {
font-size: 24rpx;
color: #999;
margin-left: 44rpx;
}
.user_list {
flex: 1;
margin-top: 24rpx;
background-color: #fff;
}
}
</style>

View File

@@ -0,0 +1,57 @@
<template>
<view class="search_group_container">
<custom-nav-bar title="搜索群组" />
<view class="search_bar_wrap">
<u-search
class="search_bar"
shape="square"
placeholder="搜索群组"
:showAction="false"
v-model="keyword"
/>
</view>
<view class="search_results">
<u-empty mode="search" />
</view>
</view>
</template>
<script>
import CustomNavBar from "@/components/CustomNavBar/index.vue";
import GroupItem from "../groupList/GroupItem.vue";
export default {
components: {
CustomNavBar,
GroupItem,
},
data() {
return {
keyword: "",
};
},
mounted() {},
methods: {
userClick() {},
},
};
</script>
<style lang="scss" scoped>
.search_group_container {
@include colBox(false);
height: 100vh;
.search_bar_wrap {
height: 34px;
padding: 12px 22px;
}
.search_results {
flex: 1;
.group_list {
height: 100% !important;
}
}
}
</style>

View File

@@ -0,0 +1,99 @@
<template>
<view class="switch_join_container">
<custom-nav-bar title="加入群聊" />
<view class="action_row">
<action-item
@click="actionClick(item)"
v-for="item in joinGroupMenus"
:action="item"
:key="item.idx"
>
<view
class="custom_icon"
:class="{ custom_icon_id: item.idx === 1 }"
slot="icon"
>
<image :src="item.icon" mode=""> </image>
</view>
</action-item>
</view>
</view>
</template>
<script>
import CustomNavBar from "@/components/CustomNavBar/index.vue";
import ActionItem from "../contactAdd/ActionItem.vue";
export default {
components: {
CustomNavBar,
ActionItem,
},
data() {
return {
joinGroupMenus: [
{
idx: 1,
title: "群ID号加入",
desc: "向管理员或团队成员询问ID",
icon: require("static/images/switch_join_id.png"),
},
],
};
},
methods: {
actionClick({ idx }) {
if (idx) {
uni.navigateTo({
url: "/pages/common/searchUserOrGroup/index?isSearchGroup=true",
});
}
},
},
};
</script>
<style lang="scss" scoped>
.switch_join_container {
height: 100vh;
background-color: #f8f8f8;
.desc_title {
font-size: 24rpx;
color: #999;
padding: 24rpx 44rpx;
}
.action_row {
background-color: #fff;
.custom_icon {
@include centerBox();
width: 44px;
min-width: 44px;
height: 44px;
border-radius: 50%;
background-color: #5496eb;
image {
width: 20px;
height: 20px;
}
&_id {
background-color: #ffc563;
}
}
/deep/ .action_item {
align-items: start;
}
.action_item:last-child {
.bottom_line {
height: 0;
}
}
}
}
</style>