...
 
Commits (9)
    https://gitcode.net/dcloud/uni-im/-/commit/22d1c411d39199712ced2577493907254be0c880 更新 修复conversation_grade为100且customer_service_uids未配置时,未拦截非好友通讯 2024-11-07T18:02:46+08:00 linju linju@dcloud.io https://gitcode.net/dcloud/uni-im/-/commit/5628941c82a79a9254b8a14c97fda618878b33f2 Update index.vue 2024-11-08T20:12:37+08:00 linju linju@dcloud.io https://gitcode.net/dcloud/uni-im/-/commit/5a7c2ff24f17b180682d22c3d94eea577f3b7f01 Update video.vue 2024-11-08T20:12:37+08:00 linju linju@dcloud.io https://gitcode.net/dcloud/uni-im/-/commit/0fe5bd2bd385a3e5cc9939afe21b983f1ab3d2cb 更新 新增配置check_mobile,用于配置在发起会话和申请加入群聊时,是否校验手机号码 2024-11-08T20:12:37+08:00 linju linju@dcloud.io https://gitcode.net/dcloud/uni-im/-/commit/7ea67d3c8824a5dcf07790a2dcf4e463c6914ffe 更新 修复部分情况下没有走__afterFind的问题 2024-11-08T20:12:37+08:00 linju linju@dcloud.io https://gitcode.net/dcloud/uni-im/-/commit/4fee4e75c6302861e604d7b79d80fe661827f3cf 更新 Conversation. __get 参数支持传param.id表示param.conversation_id 2024-11-08T20:12:37+08:00 linju linju@dcloud.io https://gitcode.net/dcloud/uni-im/-/commit/0e7827965ee22c163be263c30237da6de536a7f6 更新 修复web端在部分情况下,本地创建的单聊临时会话相关页面,打开后直接刷新会出错的问题 2024-11-08T20:12:37+08:00 linju linju@dcloud.io https://gitcode.net/dcloud/uni-im/-/commit/02645be07e12884763044cccb1dd716101fc1a64 更新 修复会话的最后一条消息带 action 的情况下,界面刷新/重启后会重复触发的问题 2024-11-08T20:12:37+08:00 linju linju@dcloud.io https://gitcode.net/dcloud/uni-im/-/commit/533420c903ad03ca8aea06ec9fdcc6bf5997c100 更新 优化文件消息的样式 2024-11-08T20:43:05+08:00 linju linju@dcloud.io
......@@ -95,10 +95,11 @@
flex-direction: row;
justify-content: space-between;
.file-msg-info {
flex: 1;
flex-direction: column;
justify-content: space-around;
.name {
word-wrap: break-word;
word-break: break-all;
font-size: 16px;
}
.size {
......
......@@ -67,7 +67,7 @@
qiniu: 'vframe/jpg/offset/0/w/200'
}
this.videoPoster += paramObj[config.cloudFile.provider]
console.log('this.videoPoster',this.videoPoster);
// console.log('this.videoPoster',this.videoPoster);
}
},
deep: true,
......
......@@ -412,6 +412,18 @@
this.$refs["chat-input"]?.focus()
}, 100)
}
const {is_temp,friend_uid} = this.conversation
if(is_temp && friend_uid){
// 为了避免在web端刷新页面之后,本地单聊临时会话丢失,将地址栏中的会话id参数替换为好友的uid,以此来确保在刷新页面之后,本地能够再次创建临时会话。
const {route:path,options} = getCurrentPages().pop()
delete options.conversation_id
options.user_id = friend_uid
let paramSrt
for (const key in options) {
paramSrt = `${key}=${options[key]}`
}
history.replaceState(null, '', `/#/${path}?${paramSrt}`)
}
// #endif
},
onclickMsgList(){
......
......@@ -97,23 +97,9 @@ export default {
methods: {
async load(options) {
console.log('options',options);
let conversation_id = options.conversation_id || options.id
// 如果只传了user_id,需要先获取conversation_id
if(!conversation_id){
if(!options.user_id){
console.error('参数错误')
return uni.showToast({
title: '参数错误',
icon: 'none'
});
}
conversation_id = await uniIm.utils.getConversationId(options.user_id)
console.log('conversation_id',conversation_id);
}
let conversation = await uniIm.conversation.get(conversation_id)
this.conversation = conversation
this.friend_uid = conversation.friend_uid
const {user_id,id} = options
this.conversation = await uniIm.conversation.get(user_id ? {user_id} : id)
this.friend_uid = this.conversation.friend_uid
let field = '_id,nickname,avatar_file'
if (this.uniIDHasRole('staff')) {
field += ',email'
......
......@@ -57,7 +57,7 @@
ref="uni-im-filtered-conversation-list"
id="conversation-list-box"
:keyword="keyword"
@to-chat="toChat($event)"
@to-chat="toChat"
@to-chat-filtered="toChatFiltered($event)"
></uni-im-filtered-conversation-list>
</template>
......@@ -81,7 +81,7 @@
<uni-icons @click="showChatInfo" class="more" type="more-filled" size="20"></uni-icons>
</view>
<view class="content">
<chat-filtered v-if="filteredConversationId" ref="chat-filtered" @to-chat="toChat($event)"/>
<chat-filtered v-if="filteredConversationId" ref="chat-filtered" @to-chat="toChat"/>
<chat-view v-else ref="chat-view"></chat-view>
<view v-if="chatInfoIsShow" class="chatInfoBox" @click.stop="chatInfoIsShow = false">
<view @click.stop class="group-info-parent">
......@@ -473,35 +473,19 @@
// goods,
// user_id
// });
if(user_id || conversation_id){
this.toChat(conversation_id || {user_id})
}
// 如果初始化时,指定了要访问的会话。将指定要访问的会话排序位置置顶,方便看到
setTimeout(()=> this.currentConversation.customIndex = Date.now(), 0);
// 如果列表小于30个会话,尝试着从云端拉取一次
if( this.conversationList.length < 30 ){
await this.$nextTick()
await this.$refs['uni-im-conversation-list'].loadMore()
await this.$nextTick()
await this.$refs['uni-im-conversation-list'].loadMore()
}else{
console.log('会话列表已满一页,需要用户自己滚动到底,再拉取更多');
}
// console.log('this.conversationList.length',this.conversationList.length);
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)
}
if(user_id){
// 如果初始化时,指定了要访问的user会话。将指定要访问的会话排序位置置顶,方便看到
// 场景:插件市场,点击联系作者。自动将此会话放到首个
setTimeout(()=> {
this.currentConversation.customIndex = Date.now()
}, 0);
}
// 传递参数goods(对象格式,包含:商品名称name,链接url。自动设置对话框默认内容
if (this.isWidescreen && goods) {
......@@ -527,7 +511,7 @@
if(joinGroup){
// #ifdef H5
//删除URL后面的参数(主要是删除joinGroup=xxx),且不刷新页面
history.pushState({}, '', '/#/');
history.replaceState(null, '', '/#/')
// #endif
this.joinGroup(joinGroup)
};
......@@ -598,45 +582,26 @@
})
}
},
async toChat(param) {
this.chatInfoIsShow = false;
this.keyword = ''
this.filteredConversationId = false
const conversation_id = await getConversationId(param)
// console.log('toChat', conversation_id)
uniIm.currentConversationId = conversation_id
const {id} = await uniIm.conversation.get(param)
uniIm.currentConversationId = id
if (this.isWidescreen) { // 若为宽屏,则切换右侧的组件
this.$nextTick(() => {
let chatViewRef = this.$refs['chat-view']
if (chatViewRef) {
chatViewRef.load(conversation_id)
chatViewRef.load(id)
}
})
} else { // 若为窄屏,则打开新窗体
// param 转成字符串
uni.navigateTo({
url: '/uni_modules/uni-im/pages/chat/chat?conversation_id=' + conversation_id,
url: '/uni_modules/uni-im/pages/chat/chat?conversation_id=' + id,
animationDuration: 300
})
}
async function getConversationId(param){
if (typeof param == 'string') {
return param
} else {
if (param.conversation_id) {
return param.conversation_id
} else if (param.group_id) {
return 'group_' + param.group_id
} else if (param.user_id || param.friend_uid) {
// 获取会话id(如果此单聊会话未创建会自动创建)
return (await uniIm.conversation.get(param)).id
} else {
throw new Error("toChat param is error")
}
}
}
},
showChatInfo() {
this.chatInfoIsShow = !this.chatInfoIsShow
......
......@@ -75,21 +75,14 @@ import uniIm from '@/uni_modules/uni-im/sdk/index.js';
'more'; // oading 的状态,可选值:more(loading前)、loading(loading中)、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
});
location.href = '/#/uni_modules/uni-im/pages/index/index?user_id=' + user_id
} else {
// 若为窄屏,则打开新窗体,在新窗体打开详情页面
uni.navigateTo({
url: '/uni_modules/uni-im/pages/chat/chat?conversation_id=' + currentConversation.id
url: '/uni_modules/uni-im/pages/chat/chat?user_id=' + user_id
});
}
},
......
......@@ -90,49 +90,25 @@ export default class CloudData {
// console.time('find dataMap.get' + this.constructor.name)
res = this.dataMap.get(mapKey)
// console.timeEnd('find dataMap.get' + this.constructor.name)
return res
} else {
console.log('注意:此次查找未走索引',param,this.indexKey,this.constructor.name)
}
}
}
console.time('find-no-index-' + this.constructor.name)
// 默认查找条件为_id
if(typeof param == 'string'){
res = dataList.find(item => item._id == param)
}else if(typeof param == 'object'){
// console.log('param',param)
function isEq(a, b) {
if (Array.isArray(a) || Array.isArray(b)) {
console.error('不支持数组比较')
return a === b;
}
let result = true;
for (let key in b) {
const valueA = a[key];
const valueB = b[key];
if (typeof valueB === 'object'
&& valueB !== null
&& typeof valueA === 'object'
&& valueA !== null
) {
return isEq(valueA, valueB);
}
result = valueA === valueB;
if (!result) {
break;
}
}
return result;
if(!res) {
console.time('find-no-index-' + this.constructor.name)
// 默认查找条件为_id
if(typeof param == 'string'){
res = dataList.find(item => item._id == param)
}else if(typeof param == 'object'){
// console.log('param',param)
res = dataList.find(item => isEq(item,param))
}else{
throw new Error('错误的查找条件')
}
res = dataList.find(item => isEq(item,param))
}else{
throw new Error('错误的查找条件')
}
if(this.__afterFind){
res = this.__afterFind({param,res})
console.timeEnd('find-no-index-' + this.constructor.name)
}
console.timeEnd('find-no-index-' + this.constructor.name)
this.__afterFind?.({param,res})
return res
}
/** @description 查询数据,先从本地查找,如果没有则从云端拉取
......@@ -327,4 +303,28 @@ function convertObjToString(obj) {
}
recursiveConvert(obj, '');
return result;
}
function isEq(a, b) {
if (Array.isArray(a) || Array.isArray(b)) {
console.error('不支持数组比较')
return a === b;
}
let result = true;
for (let key in b) {
const valueA = a[key];
const valueB = b[key];
if (typeof valueB === 'object'
&& valueB !== null
&& typeof valueA === 'object'
&& valueA !== null
) {
return isEq(valueA, valueB);
}
result = valueA === valueB;
if (!result) {
break;
}
}
return result;
}
\ No newline at end of file
......@@ -53,7 +53,7 @@ let $users = {
}
return Array.isArray(param) ? userInfoList : userInfoList[0]
},
getNickname(user_id){
getNickname(user_id,tmpNickname = '[昵称加载中...]'){
const nickname = $state.users[user_id]?.nickname
if(nickname){
return nickname
......@@ -62,7 +62,7 @@ let $users = {
$users.loadTask.add(user_id)
$state.users[user_id] = {
nickname:'[昵称加载中...]',
nickname:tmpNickname,
_id:user_id,
__loading:true
}
......
......@@ -50,6 +50,14 @@ export default class Conversation extends CloudData {
// 设置为默认按id查找会话,而不是按_id查找
return {id:param}
}else if(typeof param === 'object' && param !== null && !Array.isArray(param)){
const {user_id,friend_uid,conversation_id:id} = param
if(id){
param.id = id
delete param.conversation_id
}else if(user_id){
param.friend_uid = friend_uid || user_id
delete param.user_id
}
if('source' in param){
// 本地查找不需要source字段
const source = param.source
......@@ -67,13 +75,6 @@ export default class Conversation extends CloudData {
}
},0)
}
if('user_id' in param){
// param = {friend_uid:param.user_id}
param.friend_uid = param.user_id
delete param.user_id
}else if('conversation_id' in param){
param = {id:param.conversation_id}
}
return param
}
}
......@@ -91,7 +92,9 @@ export default class Conversation extends CloudData {
"type": param.friend_uid ? 1 : 2,
"msgList": [],
"update_time": Date.now(),
"customSortTime": Date.now()
"customSortTime": Date.now(),
// 是本地临时会话数据
"is_temp": true
}
const conversation = this.add(conversationData)
$users.get(friend_uid).then(res => {
......@@ -187,7 +190,7 @@ export default class Conversation extends CloudData {
const loadMoreType = this.loadMore?.type || 'all'
let conversation_id = param
if (typeof param === "object"){
conversation_id = param.conversation_id
conversation_id = param.id || param.conversation_id
}
const uniImCo = uniCloud.importObject("uni-im-co",{customUI: true})
const limit = this.loadLimit
......
......@@ -76,7 +76,7 @@ export default class Msg extends CloudData {
// console.log('beforeAdd',data);
// 如果此消息,创建时间在当前设备创建此会话之前,则无需执行
const conversation_time = currentConversation.update_time || currentConversation.client_create_time || 0
if (data.create_time < conversation_time) {
if (data.create_time <= conversation_time) {
return //console.log('消息创建时间早于会话最新时间,不执行',data.create_time,conversation_time);
}
// 调用扩展程序,使扩展程序可以在消息插入之前执行一些操作
......
......@@ -5,6 +5,15 @@ const dbCmd = db.command
const $ = dbCmd.aggregate
const md5 = str => crypto.createHash('md5').update(str).digest('hex')
function getConfig(key) {
// 获取 uni-im 配置
const createConfig = require("uni-config-center");
const uniImConfig = createConfig({
pluginId: 'uni-im', // 插件 id
})
return uniImConfig.config(key)
}
function getConversationId({
group_id,
from_uid,
......@@ -77,5 +86,6 @@ module.exports = {
hideUsernameStr,
hideEmailStr,
hideMobileStr,
checkParam
checkParam,
getConfig
}
\ No newline at end of file
......@@ -290,16 +290,14 @@ async function _checkConversationGrade({
}) {
// 客服模式下,如果配置的客服 id。则只能向客服发起会话
let chatToCustomerService = async () => {
const customer_service_uids = uniImConfig.config('customer_service_uids_uids')
if (customer_service_uids) {
if (typeof customer_service_uids == 'string') {
customer_service_uids = [customer_service_uids]
}
if (
!(customer_service_uids.includes(from_uid) || customer_service_uids.includes(to_uid))
) {
throw new Error('非法通讯,会话双方用户 id,均不属于 uni-im-co 中配置的 customer_service_uids')
}
const customer_service_uids = uniImConfig.config('customer_service_uids') || []
if (typeof customer_service_uids == 'string') {
customer_service_uids = [customer_service_uids]
}
if (
!(customer_service_uids.includes(from_uid) || customer_service_uids.includes(to_uid))
) {
throw new Error('非法通讯,会话双方用户 id,均不属于 uni-im-co 中配置的 customer_service_uids')
}
return true
}
......@@ -441,7 +439,9 @@ async function _createOrUpdateConversation(conversation_id, msgData, chat_source
// 不存在,需要先创建会话记录
else if (!senderConversation) {
// 除了云函数之间(包括触发器)调用 和 特殊角色用户,需验证是否绑定了手机号码
const check_mobile = uniImConfig.config('check_mobile')
if (
check_mobile &&
this.getClientInfo().source != 'function' &&
!this.current_user_role.includes('uni-im-admin') &&
!this.current_user_role.includes('staff')
......
// schema扩展相关文档请参阅:https://uniapp.dcloud.net.cn/uniCloud/jql-schema-ext.html
const db = uniCloud.database()
let t = Date.now() + parseInt(Math.random() * 999999)
const utils = require('uni-im-utils')
module.exports = {
trigger: {
async beforeCreate({
......@@ -56,8 +55,8 @@ module.exports = {
throw new Error('你已被拉黑,不能加入此群')
}
// 4. 判断用户是否已经绑定手机号,系统管理员除外
console.log('userInfo',userInfo);
if(!userInfo.role.includes('uni-im-admin') && !userInfo.role.includes('staff')){
const check_mobile = utils.getConfig('check_mobile')
if(check_mobile && !userInfo.role.includes('uni-im-admin') && !userInfo.role.includes('staff')){
let res3 = await db.collection('uni-id-users').where({_id:userInfo.uid}).get()
if(!res3.data[0].mobile_confirmed){
throw new Error('账号未绑定手机号无法加入群聊。请完成绑定后退出本系统并重新登录,再尝试加入群聊。')
......