移动app

This commit is contained in:
2023-09-24 17:55:19 +08:00
parent 736c5376e0
commit 59f7e39791
735 changed files with 80523 additions and 57 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,124 @@
<template>
<view class="container">
<uni-list :border="false" class="list">
<uni-list-chat
:avatar="friend_info.avatar_file ? friend_info.avatar_file.url:'/uni_modules/uni-im/static/avatarUrl.png'"
:title="friend_info.nickname"
></uni-list-chat>
</uni-list>
<button v-if="isFriend" class="btn" plain type="warn" @click="deteleFriend">删除好友</button>
<text v-else style="color: #999;font-size: 14px;">- 非好友的临时会话无法设置 -</text>
</view>
</template>
<script>
const db = uniCloud.database();
import uniIm from '@/uni_modules/uni-im/lib/main.js';
export default {
data() {
return {
friend_uid:'',
friend_info:{
username:'',
nickname:'',
avatar_file:{
url:''
}
}
}
},
props: {
conversation_id: {
default(){
return false
}
},
},
computed:{
isFriend(){
let friendList = uniIm.friend.get()
return friendList.find(i=>i._id == this.friend_uid)
}
},
async onLoad(options) {
this.load(options)
},
async mounted() {
if(this.conversation_id){
this.load({conversation_id:this.conversation_id})
}
},
methods: {
async load(options){
if(options.conversation_id){
let conversation = await uniIm.conversation.get(options.conversation_id)
options.user_id = conversation.friend_uid
}
this.friend_uid = options.user_id
let res = await db.collection('uni-id-users')
.doc(this.friend_uid)
.field('_id,nickname,avatar_file')
.get()
// console.log("res: ",res);
this.friend_info = res.result.data[0]
},
async deteleFriend() {
uni.showModal({
title: '确认要删除好友吗',
content: '此操作不可撤销',
showCancel: true,
cancelText: '取消',
confirmText: '确认',
complete: async (e) => {
if (e.confirm) {
uni.showLoading({
mask: true
});
try{
await db.collection('uni-im-friend').where({
friend_uid: this.friend_uid,
user_id:uniCloud.getCurrentUserInfo().uid
}).remove()
// 收到push消息后store会自动将此用户从列表中移除
uni.navigateBack({delta:2})
}catch(e){
uni.showModal({
content: JSON.stringify(e.message),
showCancel: false
});
//TODO handle the exception
}
uni.hideLoading()
}
}
});
},
}
}
</script>
<style lang="scss" scoped>
.container {
width: 750rpx;
align-items: center;
/* #ifndef APP-NVUE */
height: 100vh;
/* #endif */
flex: 1;
background-color: #fff;
}
.list {
width: 750rpx;
height: 100px;
}
.btn {
width: 600rpx;
/* height: 45px; */
text-align: center;
line-height: 45px;
border-radius: 20rpx;
}
</style>

View File

@@ -0,0 +1,50 @@
<template>
<view class="code-view" :class="{isRotate}">
默认不启用代码浏览模块如有需要请关闭注释
<!-- <uni-im-code-view :code="code" :showFullBtn="false"></uni-im-code-view> -->
<!-- <uni-im-icons id="rotate" @click="rotate" code="e664"></uni-im-icons> -->
</view>
</template>
<script>
export default {
data() {
return {
code:"",
isRotate:false
}
},
onLoad({
code
}) {
this.code = decodeURIComponent(code)
},
methods:{
rotate(){
this.isRotate = !this.isRotate
}
}
}
</script>
<style lang="scss">
.text-box,
.code-view {
background-color: #fffae5 !important;
flex: 1;
width: 750rpx;
/* #ifndef APP-NVUE */
width: 100vw;
/* #endif */
height: 100vh;
}
#rotate{
position: fixed;
right: 10px;
top: 60px;
z-index: 999;
}
.isRotate{}
</style>

View File

@@ -0,0 +1,56 @@
<template>
<view class="video-box">
<video @click="showCloseBtnFn" v-if="url" :src="url" :autoplay="true" :page-gesture="true" :show-fullscreen-btn="false" class="video"></video>
<uni-icons v-if="showCloseBtn" @click="close" size="30px" color="#FFFFFF" type="closeempty" class="close-icon"></uni-icons>
</view>
</template>
<script>
export default {
data() {
return {
url:"",
showCloseBtn:true
};
},
onLoad({url}) {
// console.log({url});
this.url = url
setTimeout(()=> {
this.showCloseBtn = false
}, 1000);
},
methods:{
close(){
uni.navigateBack()
},
showCloseBtnFn(){
// console.log('showCloseBtnFn');
this.showCloseBtn = true
setTimeout(()=> {
this.showCloseBtn = false
}, 5000);
}
}
}
</script>
<style lang="scss">
.video-box,.video{
width: 750rpx;
/* #ifndef APP-NVUE */
width: 100vw;
height: 100vh;
/* #endif */
flex: 1;
}
.close-icon{
position: fixed;
top: 80rpx;
left: 30rpx;
z-index: 9999;
/* #ifndef APP-NVUE */
text-shadow: 0 0 15px black;
/* #endif */
}
</style>

View File

@@ -0,0 +1,325 @@
<template>
<view>
<uni-nav-bar color="#999" :fixed="true" background-color="#ffffff" status-bar left-icon="left" @clickLeft="back">
<view class="segmented-box">
<uni-segmented-control :values="items" @clickItem="setActiveIndex" styleType="button" activeColor="#5fc08e" style="width:120px;"></uni-segmented-control>
</view>
</uni-nav-bar>
<view class="content">
<uni-search-bar :placeholder="activeIndex?'搜索群名称/群号':'搜索手机号/用户名/用户昵称'" :radius="100"
bgColor="#eeeeee"
v-model="keyword"
@confirm="doSearch"
@focus="searchFocus = true"
@blur="searchFocus = false"
@cancel="doClear"
@clear="doClear"
></uni-search-bar>
<view v-if="activeIndex === 0">
<!-- 搜索 -->
<uni-list v-if="usersList.length">
<uni-list-chat v-for="(item,index) in usersList" :key="index"
:title="item.nickname" :avatarCircle="true"
:avatar="item.avatar_file&&item.avatar_file.url ? item.avatar_file.url : '/uni_modules/uni-im/static/avatarUrl.png'"
>
<text @click="addUser(index)" class="chat-custom-right">加为好友</text>
</uni-list-chat>
<!--
v-if="keyword.length"
<template v-else>
<uni-list-item v-for="(tab,index) in tabs" :key="index"
class="tab-item" :title="tab.title"
:to="tab.url" showArrow :border="false"
></uni-list-item>
</template> -->
</uni-list>
<uni-load-more v-else :status="loading?'loading':(hasMore?'hasMore':'noMore')"></uni-load-more>
</view>
<view v-if="activeIndex === 1">
<uni-list v-if="groupList.length">
<uni-list-chat v-for="(item,index) in groupList" :key="index"
:title="item.name" :avatarCircle="true"
:avatar="item.avatar_file && item.avatar_file.url ? item.avatar_file.url : '/uni_modules/uni-im/static/avatarUrl.png'"
>
<text @click="addUser(index)" class="chat-custom-right">申请加入</text>
</uni-list-chat>
</uni-list>
<uni-load-more v-else :status="loading?'loading':(hasMore?'hasMore':'noMore')"></uni-load-more>
</view>
</view>
<uni-popup ref="popup" type="dialog">
<uni-popup-dialog mode="input" :title="activeIndex?'申请加群':'申请添加好友'"
placeholder="请输入验证信息" confirmText="发送" message="成功消息"
:duration="2000" :before-close="true" :value="value"
@close="close" @confirm="confirm"
></uni-popup-dialog>
</uni-popup>
</view>
</template>
<script>
import uniIm from '@/uni_modules/uni-im/lib/main.js';
const db = uniCloud.database();
export default {
data() {
return {
loading:true,
hasMore: false,
activeIndex:0,
value:'',
items: ['找人', '找群'],
searchFocus:false,//是否展示搜索列表
keyword:'',
tabs:[
{
'title':'添加手机联系人',
'url':''
},
{
'title':'扫一扫加好友',
'url':''
},
{
'title':'查找陌生人',
'url':''
}
],
usersData: [],
checkIndex:'',//申请加的群index
groupData:[]
}
},
computed: {
usersList() {
let current_uid = uniCloud.getCurrentUserInfo().uid
let friendList = uniIm.friend.dataList
return this.usersData.filter(item=>{
if(
friendList.find(i=>i._id == item._id)
||
item._id == current_uid
){
return false
}else{
return true
}
})
},
groupList() {
let groupList = uniIm.group.dataList
// console.log('groupList',groupList);
return this.groupData.filter(item=>{
console.log('i.group_info._id == item._id',item.group_info ,item._id);
if(
item.group_info && groupList.find(i=>i.group_info._id == item._id)
){
return false
}else{
return true
}
})
}
},
mounted() {
this.getUserList()
this.getGroupsList()
},
methods: {
async getGroupsList(){
const res = await db.collection('uni-im-group').get()
// console.log("uni-im-group: ",res);
if(res.result.data.length){
this.loading = false
this.hasMore = true
this.groupData = res.result.data
}
},
async getUserList(){
try{
let res = await db.collection('uni-id-users')
.field('_id,nickname,avatar_file')
.get()
let data = res.result.data
// console.log("data: ",data);
if(data.length){
this.loading = false
this.hasMore = true
this.usersData = data
}
}catch(e){
console.log(e);
//TODO handle the exception
}
},
back() {
uni.navigateBack()
},
async doSearch(e){
console.log("doSearch: ",e,this.keyword);
if(this.activeIndex){
let res = await db.collection('uni-im-group')
.where(`
"name" == "${this.keyword}" ||
"_id" == "${this.keyword}"
`)
.get()
console.log(res);
this.groupData = res.result.data
}else{
let res = await db.collection('uni-id-users')
.where(`
"_id" == "${this.keyword}" ||
"username" == "${this.keyword}" ||
"nickname" == "${this.keyword}" ||
"email" == "${this.keyword}" ||
"mobile" == "${this.keyword}"
`)
.field('_id,nickname,avatar_file')
.get()
console.log(res);
this.usersData = res.result.data
}
},
doClear() {
this.keyword = ''
this.getUserList()
this.getGroupsList()
},
setActiveIndex(e) {
// console.log("activeIndex: ",e);
if (this.activeIndex != e.currentIndex) {
this.activeIndex = e.currentIndex;
}
},
addUser(index){
this.checkIndex = index
this.$refs.popup.open()
},
async confirm(value){
// if(!value){
// uni.showToast({
// title: '验证信息不能为空!',
// icon:'none'
// });
// return
// }
// console.log('提供的验证信息',value);
this.value = value
this.$refs.popup.close()
if(this.activeIndex === 0){
//添加好友
const uniImCo = uniCloud.importObject("uni-im-co")
await uniImCo.addFriendInvite({
"to_uid": this.usersList[this.checkIndex]._id,
"message": this.value
}).then((res)=>{
console.log("res: ",res);
uni.showToast({
title: '已申请',
icon: 'none'
});
}).catch((err) => {
uni.showModal({
content: err.message || '请求服务失败',
showCancel: false
})
})
}else{
// console.log('1233123132123132',this.groupData,this.checkIndex);
//申请加群
db.collection('uni-im-group-join').add({
"group_id":this.groupList[this.checkIndex]._id,
"message":this.value
}).then((res) => {
console.log("res: ",res);
uni.showToast({
icon: 'none',
title: '已申请'
})
}).catch((err) => {
uni.showModal({
content: err.message || '请求服务失败',
showCancel: false
})
})
}
setTimeout(()=> {
this.value = ''
}, 100);
},
close(){
console.log('取消了');
this.$refs.popup.close()
}
}
}
</script>
<style lang="scss" scoped>
.segmented-box{
flex: 1;
justify-content: center;
align-items: center;
}
/* #ifdef H5 */
@media screen and (min-width:960px){
::v-deep .uni-navbar__header-btns-left,
::v-deep .uni-navbar__placeholder,
{
display: none;
}
::v-deep .uni-navbar--fixed{
position: relative;
left: 0
}
}
/* #endif */
.content{
/* #ifdef APP-NVUE */
margin-top: 75px;
/* #endif */
}
.tab-item{
border-bottom: #f5f5f5 solid 1px;
height:60px;
justify-content: center;
padding: 0 15rpx;
}
.uni-list-item{
width:720rpx;
}
.background{
background-color: #f5f5f5;
}
.grey{
color: #ddd;
}
.chat-custom-right {
width:70px;
height:30px;
line-height: 30px;
color: #666;
font-size: 12px;
text-align: center;
background-color: #efefef;
/* #ifdef H5 */
cursor: pointer;
/* #endif */
border-radius: 100px;
}
.border{
border: #ddd solid 1px;
}
.state-text{
text-align: center;
font-size: 28rpx;
}
</style>

View File

@@ -0,0 +1,394 @@
<template>
<view class="container" @click="hiddenDeleteBtn">
<uni-list :border="false" class="list-box">
<template v-if="showMenu">
<uni-list-item v-for="(menu,menuIndex) in menuList" :key="menuIndex" class="menu-item"
:title="menu.title" link
@click="openPages(menu)" :border="false" :showBadge="true"
>
<template v-slot:header>
<view class="slot-icon-box green">
<image class="slot-icon" :src="'/uni_modules/uni-im/static/noticeIcon/' + menu.srcName + '.png'" mode="widthFix"></image>
</view>
</template>
</uni-list-item>
<uni-list-item v-for="(item,index) in noticeList" :key="item.id" class="menu-item" :title="item.title"
:showBadge="true" :badgeText="item.badge" :badgeStyle="item.badgeStyle" link @click="openPages(item)" :border="false">
<template v-slot:header>
<view class="slot-icon-box blue">
<image class="slot-icon" :src="item.icon" mode="widthFix"></image>
</view>
</template>
</uni-list-item>
</template>
<template v-if="showUser">
<uni-list-item :customStyle="{padding:0}" :border="false">
<template v-slot:body>
<text class="grey">好友列表</text>
</template>
</uni-list-item>
<uni-list-item v-for="(item, index) in friendList" :key="item._id" :customStyle="{padding:0}" class="user-list-item">
<template v-slot:body>
<scroll-view scroll-x="true" @scroll="scroll"
:scroll-left="activeIndex === index ?'':scrollLeft[index]" :show-scrollbar="false"
:scroll-with-animation="true" class="user-list-item-scroll-view">
<view class="item" @click="toChat(item)" @touchstart.passive="activeIndex = index">
<image class="avatar"
:src="item.avatar_file&&item.avatar_file.url ? item.avatar_file.url : '/uni_modules/uni-im/static/avatarUrl.png'"
mode="widthFix"></image>
<text class="username">{{item.nickname}}</text>
<button @click.stop="deleteItem(item,index,$event)" class="delete-btn" size="mini" type="warn">删除</button>
</view>
</scroll-view>
</template>
</uni-list-item>
<uni-list-item :customStyle="{padding:0}">
<template v-slot:body>
<uni-load-more class="tip" :status="friendHasMore?'loading':'noMore'"></uni-load-more>
</template>
</uni-list-item>
</template>
</uni-list>
</view>
</template>
<script>
import uniIm from '@/uni_modules/uni-im/lib/main.js';
const db = uniCloud.database()
export default {
emits:['clickMenu'],
props: {
// pc端时会控制隐藏
showMenu: {
type: Boolean,
default: true
},
// pc端时会控制隐藏
showUser: {
type: Boolean,
default: true
},
},
data() {
return {
scrollLeft: {
0: 0,
1: 1
},
activeIndex: false,
menuList:[
{
title:'加人/加群',
path:'./addPeopleGroups/addPeopleGroups',
srcName:'search'
},
{
title:'群聊',
path:'./groupList/groupList',
srcName:'group'
},
{
title:'创建群聊',
path:'./createGroup/createGroup',
srcName:'createGroup'
}
]
}
},
computed: {
//是否为pc宽屏width>960px
isWidescreen(){
return uniIm.isWidescreen
},
friendList() {
return uniIm.friend.dataList
},
friendHasMore(){
return uniIm.friend.hasMore
},
noticeList() {
return [{
title: "新朋友",
param: {
type: ['uni-im-friend-invite']
},
icon: "/uni_modules/uni-im/static/noticeIcon/newFriend.png"
},
{
title: "群通知",
param: {
type: ['uni-im-group-join-request']
},
icon: "/uni_modules/uni-im/static/noticeIcon/groupNotice.png"
},
{
title: "系统通知",
param: {
excludeType: ['uni-im-group-join-request', 'uni-im-friend-invite']
},
icon: "/uni_modules/uni-im/static/noticeIcon/notification.png"
}
].reduce((sum,item,index) => {
let {param:filterNotice,title} = item,
param = {filterNotice,title}
// console.log('param----',param);
sum.push({
title: item.title,
badge: this.getUnreadCount(item.param),
badgeStyle: {
backgroundColor: '#d60000'
},
path: "./notification/notification?param=" + encodeURIComponent(JSON.stringify(param)),
param,
icon: item.icon,
id:Date.now()+'-'+index
})
return sum
}, [])
}
},
onPullDownRefresh() {
this.$refs.udb.loadData({
clear: true
}, () => {
uni.stopPullDownRefresh()
})
},
onReachBottom() {
// this.$refs.udb.loadMore()
},
methods: {
openPages(item,index){
// #ifdef H5
if(this.isWidescreen){
let componentName = 'uni-im-' + item.path.split('/')[1],
param = item.param
return this.$emit('clickMenu',{componentName,param,title:item.title})
}
// #endif
// console.log('item',item);
uni.navigateTo({
url:item.path,
fail: (e) => {
console.error(e,item.path);
}
})
},
getUnreadCount(param) {
return uniIm.notification.unreadCount(param)
},
toChat(item) {
// console.log('this.isWidescreen',this.isWidescreen)
if (this.isWidescreen) {
//若为宽屏,则触发右侧详情页的自定义事件,通知右侧窗体刷新详情
uni.$emit('uni-im-toChat',{user_id:item._id})
} else {
// 若为窄屏,则打开新窗体,在新窗体打开详情页面
openPages('/uni_modules/uni-im/pages/chat/chat?user_id=' + item._id);
}
function openPages(url) {
uni.navigateTo({
url,
fail: (err1) => {
console.log({err1});
uni.switchTab({
url,
fail: (err2) => {
console.error({err1,err2})
}
});
}
});
}
},
hiddenDeleteBtn() {
this.activeIndex = false
this.$nextTick(() => {
for (let i in this.scrollLeft) {
this.$set(this.scrollLeft, i, 0)
// this.scrollLeft[i] = 0
}
})
},
async deleteItem(item, index,event) {
uni.showModal({
title: '确认要删除好友吗',
content: '此操作不可撤销',
showCancel: true,
cancelText: '取消',
confirmText: '确认',
complete: async (e) => {
if (e.confirm) {
uni.showLoading({
mask: true
});
await db.collection('uni-im-friend').where({
friend_uid: item._id,
user_id:uniCloud.getCurrentUserInfo().uid
}).remove()
uni.hideLoading()
// 收到push消息后会自动将此用户从列表中移除
}
}
});
this.hiddenDeleteBtn()
event.stopPropagation()
event.preventDefault()
},
scroll(e) {
// console.log(this.inMove);
this.$set(this.scrollLeft, this.activeIndex, e.detail.scrollLeft)
// this.scrollLeft[this.activeIndex] = e.detail.scrollLeft
for (let i in this.scrollLeft) {
if (i != this.activeIndex) {
this.$set(this.scrollLeft, i, 0)
// this.scrollLeft[i] = 0
}
}
},
handleItemClick(id) {
uni.navigateTo({
url: './detail?id=' + id
})
},
fabClick() {
// 打开新增页面
uni.navigateTo({
url: './add',
events: {
// 监听新增数据成功后, 刷新当前页面数据
refreshData: () => {
this.$refs.udb.loadData({
clear: true
})
}
}
})
}
}
}
</script>
<style lang="scss" scoped>
.tip {
width: 750rpx;
/* #ifndef APP-NVUE */
position: relative;
// left: -15px;
/* #endif */
text-align: center;
padding:30px 0;
color: #999999;
/* #ifdef H5 */
cursor: default;
/* #endif */
background-color: #f5f5f5;
}
.grey {
background-color: #f5f5f5;
text-align: left;
padding: 8px;
font-size: 12px;
width: 750rpx;
}
.container {
width: 750rpx;
/* #ifndef APP-NVUE */
height: 100vh;
/* #endif */
/* #ifdef APP-NVUE */
flex: 1;
/* #endif */
background-color: #f5f5f5;
}
/* #ifdef APP-NVUE */
.list-box{
background-color: #f5f5f5;
}
/* #endif */
.menu-item {
width: 750rpx;
height: 60px;
border-bottom: #f5f5f5 solid 1px;
justify-content: space-around;
/* #ifndef MP */
// padding: 0 15rpx;
/* #endif */
}
.user-list-item-scroll-view{
width: 750rpx;
background-color: #ffffff;
}
/* #ifndef APP-NVUE */
.user-list-item-scroll-view ::v-deep .uni-scroll-view ::-webkit-scrollbar {
display: none!important;
}
/* #endif */
.item {
width: 880rpx;
position: relative;
height: 60px;
align-items: center;
padding: 8px 15px;
flex-direction: row;
}
.avatar {
background-color: #fefefe;
width: 40px;
height: 40px;
border-radius: 5px;
}
.username {
line-height: 30px;
margin-left: 30rpx;
font-size: 16px;
}
.delete-btn {
border-radius: 0;
position: absolute;
right: 0;
top: 0;
height: 60px;
line-height: 60px;
width: 130rpx;
font-size: 26rpx;
padding: 0;
}
.slot-icon-box {
width: 80rpx;
height: 80rpx;
align-items: center;
justify-content: center;
border-radius: 10rpx;
margin-right: 20rpx;
}
.slot-icon {
width: 50rpx;
height: 50rpx;
}
.warn {
background-color: #FA9E3B;
}
.green {
background-color: #08C060;
}
.blue {
background-color: #5DBAFF;
}
</style>

View File

@@ -0,0 +1,294 @@
<template>
<view class="create-group-box">
<view class="header-box">
<uni-search-bar v-model="keyword"
placeholder="搜索" bgColor="#fff"
:radius="100"
@confirm="getFriendsData"
@cancel="doClear"
@clear="doClear"
></uni-search-bar>
<!--
checkFriendsSearchWidth
<view v-if="checkFriendIds.length" class="image-box"
:style="{'width':checkFriendsWidth + 'rpx','transform':'translateX' + ( translateXWidth + 'rpx')}">
<image v-for="(img,index) in checkFriendImg" :key="index"
class="avatar" :src="img && img.url ? img.url : '/uni_modules/uni-im/static/avatarUrl.png'"
></image>
</view> -->
</view>
<view class="content-box">
<checkbox-group @change="checkboxChange">
<label v-for="(item,index) in friendList" :key="index" class="label-box" >
<checkbox :value="item._id" class="checkbox" />
<view>
<uni-list :border="false">
<uni-list-chat :avatar-circle="true"
:title="item.nickname"
:avatar="item.avatar_file && item.avatar_file.url ? item.avatar_file.url : '/uni_modules/uni-im/static/avatarUrl.png'"
>
</uni-list-chat>
</uni-list>
</view>
</label>
</checkbox-group>
</view>
<view class="foot-box">
<!-- 创建新群可以不选择好友直接创建,要求好友进群必须选择好友 -->
<button :disabled="group_id? !checkFriendIds.length : false " class="btn" type="primary" @click="createGroup">{{btnText}}{{checkFriendNum}}</button>
</view>
<uni-load-more :status="loading?'loading':(hasMore?'hasMore':'noMore')"
:contentText='{"contentnomore": friendList.length?"没有更多好友":"没有可以选择的好友"}'
></uni-load-more>
</view>
</template>
<script>
import uniIm from '@/uni_modules/uni-im/lib/main.js';
const db = uniCloud.database();
export default {
data() {
return {
loading:true,
hasMore: false,
keyword:'',
checkFriendIds: [],
friendData: [],
groupMemberUid:[] ,//选人进群时已经在群里的人的id
group_id:false
}
},
computed: {
friendList(){
return this.friendData.filter(item=>!this.groupMemberUid.includes(item._id))
},
checkFriendNum() {
return this.checkFriendIds.length > 0 ? ''+ this.checkFriendIds.length +'': ''
},
btnText(){
return this.group_id ? '立即邀请' : '立即创建'
},
checkFriendsWidth() {
return this.checkFriendIds.length > 6 ? '360' : this.checkFriendIds.length * 65
},
// checkFriendsSearchWidth() {
// return this.checkFriendIds.length > 6 ? '360' : 720 - (this.checkFriendIds.length * 60)
// },
translateXWidth() {
return this.checkFriendIds.length > 6 ? this.checkFriendIds.length * 65 : '60'
},
checkFriendImg(){
return this.friendList.reduce((sum,current)=>{
if(this.checkFriendIds.includes(current._id)){
sum.push(current)
}
return sum
},[]).map(item=>item.avatar_file)
}
},
async onLoad(options) {
this.setParam(options)
},
methods: {
async setParam(options = {}){
console.log("group_id",options);
if(options.group_id){
this.group_id = options.group_id
uni.setNavigationBarTitle({
title:'邀请新成员'
})
//查本群,成员,
let res = await db.collection('uni-im-group-member').where({
group_id: options.group_id
})
.get()
console.log("res:查本群,成员 ",res);
this.groupMemberUid = res.result.data.map(item=>item.user_id)
console.log('this.groupMemberUid',this.groupMemberUid);
}
this.getFriendsData()
},
async getFriendsData(){
let whereString = {}
if(this.keyword){
whereString = `
"_id" == "${this.keyword}" ||
"username" == "${this.keyword}" ||
"nickname" == "${this.keyword}" ||
"email" == "${this.keyword}" ||
"mobile" == "${this.keyword}"
`
}
let res = await db.collection(
db.collection('uni-im-friend').where('"user_id" == $cloudEnv_uid').field('friend_uid,mark,class_name').getTemp(),
db.collection('uni-id-users').where(whereString).field('_id,nickname,avatar_file').getTemp()
).get()
// console.log(res);
let data = res.result.data
data.forEach((item,index)=>{
if(item.friend_uid[0]){
data[index] = item.friend_uid[0]
}else{
delete data[index]
}
})
this.friendData = data
this.loading = false
this.hasMore = this.friendList.length != 0
},
doClear() {
this.keyword = ''
this.getFriendsData()
},
checkboxChange(e) {
// console.log("checkboxChange-value",e.detail.value);
this.checkFriendIds = e.detail.value
},
async createGroup() {
// console.log('创建', this.checkFriendIds.length)
const uniImCo = uniCloud.importObject("uni-im-co")
let res = await uniImCo.chooseUserIntoGroup({
user_ids:this.checkFriendIds,
group_id:this.group_id
})
this.checkFriendIds = []
// console.log('createGroup',res);
if(this.group_id){
uni.navigateBack({
delta:1
})
}else{
// #ifdef H5
if(uniIm.isWidescreen){
uni.$emit('uni-im-toChat','group_' + res.data.group_id)
}else{
uni.redirectTo({
url: '/uni_modules/uni-im/pages/chat/chat?conversation_id=' + 'group_' + res.data.group_id,
animationDuration: 300,
fail: (e) => {
console.log(e);
}
})
}
// #endif
// #ifndef H5
uni.redirectTo({
url: '/uni_modules/uni-im/pages/chat/chat?conversation_id=' + 'group_' + res.data.group_id,
animationDuration: 300,
complete: (e) => {
console.log(e);
}
})
// #endif
}
}
}
}
</script>
<style lang="scss" scoped>
.create-group-box {
flex: 1;
flex-direction: column;
position: relative;
background-color: #f5f5f5;
/* #ifdef H5 */
align-items: center;
height: 100vh;
padding-top: 60px;
/* #endif */
/* #ifdef MP-WEIXIN */
height: 100vh;
/* #endif */
}
/* #ifdef H5 */
.create-group-box * {
max-width: 950px;
}
/* #endif */
.header-box {
width: 750rpx;
/* #ifdef H5 */
position: fixed;
top: 44px;
z-index: 99;
display: flex;
width: 100%;
/* #endif */
flex-direction: column;
background-color: #f5f5f5;
}
.image-box {
flex-direction: row;
align-items: center;
/* #ifndef APP-NVUE */
transition: 0.3s;
display: flex;
white-space: nowrap;
overflow-x: scroll;
/* #endif */
}
.avatar {
width: 60rpx;
height: 60rpx;
border-radius: 50px;
/* #ifndef APP-NVUE */
flex-shrink: 0;
/* #endif */
}
.content-box .label-box .uni-list-chat__content-title{
line-height: 41px;
}
/* #ifdef H5 */
.content-box ::v-deep .uni-list-chat__content-title {
position: relative;
top: 8px;
}
/* #endif */
.content-box {
/* #ifdef H5 */
// margin-top: 58px;
width: 100%;
/* #endif */
background-color: #fff;
z-index: 10;
}
.label-box{
flex-direction: row;
align-items: center;
height: 80px;
margin-right: 20rpx;
}
.checkbox{
margin: 0 20rpx 0 30rpx;
transform: scale(1.2);
}
.foot-box {
width: 750rpx;
height: 80px;
justify-content: center;
align-items: center;
position: fixed;
bottom: 0;
z-index: 99;
background-color: #f5f5f5;
/* #ifdef H5 */
width: 100%;
@media screen and (min-width:960px){
bottom: 10vh;
// right: 25vw;
}
/* #endif */
}
.btn {
width: 300px;
}
</style>

View File

@@ -0,0 +1,80 @@
<template>
<view>
<uni-search-bar placeholder="搜索群号/群名称" :radius="100" bgColor="#eeeeee" v-model="keyword"
@cancel="doClear"
@clear="doClear"
></uni-search-bar>
<uni-list :border="false">
<uni-list-chat v-for="(item,index) in groupList" :key="index"
@click="toChat(item.group_info._id)" link
:title="item.group_info.name"
:avatar="item.group_info.avatar_file&&item.group_info.avatar_file.url ? item.group_info.avatar_file.url : '/uni_modules/uni-im/static/avatarUrl.png'">
</uni-list-chat>
</uni-list>
<uni-load-more :status="groupHasMore?'loading':'noMore'"></uni-load-more>
</view>
</template>
<script>
import uniIm from '@/uni_modules/uni-im/lib/main.js';
export default {
data() {
return {
keyword: '',
groupData:false
}
},
computed: {
//是否为pc宽屏width>960px
isWidescreen(){
return uniIm.isWidescreen
},
groupList() {
let groupList = uniIm.group.get()
if(this.keyword){
return groupList.filter(item=>{
return item.group_info.name.includes(this.keyword) || item.group_info._id.includes(this.keyword)
})
}else{
return groupList
}
},
groupHasMore(){
return uniIm.group.hasMore
}
},
onLoad() {
},
methods: {
doClear(){
this.keyword = ''
},
toChat(group_id) {
let conversation_id = 'group_' + group_id
if(this.isWidescreen){
uni.$emit('uni-im-toChat',conversation_id)
}else{
let url = "/uni_modules/uni-im/pages/chat/chat?conversation_id=" + conversation_id
uni.navigateTo({
url,
animationDuration: 300,
fail: (error1) => {
uni.switchTab({
url,
animationDuration: 300,
fail: (error2) => {
console.error(error1,error2);
}
})
}
})
}
}
}
}
</script>
<style lang="scss" scoped>
</style>

View File

@@ -0,0 +1,61 @@
const db = uniCloud.database();
export default async function({
subType,
confirm,
cancel,
item
},callback) {
console.log({
subType,
confirm,
cancel,
item
})
switch (subType) {
case 'uni-im-friend-invite':
uni.showLoading({
mask:false
})
return db.collection("uni-im-friend-invite")
.doc(item.payload.data._id)
.update({
state:confirm?100:-100
})
.then((res) => {
uni.hideLoading()
callback()
}).catch((err) => {
console.log(err);
uni.showModal({
content: err.message || '请求服务失败',
showCancel: false
})
})
break;
case 'uni-im-group-join-request':
uni.showLoading({
mask:false
})
let res = await db.collection('uni-im-group-join')
.where({
_id:item.payload.data.doc_id
})
.update({
state:confirm?100:-100
})
.then((res) => {
uni.hideLoading()
callback()
}).catch((err) => {
console.log(err);
uni.showModal({
content: err.message || '请求服务失败',
showCancel: false
})
})
break;
default:
console.log({subType})
break;
}
}

View File

@@ -0,0 +1,275 @@
<template>
<view class="notification-box">
<text class="tips" v-if="tips">{{tips}}</text>
<uni-list :border="false">
<template v-if="notificationDatas && notificationDatas.length">
<uni-list-chat v-for="(item,index) in notificationDatas" :key="item.id"
:avatarCircle="true" :clickable="true"
:badge-text="item.is_read?'':'dot'" badgePositon="left"
:title="item.payload.title||item.title"
:note="item.payload.content||item.content||'无'"
:avatar="item.payload.avatar_file&&item.payload.avatar_file.url ? item.payload.avatar_file.url : '/uni_modules/uni-im/static/noticeIcon/notification2.png'"
@click.native="clickHandle(index,item)" direction="column" :time="friendlyTime(item.create_time)"
>
<view class="handle-box">
<template v-if="item.payload.state">
<text class="handle done">
{{'已'+(item.payload.state == 'confirm'?item.payload.confirmText:item.payload.cancelText)}}
</text>
</template>
<template v-else>
<text class="handle"
@click.stop="doAction(index,0)"
v-if="item.payload.cancelText"
>{{item.payload.cancelText}}</text>
<text
class="handle"
@click.stop="doAction(index,1)"
v-if="item.payload.confirmText"
>{{item.payload.confirmText}}</text>
<uni-icons v-if="!item.payload.cancelText && !item.payload.confirmText && item.path"
type="right" color="#cccccc"></uni-icons>
</template>
</view>
</uni-list-chat>
</template>
<uni-list-item v-else class="load-more">
<template v-slot:body>
<uni-load-more class="tip" :status="hasMore?'loading':'noMore'"></uni-load-more>
</template>
</uni-list-item>
</uni-list>
</view>
</template>
<script>
import uniImUtils from '@/uni_modules/uni-im/common/utils.js';
import uniIm from '@/uni_modules/uni-im/lib/main.js';
import action from './action.js';
const db = uniCloud.database();
export default {
data() {
return {
filterNotice:{},
tips:"",
hasMore:true
// notificationDatas:[]
}
},
async onLoad({param}) {
// console.log(param,decodeURIComponent(param))
param = JSON.parse(decodeURIComponent(param))
// console.log(param)
this.setParam(param)
},
computed: {
//是否为pc宽屏width>960px
isWidescreen(){
return uniIm.isWidescreen
},
notificationDatas(){
let notificationDatas = uniIm.notification.get(this.filterNotice)
if(notificationDatas.length == 0){
setTimeout(()=> {
this.hasMore = false
}, 100);
}
return notificationDatas
}
},
mounted() {
this.hasMore = uniIm.notification.hasMore
},
methods: {
setParam({filterNotice,title}){
if(typeof filterNotice == 'string'){
filterNotice = JSON.parse(decodeURIComponent(filterNotice))
}
this.filterNotice = filterNotice
console.log('filterNotice',filterNotice)
uni.setNavigationBarTitle({
title
})
if(title == '新朋友' && !this.isWidescreen){
this.tips = '好友请求通知'
}
},
async setItem({_id},param){
const datas = uniIm.notification.get(this.filterNotice)
for (let i = 0; i < datas.length; i++) {
if(datas[i]._id == _id){
datas[i] = deepAssign(datas[i],param)
uniIm.notificationDatas = datas
console.log('uniIm.notificationDatas',uniIm.notificationDatas)
break;
}
}
let ares = await db.collection('uni-im-notification')
.where(`"_id" == "${_id}" && "user_id" == $cloudEnv_uid`)
.get()
// console.log(13231,ares);
let res = await db.collection('uni-im-notification')
.where(`"_id" == "${_id}" && "user_id" == $cloudEnv_uid`)
.update(param)
// console.log('res---66666',param,res.result.updated);
/**
*判断对象是否是一个纯粹的对象
*/
function isPlainObject(obj){
return typeof obj === 'object' && Object.prototype.toString.call(obj) === '[object Object]'
}
/**
*深度合并多个对象的方法
*/
function deepAssign( ){
let len = arguments.length, target = arguments[0]
if(!isPlainObject(target)){
target = {}
}
for (let i = 1; i < len; i++){
let source = arguments[i]
if( isPlainObject( source ) ){
for( let s in source ){
if ( s === '__proto__' || target === source[s] ) {
continue
}
if( isPlainObject( source[s] ) ){
target[s] = deepAssign(target[s], source[s])
}else{
target[s] = source[s]
}
}
}
}
return target
}
},
async clickHandle(index,item){
// console.log('index',index,item);
//如果未读,设置为已读
if(!item.is_read){
this.setItem(item,{is_read:true})
}
//存在链接就跳转
let path = item.path || item.payload.path
if(path){
uni.navigateTo({
url:path,
fail: (e) => {
console.error(e);
}
})
}
// let item = this.notificationDatas[index]
// item.data.is_read = true
// this.notificationDatas[index] = Object.assign({},item)
// console.log(this.notificationDatas);
},
doAction(index,type){
let item = this.notificationDatas[index]
let e = {
subType:item.payload.subType,
confirm:type===1,
cancel:type===0,
item
}
action(e,data=>{
console.log('doAction',data)
this.setItem(item,{
is_read:true,
payload:{
state : type===1?'confirm':'cancel'
}
})
})
// console.log(index);
},
friendlyTime(timestamp) {
return uniImUtils.toFriendlyTime(timestamp)
},
handleText(state){
switch (state){
case 0:
return '同意'
break;
case 100:
return '已同意'
break;
case -100:
return '已拒绝'
break;
default:
return '其他'
break;
}
}
}
}
</script>
<style lang="scss" scoped>
.notification-box{
/* #ifndef APP-NVUE */
height: 100vh;
// width: 750rpx;
/* #endif */
/* #ifdef APP-NVUE */
flex: 1;
/* #endif */
background-color: #f5f5f5;
}
.tips{
height: 40px;
line-height: 40px;
padding-left: 20rpx;
font-size: 26rpx;
color: #666;
}
.handle-box{
flex-direction: row;
height: 40px;
align-items: center;
}
.handle{
width: 50px;
text-align: center;
height: 25px;
line-height: 25px;
background-color: #efefef;
border-radius: 50px;
font-size: 12px;
margin:0 5px;
/* #ifdef H5 */
cursor: pointer;
/* #endif */
}
.done{
width: 50px;
background-color: #FFF;
color: #aaa;
/* #ifdef H5 */
cursor: default;
/* #endif */
}
.load-more{
background-color: #f5f5f5!important;
justify-content: center;
}
.tip{
position: relative;
left: -15px;
width: 750rpx;
/* #ifndef APP-NVUE */
/* pc宽屏时需要使用100vw */
width: 100vw;
/* #endif */
}
/* #ifdef MP-WEIXIN */
.load-more ::v-deep .uni-list-item{
background-color: #f5f5f5!important;
}
/* #endif */
</style>

View File

@@ -0,0 +1,178 @@
<template>
<view class="container">
<view class="qr-code">
<view class="code-info">
<text class="group-name">{{name}}</text>
<text class="group-id" @click="copyGroupID">群号:{{group_id}}</text>
<!--uqrcode 组件来源插件Sansnn-uQRCode 链接地址https://ext.dcloud.net.cn/plugin?id=1287 -->
<!-- #ifndef MP-WEIXIN -->
<!-- <uqrcode ref="uqrcode" :start="false" :size="200" canvas-id="qrcode" :value="qrcodeData"></uqrcode> -->
<!-- #endif -->
</view>
<!-- #ifndef APP-NVUE -->
<image class="group-avatar" :src="avatar_file || '/uni_modules/uni-im/static/avatarUrl.png'" mode="">
</image>
<!-- #endif -->
</view>
<!-- #ifdef APP-NVUE -->
<image class="group-avatar" :src="avatar_file || '/uni_modules/uni-im/static/avatarUrl.png'" mode=""></image>
<!-- #endif -->
<!-- <view class="btn-box">
<view class="btn-item" @click="save">
<uni-icons type="arrow-down" size="30"></uni-icons>
<text class="btn-text">保存</text>
</view>
<view class="btn-item" @click="share">
<uni-icons type="paperplane" size="30"></uni-icons>
<text class="btn-text">分享</text>
</view>
</view> -->
</view>
</template>
<script>
import uqrcode from "@/uni_modules/Sansnn-uQRCode/components/uqrcode/uqrcode"
export default {
components: {
uqrcode
},
data() {
return {
group_id: '',
name: '',
avatar_file: ''
}
},
computed: {
qrcodeData() {
let data = {
"type": "uni-im",
"subType": "groupInfo",
"data": {
group_id: this.group_id,
name: this.name,
avatar_file: this.avatar_file
}
}
return JSON.stringify(data)
}
},
onLoad(options) {
// console.log("options: ",options);
this.group_id = options.id
this.name = options.name
this.avatar_file = options.avatar_file
},
onReady(){
setTimeout(()=>{
this.$refs.uqrcode.make({
success: () => {
// console.log('生成成功');
},
fail: err => {
// console.log(err)
}
});
},1000)
},
methods: {
copyGroupID() {
uni.setClipboardData({
data: this.group_id,
success: function() {
console.log('success');
}
});
},
save() {
console.log('保存');
},
share() {
console.log('分享');
}
}
}
</script>
<style lang="scss" scoped>
.container {
/* #ifndef APP-NVUE */
height: 100vh;
/* #endif */
flex: 1;
padding-top: 200rpx;
// justify-content: center;
align-items: center;
background-color: #f5f5f5;
}
.qr-code {
width: 550rpx;
height: 780rpx;
align-items: center;
justify-content: center;
border-radius: 20rpx;
background-color: #fff;
position: relative;
}
.code-info {
align-items: center;
justify-content: center;
}
.group-avatar {
width: 150rpx;
height: 150rpx;
border-radius: 100rpx;
position: absolute;
/* #ifdef APP-NVUE */
top: 150rpx;
/* #endif */
/* #ifndef APP-NVUE */
top: -60rpx;
/* #endif */
}
.group-name {
width: 400rpx;
font-size: 46rpx;
/* #ifdef APP-NVUE */
lines: 1;
/* #endif */
/* #ifndef APP-PLUS */
white-space: nowrap;
overflow: hidden;
/* #endif */
text-overflow: ellipsis;
margin-top: 120rpx;
text-align: center;
}
.group-id {
margin: 40rpx 0;
font-size: 30rpx;
}
.btn-box {
flex-direction: row;
margin-top: 100rpx;
}
.btn-item {
align-items: center;
justify-content: center;
width: 130rpx;
height: 130rpx;
border-radius: 100rpx;
background-color: #fff;
margin: 0 80rpx;
border: 1px solid #eee;
}
.btn-text {
font-size: 28rpx;
}
</style>

View File

@@ -0,0 +1,569 @@
<template>
<view class="pages">
<view class="usersInfo">
<scroll-view class="usersInfo" scroll-y="true" :enable-flex="true" >
<view style="height: 150px;width: 750rpx;flex-direction: row;flex-wrap: wrap;">
<view class="invite-box">
<view class="invite">
<uni-icons @click="invite" color="#989898" size="20px" class="plusempty" type="plusempty">
</uni-icons>
</view>
<text class="nickname">邀请</text>
</view>
<view class="item" v-for="(item,index) in member_list" :key="index">
<image class="avatar"
:src="item.avatar_file ? item.avatar_file.url:'/uni_modules/uni-im/static/avatarUrl.png'"
mode="widthFix"></image>
<text class="nickname">{{item.nickname||'匿名用户'}}</text>
<uni-icons @click="expel(item)" v-if="manage" color="#e64348" size="20px" class="minus-filled"
type="minus-filled">
</uni-icons>
</view>
</view>
</scroll-view>
</view>
<uni-list>
<uni-list-item @click="toQRCode" :clickable="true" title="群号和二维码" v-if="conversation.group_id" link>
<template v-slot:footer>
<view class="slot-code">
<!-- <text class="group-name"></text> 先省略,后续会建群号表关联 -->
<image class="group-code" src="/uni_modules/uni-im/static/qrCode.png" mode="widthFix"></image>
</view>
</template>
</uni-list-item>
<uni-list-item @click.native="openPopupInfo('editorName')" title="群聊名称" :showArrow="isAdmin" :clickable="true">
<template v-slot:footer>
<text class="introduction">{{conversation.group_info.name}}</text>
</template>
</uni-list-item>
<uni-list-item @click.native="openPopupInfo('editorInfo')" title="简介" :showArrow="isAdmin" :clickable="true">
<template v-slot:footer>
<text class="introduction">{{conversation.group_info.introduction || '未设置'}}</text>
</template>
</uni-list-item>
<uni-list-item @click.native="setAvatar" title="群头像" :clickable="true">
<template v-slot:footer>
<image class="logo" :src="logoUrl||'/uni_modules/uni-im/static/avatarUrl.png'" mode=""></image>
</template>
</uni-list-item>
<uni-list-item @click.native="setAddGroupType" title="加群方式" note="申请加入本群的验证规则" :clickable="true">
<template v-slot:footer>
<text class="join_option">{{join_option}}</text>
</template>
</uni-list-item>
</uni-list>
<button class="exitGroup" @click="exitGroup">{{isAdmin?'解散群聊':'退出群聊'}}</button>
<uni-popup ref="popupInfo" type="dialog">
<uni-popup-dialog mode="input" :title="editorType == 'editorName'?'编辑群聊名称':'编辑群聊简介'"
:placeholder="editorType == 'editorName'?'请输入群聊名称':'请输入群聊简介'" :duration="2000" :before-close="true"
:value="value" @close="closePopupInfo" @confirm="confirmPopupInfo"></uni-popup-dialog>
</uni-popup>
</view>
</template>
<script>
const db = uniCloud.database()
import uniIm from '@/uni_modules/uni-im/lib/main.js';
export default {
data() {
return {
conversation:{
group_info:{
user_id:""
},
group_member:{}
},
member_list:[],
manage: false,
editorType: '',
value: '',
groupType: '',
isAdmin:false
};
},
computed: {
...uniIm.mapState(['isWidescreen']),
logoUrl() {
return this.conversation.group_info.avatar_file ? this.conversation.group_info.avatar_file.url :
false
},
join_option() {
let val = this.conversation.group_info.join_option
return {
needPermission: "需要验证权限",
freeAccess: "自由加入",
disableApply: "禁止加入"
} [val]
}
},
watch: {
"conversation.group_info.user_id"(adminUserId){
this.isAdmin = adminUserId == uniCloud.getCurrentUserInfo().uid
//非群主 隐藏【管理】按钮
if (!this.isAdmin) {
if(!this.isWidescreen){
// #ifdef H5
let dom = document.getElementsByClassName('uni-page-head-btn')[1]
dom.style.visibility = 'hidden'; // 隐藏元素
// #endif
// #ifdef APP-PLUS
var webview = this.$scope.$getAppWebview();
// console.log('webview', webview);
webview.setStyle({
titleNView:{
buttons:[]
}
});
// #endif
}
}else{
if(this.isWidescreen){
this.manage = true
}
}
},
"conversation.group_member":{
handler(group_member, oldValue) {
console.log('group_member',group_member);
this.member_list = []
for (let key in group_member) {
this.member_list.push(group_member[key])
}
let title = "群信息(" + this.member_list.length + "人)"
uni.setNavigationBarTitle({
title
});
},
deep:true,
immediate:true
}
// (后续)通过监听实现实时切换管理员实时刷新权限
// console.log('isAdmin',isAdmin);
},
props: {
conversation_id: {
default(){
return false
}
},
},
async onLoad(e) {
if(!e.conversation_id){
throw new Error("会话id不能为空")
}
this.load(e.conversation_id)
},
mounted() { //pc端以组件模式加载时逻辑
if(this.conversation_id){
this.load(this.conversation_id)
}
},
onShow() {
// console.log("this.conversation: ", this.conversation.group_member);
},
onNavigationBarButtonTap(e) {
if (e.index === 0) {
this.manage = !this.manage
// #ifdef H5
let dom = document.getElementsByClassName('uni-btn-icon')[1]
// console.log("dom:22 ", dom);
dom.innerHTML = this.manage ? "退出管理" : "管理"
// #endif
// #ifdef APP-PLUS
var webview = this.$scope.$getAppWebview();
webview.setTitleNViewButtonStyle(0, {
text: this.manage ? "退出" : "管理"
});
// #endif
}
},
methods: {
async load(conversation_id){
this.conversation = await uniIm.conversation.get(conversation_id)
},
async expel(item) {
uni.showModal({
title: '确定要将该用户移出本群吗?',
content: '不能撤销,请谨慎操作',
cancelText: '取消',
confirmText: '确认',
complete: async (e) => {
// console.log(e);
if (e.confirm) {
uni.showLoading({
mask: true
});
try{
let res = await db.collection('uni-im-group-member').where({
user_id: item._id,
group_id: this.conversation.group_info._id
})
.remove()
if (res.result.deleted) {
uni.showToast({
title: '成功移除',
icon: 'none',
complete: () => {}
});
// console.log('exitGroup', res);
}
}catch(error){
uni.showToast({
title: error.message,
icon: 'error',
complete: () => {}
});
//TODO handle the exception
}
uni.hideLoading()
}
}
});
},
invite() {
console.log('group_info._id', this.conversation.group_info._id);
uni.navigateTo({
url: '/uni_modules/uni-im/pages/contacts/createGroup/createGroup?group_id=' + this
.conversation.group_info._id
})
},
async exitGroup() {
const group_id = this.conversation.group_info._id
if (this.isAdmin) {
uni.showModal({
title: '确认要解散群聊吗?',
content: '不能撤销,请谨慎操作',
cancelText: '取消',
confirmText: '确认',
complete: async (e) => {
console.log(e);
if (e.confirm) {
uni.showLoading({
mask: true
});
let res = await db.collection('uni-im-group')
.where({
_id: group_id
})
.remove()
.finally((res) => {
// uni.navigateBack({ // 收到离群的推送通知会自动关闭当前页面
// delta: 2
// })
uni.hideLoading()
})
console.log('exitGroup', res);
}
}
});
} else {
uni.showModal({
title: '确认要退出群聊吗?',
content: '不能撤销,请谨慎操作',
cancelText: '取消',
confirmText: '确认',
complete: async (e) => {
console.log(e);
if (e.confirm) {
// uni.navigateBack({ // 收到离群的推送通知会自动关闭当前页面
// delta: 2
// })
uni.showLoading({
mask: true
});
let res = await db.collection('uni-im-group-member').where({
user_id: uniCloud.getCurrentUserInfo().uid,
group_id
})
.remove()
if (res.result.deleted) {
uni.showToast({
title: '成功退出',
icon: 'none'
});
}
uni.hideLoading()
console.log('exitGroup', res);
}
}
});
}
},
openPopupInfo(type) {
console.log(type);
if (!this.isAdmin) return
this.editorType = type
console.log(this.conversation.group_info.name, 11);
console.log(this.conversation.group_info.introduction, 22);
if (type == 'editorName' && this.conversation.group_info.name) {
this.value = this.conversation.group_info.name
} else if (type == 'editorInfo' && this.conversation.group_info.introduction) {
this.value = this.conversation.group_info.introduction
} else {
this.value = ''
}
this.$refs.popupInfo.open()
},
closePopupInfo() {
this.$refs.popupInfo.close()
},
confirmPopupInfo(value) {
if (!value) {
uni.showToast({
title: '内容不能为空!',
icon: 'none'
});
return
}
console.log('----', value);
if (this.editorType == 'editorName') {
// 改群名称
this.editGroupInfo({
name: value
})
} else {
this.editGroupInfo({
introduction: value
})
}
this.$refs.popupInfo.close()
},
setAddGroupType() {
if (!this.isAdmin) return
uni.showActionSheet({
itemList: ['自由加入', '需要验证权限', '禁止加入'],
success: (e) => {
let join_option = ['freeAccess', 'needPermission', 'disableApply'][e.tapIndex]
this.editGroupInfo({
join_option
})
},
fail: (err) => {
console.log("err: ", err);
}
})
},
async editGroupInfo(group_info) {
console.log('group_info---------',group_info);
this.conversation.group_info = Object.assign(this.conversation.group_info,group_info)
let res = await db.collection('uni-im-group')
.doc(this.conversation.group_id)
.update(group_info)
console.log('change group info', res.result.updated,this.conversation);
},
async setAvatar() {
if (!this.isAdmin) return
const crop = {
quality: 100,
width: 600,
height: 600,
resize: true
};
uni.chooseImage({
count: 1,
crop,
success: async (res) => {
console.log(899889,res);
let tempFile = res.tempFiles[0],
avatar_file = {
// #ifdef H5
extname: tempFile.name.split('.')[tempFile.name.split('.').length - 1],
// #endif
// #ifndef H5
extname: tempFile.path.split('.')[tempFile.path.split('.').length - 1]
// #endif
},
filePath = res.tempFilePaths[0]
// #ifndef APP-PLUS
//非app端用前端组件剪裁头像app端用内置的原生裁剪
let isPC = false
// #ifdef H5
isPC = !['ios', 'android'].includes(uni.getSystemInfoSync().platform)
// #endif
if (!isPC) {
filePath = await new Promise((callback) => {
uni.navigateTo({
url: '/uni_modules/uni-id-pages/pages/userinfo/cropImage/cropImage?path=' +
filePath + `&options=${JSON.stringify(crop)}`,
animationType: "fade-in",
events: {
success: url => {
callback(url)
}
},
complete(e) {
// console.log(e);
}
});
})
}
// #endif
// console.log(this.userInfo);
let cloudPath = uniCloud.getCurrentUserInfo().uid + '' + Date.now()
avatar_file.name = cloudPath
uni.showLoading({
title: "更新中",
mask: true
});
let {
fileID
} = await uniCloud.uploadFile({
filePath,
cloudPath,
fileType: "image"
});
// console.log(result)
avatar_file.url = fileID
// console.log({avatar_file});
uni.hideLoading()
this.editGroupInfo({
avatar_file
})
}
})
},
toQRCode() {
let url = this.logoUrl ? this.logoUrl : ''
uni.navigateTo({
url: '/uni_modules/uni-im/pages/group/groupQRCode?id=' +
this.conversation.group_info._id +
'&name=' + this.conversation.group_info.name +
'&avatar_file=' + url,
complete: (e) => {
// console.log(e);
}
});
}
}
}
</script>
<style lang="less" scoped>
/* #ifndef APP-NVUE */
page,
/* #endif */
.pages {
width: 750rpx;
flex: 1;
background-color: #f5f5f5;
/* #ifndef APP-NVUE */
height: 100vh;
/* #endif */
}
.usersInfo {
flex-direction: row;
// padding: 10px 0;
margin-bottom: 8px;
background-color: #FFFFFF;
flex-wrap: wrap;
}
.item {
width: 150rpx;
margin: 5px 0;
align-items: center;
justify-content: center;
position: relative;
}
.minus-filled {
position: absolute;
top: 0;
right: 5px;
/* #ifdef H5 */
cursor: pointer;
/* #endif */
}
.avatar {
width: 100rpx;
height: 100rpx;
border-radius: 10px;
}
.nickname {
width: 150rpx;
text-align: center;
font-size: 14px;
color: #666;
padding: 0 16rpx;
/* #ifndef APP-NVUE */
white-space: nowrap;
/* #endif */
overflow: hidden;
text-overflow: ellipsis;
lines:1;
}
.logo {
width: 50px;
height: 50px;
}
.invite-box {
align-items: center;
}
.invite {
width: 100rpx;
height: 100rpx;
margin: 5px 0;
justify-content: center;
border-radius: 10px;
background-color: #f5f5f5;
/* #ifdef H5 */
cursor: pointer;
/* #endif */
}
.exitGroup {
margin: 10px 0;
background-color: #FFFFFF;
padding: 6px 0;
color: #e64141;
border-radius: 0;
}
/* #ifndef APP-NVUE */
.exitGroup::after {
display: none;
}
/* #endif */
.introduction {
color: #666;
font-size: 14px;
/* #ifndef APP-NVUE */
max-width: 560rpx;
/* #endif */
/* #ifdef APP-NVUE */
width: 560rpx;
/* #endif */
text-align: right;
}
.join_option {
color: #666;
font-size: 14px;
}
.slot-code {
align-items: center;
flex-direction: row;
}
.group-code {
width: 50rpx;
height: 50rpx;
margin-left: 10rpx;
}
</style>

View File

@@ -0,0 +1,565 @@
<template>
<view id="page">
<!-- 底部版权声明栏 -->
<view id="about" v-if="isWidescreen" space="nbsp">
<text>欢迎体验uni-im &#8203;</text>
<uni-link href="https://ext.dcloud.net.cn/plugin?id=9711" text="[点此下载插件]"></uni-link>
</view>
<!-- #ifdef H5 -->
<!-- 布局最左侧 菜单栏 -->
<view id="left-view" v-if="isWidescreen" @click="chatInfoIsShow = false;">
<cloud-image class="user-avatar" @click="toUcenter" :src="avatarUrl" width="40px" height="40px"
borderRadius="100px"></cloud-image>
<!-- {{currentUserInfo.username}} -->
<uni-badge size="small" :text="unreadMsgCount" absolute="rightTop" type="error">
<uni-icons class="chat-icon" @click="showContactsView = false"
:color="showContactsView?'#c5c5c5':'#5fc08e'" size="32" type="chatbubble-filled"></uni-icons>
</uni-badge>
<uni-badge size="small" :text="unreadnotificationCount" absolute="rightTop" type="error">
<uni-icons @click="showContactsView = true" :color="showContactsView?'#5fc08e':'#c5c5c5'" size="32"
type="staff-filled"></uni-icons>
</uni-badge>
</view>
<!-- #endif -->
<!-- 会话列表 -->
<view id="center-view">
<!-- #ifdef H5 -->
<!-- 搜索会话用户、聊天记录... -->
<view id="search-bar-box" v-if="isWidescreen" @click="clickSearchBarBox">
<uni-search-bar :readonly="true" id="search-bar" radius="5" placeholder="搜索" clearButton="auto" cancelButton="none"
></uni-search-bar>
<uni-icons color="#848386" size="26" type="plus"></uni-icons>
</view>
<view id="uni-im-contacts-box" v-show="isWidescreen && showContactsView">
<uni-im-contacts @clickMenu="clickMenu" id="uni-im-contacts"></uni-im-contacts>
</view>
<!-- #endif -->
<!-- #ifdef H5 -->
<scroll-view id="user-list-box" scroll-y="true" @scrolltolower="loadMore()">
<!-- #endif -->
<!-- 会话用户列表 -->
<uni-list class="user-list" :style="{'height':wHeight,'width':'750rpx'}" :border="false">
<uni-list-chat @contextmenu.prevent.native="toChat(item.id)"
v-for="(item,index) in conversationList" :key="item.id" :showBadge="item.unread_count>0"
:badgeText="item.unread_count" link :title="item.title" class="user-list-item"
:class="{activeConversation:currentConversationId==item.id}" :note="item.last_msg_note"
:avatar="item.avatar_file&&item.avatar_file.url ? item.avatar_file.url : '/uni_modules/uni-im/static/avatarUrl.png'"
@click="toChat(item.id)" direction="column" :time="friendlyTime(item.update_time)"
:hasCallMe="item.call_list.length">
<template v-slot:header>
<text class="group-icon" v-if="item.group_id">群</text>
</template>
</uni-list-chat>
<!-- #ifdef APP-NVUE -->
<!-- nvue端appear元素一旦显示在可视窗口中就触发加载更多。-->
<cell v-if="conversationList.length" @appear="loadMore()"></cell>
<!-- #endif -->
<uni-list-item :customStyle="{backgroundColor:'#f5f5f5',padding:0}">
<template v-slot:body>
<uni-load-more class="tip" :contentText="loadMoreContentText"
:status="conversationHasMore?'loading':'noMore'"></uni-load-more>
</template>
</uni-list-item>
</uni-list>
<!-- #ifdef H5 -->
</scroll-view>
<!-- #endif -->
</view>
<!-- #ifdef H5 -->
<view id="right-view" v-if="isWidescreen">
<!-- 聊天窗口 -->
<view id="chat-view-box">
<template v-if="!showContactsView && currentConversationId">
<view id="chat-header" v-if="!showContactsView">
<!-- 群标题 -->
<text :selectable="true">{{currentConversation.title}}</text>
<uni-icons @click="showChatInfo" class="more" type="more-filled" size="20"></uni-icons>
</view>
<view id="chat-view">
<chat-view ref="chat-view"></chat-view>
</view>
<view v-if="chatInfoIsShow" class="chatInfoBox" @click.stop="chatInfoIsShow = false">
<uni-im-group-info @click.native.stop v-if="currentConversation.group_id"
:conversation_id="currentConversation.id"></uni-im-group-info>
<uni-im-chat-info @click.native.stop v-else
:conversation_id="currentConversation.id"></uni-im-chat-info>
</view>
</template>
<view v-else id="ccid-is-null-tip">
未选择会话对象
</view>
</view>
<view id="dynamic-component-box" v-show="showContactsView">
<view class="dynamic-component-title">{{view2Title}}</view>
<component ref="dynamicComponent" :is="dynamicComponentName"></component>
</view>
</view>
<!-- #endif -->
</view>
</template>
<script>
const db = uniCloud.database();
// #ifdef H5
import chatView from '@/uni_modules/uni-im/pages/chat/chat';
// #endif
import uniImUtils from '@/uni_modules/uni-im/common/utils.js';
import {
store as uniIdStore,
mutations as uniIdMutations
} from '@/uni_modules/uni-id-pages/common/store.js';
import uniIm from '@/uni_modules/uni-im/lib/main.js';
import contacts from '@/uni_modules/uni-im/pages/contacts/contacts';
// #ifdef H5
import notification from '@/uni_modules/uni-im/pages/contacts/notification/notification';
import addPeopleGroups from '@/uni_modules/uni-im/pages/contacts/addPeopleGroups/addPeopleGroups';
import groupList from '@/uni_modules/uni-im/pages/contacts/groupList/groupList';
import createGroup from '@/uni_modules/uni-im/pages/contacts/createGroup/createGroup';
import chatInfo from '@/uni_modules/uni-im/pages/chat/info';
import groupInfo from '@/uni_modules/uni-im/pages/group/info';
import {version} from '@/uni_modules/uni-im/package.json'
// #endif
let lastConversationId = false
let sortIndex = 0
export default {
// #ifdef H5
components: {
chatView,
"uni-im-contacts": contacts,
"uni-im-notification": notification,
"uni-im-addPeopleGroups": addPeopleGroups,
"uni-im-groupList": groupList,
"uni-im-createGroup": createGroup,
"uni-im-chat-info": chatInfo,
"uni-im-group-info": groupInfo
},
// #endif
data() {
return {
wHeight: 'auto',
userInfo: {},
dynamicComponentName: 'uni-im-addPeopleGroups', //通过动态组件引入页面在pc端显示
view2Title: '加人/加群',
showContactsView: false,
chatInfoIsShow: false,
currentConversation: {}
};
},
computed: {
conversationList(){
sortIndex ++
// console.log('根据会话时间排序',uniIm.conversation.dataList,sortIndex)
let conversationList = uniIm.conversation.dataList
setTimeout(()=> {
sortIndex = 0
}, 1000);
if(sortIndex > 6){
return conversationList
}
return conversationList.sort(function(a, b) {
if(b.id == uniIm.currentConversationId) {
// 当前会话正在输入时不需要重新排序避免change频繁触发导致排序频繁
return 0
}
// 如果该会话的输入框已经输入了内容未发就排在前面
if(b.chatText){
b.update_time = Date.now()
}
let a_update_time = a.update_time || 0
let b_update_time = b.update_time || 0
let aml = a.msgList.length
let bml = b.msgList.length
if (aml) {
let create_time = a.msgList[aml - 1].create_time
if (create_time > a_update_time) {
a_update_time = create_time
}
}
if (bml) {
let create_time = b.msgList[bml - 1].create_time
if (create_time > b_update_time) {
b_update_time = create_time
}
}
return b_update_time - a_update_time
})
},
loadMoreContentText() {
return {
contentrefresh: "正在加载...",
contentnomore: (this.conversationList.length ? "没有更多数据了" : "没有会话数据")
}
},
conversationHasMore() {
return uniIm.conversation.hasMore
},
// 导入uniIm响应式数据支持别名比如:['a as b']
...uniIm.mapState(['currentConversationId', 'isWidescreen']),
unreadMsgCount() {
return uniIm.conversation.unreadCount()
},
unreadnotificationCount() {
return uniIm.notification.unreadCount()
},
currentUserInfo() {
return uniIdStore.userInfo
},
avatarUrl() {
if (this.currentUserInfo.avatar_file && this.currentUserInfo.avatar_file.url) {
return this.currentUserInfo.avatar_file.url
}
return '/uni_modules/uni-im/static/avatarUrl.png'
}
},
watch: {
unreadMsgCount(unreadMsgCount) {
console.log({
unreadMsgCount
});
// #ifdef APP
plus.runtime.setBadgeNumber(unreadMsgCount)
// #endif
if (unreadMsgCount == 0) {
uni.removeTabBarBadge({
index: 0,
complete: (e) => {
console.log(e)
}
})
} else {
uni.setTabBarBadge({
index: 0,
text: unreadMsgCount + '',
complete: (e) => {
// console.log(e)
}
})
}
},
showContactsView(showContactsView) {
if (showContactsView) {
lastConversationId = this.currentConversationId
uniIm.currentConversationId = false
} else {
if (lastConversationId) {
uniIm.currentConversationId = lastConversationId
this.$nextTick(() => {
this.toChat(lastConversationId)
})
}
}
},
async currentConversationId(id) {
this.currentConversation = await uniIm.conversation.get(id)
}
},
created() {
// #ifdef APP-NVUE
this.wHeight = uni.getSystemInfoSync().windowHeight + 'px'
// #endif
},
async onLoad(param) {
let {
token,
user_id,
conversation_id,
joinGroup
} = param
let version = "2023-05-22-01"
// 发布新版本后清理旧版本下的storage避免脏数据引发问题
let lastVersion = uni.getStorageSync('uni-im-storage-version')
if (lastVersion && lastVersion != version) {
uni.setStorageSync('uni-im-storage-version', version)
uni.clearStorage()
}
let {
tokenExpired
} = uniCloud.getCurrentUserInfo()
if (!tokenExpired || tokenExpired < Date.now()) {
console.info('当前用户的登录状态无效,将自动跳转至登录页面。', param)
let url = '/uni_modules/uni-id-pages/pages/login/login-withpwd?uniIdRedirectUrl='
let paramString = '/uni_modules/uni-im/pages/index/index?'
for (let key in param) {
paramString += `${key}=${param[key]}&`
}
paramString = paramString.substring(0, paramString.length - 1) //携带参数,实现登录成功后 跳回首页时传回
url += encodeURIComponent(paramString)
return uni.reLaunch({
url
})
}
this.$nextTick(() => {
this.init({
user_id,
conversation_id
})
})
this.onLoginSuccess = async () => {
this.init({
user_id,
conversation_id
})
}
uni.$on('uni-id-pages-login-success', this.onLoginSuccess)
uni.$on('uni-im-toChat', param => {
if (param) {
// 关闭最后一次的会话id防止切回后重新显示最后一次会话而邮箱指定显示到某个会话
lastConversationId = false
this.toChat(param)
}
this.showContactsView = false
})
/**
* 在本页面链接传递参数 joinGroup=group_id即可申请加入群
* 比如http://localhost:8082/#/uni_modules/uni-im/pages/index/index?joinGroup=xxx
*/
if(joinGroup){
let group_id = joinGroup
// #ifdef H5
//删除地址栏的token且不刷新页面
history.pushState({}, '', '/#/');
// #endif
console.log('group_id',group_id);
db.collection('uni-im-group-join').add({
group_id,
"message":''
}).then((res) => {
console.log("res: ",res);
uni.showToast({
icon: 'none',
title: '已申请'
})
}).catch((err) => {
uni.showModal({
content: err.message || '请求服务失败',
showCancel: false
})
})
}
},
async onReady() {
// #ifdef H5
let systemInfo = uni.getSystemInfoSync()
uniIm.systemInfo = systemInfo
// console.log('systemInfo',systemInfo);
if (!['edge', 'chrome', 'safari'].includes(systemInfo.browserName)) {
let newElement = document.createElement('div')
newElement.innerHTML = `
<div style="background: #fff9ea;color: #ff9a43;position: fixed;top: 0;left: 0;width: 100vw;padding: 15px;font-size: 18px;">
注意本系统仅兼容chrome、edge、safari浏览器
</div>
`
document.body.appendChild(newElement)
}
// #endif
},
onUnload() {
uni.$off('uni-id-pages-login-success', this.onLoginSuccess)
},
onHide() {},
methods: {
clickSearchBarBox(){
uni.showToast({
title: '暂不支持',
icon: 'none'
});
},
async loadMore() {
let data = await uniIm.conversation.loadMore()
return data
},
clickMenu(data) {
// console.log('79879789798898798978789', data);
this.dynamicComponentName = data.componentName
if (data.title) {
this.view2Title = data.title
}
if (data.param) {
this.$nextTick(() => {
this.$refs.dynamicComponent.setParam(data.param)
})
}
// console.log('data.componentName----',data.componentName);
if (data.componentName == 'uni-im-createGroup') {
this.$nextTick(() => {
this.$refs.dynamicComponent.getFriendsData()
})
}
},
readQrCode() {
uni.scanCode({
complete: (e) => {
// console.log(e);
try {
let data = JSON.parse(e.result)
// console.log(data);
if (data.type == 'uni-im' && data.subType == "groupInfo") {
}
} catch (e) {
//TODO handle the exception
}
}
})
},
async init({
conversation_id,
user_id
}) {
// 初始化会话列表
// console.log('初始化会话列表',{
// conversation_id,
// user_id,
// });
await this.loadMore()
if (conversation_id) {
// console.log('conversation_id', conversation_id);
this.toChat(conversation_id)
} else if (user_id) {
//创建会话
const currentConversation = await uniIm.conversation.get({
friend_uid: user_id
})
// console.log('currentConversation', currentConversation);
// 当前用户给对方发个消息
this.toChat(currentConversation.id)
} else {
if (this.isWidescreen) {
let [firstConversation] = this.conversationList
if (firstConversation) {
this.currentConversation = await uniIm.conversation.get(firstConversation.id)
this.toChat(firstConversation.id)
} else {
// uni.showModal({
// content: '没有任何会话,请先到用户列表选择用户',
// showCancel: false
// });
}
}
}
},
search(e) {
// console.log("search-e: " + JSON.stringify(e));
uni.showToast({
title: '加好友功能入口,暂时在左侧菜单的通讯录中',
icon: 'none',
duration: 3000
});
},
addUser() {
uni.showToast({
title: '加好友功能入口,暂时在左侧菜单的通讯录中',
icon: 'none',
duration: 3000
});
},
async toChat(param) {
this.chatInfoIsShow = false;
// console.log('param',param);
let conversation_id = ''
if (typeof param == 'string') {
conversation_id = param
} else {
if (param.conversation_id) {
conversation_id = param.conversation_id
} else if (param.group_id) {
conversation_id = 'group_' + param.group_id
} else if (param.user_id || param.friend_uid) {
conversation_id = uniImUtils.getConversationId(param.user_id || param.friend_uid)
// console.log('conversation_id',conversation_id)
} else {
throw new Error("toChat param is error")
}
}
uniIm.currentConversationId = conversation_id
if (this.isWidescreen) { //若为宽屏,则触发右侧详情页的自定义事件,通知右侧窗体刷新详情
this.$nextTick(() => {
let chatViewRef = this.$refs['chat-view']
if (chatViewRef) {
chatViewRef.load(conversation_id)
}
})
} else { // 若为窄屏,则打开新窗体,在新窗体打开详情页面
uni.navigateTo({
url: '/uni_modules/uni-im/pages/chat/chat?conversation_id=' + conversation_id,
animationDuration: 300
})
}
},
showChatInfo() {
this.chatInfoIsShow = !this.chatInfoIsShow
},
toUcenter() {
uni.navigateTo({
url: '/uni_modules/uni-id-pages/pages/userinfo/userinfo?showLoginManage=true',
complete(e) {
console.log("e: " + JSON.stringify(e));
}
})
},
friendlyTime(timestamp) {
return uniImUtils.toFriendlyTime(timestamp)
},
},
async onReachBottom() {
await this.loadMore()
},
onNavigationBarButtonTap(e) {
// console.log(e);
if (e.index) {
let data = uni.getStorageInfoSync();
// console.log('data.keys', JSON.stringify(data.keys));
data.keys.forEach(item => {
if (item.includes('uni-im-msg:') || item.includes('uni-im-conversation')) {
// console.log(item);
uni.removeStorageSync(item);
// console.log(uni.getStorageSync(item));
}
});
uni.showToast({
title: 'clear storage ok',
icon: 'none'
});
} else {
uni.navigateTo({
url: '/uni_modules/uni-id-pages/pages/userinfo/userinfo?showLoginManage=true',
complete: e => {
console.log(e);
}
});
}
}
}
</script>
<style lang="scss" scoped>
@import url("./index.scss");
</style>

View File

@@ -0,0 +1,312 @@
/* #ifdef APP */
.group-icon {
position: absolute;
top: 5px;
left:55px;
background-color: #ea4938;
color: #fff;
font-size: 12px;
width: 16px;
height: 16px;
line-height: 16px;
text-align: center;
}
/* #endif */
/* #ifndef APP */
/* #ifdef VUE3 */
#center-view ::v-deep .slot-header .group-icon
/* #endif */
/* #ifdef VUE2 */
#center-view ::v-deep .group-icon
/* #endif */
{
position: relative;
top: -5px;
left: -10px;
margin-right: -20px;
background-color: #ea4938;
color: #fff;
font-size: 12px;
width: 16px;
height: 16px;
line-height: 16px;
text-align: center;
}
/* #endif */
.tip{
flex: 1;
}
/* #ifdef APP-NVUE */
.user-list {
flex:1;
background-color: #f5f5f5;
}
/* #endif */
/* #ifndef APP-NVUE */
#center-view{
height: 100vh;
background-color: #f5f5f5 !important;
}
/* #endif */
/* #ifdef H5 */
@media screen and (min-width:960px){
#page {
flex-direction: row;
justify-content: center;
align-items: center;
height: 100vh;
background-color: #2e2e3e;
}
#about {
position: fixed;
bottom: 4vh;
flex-direction: row;
color: #FFFFFF;
}
#about .uni-link:hover{
color: #00aa55 !important;
}
#left-view,
#center-view,
#right-view{
height: 85vh;
position: relative;
top: -2vh;
background-color: #FFFFFF;
}
#left-view *,#left-view ::v-deep *,
#center-view *,#center-view ::v-deep *,
#right-view *,#right-view ::v-deep *{
max-height: 85vh;
}
#center-view ::v-deep #user-list-box{
max-height: calc(85vh - 70px);
}
#left-view > *{
cursor: pointer;
margin-top: 36px;
}
#left-view > *:hover{
/* border: 1px solid #fefefe; */
box-shadow: 0 0 20px 2px #fefefe;
border-radius: 10px;
}
#left-view{
width:60px;
align-items: center;
padding-top: 100px;
background-color: #ececec;
border-radius: 20px 0 0 20px;
}
#center-view{
width:300px;
}
#center-view *,#center-view ::v-deep *{
max-width:300px;
}
#center-view #search-bar-box {
flex-direction: row;
align-items: center;
height: 70px;
}
#center-view #search-bar {
flex: 1;
}
#center-view #user-list-box .user-list-item {
cursor: pointer;
}
#center-view #user-list-box .tip{
/* background-color: #FFFFFF;*/
}
#center-view #user-list-box .user-list-item ::v-deep .uni-list-chat__content-title{
font-size: 14px;
}
#center-view #user-list-box .user-list-item.activeConversation {
background-color: #f8f8f8;
}
#right-view{
width:700px;
border-radius: 0 20px 20px 0;
overflow: hidden;
}
#right-view *,#right-view ::v-deep *{
max-width:700px;
}
#right-view #chat-header{
height: 70px;
padding:0 20px;
flex-direction: row;
justify-content: space-between;
align-items: center;
}
#right-view #chat-header .more{
cursor: pointer;
}
#right-view #chat-view,
#right-view #chat-view *,
#right-view #chat-view ::v-deep *
{
max-height:calc(85vh - 70px);
}
#right-view #chat-view ::v-deep .page * {
/* display: none; */
}
#right-view #chat-view ::v-deep .page {
flex: auto;
}
#right-view #chat-view ::v-deep .unread_count {
display: none;
}
#right-view #chat-view ::v-deep .msg-list .uni-im-list .scroll-view{
height: calc(85vh - 330px);
}
#right-view #chat-view ::v-deep .msg-list .uni-im-list .uni-im-msg{
width: 100%;
padding:0 10px;
}
#right-view #chat-view ::v-deep .msg-list .uni-im-list .uni-im-msg .cite-box{
max-width:500px;
}
#right-view #chat-view ::v-deep .msg-list .uni-im-list .uni-im-msg .exceed,
#right-view #chat-view ::v-deep .msg-list .uni-im-list .uni-im-msg .rich-text-box,
#right-view #chat-view ::v-deep .msg-list .uni-im-list .uni-im-msg .rich-text-box rich-text{
width: 400px;
}
#right-view #chat-view ::v-deep .chat-foot{
position: relative;
bottom: 0;
}
#right-view #chat-view ::v-deep .chat-foot .pc{
display: flex;
height: 260px;
width: 700px;
position: absolute;
bottom:0;
background-color: #f7f7f7;
}
#right-view #chat-view ::v-deep .chat-foot .pc .tool-bar,
#right-view #chat-view ::v-deep .chat-foot .pc .tool-bar .icons,
#right-view #chat-view ::v-deep .chat-foot .pc .tool-bar .code-model{
flex-direction: row;
height: 60px;
align-items: center;
}
#right-view #chat-view ::v-deep .chat-foot .pc .tool-bar .icons .uni-im-icons{
padding: 0 15px;
}
#right-view #chat-view ::v-deep .chat-foot .pc .answer-msg{
padding: 6px 10px;
width: 670px;
margin: 0 15px;
margin-bottom: 6px;
}
#right-view #chat-view ::v-deep .chat-foot .pc .answer-msg-text{
font-size: 14px;
width: 700px;
}
#right-view #chat-view ::v-deep .chat-foot .pc .textarea{
width: 700px;
height: 200px;
padding:0 15px;
background-color: #f7f7f7;
}
#right-view .chatInfoBox {
z-index: 999;
position: absolute;
right:0;
top: 70px;
background-color: rgba(0,0,0,0.2);
height: calc(85vh - 70px);
width: 100%;
align-items: flex-end;
}
#right-view .chatInfoBox ::v-deep .introduction{
max-width: 560px !important;
}
#uni-im-contacts-box {
z-index: 10;
height: 85vh;
position: absolute;
}
/* pc端隐藏删除好友的按钮后续改成长按右键可见 */
#uni-im-contacts-box ::v-deep .delete-btn{
display: none;
}
#ccid-is-null-tip{
height: 85vh;
padding-top: 15vh;
align-items: center;
background-color: #efefef;
}
#dynamic-component-box {
width: 700px;
z-index: 99;
height: 85vh;
position: absolute;
background-color: #fff;
right: 0;
}
#dynamic-component-box .dynamic-component-title{
padding-left: 15px;
height: 70px;
justify-content: center;
border: 1px solid #efefef;
}
#right-view #dynamic-component-box .system-notice-box{
width: 700px;
}
#right-view ::v-deep #dynamic-component-box .create-group-box .header-box{
top: calc(7vh + 55px);
}
/* 处理特殊情况 */
#page ::v-deep .uni-popup * {
max-width: 100vw;
max-height: 100vh;
}
}
/* #endif */

View File

@@ -0,0 +1,113 @@
<template>
<view>
<unicloud-db ref="udb" @load="handleLoad" v-slot:default="{ data, loading, pagination, error, options }"
collection="uni-id-users" field="_id,nickname,avatar_file" :where="udbWhere">
<view v-if="error" class="error">
<text>{{ error.message }}</text>
</view>
<uni-list v-else>
<uni-list-chat v-for="(item, index) in data" :key="item._id" link
:title="item.nickname"
:avatar="item.avatar_file ? item.avatar_file.url : '/uni_modules/uni-im/static/avatarUrl.png'"
@click="toChat(item._id)"></uni-list-chat>
</uni-list>
<uni-load-more :status="loading ? 'loading' : loadMoreStatus"></uni-load-more>
</unicloud-db>
</view>
</template>
<script>
import uniIm from '@/uni_modules/uni-im/lib/main.js';
export default {
onLoad() {
},
computed: {
//是否为pc宽屏width>960px
isWidescreen(){
return uniIm.isWidescreen
},
},
data() {
return {
loadMoreStatus: 'more',
udbWhere: '', //'_id != $cloudEnv_uid',
};
},
onPullDownRefresh() {
this.$refs.udb.loadData({
clear: true
},
() => {
uni.stopPullDownRefresh();
}
);
},
onReachBottom() {
this.$refs.udb.loadMore();
},
onNavigationBarButtonTap(e) {
console.log(e);
if (e.index) {
let data = uni.getStorageInfoSync();
console.log('data.keys', JSON.stringify(data.keys));
data.keys.forEach(item => {
if (item.includes('uni-im-msg:') || item.includes('uni-im-conversation')) {
// console.log(item);
uni.removeStorageSync(item);
console.log(uni.getStorageSync(item));
}
});
uni.showToast({
title: 'clear storage ok',
icon: 'none'
});
} else {
uni.navigateTo({
url: '/uni_modules/uni-id-pages/pages/login/login-withpwd',
complete: e => {
console.log(e);
}
});
}
},
methods: {
handleLoad(data, ended) {
this.loadMoreStatus = ended ? 'noMore' :
'more'; // oading 的状态可选值moreloading前、loadingloading中、noMore没有更多了
},
async toChat(user_id) {
//拿到会话(如果没有自动创建)
const currentConversation = await uniIm.conversation.get({
friend_uid:user_id
});
console.log('currentConversation', currentConversation);
// 当前用户给对方发个消息
if (this.isWidescreen) {
//若为宽屏,则触发右侧详情页的自定义事件,通知右侧窗体刷新详情
uni.navigateTo({
url: '/uni_modules/uni-im/pages/index/index?conversation_id=' + currentConversation.id
});
} else {
// 若为窄屏,则打开新窗体,在新窗体打开详情页面
uni.navigateTo({
url: '/uni_modules/uni-im/pages/chat/chat?conversation_id=' + currentConversation.id
});
}
},
toAdd() {
uni.navigateTo({
url: '../uni-id-users/add',
events: {
// 为指定事件添加一个监听器,获取被打开页面传送到当前页面的数据
refreshData: () => {
this.$refs.udb.loadData({
clear: true
});
}
}
});
}
}
};
</script>
<style lang="scss" scoped>
</style>