...
 
Commits (8)
    https://gitcode.net/dcloud/uni-im/-/commit/c820842ef2d980af627f438de2ccf9a49a4c1627 新增 客户端错误日志收集功能 2024-11-15T15:27:31+08:00 linju linju@dcloud.io https://gitcode.net/dcloud/uni-im/-/commit/23078bb8dcbf8d04e60a97ab3ad783c1db27b1d7 更新 捕获ConversationItem创建错误,并上报 2024-11-15T15:27:31+08:00 linju linju@dcloud.io https://gitcode.net/dcloud/uni-im/-/commit/08210daa865bdba940d86cf52e2bffa41a52c5bd Update msg.js 2024-11-15T15:27:31+08:00 linju linju@dcloud.io https://gitcode.net/dcloud/uni-im/-/commit/dc6475c54ce3677654c76c8f2a442214794fbfcd 更新 新增监听错误并上报 2024-11-15T15:27:31+08:00 linju linju@dcloud.io https://gitcode.net/dcloud/uni-im/-/commit/2089ffcd0d238970c794baf6132d9b824064708e 更新 解决 web-pc 端退出登录后,补充oauthToken重定向后也会跳转到登录页面的问题 2024-11-15T15:27:31+08:00 linju linju@dcloud.io https://gitcode.net/dcloud/uni-im/-/commit/a77462d77a4c788c1be5f9f842638edc2de48a91 更新 修复由3.4.37更新引起的解散群功能出错的问题 2024-11-15T15:27:31+08:00 linju linju@dcloud.io https://gitcode.net/dcloud/uni-im/-/commit/5ee53bf6c43c2910fa5a56b068af5fb44f847fcf 更新 拦截异常继续执行 2024-11-15T15:27:32+08:00 linju linju@dcloud.io https://gitcode.net/dcloud/uni-im/-/commit/80436324e2657606eabef5c4ffb1b93da5133147 Update readme.md 2024-11-15T15:29:21+08:00 linju linju@dcloud.io
**uni-im 已开放需求征集和投票** [点此前往](https://vote.dcloud.net.cn/#/?name=uni-im)
# 简介
uni-im是云端一体的、全平台的、免费的、开源即时通讯系统。
uni-im 是一款云端一体、全平台、免费且开源的即时通讯系统
- 基于uni-app,App、小程序、web全端兼容
- 基于uniCloud,前后端都使用js开发
- 基于[uni-push2](https://uniapp.dcloud.net.cn/unipush-v2.html),专业稳定的全端推送系统
- 基于[uni-id](https://uniapp.dcloud.net.cn/uniCloud/uni-id/summary.html),完善的账户体系
- 支持服务端为非uniCloud(比如:应用服务端的开发语言是php、java、go、.net、python、c#等)或 不基于uni-id-pages 开发的项目接入
- 基于[uni-push2](https://uniapp.dcloud.net.cn/unipush-v2.html),专业稳定的全端消息推送系统(聚合多个手机厂商推送通道,App关闭后也能收到消息)
- 开放性高,支持非uniCloud(即支持服务端是php、java、go、.net、python、c#等开发语言的项目),甚至非uni-app开发的项目都可以接入使用
- 性价比高,前后端代码均免费开源,与同类产品相比,使用uni-im仅需支付因托管在 uniCloud(serverless 服务器)而产生的少量费用,详情可查看文末`费用说明`部分
案例:
1. 应用名称:DCloud,该 App 的内置聊天模块,即基于 uni-im 开发。下载地址为:[https://im.dcloud.net.cn/uni-portal.html](https://im.dcloud.net.cn/uni-portal.html)
## 案例:
应用名称:DCloud。此 App 的内置聊天模块即是基于 uni-im 开发的。
2. 如图:在插件市场任意插件详情页面,点击“进入交流群”按钮,即可看到基于uni-im搭建的客服系统。
<img width="600px" src="https://web-ext-storage.dcloud.net.cn/unicloud/uni-im/img/17198039234743b6c4dd0-27b8-11eb-9e1d-136fabf12402.png">
web端网址(支持PC宽屏和移动端):[https://im.dcloud.net.cn](https://im.dcloud.net.cn)
下载地址:[https://ext.dcloud.net.cn/plugin?name=uni-im](https://ext.dcloud.net.cn/plugin?name=uni-im)
扫码体验: ![](https://web-ext-storage.dcloud.net.cn/doc/im/download.png)
## 特点优势
- 性价比高;前后端代码均免费开源,相比同类产品使用uni-im仅需花费极少的托管在uniCloud(serverless服务器)产生的费用[详情查看](#cost)
- 全端可用
- App端支持nvue,更好的长列表性能。list组件性能优势[详情参考](https://uniapp.dcloud.net.cn/component/list.html)
- 中心化响应式数据管理,切换会话无需重新加载数据,更流畅的体验
- App端聚合多个手机厂商推送通道,app不在线也可以收到消息
下载地址为:[https://im.dcloud.net.cn/uni-portal.html](https://im.dcloud.net.cn/uni-portal.html)
优先开发哪些,取决于开发者的反馈。同时也欢迎开发者共建这个开源项目。
> uni-im相关功能建议或问题,可以加入由uni-im(本插件)搭建的交流群[点此加入](https://im.dcloud.net.cn/#/?joinGroup=63ef49711d358337456f4d67)
# 快速部署体验
## 前提条件
1. 获取运行uni-im服务端代码的云服务环境
注意:这里和你自己项目服务端代码是什么语言开发的,以及运行在什么服务器环境无关。uni-im运行在专有的运行环境uniCloud(一种[serverless 服务器](https://uniapp.dcloud.net.cn/uniCloud/#%E4%BB%80%E4%B9%88%E6%98%AFserverless))下。
你的项目服务端和uni-im的服务端之间分别“独立部署”,二者通过发送 http 请求并借助事件进行通讯。
当然,如果你的项目服务端也是基于uniCloud开发的,就可以部署在同一个服务空间内;通过云函数互调通讯。
- 公有云
开通地址:[https://unicloud.dcloud.net.cn/](https://unicloud.dcloud.net.cn/) 服务商推荐选择“支付宝云”,性能更好。
- 私有云
普通中小企业项目使用公有云即可,但如果的项目存在特殊需求,例如:政务类、对信息保密性要求较高、用户都在海外的项目,这种情况下则需要进行私有化部署,详情可点击[此处](https://doc.dcloud.net.cn/uniCloud/software/#uni%E4%BA%91%E5%BC%80%E5%8F%91%E8%BD%AF%E4%BB%B6%E7%89%88)
2. 开通可实时发送消息的推送服务
这里我们需要开通`uni-push`,它是基于个推封装的服务;个推是A股上市公司,专业性在推送领域领先。
开通指南:[点此打开](https://uniapp.dcloud.net.cn/unipush-v2.html#%E7%AC%AC%E4%B8%80%E6%AD%A5-%E5%BC%80%E9%80%9A)
## 体验步骤
1. 下载示例项目
打开`uni-im`插件下载地址:[https://ext.dcloud.net.cn/plugin?name=uni-im](https://ext.dcloud.net.cn/plugin?name=uni-im) 点击`使用HBuilderX导入示例项目`
2. 绑定项目的服务空间
在项目根目录uniCloud右键选择“关联云服务空间或项目”(注意:选择关联的服务空间,需在项目的 uni-push2.0的[web控制台](https://dev.dcloud.net.cn/pages/app/push2/info)被关联)
3. 运行项目
在菜单`运行`->`运行到浏览器` 选择要运行的浏览器
这里需要运行到两个不同的浏览器(避免同一浏览器打开多个uni-im页面,引起socket占线),`注册账号并登录`2个账号,体验对话效果
5. 向指定用户发起会话
通过访问路径:`/uni_modules/uni-im/pages/chat/chat?user_id=` + `指定用户的id`即可。
如果你不知道用户的id,可通过在浏览器控制台执行`uni.imObservableData.currentUser._id`可获取当前登录的账号id
注意:以上为连接本地云函数体验,如果要发行为正式项目,需要把uniCloud内的文件部署到云端。操作方式为:对项目根目录uniCloud点右键选择“云服务空间初始化向导”界面按提示部署项目
## 部署到自己的项目
[详情查看](https://doc.dcloud.net.cn/uniCloud/uni-im.html#%E9%83%A8%E7%BD%B2%E5%88%B0%E8%87%AA%E5%B7%B1%E7%9A%84%E9%A1%B9%E7%9B%AE)
## 使用uniCloud产生的费用说明@cost
uni-im本身并不收费,实际使用中需要依赖uniCloud云服务,会产生费用;而uniCloud的价格很实惠:
- 调用10000次云函数仅需0.0133元
- 调用10000次数据库查询仅需0.015元
> 更多计费参考:[阿里云版uniCloud按量计费文档](https://uniapp.dcloud.net.cn/uniCloud/price.html#aliyun-postpay)
> 更多计费参考:[支付宝云版uniCloud按量计费文档](https://doc.dcloud.net.cn/uniCloud/price.html#alipay)
### 举例说明:
- 单聊场景,向用户发送一条消息的过程:
......
......@@ -193,6 +193,7 @@ export default class CloudData {
return param == undefined ? datas : datas[0]
}
set(data){
if(!data) return
// 先判断是否存在
let item = this.find(data.id || data._id || Object.keys(data)[0])
if(item){
......
......@@ -61,6 +61,12 @@ export default async function (initParam) {
});
}
// 监听所有错误并上报
window.addEventListener('error', function(e) {
console.error('监听所有错误并准备上报 error', e)
$utils.reportError(e.error)
});
$state.networkConnected = navigator.onLine;
window.addEventListener('online', function() {
$state.networkConnected = true;
......@@ -186,7 +192,7 @@ export default async function (initParam) {
// 第二次 activate 之后开始 检查token是否已经过期,如果已经过期则重定向至登录页面
const { tokenExpired } = $state.currentUser
if (!isLoginPage && count > 1 && tokenExpired < Date.now()) {
if (!currentPage?.options?.oauthToken && !isLoginPage && count > 1 && tokenExpired < Date.now()) {
console.info('uni-im检测到,当前用户登录过且当前登录状态已过期,将自动跳转至登录页面。')
uni.reLaunch({
url: '/uni_modules/uni-id-pages/pages/login/login-withpwd',
......
......@@ -129,12 +129,16 @@ export default class Conversation extends CloudData {
// console.log('新增会话', item)
// 插入客户端创建此会话的时间
item.client_create_time = Date.now()
try{
let conversation = new ConversationItem(item)
// console.log('新增会话', conversation)
const usersInfo = conversation.getUsersInfo()
// 把会话相关的用户信息合并到 $users
$users.merge(usersInfo)
resList.push(conversation)
}catch(e){
$utils.reportError(e)
}
return resList
}, [])
}
......
......@@ -11,8 +11,9 @@ class ConversationItem {
constructor(data) {
// 检查是否关联用户/群被删除
if (!data.group_id && !data.user_info) {
console.error(JSON.stringify(data));
throw new Error('会话列表失效,疑似关联用户/群被删除(请改为软删除避免系统异常)');
// 删除本地生成的 data.client_create_time 避免错误重复上报
delete data.client_create_time
throw new Error('会话列表失效,疑似关联用户/群被删除(请改为软删除避免系统异常)data:'+JSON.stringify(data));
}
// 对话框消息内容
this.chatInputContent = ""
......@@ -38,8 +39,8 @@ class ConversationItem {
// 群聊
this.group = $state.group.find(this.group_id)
if (!this.group) {
console.error('群聊本地不存在 this.group_id', this.group_id);
// throw new Error('群聊不存在')
console.error('群聊不存在', this)
throw new Error('群聊不存在')
}
// 2. 设置群tag
......
......@@ -271,4 +271,30 @@ export default {
showCancel: false
});
},
async reportError(error){
// 上报错误
const dbJQL = uniCloud.databaseForJQL()
let content = {
stack: error.stack,
message: error.message,
code: error.code
}
content = JSON.stringify(content)
const content_md5 = md5(error.message)
// 查询是否已经上报过
let res = await dbJQL.collection('uni-im-error-log').where({
content_md5
}).get()
if(res.data.length === 0){
res = await dbJQL.collection('uni-im-error-log').add({
content,
content_md5
})
}else{
res = await dbJQL.collection('uni-im-error-log').doc(res.data[0]._id).update({
count: (res.data[0]?.count || 1) + 1
})
}
console.warn('【bug已上报】uni-im-sdk error has reported',res,{error})
}
}
......@@ -133,7 +133,11 @@ async function sendMsg(params) {
nickname = userInfo.nickname
avatar_file = userInfo.avatar_file
} else {
console.error('用户信息不存在',from_uid);
return {
"code": 30202,
"errCode": "uni-id-check-token-failed",
"errMsg": "请重新登录"
}
}
}
......@@ -425,6 +429,7 @@ async function _createOrUpdateConversation(conversation_id, msgData, chat_source
name: true
})
.get()
console.error('groupInfo------', res.data[0]);
groupInfo = res.data[0]
}
......@@ -732,7 +737,7 @@ async function _processPush({ msgData, isMute, appId,groupInfo }) {
const { nickname, avatar_file } = msgData
let title
let content
if(msgData.group_id){
if(groupInfo){
title = groupInfo.name
content = nickname.slice(0, 20) + '' + (msgData.type == 'text'? msgData.body : '[多媒体]')
}else{
......
// 文档教程: https://uniapp.dcloud.net.cn/uniCloud/schema
{
"bsonType": "object",
"required": [],
"permission": {
"read": false,
"create": "auth.uid != null",
"update": false,
"delete": false
},
"properties": {
"_id": {
"description": "ID,系统自动生成"
},
"user_id": {
"bsonType": "string",
"description": "反馈用户ID",
"foreignKey": "uni-id-users._id",
"forceDefaultValue": {
"$env": "uid"
}
},
"create_time": {
"bsonType": "timestamp",
"forceDefaultValue": {
"$env": "now"
}
},
"content": {
"bsonType": "string",
"title": "内容"
},
"count": {
"bsonType": "int",
"description": "反馈次数"
},
"content_md5": {
"bsonType": "string",
"description": "内容MD5,用于防止重复插入重复的信息"
},
"is_fixed": {
"bsonType": "bool",
"description": "是否已修复",
"forceDefaultValue": false
}
}
}
\ No newline at end of file
......@@ -111,12 +111,12 @@ module.exports = {
groupName:triggerContext.groupInfo.name,
}
}
await uniImCo.sendMsg(msgData,userInfo.uid)
// 临时方案 加一条被软删除的群记录
await db.collection('uni-im-group').add({
...triggerContext.groupInfo,
is_delete:true
})
await uniImCo.sendMsg(msgData,userInfo.uid)
}
}
}