38 Commits

Author SHA1 Message Date
c7ba7bd426 ... 2022-02-23 10:10:18 +08:00
db9f5f6bde .. 2022-02-23 10:08:18 +08:00
2a61a263de 群消息已读数量优化,撤回消息的功能扩展到语音图片等 2022-02-23 10:07:24 +08:00
31c60bb319 群消息已读反馈,消息状态组件抽离 2022-02-23 09:48:34 +08:00
36f70e1b5e 音视频组件展示 2022-02-22 17:44:15 +08:00
6e2414f160 Merge branch 'master' of https://git.yuzhankeji.cn/TmOct5/ZhHealth 2022-02-22 17:20:58 +08:00
17e443fdeb 本地发出的语音播放优化,必须从远端下载到本地之后再播放就好了,版本号升级,发布demo 2022-02-22 17:20:51 +08:00
Z
e21d0e928d 新朋友无数据处理,我的群组没数据处理 2022-02-22 17:20:26 +08:00
5a52bdf2dd merge 2022-02-22 16:51:20 +08:00
01627f6794 消息列表组件化,统一私聊和群聊样式 2022-02-22 16:48:49 +08:00
Z
054a84dae7 ... 2022-02-22 16:43:40 +08:00
Z
cdcfc95f88 权限邀请调试测试 2022-02-22 16:42:57 +08:00
唐明明
91144195cf merge 2022-02-22 16:38:54 +08:00
唐明明
d92fb30648 调整语音组件 2022-02-22 16:38:41 +08:00
Z
d1c1c6d5ba ... 2022-02-22 15:28:53 +08:00
ab35229331 群聊消息回执的部分测试 2022-02-22 15:16:08 +08:00
Z
b92fc0fc7e 邀请模块优化 2022-02-22 15:00:40 +08:00
66092967cb 群邀请消息获取 2022-02-22 14:59:53 +08:00
d812ac2862 语音消息条,长度优化 2022-02-22 11:27:28 +08:00
a396f75041 语音消息优化 2022-02-22 11:13:09 +08:00
f03c3a0989 聊天内容,文本,图片,语音消息结构优化 2022-02-22 10:16:44 +08:00
914f3f9371 merge 2022-02-21 18:10:42 +08:00
7220c3466d 语音组件优化,下载过程使用RC接口,播放优化 2022-02-21 18:04:04 +08:00
Z
ca9f7e80ca ... 2022-02-21 18:01:11 +08:00
Z
ee3087b320 h大健康群公告列表页面重构,详情页处理接口及样式兼容,群消息页面的群公告显示重构,群聊邀请审核扫码模式处理接口及样式; 2022-02-21 18:00:23 +08:00
d8b90f97d1 会话列表,长按选中的状态调整 2022-02-21 16:37:05 +08:00
fbe1add9cf 统一聊天页的头像大小,改用rpx2px的计算,84rpx 2022-02-21 16:28:34 +08:00
883f32f54c 视频通话时长转换 2022-02-21 15:46:05 +08:00
1be73f5bbb 邀请好友,搜索算法 2022-02-21 14:24:14 +08:00
Z
ad40d0d4d1 Merge branch 'master' of https://git.yuzhankeji.cn/TmOct5/ZhHealth 2022-02-21 14:04:07 +08:00
Z
936a66a8aa ... 2022-02-21 14:04:02 +08:00
da59b2c31d merge 2022-02-21 14:02:06 +08:00
77ed9dd6f9 邀请好友 2022-02-21 14:01:20 +08:00
Z
e99ef72050 Merge branch 'master' of https://git.yuzhankeji.cn/TmOct5/ZhHealth 2022-02-21 13:27:51 +08:00
Z
57cba65206 公告模块重构样式 2022-02-21 13:27:46 +08:00
31ff366457 语音通话展示 2022-02-21 13:24:52 +08:00
f4b06bbf01 语音通话类型展示 2022-02-21 12:05:19 +08:00
ce954c5dcc 音视频呼叫优化 2022-02-21 09:30:00 +08:00
42 changed files with 1757 additions and 1283 deletions

View File

@@ -5,7 +5,7 @@
import im from '@/utils/im/index.js' import im from '@/utils/im/index.js'
export default { export default {
onLaunch: function() { onLaunch: function() {
im.initIm('lmxuhwaglu76d') im.initIm('lmxuhwaglu76d')
return return
//#ifdef APP-PLUS //#ifdef APP-PLUS
@@ -29,7 +29,7 @@
uni.downloadFile({ uni.downloadFile({
url: res.info.download, url: res.info.download,
success: apkPick => { success: apkPick => {
plus.runtime.install(apkPick plus.runtime.install(apkPick
.tempFilePath, '', .tempFilePath, '',
installRES => { installRES => {
// 安装完成用于提示新版本引导,暂时无用 // 安装完成用于提示新版本引导,暂时无用

View File

@@ -88,9 +88,9 @@ const searchFriend = (value) => {
const pedingFriend = (recipient, message) => { const pedingFriend = (recipient, message) => {
return request({ return request({
method: 'POST', method: 'POST',
url: 'im/friends/' + recipient, url: 'im/friends/' + recipient,
data: { data: {
message message
} }
}) })
} }
@@ -120,19 +120,19 @@ const getGroupBase = (groupId) => {
}) })
} }
const getGroupUsers = (groupId, limit) => { const getGroupUsers = (groupId, limit) => {
limit = limit || 0 limit = limit || 0
return request({ return request({
url: 'im/groups/' + groupId + '/users?limit=' + limit url: 'im/groups/' + groupId + '/users?limit=' + limit
}) })
} }
// 公告列表
const getGroupAnnouncements = (groupId) => { const getGroupAnnouncements = (groupId) => {
return request({ return request({
url: 'im/groups/' + groupId + '/announcements' url: 'im/groups/' + groupId + '/announcements'
}) })
} }
// 创建公告
const createGroupAnnouncement = (groupId, content) => { const createGroupAnnouncement = (groupId, content) => {
return request({ return request({
method: 'POST', method: 'POST',
@@ -142,13 +142,27 @@ const createGroupAnnouncement = (groupId, content) => {
} }
}) })
} }
// 查看该公告详情
const getGroupAnnouncement = (groupId, announcementId) => {
return request({
method: 'GET',
url: 'im/groups/' + groupId + '/announcements/' + announcementId
})
}
// 删除该公告
const deleteGroupAnnouncement = (groupId, announcementId) => { const deleteGroupAnnouncement = (groupId, announcementId) => {
return request({ return request({
method: 'DELETE', method: 'DELETE',
url: 'im/groups/' + groupId + '/announcements/' + announcementId url: 'im/groups/' + groupId + '/announcements/' + announcementId
}) })
} }
// 置顶群公告
const topGroupAnnouncement = (groupId, announcementId) => {
return request({
method: 'POST',
url: 'im/groups/' + groupId + '/announcements/' + announcementId + '/top',
})
}
/** /**
* 创建群聊 * 创建群聊
@@ -227,12 +241,13 @@ const removeGroupUser = (groupId, userId) => {
/** /**
* 邀请群成员 * 邀请群成员
*/ */
const inviteGroupUser = (groupId, userIds) => { const inviteGroupUser = (groupId, userIds, allowIds) => {
return request({ return request({
method: 'POST', method: 'POST',
url: 'im/groups/' + groupId + '/invite', url: 'im/groups/' + groupId + '/invite',
data: { data: {
userIds userIds: userIds,
allowIds: allowIds
} }
}) })
} }
@@ -267,19 +282,16 @@ const transferGroupOwner = (groupId, userId) => {
}) })
} }
// //群成员待审核表 -- 废弃
// const getGroupMakeSure = (groupId) => { // 通过审核验证群成员
// return request({ const groupMakeSure = (groupId, user) => {
// url:`im/groups/${groupId}/makesure` return request({
// }) url: `im/groups/${groupId}/makesure/${user}`,
// } method: 'POST'
// // 群成员审核通过 })
// const getGroupMakeSureAllow = (groupId, userId) => { }
// return request({
// method: 'POST',
// url: 'im/groups/' + groupId + '/owner/' + userId
// })
// }
export { export {
getImToken, getImToken,
@@ -300,17 +312,18 @@ export {
getGroupBase, getGroupBase,
getGroupUsers, getGroupUsers,
getGroupAnnouncements, getGroupAnnouncements,
getGroupAnnouncement,
createGroupAnnouncement, createGroupAnnouncement,
deleteGroupAnnouncement, deleteGroupAnnouncement,
topGroupAnnouncement,
searchGroup, searchGroup,
joinGroupPre, joinGroupPre,
joinGroup, joinGroup,
quitGroup, quitGroup,
dismissGroup, dismissGroup,
inviteGroupUser, inviteGroupUser,
removeGroupUser, removeGroupUser,
setGroupAdmin, setGroupAdmin,
removeGroupAdmin, removeGroupAdmin,
// transferGroupOwner, // -废弃待审核列表 groupMakeSure, // 通过审核
// getGroupMakeSure // -废弃待审核列表
} }

View File

@@ -2,8 +2,8 @@
"name" : "ZH-HEALTH", "name" : "ZH-HEALTH",
"appid" : "__UNI__C29473D", "appid" : "__UNI__C29473D",
"description" : "ZH-HEALTH您手上的健康管理专家", "description" : "ZH-HEALTH您手上的健康管理专家",
"versionName" : "1.0.10", "versionName" : "1.0.13",
"versionCode" : 110, "versionCode" : 113,
"transformPx" : false, "transformPx" : false,
/* 5+App */ /* 5+App */
"app-plus" : { "app-plus" : {
@@ -24,7 +24,9 @@
"SQLite" : {}, "SQLite" : {},
"VideoPlayer" : {}, "VideoPlayer" : {},
"Geolocation" : {}, "Geolocation" : {},
"Fingerprint" : {} "Fingerprint" : {},
"Maps" : {},
"Push" : {}
}, },
/* */ /* */
"distribute" : { "distribute" : {
@@ -80,7 +82,9 @@
} }
}, },
"ad" : {}, "ad" : {},
"push" : {}, "push" : {
"unipush" : {}
},
"geolocation" : { "geolocation" : {
"amap" : { "amap" : {
"__platform__" : [ "android" ], "__platform__" : [ "android" ],
@@ -90,6 +94,12 @@
"system" : { "system" : {
"__platform__" : [ "android" ] "__platform__" : [ "android" ]
} }
},
"maps" : {
"amap" : {
"appkey_ios" : "",
"appkey_android" : "05b7f32ca9c897c8b63c505d92cd654b"
}
} }
}, },
"icons" : { "icons" : {

383
package-lock.json generated
View File

@@ -9,8 +9,6 @@
"version": "1.0.0", "version": "1.0.0",
"license": "ISC", "license": "ISC",
"dependencies": { "dependencies": {
"bitcore-lib": "^8.25.25",
"bitcore-mnemonic": "^8.25.25",
"moment": "^2.29.1", "moment": "^2.29.1",
"uni-read-pages": "^1.0.5", "uni-read-pages": "^1.0.5",
"uni-simple-router": "^2.0.7", "uni-simple-router": "^2.0.7",
@@ -19,171 +17,6 @@
}, },
"devDependencies": {} "devDependencies": {}
}, },
"node_modules/base-x": {
"version": "3.0.9",
"resolved": "https://registry.npmjs.org/base-x/-/base-x-3.0.9.tgz",
"integrity": "sha512-H7JU6iBHTal1gp56aKoaa//YUxEaAOUiydvrV/pILqIHXTtqxSkATOnDA2u+jZ/61sD+L/412+7kzXRtWukhpQ==",
"dependencies": {
"safe-buffer": "^5.0.1"
}
},
"node_modules/bech32": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/bech32/-/bech32-2.0.0.tgz",
"integrity": "sha512-LcknSilhIGatDAsY1ak2I8VtGaHNhgMSYVxFrGLXv+xLHytaKZKcaUJJUE7qmBr7h33o5YQwP55pMI0xmkpJwg=="
},
"node_modules/bigi": {
"version": "1.4.2",
"resolved": "https://registry.npmjs.org/bigi/-/bigi-1.4.2.tgz",
"integrity": "sha1-nGZalfiLiwj8Bc/XMfVhhZ1yWCU="
},
"node_modules/bip-schnorr": {
"version": "0.6.4",
"resolved": "https://registry.npmjs.org/bip-schnorr/-/bip-schnorr-0.6.4.tgz",
"integrity": "sha512-dNKw7Lea8B0wMIN4OjEmOk/Z5qUGqoPDY0P2QttLqGk1hmDPytLWW8PR5Pb6Vxy6CprcdEgfJpOjUu+ONQveyg==",
"dependencies": {
"bigi": "^1.4.2",
"ecurve": "^1.0.6",
"js-sha256": "^0.9.0",
"randombytes": "^2.1.0",
"safe-buffer": "^5.2.1"
},
"engines": {
"node": ">=8.0.0"
}
},
"node_modules/bitcore-lib": {
"version": "8.25.25",
"resolved": "https://registry.npmjs.org/bitcore-lib/-/bitcore-lib-8.25.25.tgz",
"integrity": "sha512-H6qNCVl4M8/MglXhvc04mmeus1d6nrmqTJGQ+xezJLvL7hs7R3dyBPtOqSP3YSw0iq/GWspMd8f5OOlyXVipJQ==",
"dependencies": {
"bech32": "=2.0.0",
"bip-schnorr": "=0.6.4",
"bn.js": "=4.11.8",
"bs58": "^4.0.1",
"buffer-compare": "=1.1.1",
"elliptic": "^6.5.3",
"inherits": "=2.0.1",
"lodash": "^4.17.20"
}
},
"node_modules/bitcore-mnemonic": {
"version": "8.25.25",
"resolved": "https://registry.npmjs.org/bitcore-mnemonic/-/bitcore-mnemonic-8.25.25.tgz",
"integrity": "sha512-7HvRxHrmd+Rh0Ohl0SEDMKQBAM+FoevXbCFnxGju6H+uZjtWMOToHA8vUg0+B91pfEMjdt9mQVB/wSA8GMqnCA==",
"dependencies": {
"bitcore-lib": "^8.25.25",
"unorm": "^1.4.1"
},
"peerDependencies": {
"bitcore-lib": "^8.20.1"
}
},
"node_modules/bn.js": {
"version": "4.11.8",
"resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.8.tgz",
"integrity": "sha512-ItfYfPLkWHUjckQCk8xC+LwxgK8NYcXywGigJgSwOP8Y2iyWT4f2vsZnoOXTTbo+o5yXmIUJ4gn5538SO5S3gA=="
},
"node_modules/brorand": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz",
"integrity": "sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8="
},
"node_modules/bs58": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/bs58/-/bs58-4.0.1.tgz",
"integrity": "sha1-vhYedsNU9veIrkBx9j806MTwpCo=",
"dependencies": {
"base-x": "^3.0.2"
}
},
"node_modules/buffer-compare": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/buffer-compare/-/buffer-compare-1.1.1.tgz",
"integrity": "sha1-W+e+hTr4kZjR9N3AkNHWakiu9ZY="
},
"node_modules/ecurve": {
"version": "1.0.6",
"resolved": "https://registry.npmjs.org/ecurve/-/ecurve-1.0.6.tgz",
"integrity": "sha512-/BzEjNfiSuB7jIWKcS/z8FK9jNjmEWvUV2YZ4RLSmcDtP7Lq0m6FvDuSnJpBlDpGRpfRQeTLGLBI8H+kEv0r+w==",
"dependencies": {
"bigi": "^1.1.0",
"safe-buffer": "^5.0.1"
}
},
"node_modules/elliptic": {
"version": "6.5.4",
"resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.4.tgz",
"integrity": "sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ==",
"dependencies": {
"bn.js": "^4.11.9",
"brorand": "^1.1.0",
"hash.js": "^1.0.0",
"hmac-drbg": "^1.0.1",
"inherits": "^2.0.4",
"minimalistic-assert": "^1.0.1",
"minimalistic-crypto-utils": "^1.0.1"
}
},
"node_modules/elliptic/node_modules/bn.js": {
"version": "4.12.0",
"resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz",
"integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA=="
},
"node_modules/elliptic/node_modules/inherits": {
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
},
"node_modules/hash.js": {
"version": "1.1.7",
"resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz",
"integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==",
"dependencies": {
"inherits": "^2.0.3",
"minimalistic-assert": "^1.0.1"
}
},
"node_modules/hash.js/node_modules/inherits": {
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
},
"node_modules/hmac-drbg": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz",
"integrity": "sha1-0nRXAQJabHdabFRXk+1QL8DGSaE=",
"dependencies": {
"hash.js": "^1.0.3",
"minimalistic-assert": "^1.0.0",
"minimalistic-crypto-utils": "^1.0.1"
}
},
"node_modules/inherits": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz",
"integrity": "sha1-sX0I0ya0Qj5Wjv9xn5GwscvfafE="
},
"node_modules/js-sha256": {
"version": "0.9.0",
"resolved": "https://registry.npmjs.org/js-sha256/-/js-sha256-0.9.0.tgz",
"integrity": "sha512-sga3MHh9sgQN2+pJ9VYZ+1LPwXOxuBJBA5nrR5/ofPfuiJBE2hnjsaN8se8JznOmGLN2p49Pe5U/ttafcs/apA=="
},
"node_modules/lodash": {
"version": "4.17.21",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="
},
"node_modules/minimalistic-assert": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz",
"integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A=="
},
"node_modules/minimalistic-crypto-utils": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz",
"integrity": "sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo="
},
"node_modules/moment": { "node_modules/moment": {
"version": "2.29.1", "version": "2.29.1",
"resolved": "https://registry.npmjs.org/moment/-/moment-2.29.1.tgz", "resolved": "https://registry.npmjs.org/moment/-/moment-2.29.1.tgz",
@@ -192,33 +25,6 @@
"node": "*" "node": "*"
} }
}, },
"node_modules/randombytes": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz",
"integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==",
"dependencies": {
"safe-buffer": "^5.1.0"
}
},
"node_modules/safe-buffer": {
"version": "5.2.1",
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
"integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==",
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/feross"
},
{
"type": "patreon",
"url": "https://www.patreon.com/feross"
},
{
"type": "consulting",
"url": "https://feross.org/support"
}
]
},
"node_modules/uni-read-pages": { "node_modules/uni-read-pages": {
"version": "1.0.5", "version": "1.0.5",
"resolved": "https://registry.npmjs.org/uni-read-pages/-/uni-read-pages-1.0.5.tgz", "resolved": "https://registry.npmjs.org/uni-read-pages/-/uni-read-pages-1.0.5.tgz",
@@ -230,14 +36,6 @@
"resolved": "https://registry.npmjs.org/uni-simple-router/-/uni-simple-router-2.0.7.tgz", "resolved": "https://registry.npmjs.org/uni-simple-router/-/uni-simple-router-2.0.7.tgz",
"integrity": "sha512-8FKv5dw7Eoonm0gkO8udprrxzin0fNUI0+AvIphFkFRH5ZmP5ZWJ2pvnWzb2NiiqQSECTSU5VSB7HhvOSwD5eA==" "integrity": "sha512-8FKv5dw7Eoonm0gkO8udprrxzin0fNUI0+AvIphFkFRH5ZmP5ZWJ2pvnWzb2NiiqQSECTSU5VSB7HhvOSwD5eA=="
}, },
"node_modules/unorm": {
"version": "1.6.0",
"resolved": "https://registry.npmjs.org/unorm/-/unorm-1.6.0.tgz",
"integrity": "sha512-b2/KCUlYZUeA7JFUuRJZPUtr4gZvBh7tavtv4fvk4+KV9pfGiR6CQAQAWl49ZpR3ts2dk4FYkP7EIgDJoiOLDA==",
"engines": {
"node": ">= 0.4.0"
}
},
"node_modules/uview-ui": { "node_modules/uview-ui": {
"version": "2.0.19", "version": "2.0.19",
"resolved": "https://registry.npmjs.org/uview-ui/-/uview-ui-2.0.19.tgz", "resolved": "https://registry.npmjs.org/uview-ui/-/uview-ui-2.0.19.tgz",
@@ -256,187 +54,11 @@
} }
}, },
"dependencies": { "dependencies": {
"base-x": {
"version": "3.0.9",
"resolved": "https://registry.npmjs.org/base-x/-/base-x-3.0.9.tgz",
"integrity": "sha512-H7JU6iBHTal1gp56aKoaa//YUxEaAOUiydvrV/pILqIHXTtqxSkATOnDA2u+jZ/61sD+L/412+7kzXRtWukhpQ==",
"requires": {
"safe-buffer": "^5.0.1"
}
},
"bech32": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/bech32/-/bech32-2.0.0.tgz",
"integrity": "sha512-LcknSilhIGatDAsY1ak2I8VtGaHNhgMSYVxFrGLXv+xLHytaKZKcaUJJUE7qmBr7h33o5YQwP55pMI0xmkpJwg=="
},
"bigi": {
"version": "1.4.2",
"resolved": "https://registry.npmjs.org/bigi/-/bigi-1.4.2.tgz",
"integrity": "sha1-nGZalfiLiwj8Bc/XMfVhhZ1yWCU="
},
"bip-schnorr": {
"version": "0.6.4",
"resolved": "https://registry.npmjs.org/bip-schnorr/-/bip-schnorr-0.6.4.tgz",
"integrity": "sha512-dNKw7Lea8B0wMIN4OjEmOk/Z5qUGqoPDY0P2QttLqGk1hmDPytLWW8PR5Pb6Vxy6CprcdEgfJpOjUu+ONQveyg==",
"requires": {
"bigi": "^1.4.2",
"ecurve": "^1.0.6",
"js-sha256": "^0.9.0",
"randombytes": "^2.1.0",
"safe-buffer": "^5.2.1"
}
},
"bitcore-lib": {
"version": "8.25.25",
"resolved": "https://registry.npmjs.org/bitcore-lib/-/bitcore-lib-8.25.25.tgz",
"integrity": "sha512-H6qNCVl4M8/MglXhvc04mmeus1d6nrmqTJGQ+xezJLvL7hs7R3dyBPtOqSP3YSw0iq/GWspMd8f5OOlyXVipJQ==",
"requires": {
"bech32": "=2.0.0",
"bip-schnorr": "=0.6.4",
"bn.js": "=4.11.8",
"bs58": "^4.0.1",
"buffer-compare": "=1.1.1",
"elliptic": "^6.5.3",
"inherits": "=2.0.1",
"lodash": "^4.17.20"
}
},
"bitcore-mnemonic": {
"version": "8.25.25",
"resolved": "https://registry.npmjs.org/bitcore-mnemonic/-/bitcore-mnemonic-8.25.25.tgz",
"integrity": "sha512-7HvRxHrmd+Rh0Ohl0SEDMKQBAM+FoevXbCFnxGju6H+uZjtWMOToHA8vUg0+B91pfEMjdt9mQVB/wSA8GMqnCA==",
"requires": {
"bitcore-lib": "^8.25.25",
"unorm": "^1.4.1"
}
},
"bn.js": {
"version": "4.11.8",
"resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.8.tgz",
"integrity": "sha512-ItfYfPLkWHUjckQCk8xC+LwxgK8NYcXywGigJgSwOP8Y2iyWT4f2vsZnoOXTTbo+o5yXmIUJ4gn5538SO5S3gA=="
},
"brorand": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz",
"integrity": "sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8="
},
"bs58": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/bs58/-/bs58-4.0.1.tgz",
"integrity": "sha1-vhYedsNU9veIrkBx9j806MTwpCo=",
"requires": {
"base-x": "^3.0.2"
}
},
"buffer-compare": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/buffer-compare/-/buffer-compare-1.1.1.tgz",
"integrity": "sha1-W+e+hTr4kZjR9N3AkNHWakiu9ZY="
},
"ecurve": {
"version": "1.0.6",
"resolved": "https://registry.npmjs.org/ecurve/-/ecurve-1.0.6.tgz",
"integrity": "sha512-/BzEjNfiSuB7jIWKcS/z8FK9jNjmEWvUV2YZ4RLSmcDtP7Lq0m6FvDuSnJpBlDpGRpfRQeTLGLBI8H+kEv0r+w==",
"requires": {
"bigi": "^1.1.0",
"safe-buffer": "^5.0.1"
}
},
"elliptic": {
"version": "6.5.4",
"resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.4.tgz",
"integrity": "sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ==",
"requires": {
"bn.js": "^4.11.9",
"brorand": "^1.1.0",
"hash.js": "^1.0.0",
"hmac-drbg": "^1.0.1",
"inherits": "^2.0.4",
"minimalistic-assert": "^1.0.1",
"minimalistic-crypto-utils": "^1.0.1"
},
"dependencies": {
"bn.js": {
"version": "4.12.0",
"resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz",
"integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA=="
},
"inherits": {
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
}
}
},
"hash.js": {
"version": "1.1.7",
"resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz",
"integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==",
"requires": {
"inherits": "^2.0.3",
"minimalistic-assert": "^1.0.1"
},
"dependencies": {
"inherits": {
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
}
}
},
"hmac-drbg": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz",
"integrity": "sha1-0nRXAQJabHdabFRXk+1QL8DGSaE=",
"requires": {
"hash.js": "^1.0.3",
"minimalistic-assert": "^1.0.0",
"minimalistic-crypto-utils": "^1.0.1"
}
},
"inherits": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz",
"integrity": "sha1-sX0I0ya0Qj5Wjv9xn5GwscvfafE="
},
"js-sha256": {
"version": "0.9.0",
"resolved": "https://registry.npmjs.org/js-sha256/-/js-sha256-0.9.0.tgz",
"integrity": "sha512-sga3MHh9sgQN2+pJ9VYZ+1LPwXOxuBJBA5nrR5/ofPfuiJBE2hnjsaN8se8JznOmGLN2p49Pe5U/ttafcs/apA=="
},
"lodash": {
"version": "4.17.21",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="
},
"minimalistic-assert": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz",
"integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A=="
},
"minimalistic-crypto-utils": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz",
"integrity": "sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo="
},
"moment": { "moment": {
"version": "2.29.1", "version": "2.29.1",
"resolved": "https://registry.npmjs.org/moment/-/moment-2.29.1.tgz", "resolved": "https://registry.npmjs.org/moment/-/moment-2.29.1.tgz",
"integrity": "sha512-kHmoybcPV8Sqy59DwNDY3Jefr64lK/by/da0ViFcuA4DH0vQg5Q6Ze5VimxkfQNSC+Mls/Kx53s7TjP1RhFEDQ==" "integrity": "sha512-kHmoybcPV8Sqy59DwNDY3Jefr64lK/by/da0ViFcuA4DH0vQg5Q6Ze5VimxkfQNSC+Mls/Kx53s7TjP1RhFEDQ=="
}, },
"randombytes": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz",
"integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==",
"requires": {
"safe-buffer": "^5.1.0"
}
},
"safe-buffer": {
"version": "5.2.1",
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
"integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ=="
},
"uni-read-pages": { "uni-read-pages": {
"version": "1.0.5", "version": "1.0.5",
"resolved": "https://registry.npmjs.org/uni-read-pages/-/uni-read-pages-1.0.5.tgz", "resolved": "https://registry.npmjs.org/uni-read-pages/-/uni-read-pages-1.0.5.tgz",
@@ -447,11 +69,6 @@
"resolved": "https://registry.npmjs.org/uni-simple-router/-/uni-simple-router-2.0.7.tgz", "resolved": "https://registry.npmjs.org/uni-simple-router/-/uni-simple-router-2.0.7.tgz",
"integrity": "sha512-8FKv5dw7Eoonm0gkO8udprrxzin0fNUI0+AvIphFkFRH5ZmP5ZWJ2pvnWzb2NiiqQSECTSU5VSB7HhvOSwD5eA==" "integrity": "sha512-8FKv5dw7Eoonm0gkO8udprrxzin0fNUI0+AvIphFkFRH5ZmP5ZWJ2pvnWzb2NiiqQSECTSU5VSB7HhvOSwD5eA=="
}, },
"unorm": {
"version": "1.6.0",
"resolved": "https://registry.npmjs.org/unorm/-/unorm-1.6.0.tgz",
"integrity": "sha512-b2/KCUlYZUeA7JFUuRJZPUtr4gZvBh7tavtv4fvk4+KV9pfGiR6CQAQAWl49ZpR3ts2dk4FYkP7EIgDJoiOLDA=="
},
"uview-ui": { "uview-ui": {
"version": "2.0.19", "version": "2.0.19",
"resolved": "https://registry.npmjs.org/uview-ui/-/uview-ui-2.0.19.tgz", "resolved": "https://registry.npmjs.org/uview-ui/-/uview-ui-2.0.19.tgz",

View File

@@ -7,10 +7,8 @@
"moment": "^2.29.1", "moment": "^2.29.1",
"uni-read-pages": "^1.0.5", "uni-read-pages": "^1.0.5",
"uni-simple-router": "^2.0.7", "uni-simple-router": "^2.0.7",
"uview-ui": "^2.0.19", "uview-ui": "^2.0.27"
"vuex": "^3.6.2"
}, },
"devDependencies": {},
"scripts": { "scripts": {
"test": "echo \"Error: no test specified\" && exit 1" "test": "echo \"Error: no test specified\" && exit 1"
}, },

View File

@@ -373,19 +373,6 @@
{ {
"path": "pages/im/private/chat", "path": "pages/im/private/chat",
"style": { "style": {
"navigationBarBackgroundColor":"#FFFFFF",
"disableScroll": false,
"app-plus": {
"titleNView": {
"type": "default",
"buttons": [{
"float": "right",
"fontSrc": "/static/iconfont.ttf",
"text": "\ue607",
"fontSize": "20px"
}]
}
}
} }
}, },
{ {
@@ -464,7 +451,7 @@
{ {
"path": "pages/im/group/chat", "path": "pages/im/group/chat",
"name": "imGroupChat", "name": "imGroupChat",
"style": { "style": {
"navigationBarTitleText": "群聊", "navigationBarTitleText": "群聊",
"app-plus": { "app-plus": {
"titleNView": { "titleNView": {

View File

@@ -1,67 +1,67 @@
<template> <template>
<u-alert type="warning" v-if="connection != 0" :description="description" show-icon /> <u-alert type="warning" v-if="connection != 0" :description="description" show-icon />
</template> </template>
<script> <script>
export default { export default {
props: { props: {
connection: { connection: {
type: Number, type: Number,
default: 0 default: 0
} }
}, },
computed: { computed: {
description() { description() {
return this.connectionStatusMap.filter(item => item.index == this.connection)[0].text return this.connectionStatusMap.filter(item => item.index == this.connection)[0].text
} }
}, },
data() { data() {
return { return {
connectionStatusMap: [{ connectionStatusMap: [{
index: -1, index: -1,
text: '网络不可用' text: '网络不可用'
}, },
{ {
index: 0, index: 0,
text: '连接成功' text: '连接成功'
}, },
{ {
index: 1, index: 1,
text: '连接中' text: '连接中'
}, },
{ {
index: 2, index: 2,
text: '未连接' text: '未连接'
}, },
{ {
index: 3, index: 3,
text: '用户账号在其它设备登录' text: '用户账号在其它设备登录'
}, },
{ {
index: 4, index: 4,
text: 'TOKEN过期' text: 'TOKEN过期'
}, },
{ {
index: 6, index: 6,
text: '用户被禁用' text: '用户被禁用'
}, },
{ {
index: 12, index: 12,
text: '退出登录' text: '退出登录'
}, },
{ {
index: 13, index: 13,
text: '连接暂时被挂起' text: '连接暂时被挂起'
}, },
{ {
index: 14, index: 14,
text: '连接超时' text: '连接超时'
}, },
], ],
} }
} }
} }
</script> </script>
<style> <style>
</style> </style>

View File

@@ -1,10 +1,9 @@
<template> <template>
<view> <view>
<view v-for="(item, index) in conversations" :key="index" :class="['message', { 'is-top': item.isTop }]" <view v-for="(item, index) in conversations" :key="index" :class="['message', { 'is-top': item.isTop, 'is-active': pickedItem.targetId == item.targetId }]"
:data-item="item" @longpress="onLongPress" @click="toDetail(item)"> :data-item="item" @longpress="onLongPress" @click="toDetail(item)">
<message-cell :item="item" /> <message-cell :item="item" />
</view> </view>
<view class="shade" @click="hidePop" v-show="showPop"> <view class="shade" @click="hidePop" v-show="showPop">
<view class="pop" :style="popStyle" :class="{'show':showPop}"> <view class="pop" :style="popStyle" :class="{'show':showPop}">
<view v-for="(item, index) in popButton" :key="index" @click="pickerMenu" :data-index="index"> <view v-for="(item, index) in popButton" :key="index" @click="pickerMenu" :data-index="index">
@@ -131,6 +130,10 @@
&.is-top { &.is-top {
background: $window-color; background: $window-color;
}
&.is-active {
background: #F8FAFF;
} }
} }

View File

@@ -4,14 +4,16 @@
<view :class="['user', {'active': item.targetId === currentUser.targetId}]" @longpress="showAction(item)" <view :class="['user', {'active': item.targetId === currentUser.targetId}]" @longpress="showAction(item)"
v-for="(item, index) in users" :key="index" @click="toUser(item)"> v-for="(item, index) in users" :key="index" @click="toUser(item)">
<view class="avatar"> <view class="avatar">
<u-avatar :size="avatarSize" shape="square" :src="contact(item.targetId).portraitUrl" /> <u-avatar :size="avatarSize" shape="square"
:src="contact(item.targetId).portraitUrl || require('@/static/user/cover.png')" />
<view class="admin" v-if="item.is_admin === 1">管理</view> <view class="admin" v-if="item.is_admin === 1">管理</view>
<view class="owner" v-if="item.is_admin === 2">群主</view> <view class="owner" v-if="item.is_admin === 2">群主</view>
</view> </view>
<view class="name">{{ item.name }}</view> <view class="name">{{ item.name }}</view>
</view> </view>
<view class="user" v-if="isAdmin"> <view class="user" v-if="canInvite">
<u-avatar @click="inviteUser" :size="avatarSize" shape="square" icon="plus" bgColor="#f9f9f9" color="#c7c7c7" /> <u-avatar @click="inviteUser" :size="avatarSize" shape="square" icon="plus" bgColor="#f9f9f9"
color="#c7c7c7" />
<view class="name">邀请好友</view> <view class="name">邀请好友</view>
</view> </view>
</view> </view>
@@ -35,7 +37,7 @@
removeGroupAdmin, removeGroupAdmin,
transferGroupOwner transferGroupOwner
} from '@/apis/interfaces/im.js' } from '@/apis/interfaces/im.js'
import utils from '@/utils/index.js' import utils from '@/utils/index.js'
export default { export default {
props: { props: {
@@ -52,16 +54,18 @@
return { return {
users: [], users: [],
isOwner: false, isOwner: false,
isAdmin: false, isAdmin: false,
canInvite:false,// 是否可以开启邀请
adminUid: 0, adminUid: 0,
members: 0, members: 0,
actionShow: false, actionShow: false,
actionMap: [], actionMap: [],
actionTitle: '', actionTitle: '',
currentUser: {}, currentUser: {},
avatarSize: 45, avatarSize: 45,
labelSize: 14, labelSize: 14,
iconSize: 14 iconSize: 14
} }
}, },
computed: { computed: {
@@ -71,14 +75,15 @@
} }
} }
}, },
created() { created() {
this.avatarSize = utils.rpx2px(90) this.avatarSize = utils.rpx2px(90)
this.labelSize = utils.rpx2px(24) this.labelSize = utils.rpx2px(24)
this.iconSize = utils.rpx2px(26) this.iconSize = utils.rpx2px(26)
}, },
mounted() { mounted() {
this.initGroupInfo() this.initGroupInfo()
getGroupUsers(this.targetId, this.count).then(res => { getGroupUsers(this.targetId, this.count).then(res => {
console.log("res..",res)
this.users = res this.users = res
res.map(item => { res.map(item => {
this.$store.dispatch('updateContact', item) this.$store.dispatch('updateContact', item)
@@ -91,7 +96,8 @@
this.isOwner = res.is_owner this.isOwner = res.is_owner
this.isAdmin = res.is_admin this.isAdmin = res.is_admin
this.adminUid = res.user_id this.adminUid = res.user_id
this.members = res.members this.members = res.members
this.canInvite = res.can_invite
}) })
}, },
initUsers() { initUsers() {
@@ -271,8 +277,8 @@
.avatar { .avatar {
border-radius: 0 8rpx 0 0; border-radius: 0 8rpx 0 0;
position: relative; position: relative;
width: 90rpx; width: 84rpx;
height: 90rpx; height: 84rpx;
overflow: hidden; overflow: hidden;
.admin { .admin {

View File

@@ -2,7 +2,7 @@
<view class="message--cell"> <view class="message--cell">
<view class="avatar"> <view class="avatar">
<u-badge max="99" shape="horn" absolute :offset="[-5, -8]" :value="item.unreadMessageCount" /> <u-badge max="99" shape="horn" absolute :offset="[-5, -8]" :value="item.unreadMessageCount" />
<u-avatar :src="contact(item.targetId).portraitUrl" shape="square" size="44" /> <u-avatar :src="contact(item.targetId).portraitUrl" shape="square" :size="avatarSize" />
</view> </view>
<view class="content"> <view class="content">
<view class="header"> <view class="header">
@@ -18,6 +18,7 @@
<script> <script>
import messagePreview from './messagePreview' import messagePreview from './messagePreview'
import utils from '@/utils/index.js'
export default { export default {
props: { props: {
@@ -27,11 +28,16 @@
return {} return {}
} }
} }
}, },
mounted() { data() {
console.log(this.item); return {
avatarRpx: 84
}
}, },
computed: { computed: {
avatarSize() {
return utils.rpx2px(this.avatarRpx)
},
contact() { contact() {
return function(targetId) { return function(targetId) {
return this.$store.getters.contactInfo(targetId) return this.$store.getters.contactInfo(targetId)
@@ -51,6 +57,7 @@
.avatar { .avatar {
position: relative; position: relative;
padding-top: 5rpx;
.u-badge { .u-badge {
z-index: 998; z-index: 998;
@@ -62,10 +69,8 @@
box-sizing: border-box; box-sizing: border-box;
position: relative; position: relative;
flex: 1; flex: 1;
border-bottom-width: 0.5px !important; border-bottom-width: 0.5px !important;
border-color: #f9f9f9 !important; border-color: #eee !important;
border-bottom-style: solid; border-bottom-style: solid;
.header { .header {

View File

@@ -22,15 +22,18 @@
<view class="preview" v-if="msg.objectName=='RC:LBSMsg'"> <view class="preview" v-if="msg.objectName=='RC:LBSMsg'">
<text v-if="conversationType == 3">{{ user.name }}</text>[位置] <text v-if="conversationType == 3">{{ user.name }}</text>[位置]
</view> </view>
<view class="preview" v-if="msg.objectName=='RC:AudioMsg'"> <view class="preview" v-if="msg.objectName=='RC:InfoNtf' && JSON.parse(msg.message).mediaType==0">
<text v-if="conversationType == 3">{{ user.name }}</text>[语音通话] <text v-if="conversationType == 3">{{ user.name }}</text>[语音通话]
</view> </view>
<view class="preview" v-if="msg.objectName=='RC:VideoMsg'"> <view class="preview" v-if="msg.objectName=='RC:InfoNtf' && JSON.parse(msg.message).mediaType==1">
<text v-if="conversationType == 3">{{ user.name }}</text>[视频通话] <text v-if="conversationType == 3">{{ user.name }}</text>[视频通话]
</view> </view>
<view class="preview" v-if="msg.objectName=='RC:GrpNtf'"> <view class="preview" v-if="msg.objectName=='RC:GrpNtf'">
[{{ msg.message }}] [{{ msg.message }}]
</view> </view>
<view class="preview" v-if="msg.objectName=='RC:RcNtf'">
<text v-if="conversationType == 3">{{ user.name }}</text> 撤回了一条消息
</view>
</block> </block>
</view> </view>
</template> </template>

View File

@@ -16,9 +16,9 @@
</template> </template>
<script> <script>
import sentText from '../components/sentText' import sentText from './sentText'
import sentVoice from '../components/sentVoice' import sentVoice from './sentVoice'
import sentPopups from '../components/sentPopups' import sentPopups from './sentPopups'
export default { export default {
props: { props: {

View File

@@ -72,7 +72,7 @@
methods: { methods: {
singleCall(e) { singleCall(e) {
uni.navigateTo({ uni.navigateTo({
url: '/pages/im/private/call?targetId=' + this.targetId + '&mediaType=' + e.type url: '/pages/im/private/call?targetId=' + this.targetId + '&mediaType=' + e.type + '&isCall=true'
}) })
}, },
onPopupsItem(type) { onPopupsItem(type) {

View File

@@ -1,8 +1,7 @@
<template> <template>
<view class="sent--text"> <view class="sent--text">
<input class="input" type="text" :auto-blur="true" @focus="focus" @blur="blur" :focus="focusState" v-model="inputTxt" confirm-type="send" <input class="input" type="text" :auto-blur="true" @focus="focus" @blur="blur" :focus="focusState"
@confirm="sent" cursor-spacing="10" /> v-model="inputTxt" confirm-type="send" @confirm="sent" cursor-spacing="10" />
<!-- <button class="button" size="mini" :disabled="disabled" @click="demo">{{focusState ? '失焦': '聚焦'}}</button> -->
</view> </view>
</template> </template>
@@ -19,10 +18,6 @@
targetId: { targetId: {
type: String, type: String,
default: '' default: ''
},
inputTxt: {
type: String,
default: ''
} }
}, },
computed: { computed: {
@@ -33,7 +28,7 @@
return this.$store.getters.sender return this.$store.getters.sender
} }
}, },
created() { mounted() {
RongIMLib.getTextMessageDraft(this.conversationType, this.targetId, ({ RongIMLib.getTextMessageDraft(this.conversationType, this.targetId, ({
draft draft
}) => { }) => {
@@ -41,35 +36,29 @@
}) })
}, },
beforeDestroy() { beforeDestroy() {
RongIMLib.saveTextMessageDraft(this.conversationType, this.targetId, this.inputTxt, (res) => { // 保存草稿
console.log('销毁组件之前,保存草稿信息,但是没有执行', res); RongIMLib.saveTextMessageDraft(this.conversationType, this.targetId, this.inputTxt)
}) },
}, data() {
data() { return {
return {
focusState: false, focusState: false,
} inputTxt: ''
}
}, },
methods: { methods: {
// 发送文本消息
sent() { sent() {
if (!this.disabled) { if (!this.disabled) {
RongIMLib.clearTextMessageDraft(this.conversationType, this.targetId) im.sentText(this.conversationType, this.targetId, this.inputTxt, this.sender, () => {
im.sentText(this.conversationType, this.targetId, this.inputTxt, this.sender, () => { RongIMLib.clearTextMessageDraft(this.conversationType, this.targetId)
this.$emit('success') this.$emit('success')
this.inputTxt = '' this.inputTxt = ''
}) })
} }
},
demo(){
console.log(this.focusState)
this.focusState = !this.focusState
}, },
focus() { focus() {
this.$emit('focus') this.$emit('focus')
}, },
blur() { blur() {
uni.hideKeyboard() uni.hideKeyboard()
this.$emit('blur') this.$emit('blur')
} }

View File

@@ -100,7 +100,8 @@
<style scoped lang="scss"> <style scoped lang="scss">
.send--voice { .send--voice {
.voice { .voice {
display: flex;
background: $window-color; background: $window-color;
height: 70rpx; height: 70rpx;
line-height: 70rpx; line-height: 70rpx;
@@ -109,14 +110,14 @@
width: 500rpx; width: 500rpx;
border-radius: 10rpx; border-radius: 10rpx;
margin-right: 15rpx; margin-right: 15rpx;
.button { .button {
font-size: 30rpx; font-size: 30rpx;
color: #333; color: #333;
} }
} }
.modal { .modal {
display: flex;
background: rgba(0, 0, 0, .6); background: rgba(0, 0, 0, .6);
position: fixed; position: fixed;
height: 200rpx; height: 200rpx;
@@ -128,7 +129,6 @@
flex-direction: column; flex-direction: column;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
.icon { .icon {
width: 88rpx; width: 88rpx;
height: 88rpx; height: 88rpx;

View File

@@ -0,0 +1,81 @@
<template>
<view v-if="!isRemote">
<view class="state" v-if="isGroup">
<!-- 已发送 -->
<u-icon name="checkbox-mark" :size="iconSize" class="sent"
:color="message.sentStatus >= 30 ? '#34CE98' : '#999999' " />
<!-- 已阅读 -->
<text class="readers">{{ readers }}</text>
</view>
<view class="state" v-else>
<!-- 已发送 -->
<u-icon name="checkbox-mark" :size="iconSize" class="sent"
:color="message.sentStatus >= 30 ? '#34CE98' : '#999999' " />
<!-- 已阅读 -->
<u-icon name="checkbox-mark" :size="iconSize" class="receive"
:color="message.sentStatus >= 50 ? '#34CE98' : '#999999' " />
</view>
</view>
</template>
<script>
import * as RongIMLib from '@/uni_modules/RongCloud-IMWrapper/js_sdk/index'
import utils from '@/utils/index.js'
export default {
name: 'showText',
props: {
message: {
type: Object,
default: () => {
return {}
}
},
isGroup: {
type: Boolean,
default: false
},
isRemote: {
type: Boolean,
default: false
}
},
computed: {
iconSize() {
return utils.rpx2px(28)
},
readers() {
if (this.message.extra) {
return JSON.parse(this.message.extra).readers || 0
}
return 0
}
}
}
</script>
<style scoped lang="scss">
.state {
padding: 10rpx;
border-radius: 30rpx;
background-color: #ddd;
display: flex;
margin-right: 10rpx;
.sent {
z-index: 2;
}
.receive {
z-index: 1;
margin-left: -20rpx;
}
.readers {
font-size: 20rpx;
margin-left: -6rpx;
color: $text-gray-m;
}
}
</style>

View File

@@ -0,0 +1,90 @@
<template>
<view class="msg--call">
<view class="name" v-if="isGroup && isRemote">{{ contact(message.senderUserId).name }}</view>
<view class="im--text" :class="isRemote ? 'left': 'right'">
<u-icon name="camera" size="22" v-if="msg.mediaType == 1" :label="label" />
<u-icon name="phone" size="22" v-else :label="label" />
</view>
</view>
</template>
<script>
import utils from '@/utils/index.js'
import moment from 'moment'
export default {
name: 'showText',
props: {
message: {
type: Object,
default: () => {
return {}
}
},
isGroup: {
type: Boolean,
default: false
}
},
mounted() {
},
computed: {
msg() {
return JSON.parse(this.message.content.message)
},
label() {
return this.msg.connected ? '通话时长:' + duration : '未接通'
},
isRemote() {
return this.message.messageDirection == 2
},
contact() {
return function(targetId) {
return this.$store.getters.contactInfo(targetId)
}
},
duration() {
if (this.message.duration > 3600) {
return moment.utc(this.message.duration * 1000).format('HH:mm:ss')
} else {
return moment.utc(this.message.duration * 1000).format('mm:ss')
}
}
}
}
</script>
<style scoped lang="scss">
.msg--call {
.name {
font-size: 26rpx;
color: $text-gray-m;
display: inline-block;
}
.im--text {
max-width: 508rpx;
padding: 20rpx;
line-height: 46rpx;
font-size: 32rpx;
color: $text-color;
display: flex;
flex-direction: row;
&.left {
border-radius: 0 20rpx 20rpx 20rpx;
background: white;
}
&.right {
border-radius: 20rpx 0 20rpx 20rpx;
background: $main-color;
color: white;
.u-icon {
color: white;
}
}
}
}
</style>

View File

@@ -0,0 +1,122 @@
<template>
<view class="msg--image">
<message-state :message="message" :isGroup="isGroup" :isRemote="isRemote" />
<view class="">
<view class="name" v-if="isGroup && isRemote">{{ contact(message.senderUserId).name }}</view>
<view class="image" :class="isRemote ? 'left': 'right'">
<image class="img" :src="content.thumbnail" @click="previewImage" mode="widthFix"></image>
</view>
</view>
</view>
</template>
<script>
import * as RongIMLib from '@/uni_modules/RongCloud-IMWrapper/js_sdk/index'
import messageState from './messageState'
export default {
name: 'showImage',
props: {
message: {
type: Object,
default: () => {
return {}
}
},
isGroup: {
type: Boolean,
default: false
}
},
components: {
messageState
},
computed: {
isRemote() {
return this.message.messageDirection == 2
},
content() {
return this.message.content
},
contact() {
return function(targetId) {
return this.$store.getters.contactInfo(targetId)
}
}
},
methods: {
previewImage() {
if (this.content.local) {
uni.previewImage({
urls: [
this.content.local
],
success: (e) => {
console.log(e);
},
fail: (er) => {
console.log(er);
}
})
} else {
RongIMLib.downloadMediaMessage(this.messageId, {
success: (path) => {
this.content.local = path
uni.previewImage({
urls: [
path
],
success: (e) => {
console.log(e);
},
fail: (er) => {
console.log(er);
}
})
},
progress: (progress, messageId) => {
console.log('progress', progress);
},
cancel: (messageId) => {
console.log('cancel', messageId);
},
error: (errorCode, messageId) => {
console.log('errorCode', errorCode);
}
})
}
}
}
}
</script>
<style scoped lang="scss">
.msg--image {
display: flex;
align-items: flex-end;
.name {
font-size: 24rpx;
color: $text-gray-m;
}
.image {
.img {
width: 180rpx;
}
&.left {
.img {
border-radius: 0 10rpx 10rpx 10rpx;
}
}
&.right {
.img {
border-radius: 10rpx 0 10rpx 10rpx;
}
}
}
}
</style>

View File

@@ -0,0 +1,79 @@
<template>
<view class="msg--text">
<message-state :message="message" :isGroup="isGroup" :isRemote="isRemote" />
<view class="">
<view class="name" v-if="isGroup && isRemote">{{ contact(message.senderUserId).name }}</view>
<view :class="['text', isRemote ? 'left': 'right']">{{ content }}</view>
</view>
</view>
</template>
<script>
import messageState from './messageState'
export default {
name: 'showText',
props: {
message: {
type: Object,
default: () => {
return {}
}
},
isGroup: {
type: Boolean,
default: false
}
},
components: {
messageState
},
computed: {
isRemote() {
return this.message.messageDirection == 2
},
content() {
return this.message.content.content
},
contact() {
return function(targetId) {
return this.$store.getters.contactInfo(targetId)
}
}
}
}
</script>
<style scoped lang="scss">
.msg--text {
display: flex;
align-items: flex-end;
.name {
font-size: 24rpx;
color: $text-gray-m;
}
.text {
box-sizing: border-box;
max-width: 502rpx;
padding: 20rpx;
line-height: 46rpx;
font-size: 32rpx;
color: $text-color;
word-break: break-all;
&.left {
border-radius: 0 20rpx 20rpx 20rpx;
background: white;
}
&.right {
border-radius: 20rpx 0 20rpx 20rpx;
background: $main-color;
color: white;
}
}
}
</style>

View File

@@ -0,0 +1,253 @@
<template>
<view class="msg--voice">
<message-state :message="message" :isGroup="isGroup" :isRemote="isRemote" />
<view class="">
<view class="name" v-if="isGroup && isRemote">{{ contact(message.senderUserId).name }}</view>
<view class="msg-voice">
<view :class="['voice', isRemote ? 'left': 'right', {'onPlay': onPlay}]" :style="{width: width + 'rpx'}"
@click="startPlay">
<image v-if="isRemote" class="icon"
:class="{ 'videoFlicker' : onPlay && msgId == message.messageId }"
src="@/static/icon/audio_green.png" mode="widthFix"></image>
<image v-else class="icon" :class="{ 'videoFlicker' : onPlay && msgId == message.messageId }"
src="@/static/icon/audio_white.png" mode="widthFix"></image>
<text class="duration">{{ duration }}"</text>
</view>
<u-badge isDot :show="message.content.local =='' && isRemote" />
</view>
</view>
</view>
</template>
<script>
import * as RongIMLib from '@/uni_modules/RongCloud-IMWrapper/js_sdk/index'
import messageState from './messageState'
export default {
props: {
message: {
type: Object,
default: () => {
return {}
}
},
isGroup: {
type: Boolean,
default: false
}
},
components: {
messageState
},
data() {
return {
onPlay: false,
innerAC: null,
msgId: null
}
},
computed: {
duration() {
return this.message.content.duration
},
isRemote() {
return this.message.messageDirection == 2
},
contact() {
return function(targetId) {
return this.$store.getters.contactInfo(targetId)
}
},
width() {
if (this.duration > 3) {
return (this.duration * 5) + 150
} else {
return 120
}
}
},
mounted() {
// 这样能临时解决,但是会一直监听
uni.$on('onVoiceMessagePlay', (messageId) => {
if (this.message.messageId != messageId) {
this.stopPlay()
}
})
},
created() {
console.log(this.message.messageId)
},
methods: {
// 播放语音消息
startPlay() {
// 如果是正在播放的,停止当前播放
if (this.onPlay) {
this.stopPlay()
return
}
this.onPlay = true
// 如果下载到了本地,那么直接播放,否则调用下载语音消息接口,下载后再播放
if (this.message.content.local && this.message.content.local.indexOf('///data/user/') < 0) {
this.playVoice(this.message.content.local)
} else {
RongIMLib.downloadMediaMessage(this.message.messageId, {
success: (path) => {
this.message.content.local = path
this.playVoice(path)
},
progress: (progress, messageId) => {},
cancel: (messageId) => {},
error: (errorCode, messageId) => {
uni.showToast({
icon: 'none',
title: '语音播放失败'
})
}
})
}
},
playVoice(path) {
console.log('准备播放', this.message.content);
this.innerAC = uni.createInnerAudioContext()
this.innerAC.src = path
this.innerAC.autoplay = false
this.msgId = this.message.messageId
this.innerAC.onCanplay(res => {
console.log('onCanplay')
this.innerAC.play()
})
this.innerAC.onPlay(res => {
console.log('onPlay')
uni.$emit('onVoiceMessagePlay', this.message.messageId)
})
this.innerAC.onEnded(res => {
this.innerAC.stop()
})
this.innerAC.onStop(() => {
this.onPlay = false
this.innerAC.destroy()
this.innerAC = null
this.msgId = null
uni.$emit('onVoiceMessageStop', this.message.messageId)
})
this.innerAC.onError(err => {
uni.showToast({
icon: 'none',
title: '语音播放失败'
})
})
},
stopPlay() {
if (this.innerAC) {
this.innerAC.stop()
}
}
}
}
</script>
<style>
@keyframes playFlicker {
0% {
opacity: 1;
}
50% {
opacity: .5;
}
100% {
opacity: 1;
}
}
.videoFlicker {
animation: playFlicker 1s infinite;
}
</style>
<style scoped lang="scss">
.msg--voice {
display: flex;
align-items: flex-end;
.state {
padding: 10rpx;
border-radius: 30rpx;
width: 40rpx;
background-color: #ddd;
display: flex;
margin-right: 10rpx;
.sent {
z-index: 2;
}
.receive {
z-index: 1;
margin-left: -20rpx;
}
}
.name {
font-size: 24rpx;
color: $text-gray-m;
}
.msg-voice {
display: flex;
align-items: center;
.u-badge {
margin-left: 20rpx;
}
.voice {
display: flex;
flex-direction: row;
justify-content: space-between;
align-items: center;
height: 84rpx;
padding: 0 30rpx;
box-sizing: border-box;
.icon {
width: 38rpx;
height: 38rpx;
}
&.left {
border-radius: 0 20rpx 20rpx 20rpx;
background: white;
&.onPlay {
background-color: #EEEEEE;
}
.duration {
color: #333;
font-size: 30rpx;
}
}
&.right {
border-radius: 20rpx 0 20rpx 20rpx;
background: $main-color;
flex-direction: row-reverse;
&.onPlay {
background-color: darken($main-color, 10);
}
.duration {
color: white;
font-size: 30rpx;
}
}
}
}
}
</style>

View File

@@ -1,74 +0,0 @@
<template>
<view class="">
<text class="name" v-if="!guest && name">{{ name }}</text>
<view class="msg--image" :class="guest ? 'right': 'left'">
<image class="img" :src="msg.thumbnail" @click="previewImage" mode="widthFix"></image>
</view>
</view>
</template>
<script>
export default {
name: 'showImage',
props: {
msg: {
type: Object,
default: () => {
return {
local: '',
remote: '',
objectName: '',
thumbnail: '',
isFull: false
}
}
},
guest: {
type: Boolean,
default: true
},
name: {
type: String,
default: ''
}
},
methods: {
previewImage() {
uni.previewImage({
urls: [
this.msg.remote
],
current: 1
})
}
}
}
</script>
<style scoped lang="scss">
.name {
font-size: 24rpx;
line-height: 34rpx;
color: $text-gray-m;
padding-bottom: 10rpx;
}
.msg--image {
// padding: 20rpx;
&.left {
border-radius: 0 20rpx 20rpx 20rpx;
// background: white;
}
&.right {
border-radius: 20rpx 0 20rpx 20rpx;
// background: #34CE98;
}
.img {
width: 150rpx;
border-radius: 10rpx;
}
}
</style>

View File

@@ -0,0 +1,145 @@
<template>
<view class="">
<view class="notify" v-if="message.objectName === 'RC:GrpNtf'">{{ message.content.message }}</view>
<view class="notify" v-else-if="message.objectName === 'RC:RcNtf'">
{{ contact(message.senderUserId).name }} 撤回了一条消息
</view>
<view v-else :class="['cell-item', message.messageDirection == 1 ? 'right' : 'left']">
<u-avatar class="avatar" @click="toUser(message)" :size="avatarSize" shape="square"
:src="contact(message.senderUserId).portraitUrl" />
<view class="msg" @longpress="backMessage">
<show-text v-if="message.objectName === 'RC:TxtMsg'" :message="message" :isGroup="isGroup" />
<show-voice v-else-if="message.objectName === 'RC:HQVCMsg'" :message="message" :isGroup="isGroup" />
<show-image v-else-if="message.objectName === 'RC:ImgMsg'" :message="message" :isGroup="isGroup" />
<show-call v-else-if="message.objectName === 'RC:InfoNtf'" :message="message" :isGroup="isGroup" />
<view v-else class="">
[未处理的消息类型 {{ message.objectName }}]
</view>
</view>
<!-- <view class="time">{{ item.sentTime|timeCustomCN }}</view> 时间判断最好是隔一段时间没有消息才展示一个 -->
</view>
</view>
</template>
<script>
import * as IMLib from '@/uni_modules/RongCloud-IMWrapper/js_sdk/index'
import showVoice from './show/showVoice'
import showImage from './show/showImage'
import showText from './show/showText'
import showCall from './show/showCall'
import utils from '@/utils/index.js'
export default {
components: {
showCall,
showVoice,
showImage,
showText
},
props: {
message: {
type: Object,
default: function() {
return {}
}
},
isGroup: {
type: Boolean,
default: false
}
},
data() {
return {
avatarRpx: 84
}
},
computed: {
avatarSize() {
return utils.rpx2px(this.avatarRpx)
},
contact() {
return function(targetId) {
return this.$store.getters.contactInfo(targetId)
}
}
},
methods: {
toUser(item) {
if (item.messageDirection == 1) {
uni.navigateTo({
url: '/pages/im/friends/mine?targetId=' + item.senderUserId
})
} else {
uni.navigateTo({
url: '/pages/im/friends/info?targetId=' + item.senderUserId
})
}
},
// 撤回消息测试
backMessage() {
if (this.$store.getters.sender.userId != this.message.senderUserId) {
uni.showToast({
icon: 'none',
title: '不能撤回别人的消息'
})
return
}
// 判断时间超过了多久 就不能撤回 TODO
// this.message.sentTime
const pushContent = this.$store.getters.sender.name + '撤回了一条消息'
IMLib.recallMessage(this.message.messageId, pushContent,
({
code,
message
}) => {
if (code === 0) {
uni.showToast({
icon: 'none',
title: '消息撤回成功'
})
IMLib.getMessage(this.message.messageId, res => {
uni.$emit('onRecallMessage', res.message)
})
} else {
uni.showToast({
icon: 'none',
title: '撤回失败' + code
})
}
}
)
}
}
}
</script>
<style lang="scss" scoped>
.notify {
text-align: center;
font-size: 24rpx;
color: #666;
}
.cell-item {
display: flex;
width: 710rpx;
justify-content: flex-start;
&.left {
flex-direction: row;
}
&.right {
flex-direction: row-reverse;
.state {
flex-direction: row;
justify-content: flex-end;
}
}
.msg {
margin: 0 20rpx;
}
}
</style>

View File

@@ -1,58 +0,0 @@
<template>
<view class="msg--text">
<text class="name" v-if="!guest && name">{{ name }}</text>
<view>
<text class="im--text" :class="guest ? 'right': 'left'">{{ msg.content }}</text>
</view>
</view>
</template>
<script>
export default {
name: 'showText',
props: {
msg: {
type: Object,
default: () => {
return {}
}
},
name: {
type: String,
default: ''
},
guest: {
type: Boolean,
default: true
}
}
}
</script>
<style scoped lang="scss">
.msg--text {
.name {
font-size: 26rpx;
color: $text-gray-m;
display: inline-block;
}
.im--text {
max-width: 508rpx;
padding: 20rpx;
line-height: 46rpx;
font-size: 32rpx;
color: $text-color;
display: inline-block;
word-break: break-all;
&.left {
border-radius: 0 20rpx 20rpx 20rpx;
background: white;
}
&.right {
border-radius: 20rpx 0 20rpx 20rpx;
background: $main-color;
color: white;
}
}
}
</style>

View File

@@ -1,106 +0,0 @@
<template>
<view class="">
<text class="name" v-if="!guest && name">{{ name }}</text>
<view class="msg--voice" :class="guest ? 'right': 'left'" @click="onPlayMsg">
<image v-if="!guest" class="icon" src="@/static/icon/audio_green.png" mode="widthFix"></image>
<text class="duration">{{msg.duration}}"</text>
<image v-if="guest" class="icon" src="@/static/icon/audio_white.png" mode="widthFix"></image>
</view>
</view>
</template>
<script>
export default {
name: 'showVoice',
props: {
msg: {
type: Object,
default: () => {
return {
local: '',
remote: '',
objectName: '',
duration: 0
}
}
},
name: {
type: String,
default: ''
},
guest: {
type: Boolean,
default: true
}
},
methods: {
// 播放语音消息
onPlayMsg() {
uni.downloadFile({
url: this.msg.remote,
success: (res) => {
if (res.statusCode === 200) {
let innerAudioContext = uni.createInnerAudioContext()
innerAudioContext.src = res.tempFilePath
if (this.audioContextPaused) {
innerAudioContext.play()
this.audioContextPaused = false
return
}
innerAudioContext.stop()
innerAudioContext.onStop(resStop => {
this.audioContextPaused = true
})
innerAudioContext.onError(err => {
console.log(err);
})
}
}
})
}
}
}
</script>
<style scoped lang="scss">
.name {
font-size: 24rpx;
line-height: 34rpx;
color: $text-gray-m;
}
.msg--voice {
flex-direction: row;
justify-content: space-between;
align-items: center;
height: 79rpx;
width: 170rpx;
padding: 0 20rpx;
box-sizing: border-box;
.icon {
width: 38rpx;
height: 38rpx;
}
&.left {
border-radius: 0 20rpx 20rpx 20rpx;
background: white;
.duration {
color: #333;
font-size: 30rpx;
}
}
&.right {
border-radius: 20rpx 0 20rpx 20rpx;
background: $main-color;
.duration {
color: white;
font-size: 30rpx;
}
}
}
</style>

View File

@@ -12,8 +12,8 @@
</view> </view>
<block v-if="friends.length > 0"> <block v-if="friends.length > 0">
<u-index-item v-for="(item, fkey) in friends" :key="fkey"> <u-index-item v-for="(item, fkey) in friends" :key="fkey">
<u-index-anchor :text="indexs[fkey]" bgColor="#ededed" height="20" size="12" color="#666" <u-index-anchor :text="indexs[fkey]" bgColor="#f9f9f9" height="20" size="12" color="#666"
style="padding:10rpx 30rpx" /> class="anchor" />
<view v-for="(friendItem, index) in item" :key="index" class="friend-flex" <view v-for="(friendItem, index) in item" :key="index" class="friend-flex"
@click="toFriend(friendItem.targetId)"> @click="toFriend(friendItem.targetId)">
<u-avatar class="avatar-img" size="40" shape="square" <u-avatar class="avatar-img" size="40" shape="square"
@@ -37,6 +37,7 @@
getFriendsLetter getFriendsLetter
} from '@/apis/interfaces/im'; } from '@/apis/interfaces/im';
import * as RongIMLib from '@/uni_modules/RongCloud-IMWrapper/js_sdk/index' import * as RongIMLib from '@/uni_modules/RongCloud-IMWrapper/js_sdk/index'
import im from '@/utils/im/index.js'
export default { export default {
data() { data() {
@@ -86,9 +87,9 @@
// 新朋友 // 新朋友
toPending() { toPending() {
// if (this.pendingCount > 0) { // if (this.pendingCount > 0) {
uni.navigateTo({ uni.navigateTo({
url: '/pages/im/friends/pending' url: '/pages/im/friends/pending'
}); });
// } else { // } else {
// uni.showToast({ // uni.showToast({
// title: ` 暂无好友申请 ~ `, // title: ` 暂无好友申请 ~ `,
@@ -113,6 +114,12 @@
height: 70vh; height: 70vh;
} }
.anchor {
background-color: #f9f9f9 !important;
padding: 10rpx 30rpx;
border-bottom: none !important;
}
// 好友列表 // 好友列表
.friend-flex { .friend-flex {
position: relative; position: relative;
@@ -126,6 +133,8 @@
box-shadow: 0 0 20rpx rgba($color: $main-color, $alpha: 0.2); box-shadow: 0 0 20rpx rgba($color: $main-color, $alpha: 0.2);
} }
.info { .info {
flex: 1; flex: 1;
margin-left: $padding; margin-left: $padding;

View File

@@ -229,7 +229,7 @@
}, },
singleCall(e) { singleCall(e) {
uni.redirectTo({ uni.redirectTo({
url: '/pages/im/private/call?targetId=' + this.targetId + '&mediaType=' + e.type url: '/pages/im/private/call?targetId=' + this.targetId + '&mediaType=' + e.type + '&isCall=true'
}) })
} }
} }

View File

@@ -6,8 +6,15 @@
:disabled="true" :show-action="false" /> :disabled="true" :show-action="false" />
</view> </view>
</u-sticky> </u-sticky>
<view v-for="(item, index) in pendings" :key="index"> <block v-if="pendings.length > 0">
<apply-cell :message="item.latestMessage" @success="getPendingList" /> <view v-for="(item, index) in pendings" :key="index">
<apply-cell :message="item.latestMessage" @success="getPendingList" />
</view>
</block>
<view class="no-lists" v-else>
<u-image class="cover" radius="4" width="400rpx" height="400rpx"
:src="require('@/static/imgs/no-friend.png')" :lazy-load="true" />
<span> 暂无好友申请 ~ </span>
</view> </view>
</view> </view>
</template> </template>
@@ -15,14 +22,15 @@
<script> <script>
import applyCell from '../components/friendApplyCell' import applyCell from '../components/friendApplyCell'
import im from '@/utils/im/index.js' import im from '@/utils/im/index.js'
export default { export default {
components: { components: {
applyCell applyCell
}, },
data() { data() {
return { return {
pendings: [] pendings: [],
bg: '#fff'
} }
}, },
onLoad() { onLoad() {
@@ -31,7 +39,12 @@
}, },
methods: { methods: {
getPendingList() { getPendingList() {
im.getPendingList((pendings) => { im.getPendingList((pendings) => {
if (pendings.length > 0) {
this.bg = '#f9f9f9'
} else {
this.bg = '#fff'
}
this.pendings = pendings this.pendings = pendings
}) })
} }
@@ -45,18 +58,18 @@
background: $window-color; background: $window-color;
} }
.no-lists { .no-lists {
padding-top: $padding * 3; padding-top: $padding * 5;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
box-sizing: border-box; box-sizing: border-box;
font-size: $title-size-m; font-size: $title-size-m;
color: $text-gray-m; color: $text-gray-m;
span { span {
padding-top: $padding; padding-top: $padding;
} }
} }
</style> </style>

View File

@@ -1,35 +1,59 @@
<template> <template>
<view class="create"> <view class="create">
<view class="create-title">公告内容</view> <view class="create-title">公告内容</view>
<u--textarea v-model="content" count height="240" maxlength="240" placeholder="请输入公告内容" /> <block v-if="type !== 'cheack'">
<u-button type="primary" text="发布" :disabled="disabled" @click="onCreate" color="#34CE98" /> <u--textarea v-model="content" count height="240" maxlength="240" placeholder="请输入公告内容" />
<u-button type="primary" text="发布" :disabled="disabled" @click="onCreate" color="#34CE98" />
</block>
<block v-if="type === 'cheack'">
<view class="content-a"> {{content}} </view>
</block>
</view> </view>
</template> </template>
<script> <script>
import { import {
createGroupAnnouncement createGroupAnnouncement,
getGroupAnnouncement
} from '@/apis/interfaces/im.js' } from '@/apis/interfaces/im.js'
export default { export default {
data() { data() {
return { return {
targetId: '', targetId: '',
content: '' content: '',
aId: '',
type: '' // check ' 查看详情'
} }
}, },
onLoad(e) { onLoad(e) {
this.targetId = e.targetId this.targetId = e.targetId
}, if (e.type) {
computed: { this.type = e.type
disabled() { }
return this.content.length == 0 || this.content.length > 200 if (e.aId) {
} this.aId = e.aId
getGroupAnnouncement(this.targetId, this.aId).then(res => {
console.log(res.content)
this.content = res.content
}).catch(err => {
uni.showToast({
title: err.message,
icon: 'none',
mask: true
})
})
}
},
computed: {
disabled() {
return this.content.length == 0 || this.content.length > 200
}
}, },
methods: { methods: {
onCreate() { onCreate() {
createGroupAnnouncement(this.targetId, this.content).then(res => { createGroupAnnouncement(this.targetId, this.content).then(res => {
uni.$emit('groupAnnouncementCreated') uni.$emit('groupAnnouncementCreated')
uni.showToast({ uni.showToast({
title: '发布成功', title: '发布成功',
success: () => { success: () => {
@@ -52,15 +76,16 @@
<style lang="scss" scoped> <style lang="scss" scoped>
.create { .create {
padding: $padding; padding: $padding;
.create-title{
.create-title {
font-size: $title-size + 4; font-size: $title-size + 4;
padding: $padding - 10 0 $padding - 10 $padding - 10 ; padding: $padding - 10 0 $padding - 10 $padding - 10;
color: $text-color; color: $text-color;
font-weight: 800; font-weight: 800;
position: relative; position: relative;
&::before{ &::before {
content:""; content: "";
position: absolute; position: absolute;
width: 10rpx; width: 10rpx;
height: 34rpx; height: 34rpx;
@@ -69,6 +94,13 @@
top: 26rpx; top: 26rpx;
} }
} }
.content-a {
color: $text-color;
font-size: $title-size;
line-height: 1.7;
}
.u-button { .u-button {
margin-top: $padding; margin-top: $padding;
} }

View File

@@ -1,22 +1,30 @@
<template> <template>
<view class="announce"> <view class="announce" :style="`background-color:${bg};`">
<!-- 有列表 -->
<u-skeleton rows="2" :loading="loading" avatar :rows="5" v-if="announcements.length>0"> <u-skeleton rows="2" :loading="loading" avatar :rows="5" v-if="announcements.length>0">
<view v-for="(item,index) in announcements" :key="index" class="item" > <view v-for="(item,index) in announcements" :key="index" class="item"
<view class="header"> @longpress="actions(item.announcement_id)" @click="tabA(item.announcement_id)">
<u-avatar :src="item.user.portraitUrl" /> <view class="content-a"><span v-if="item.is_top">置顶</span>{{ item.content }}</view>
<view class="user"> <view class="user">
<view class="name">{{ item.user.name }}</view> <u-avatar :src="item.user.portraitUrl" size="40rpx" />
<view class="time">{{ item.created_at }}</view> <view class="name">{{ item.user.name }}</view>
</view> <view class="time">{{ item.created_at }}</view>
<view class="delete" v-if="isAdmin" @click="onDelete(item.announcement_id)">删除</view>
</view> </view>
<view class="content">{{ item.content }}</view> <!-- <view class="delete" v-if="isAdmin" @click="onDelete(item.announcement_id)">删除</view> -->
</view> </view>
</u-skeleton> </u-skeleton>
<!-- 没有列表 -->
<view class="no-lists" v-else> <view class="no-lists" v-else>
<u-image class="cover" radius="4" width="400rpx" height="400rpx" :src="require('@/static/imgs/no-level-list.png')" :lazy-load="true" /> <u-image class="cover" radius="4" width="400rpx" height="400rpx"
:src="require('@/static/imgs/no-level-list.png')" :lazy-load="true" />
<span>暂无公告内容~</span> <span>暂无公告内容~</span>
</view> </view>
<!-- 弹出 -->
<u-action-sheet :actions="actionMap" :title="actionTitle" :show="actionShow" cancelText="取消"
@close="actionShow = false" @select="handleAction" />
</view> </view>
</template> </template>
@@ -24,16 +32,30 @@
import { import {
getGroupInfo, getGroupInfo,
getGroupAnnouncements, getGroupAnnouncements,
deleteGroupAnnouncement deleteGroupAnnouncement,
topGroupAnnouncement
} from '@/apis/interfaces/im.js' } from '@/apis/interfaces/im.js'
export default { export default {
data() { data() {
return { return {
targetId: '', targetId: '',
announcements: [], groupAnnouncementId: '', // 选择公告 id
announcements: [], // 公告列表
loading: true, loading: true,
isAdmin: false isAdmin: false,
actionShow: false,
actionMap: [{
key: 2,
name: ' 删除该公告',
disabled: false
}, {
key: 3,
name: '置顶该公告',
disabled: false
}],
actionTitle: '请选择操作',
bg:'#fff'
} }
}, },
onLoad(e) { onLoad(e) {
@@ -60,27 +82,80 @@
} }
}, },
methods: { methods: {
// 获取公告信息
initData() { initData() {
getGroupAnnouncements(this.targetId).then(res => { getGroupAnnouncements(this.targetId).then(res => {
if(res.length>0){
this.bg = '#f9f9f9'
}else{
this.bg = '#fff'
}
this.announcements = res this.announcements = res
this.loading = false this.loading = false
}) })
}, },
onDelete(aId) { // 选择公告 并显示操作弹窗
uni.showModal({ actions(id) {
title: '删除公告', if (this.isAdmin) {
success: (res) => { this.groupAnnouncementId = id
if (res.confirm) { this.actionShow = true
deleteGroupAnnouncement(this.targetId, aId).then(res => { }
uni.showToast({ },
icon: 'none', // 选择了操作出发事件
title: '删除成功' handleAction(e) {
}) console.log(e.key)
this.initData() switch (e.key) {
}) case 2:
} this.onDelete(this.groupAnnouncementId)
} break;
case 3:
this.onTop(this.groupAnnouncementId)
break;
}
},
tabA(id) {
uni.navigateTo({
url: '/pages/im/group/announceCreate?type=cheack&targetId=' + this.targetId + '&aId=' + id
}) })
},
onTop(aId) {
topGroupAnnouncement(this.targetId, aId).then(res => {
uni.showToast({
icon: 'none',
title: ' 置顶成功',
mask: true
})
uni.$emit('updateAnnouncement')
this.initData()
})
// uni.showModal({
// title: ' 置顶该公告',
// success: (res) => {
// if (res.confirm) {
// }
// }
// })
},
// 删除公告
onDelete(aId) {
deleteGroupAnnouncement(this.targetId, aId).then(res => {
uni.showToast({
icon: 'none',
title: '删除成功',
mask: true
})
uni.$emit('updateAnnouncement')
this.initData()
})
// uni.showModal({
// title: '删除该公告',
// success: (res) => {
// if (res.confirm) {
// }
// }
// })
} }
} }
} }
@@ -88,7 +163,8 @@
<style lang="scss" scoped> <style lang="scss" scoped>
.announce { .announce {
padding: 0 $padding $padding $padding; min-height: 99vh;
.no-lists { .no-lists {
padding-top: $padding * 5; padding-top: $padding * 5;
display: flex; display: flex;
@@ -98,46 +174,61 @@
box-sizing: border-box; box-sizing: border-box;
font-size: $title-size-m; font-size: $title-size-m;
color: $text-gray-m; color: $text-gray-m;
span { span {
padding-top: $padding; padding-top: $padding;
} }
} }
.item {
border-bottom: solid 1rpx #f9f9f9 !important;
padding-top: $padding;
.header { .item {
background-color: #fff;
padding: $padding $padding + 10 10rpx $padding + 10;
border-bottom: $padding solid #f9f9f9;
.user {
display: flex; display: flex;
flex-direction: row; flex-direction: row;
justify-content: flex-start;
align-items: center; align-items: center;
box-sizing: border-box;
font-size: $title-size-m;
color: $text-gray-m;
padding: 10rpx;
.user { .name {
margin-left: $padding; padding-left: 10rpx;
flex: 1;
display: flex;
flex-direction: column;
justify-content: space-between;
.name {}
.time {
font-size: 24rpx;
color: $text-gray-m;
}
} }
.delete { .time {
color: $text-price; margin-left: 20rpx;
font-size: 28rpx;
} }
} }
.content { .content-a {
padding: 20rpx $padding;
font-size: $title-size; font-size: $title-size;
color: $text-gray; color: $text-color;
max-width: 100%; max-width: 100%;
margin-bottom: 10rpx;
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 3;
overflow: hidden;
line-height: 1.5;
border-bottom: solid 1rpx #F9F9F9;
padding-bottom: 20rpx;
span {
color: #fff;
display: inline-block;
border-radius: 10rpx;
background-color: $main-color;
font-size: $title-size-m - 4;
padding: 4rpx 10rpx;
margin-right: 10rpx;
line-height: 1.4;
margin-bottom: 10rpx;
}
} }
} }
} }

View File

@@ -4,20 +4,8 @@
<view class="body"> <view class="body">
<view class="scroll"> <view class="scroll">
<view class="cell" v-for="(item, index) in messages" :key="index"> <view class="cell" v-for="(message, index) in messages" :key="index">
<view class="time" v-if="item.senderUserId === '__system__'">{{ item.content.message }}</view> <show-message-cell :message="message" isGroup />
<view v-else :class="['cell-item', item.messageDirection == 1 ? 'right' : 'left']">
<u-avatar class="avatar" @click="toUser(item)" size="36" shape="square"
:src="contact(item.senderUserId).portraitUrl" />
<view class="msg">
<show-voice v-if="item.objectName === 'RC:HQVCMsg'" :guest="item.messageDirection == 1"
:msg="item.content" :name="contact(item.senderUserId).name" />
<show-image v-if="item.objectName === 'RC:ImgMsg'" :guest="item.messageDirection == 1"
:msg="item.content" :name="contact(item.senderUserId).name" />
<show-text v-if="item.objectName === 'RC:TxtMsg'" :guest="item.messageDirection == 1"
:msg="item.content" :name="contact(item.senderUserId).name" />
</view>
</view>
</view> </view>
</view> </view>
</view> </view>
@@ -25,28 +13,23 @@
</template> </template>
<script> <script>
import {
timeCustomCN
} from '@/utils/filters.js'
import { import {
getGroupBase getGroupBase
} from '@/apis/interfaces/im.js' } from '@/apis/interfaces/im.js'
import * as RongIMLib from '@/uni_modules/RongCloud-IMWrapper/js_sdk/index' import * as RongIMLib from '@/uni_modules/RongCloud-IMWrapper/js_sdk/index'
import im from '@/utils/im/index.js' import im from '@/utils/im/index.js'
import showVoice from '../components/showVoice'
import showImage from '../components/showImage'
import showText from '../components/showText'
import sentMessageBar from '../components/sentMessageBar' import sentMessageBar from '../components/sentMessageBar'
import showMessageCell from '../components/showMessageCell'
import utils from '@/utils/index.js'
export default { export default {
components: { components: {
showVoice, sentMessageBar,
showImage, showMessageCell
showText,
sentMessageBar
}, },
data() { data() {
return { return {
avatarRpx: 84,
targetId: '', targetId: '',
conversationType: RongIMLib.ConversationType.GROUP, conversationType: RongIMLib.ConversationType.GROUP,
messages: [], messages: [],
@@ -64,11 +47,6 @@
sentTime: 0 sentTime: 0
} }
} }
},
contact() {
return function(targetId) {
return this.$store.getters.contactInfo(targetId)
}
} }
}, },
onLoad(e) { onLoad(e) {
@@ -76,7 +54,7 @@
// 获取群成员数量 // 获取群成员数量
getGroupBase(this.targetId).then(res => { getGroupBase(this.targetId).then(res => {
uni.setNavigationBarTitle({ uni.setNavigationBarTitle({
title: this.groupInfo.name + `(${res.members})` title: res.name + `(${res.members})`
}) })
}) })
// 获取历史消息列表 // 获取历史消息列表
@@ -87,8 +65,45 @@
this.getNewMessage() this.getNewMessage()
} }
}) })
uni.$on('onReceiptRequest', (msg) => {
if (msg.targetId == this.targetId) {
RongIMLib.getMessageByUId(msg.messageUId, (result) => {
RongIMLib.sendReadReceiptResponse(3, this.targetId, [result.message], (res) => {
console.error('发送群聊已读回执成功', res);
})
})
}
})
// 群已读回执
uni.$on('onReceiptResponse', (msg) => {
if (msg.targetId == this.targetId) {
this.messages = this.messages.map(item => {
if (msg.messageId == item.messageId) {
return msg
} else {
return item
}
})
}
})
// 清理聊天记录 // 清理聊天记录
uni.$once('cleanGroupMessage', this.getMessageList) uni.$once('cleanGroupMessage', this.getMessageList)
uni.$on('onRecallMessage', (res) => {
if (res.targetId == this.targetId) {
this.messages = this.messages.map(item => {
if (res.messageId == item.messageId) {
return res
} else {
return item
}
})
}
})
},
onUnload() {
uni.$off('onRecallMessage')
uni.$off('onReceiptRequest')
uni.$off('onReceiptResponse')
}, },
onNavigationBarButtonTap() { onNavigationBarButtonTap() {
uni.navigateTo({ uni.navigateTo({
@@ -99,20 +114,6 @@
onScroll(e) { onScroll(e) {
this.$refs.messageBar.onHidePopus() this.$refs.messageBar.onHidePopus()
}, },
toUser(item) {
if (item.senderUserId == '__system__') {
return
}
if (item.messageDirection == 1) {
uni.navigateTo({
url: '/pages/im/friends/mine?targetId=' + item.senderUserId
})
} else {
uni.navigateTo({
url: '/pages/im/friends/info?targetId=' + item.senderUserId
})
}
},
getNewMessage() { getNewMessage() {
im.getMessageList( im.getMessageList(
this.conversationType, this.conversationType,
@@ -134,6 +135,18 @@
20, 20,
true, true,
(messages) => { (messages) => {
console.log('获取消息列表', messages);
const msgs = messages.filter(item => item.receivedStatus == 0)
console.log('未读消息', msgs);
if (msgs.length) {
RongIMLib.sendReadReceiptResponse(3, this.targetId, msgs, (res) => {
console.error('发送群聊已读回执成功', res);
msgs.map(item => {
RongIMLib.setMessageReceivedStatus(item.messageId, 1)
})
})
}
this.messages = messages this.messages = messages
this.scrollBottom() this.scrollBottom()
}) })
@@ -144,12 +157,14 @@
// 清理当前会话,未读消息数量 // 清理当前会话,未读消息数量
RongIMLib.clearMessagesUnreadStatus(this.conversationType, this.targetId, this.latestMessage RongIMLib.clearMessagesUnreadStatus(this.conversationType, this.targetId, this.latestMessage
.sentTime) .sentTime)
// // 发送消息已读状态给对方
// RongIMLib.sendReadReceiptMessage(this.conversationType, this.targetId, this.latestMessage.sentTime)
// 更新badge提醒数量 // 更新badge提醒数量
im.setNotifyBadge() im.setNotifyBadge()
} }
} }
},
onHide() {
// console.log(JSON.stringify(this.$refs))
this.$refs.voice.stopPlay()
} }
} }
</script> </script>
@@ -175,53 +190,9 @@
justify-content: flex-end; justify-content: flex-end;
.cell { .cell {
padding: 10rpx 30rpx; padding: 10rpx 20rpx;
.time {
text-align: center;
font-size: 24rpx;
color: #666;
}
.cell-item {
display: flex;
width: 690rpx;
justify-content: flex-start;
&.left {
flex-direction: row;
}
&.right {
flex-direction: row-reverse;
.state {
flex-direction: row;
justify-content: flex-end;
}
}
.msg {
margin: 0 20rpx;
.state {
padding-top: 10rpx;
.state-text {
font-size: $title-size-m - 2;
color: rgba($color: $main-color, $alpha: 0.3)
}
.state-text-active {
font-size: $title-size-m - 2;
color: #cecece;
}
}
}
}
.cell-footer {
height: 20rpx;
}
} }
} }
} }

View File

@@ -1,13 +1,20 @@
<template> <template>
<view class="group"> <view class="group" :style="`background-color:${bg};`">
<view class="title"> 群聊 </view> <block v-if="groups.length > 0">
<view v-for="(item, index) in groups" :key="index" class="friend-flex" @click="toGroup(item.targetId)"> <view class="title"> 群聊 </view>
<u-avatar size="38" shape="square" :src="contact(item.targetId).portraitUrl" /> <view v-for="(item, index) in groups" :key="index" class="friend-flex" @click="toGroup(item.targetId)">
<view class="info"> <u-avatar size="38" shape="square" :src="contact(item.targetId).portraitUrl" />
<view class="name">{{ item.name }}</view> <view class="info">
<view class="name">{{ item.name }}</view>
</view>
</view> </view>
<view class="group-count"> {{groups.length}}个群聊 </view>
</block>
<view class="no-lists" v-else>
<u-image class="cover" radius="4" width="400rpx" height="400rpx"
:src="require('@/static/imgs/no-friend.png')" :lazy-load="true" />
<span>空空如也~</span>
</view> </view>
<view class="group-count"> {{groups.length}}个群聊 </view>
<u-modal negativeTop="300" :show="createModal" title="创建群聊" showCancelButton @cancel="onHideModal" <u-modal negativeTop="300" :show="createModal" title="创建群聊" showCancelButton @cancel="onHideModal"
@confirm="onCreateGroup"> @confirm="onCreateGroup">
<view class="slot-content"> <view class="slot-content">
@@ -28,7 +35,8 @@
return { return {
groups: [], groups: [],
createModal: false, createModal: false,
groupName: '' groupName: '',
bg: '#fff'
} }
}, },
computed: { computed: {
@@ -48,6 +56,11 @@
methods: { methods: {
initData() { initData() {
getMyGroups().then((res) => { getMyGroups().then((res) => {
if (res.length > 0) {
this.bg = '#f9f9f9'
} else {
this.bg = '#fff'
}
this.groups = res this.groups = res
res.map(item => { res.map(item => {
this.$store.dispatch('updateContact', item) this.$store.dispatch('updateContact', item)
@@ -88,17 +101,19 @@
.group { .group {
min-height: 100vh; min-height: 100vh;
background-color: $window-color; background-color: $window-color;
.title{
.title {
font-size: $title-size-m; font-size: $title-size-m;
color: $text-gray-m; color: $text-gray-m;
padding: 10rpx $padding; padding: 10rpx $padding;
} }
.group-count{
.group-count {
text-align: center; text-align: center;
font-size: $title-size; font-size: $title-size;
color: $text-gray; color: $text-gray;
background-color: #fff; background-color: #fff;
padding: 10rpx $padding $padding $padding; padding: 10rpx $padding 20rpx $padding;
font-weight: normal; font-weight: normal;
} }
} }
@@ -130,4 +145,19 @@
} }
} }
} }
.no-lists {
padding-top: $padding * 5;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
box-sizing: border-box;
font-size: $title-size-m;
color: $text-gray-m;
span {
padding-top: $padding;
}
}
</style> </style>

View File

@@ -4,10 +4,13 @@
<group-user-list ref="userList" :targetId="targetId" :count="14" /> <group-user-list ref="userList" :targetId="targetId" :count="14" />
</view> </view>
<u-cell-group class="cells" :border="false" > <u-cell-group class="cells" :border="false">
<u-cell :border="false" class="u-border-bottom" isLink title="群公告" :label="announcement" @click="toAnnouncement" /> <u-cell :border="false" class="u-border-bottom" isLink title="群公告" @click="toAnnouncement">
<view slot="label" class="announcement-label "> {{announcement}} </view>
</u-cell>
<u-cell :border="false" class="u-border-bottom" isLink title="二维码" @click="showGroupQrCode" /> <u-cell :border="false" class="u-border-bottom" isLink title="二维码" @click="showGroupQrCode" />
<u-cell :border="false" class="u-border-bottom" v-if="group.can_makesure" isLink title="群聊邀请确认" @click="showGroupsSure" /> <u-cell :border="false" class="u-border-bottom" v-if="group.can_makesure" isLink title="群聊邀请确认"
@click="showGroupsSure" />
<u-cell :border="false" class="u-border-bottom" title="聊天置顶"> <u-cell :border="false" class="u-border-bottom" title="聊天置顶">
<u-switch slot="value" size="20" v-model="isTop" activeColor="#34CE98" @change="setTop" /> <u-switch slot="value" size="20" v-model="isTop" activeColor="#34CE98" @change="setTop" />
</u-cell> </u-cell>
@@ -17,11 +20,13 @@
</u-cell-group> </u-cell-group>
<u-cell-group class="cells" v-if="group.is_admin" :border="false"> <u-cell-group class="cells" v-if="group.is_admin" :border="false">
<u-cell :border="false" class="u-border-bottom" isLink title="修改群聊名称" :value="groupName" @click="onGroupName" /> <u-cell :border="false" class="u-border-bottom" isLink title="修改群聊名称" :value="groupName"
@click="onGroupName" />
<u-cell :border="false" class="u-border-bottom" isLink title="修改群头像" @click="onGroupAvatar"> <u-cell :border="false" class="u-border-bottom" isLink title="修改群头像" @click="onGroupAvatar">
<u-avatar slot="value" size="25" shape="square" :src="group.cover" /> <u-avatar slot="value" size="25" shape="square" :src="group.cover" />
</u-cell> </u-cell>
<u-cell :border="false" class="u-border-bottom" isLink v-if="group.is_owner" title="准入方式" :value="joinType" @click="onChangeJoinType" /> <u-cell :border="false" class="u-border-bottom" isLink v-if="group.is_owner" title="准入方式" :value="joinType"
@click="onChangeJoinType" />
</u-cell-group> </u-cell-group>
<view class="cells actions" v-if="loaded"> <view class="cells actions" v-if="loaded">
@@ -30,7 +35,8 @@
<view class="action u-border-bottom" v-else @click="onQuite">删除并退出</view> <view class="action u-border-bottom" v-else @click="onQuite">删除并退出</view>
</view> </view>
<u-modal negativeTop="300" :show="modalShow" title="修改群名称" showCancelButton @cancel="onHideModal" @confirm="onChangeGroupName"> <u-modal negativeTop="300" :show="modalShow" title="修改群名称" showCancelButton @cancel="onHideModal"
@confirm="onChangeGroupName">
<view class="slot-content"> <view class="slot-content">
<u--input placeholder="群名称" border="surround" focus v-model="groupName" /> <u--input placeholder="群名称" border="surround" focus v-model="groupName" />
</view> </view>
@@ -42,7 +48,8 @@
</view> </view>
</u-modal> </u-modal>
<u-action-sheet @select="doAction" :actions="joinTypeMap" cancelText="取消" :show="showActions" @close="showActions=false" /> <u-action-sheet @select="doAction" :actions="joinTypeMap" cancelText="取消" :show="showActions"
@close="showActions=false" />
</view> </view>
</template> </template>
@@ -84,10 +91,15 @@
onLoad(e) { onLoad(e) {
this.targetId = e.targetId this.targetId = e.targetId
this.qrContent += e.targetId this.qrContent += e.targetId
RongIMLib.getConversationNotificationStatus(this.conversationType, this.targetId, ({status}) => { RongIMLib.getConversationNotificationStatus(this.conversationType, this.targetId, ({
status
}) => {
this.status = !Boolean(status) this.status = !Boolean(status)
}) })
RongIMLib.getConversation(this.conversationType, this.targetId, ({code,conversation}) => { RongIMLib.getConversation(this.conversationType, this.targetId, ({
code,
conversation
}) => {
if (code == 0) { if (code == 0) {
this.isTop = conversation.isTop this.isTop = conversation.isTop
} }
@@ -95,9 +107,12 @@
this.initData() this.initData()
uni.$on('groupAnnouncementCreated', this.initData) uni.$on('groupAnnouncementCreated', this.initData)
uni.$on('groupInvitedUser', this.updateUserList) uni.$on('groupInvitedUser', this.updateUserList)
uni.$on('updateAnnouncement', this.initData)
}, },
onUnload() { onUnload() {
uni.$off('groupAnnouncementCreated') uni.$off('groupAnnouncementCreated')
uni.$off('groupInvitedUser')
uni.$off('updateAnnouncement')
}, },
methods: { methods: {
updateUserList() { updateUserList() {
@@ -105,7 +120,6 @@
}, },
initData() { initData() {
getGroupInfo(this.targetId).then(res => { getGroupInfo(this.targetId).then(res => {
console.log(res,'群信息。。。。。')
this.group = res.group this.group = res.group
this.groupName = res.group.name this.groupName = res.group.name
this.announcement = res.announcement this.announcement = res.announcement
@@ -152,9 +166,9 @@
this.qrCodeShow = true this.qrCodeShow = true
}, },
// 群聊邀请待确认 // 群聊邀请待确认
showGroupsSure(){ showGroupsSure() {
uni.navigateTo({ uni.navigateTo({
url:"/pages/im/group/reviewed?id="+this.targetId url: "/pages/im/group/reviewed?targetId=" + this.targetId
}) })
}, },
onGroupName() { onGroupName() {
@@ -243,8 +257,11 @@
} }
return item return item
}) })
this.initData()
this.joinType = e.name this.joinType = e.name
this.$nextTick(() => {
this.$refs.userList.initGroupInfo()
this.initData()
})
this.showActions = false this.showActions = false
}).catch(err => { }).catch(err => {
console.log(err); console.log(err);
@@ -326,6 +343,20 @@
.cells { .cells {
margin-top: $padding; margin-top: $padding;
background-color: white; background-color: white;
.announcement-label {
font-size: $title-size-m + 2;
padding-top: 10rpx;
color: $text-gray-m;
overflow: hidden;
width: 620rpx;
display: inline-block;
overflow: hidden;
text-overflow: ellipsis;
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 3;
}
} }
.members { .members {
@@ -347,5 +378,4 @@
.u-border-bottom { .u-border-bottom {
border-bottom: solid 1rpx #f9f9f9 !important; border-bottom: solid 1rpx #f9f9f9 !important;
} }
</style> </style>

View File

@@ -1,15 +1,15 @@
<template> <template>
<view class="invite"> <view class="invite">
<view class="search"> <view class="search u-border-bottom">
<u--input class="search-input" placeholder="搜索" border="none" prefixIcon="search" v-model="searchTxt" <u--input class="search-input" placeholder="搜索好友" border="none" prefixIcon="search" v-model="searchTxt"
disabledColor="#Fff" prefixIconStyle="font-size: 22px;color: #909399" @change="onSearch" /> disabledColor="#Fff" prefixIconStyle="font-size: 22px;color: #909399" @change="onSearch" />
</view> </view>
<block v-if="friends.length > 0"> <block v-if="friends.length > 0">
<u-index-list :index-list="indexs" inactiveColor="#666" activeColor="#34CE98"> <u-index-list :index-list="indexs" inactiveColor="#666" activeColor="#34CE98">
<u-checkbox-group v-if="friends.length > 0" v-model="checkboxValue" placement="column"> <u-checkbox-group v-if="friends.length > 0" v-model="checkboxValue" placement="column">
<u-index-item v-for="(item, fkey) in friends" :key="fkey"> <u-index-item v-for="(item, fkey) in friends" :key="fkey">
<u-index-anchor :text="indexs[fkey]" v-if="indexs[fkey]" bgColor="#ededed" height="20" size="12" <u-index-anchor :text="indexs[fkey]" v-if="indexs[fkey]" bgColor="#f9f9f9f" height="20" size="12"
color="#666" style="padding:10rpx 30rpx" /> color="#666" style="border:none !important;padding: 10rpx 30rpx;background-color: #f9f9f9 !important;" />
<view v-for="(friendItem, index) in item" :key="index" class="friend-flex" <view v-for="(friendItem, index) in item" :key="index" class="friend-flex"
@click="addContact(friendItem.targetId)"> @click="addContact(friendItem.targetId)">
<u-checkbox :name="friendItem.targetId" shape="circle" activeColor="#34ce98" <u-checkbox :name="friendItem.targetId" shape="circle" activeColor="#34ce98"
@@ -72,20 +72,19 @@
this.getFriendList() this.getFriendList()
}, },
methods: { methods: {
onSearch(val) { onSearch() {
if (val) { if (this.searchTxt) {
var ix = []
this.friends = this.orignalFriends.map((list, index) => { this.friends = this.orignalFriends.map((list, index) => {
const resList = list.filter(item => item.name.indexOf(val) > 0) const resList = list.filter(item => {
if (resList.length > 0) { return item.name.indexOf(this.searchTxt) >= 0
this.indexs = this.orignalIndexs.map((t, i) => {}) })
} else {
return;
}
return resList return resList
}) })
this.friends = this.friends.filter(n => n) this.indexs = this.orignalIndexs.map((t, i) => {
if (this.friends[i].length > 0) {
return t
}
})
} else { } else {
this.friends = this.orignalFriends this.friends = this.orignalFriends
this.indexs = this.orignalIndexs this.indexs = this.orignalIndexs
@@ -102,7 +101,8 @@
this.orignalIndexs = res.indexList this.orignalIndexs = res.indexList
}) })
getGroupUsers(this.targetId).then(res => { getGroupUsers(this.targetId).then(res => {
res.map(res => { res.map(res => {
console.log(res)
this.checkboxValue.push(String(res.targetId)) this.checkboxValue.push(String(res.targetId))
this.selectValue.push(String(res.targetId)) this.selectValue.push(String(res.targetId))
}) })
@@ -122,9 +122,17 @@
} }
}, },
onInvite() { onInvite() {
inviteGroupUser(this.targetId, this.checkboxValue).then(res => { console.log(this.checkboxValue,'userIds.....')
console.log(res, 'res') console.log(this.selectValue,'userIds.....')
let userIds = []
this.checkboxValue.filter(item=>{
if(!utils.inArray(item, this.selectValue)){
userIds.push(item)
}
})
// console.log(userIds)
inviteGroupUser(this.targetId, this.checkboxValue,userIds).then(res => {
uni.navigateBack({ uni.navigateBack({
delta: 1, delta: 1,
animationType: 'pop-out', animationType: 'pop-out',

View File

@@ -1,79 +1,170 @@
<!-- 群聊邀请确认列表页面 --> <!-- 群聊邀请确认列表页面 -->
<template> <template>
<view class="reviewed"> <view class="reviewed">
<view class="reviewed-item"> <block v-if="pendings.length > 0">
<u-avatar class="avatar" src="require('@/static/user/cover.png')" shape="square" size="36" /> <view class="reviewed-item" v-for="(item, index) in pendings" :key="index">
<view style="flex:1;"> <u-avatar class="avatar"
<view class="nickname"><span>{{`艾米的猫儿 `}}</span>想邀请<span>{{` 用户8066`}}</span>加入群聊</view> :src="JSON.parse(item.content.extra).portraitUrl || require('@/static/user/cover.png')"
<view> 申请原因{{`呵呵哒。。`}}</view> shape="square" size="46" />
</view> <view style="flex:1;" v-if="item.content.operation == 'GroupPending'">
<view class="sure" @click="sure(2)"> 通过 </view> <view class="nickname">{{ JSON.parse(item.content.extra).name }} 申请加入群聊</view>
</view> <view> 申请原因{{ item.content.message }}</view>
</view> </view>
</template> <view style="flex:1;" v-if="item.content.operation == 'GroupInvite'">
<view class="nickname">
<script> <text>{{ contact(item.content.sourceUserId).name }}</text>想邀请<span>{{ JSON.parse(item.content.extra).name }}</span>加入群聊
import { </view>
getGroupMakeSure, </view>
getGroupMakeSureAllow <view class="sure" @click="sure(item.content.targetUserId,item.messageId)"> 通过 </view>
} from "@/apis/interfaces/im.js" </view>
export default { </block>
data() {
return { <view class="no-lists" v-else>
lists: [], <u-image class="cover" radius="4" width="400rpx" height="400rpx"
}; :src="require('@/static/imgs/no-friend.png')" :lazy-load="true" />
}, <span> 暂无群聊申请数据~</span>
methods: { </view>
</view>
sure(id) { </template>
console.log(id, '....') <script>
uni.navigateTo({ import {
url: "/pages/im/group/reviewedInfo?id=" + id getGroupMakeSure,
}) getGroupMakeSureAllow,
} groupMakeSure
} } from "@/apis/interfaces/im.js"
}; import im from '@/utils/im/message.js'
</script> import * as RongIMLib from '@/uni_modules/RongCloud-IMWrapper/js_sdk/index'
<style lang="scss" scoped>
.reviewed { export default {
.reviewed-item { data() {
margin: $padding - 10; return {
display: flex; targetId: '',
flex-direction: row; pendings: [],
align-items: flex-start; };
justify-content: flex-start; },
box-sizing: border-box; computed: {
border-bottom: solid 1rpx #f9f9f9; contact() {
font-size: $title-size-m - 2; return function(targetId) {
padding-bottom: 20rpx; return this.$store.getters.contactInfo(targetId)
color: $text-gray-m; }
}
.avatar { },
background-color: $main-color; onLoad(e) {
border-radius: 6rpx; this.targetId = e.targetId
margin-right: 20rpx; this.getList()
} },
methods: {
.nickname { getList() {
font-size: $title-size-m; im.getGroupPendinglist(this.targetId, (result) => {
console.log(result)
span { this.pendings = result
color: $text-color; })
font-size: $title-size-m +1; },
} sure(userId, latestMessageId) {
} groupMakeSure(this.targetId, userId).then(res => {
// 清除聊天列表
.sure { RongIMLib.deleteMessagesByIds([latestMessageId], ({
background-color: $main-color; code
color: #Fff; }) => {
text-align: center; console.log('code', code)
font-size: $title-size-m; if (code == 0) {
padding: 6rpx 20rpx; uni.showToast({
border-radius: 10rpx; title: ` 通过 `,
margin-left: 10rpx; icon: 'none',
} mask: true,
} duration: 2000
})
} this.getList()
uni.$emit('groupInvitedUser')
}
})
}).catch(err => {
// uni.showToast({
// title: err.message,
// icon: 'none',
// mask: true,
// duration: 2000
// })
RongIMLib.deleteMessagesByIds([latestMessageId], ({
code
}) => {
console.log('code', code)
if (code == 0) {
uni.showToast({
title:err.message,
icon: 'none',
mask: true,
duration: 2000
})
this.getList()
uni.$emit('groupInvitedUser')
}
})
})
// 直接调用通过或拒绝的接口
}
}
};
</script>
<style lang="scss" scoped>
.reviewed {
.reviewed-item {
margin: $padding - 10;
display: flex;
flex-direction: row;
align-items: flex-start;
justify-content: flex-start;
box-sizing: border-box;
border-bottom: solid 1rpx #f9f9f9;
font-size: $title-size-m;
padding-bottom: 20rpx;
color: $text-gray-m;
.avatar {
background-color: $main-color;
border-radius: 6rpx;
margin-right: 20rpx;
}
.nickname {
font-size: $title-size;
color: $text-color;
padding-bottom: 6rpx;
span {
color: $text-color;
font-size: $title-size-m +1;
padding-top: 20rpx;
}
}
.sure {
background-color: $main-color;
color: #Fff;
text-align: center;
font-size: $title-size-m;
padding: 6rpx 20rpx;
border-radius: 10rpx;
margin-left: 10rpx;
}
}
}
.no-lists {
padding-top: $padding * 5;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
box-sizing: border-box;
font-size: $title-size-m;
color: $text-gray-m;
span {
padding-top: $padding;
}
}
</style> </style>

View File

@@ -1,62 +0,0 @@
<!-- 群聊邀请确认列表页面 -->
<template>
<view class="reviewed">
确认信息页面
</view>
</template>
<script>
export default {
data() {
return {
lists: [],
};
},
onLoad() {
},
methods: {
sure(id) {
uni.navigateTo({
url:"/pages/im/group/reviewedInfo?id="+id
})
}
}
};
</script>
<style lang="scss" scoped>
.reviewed {
.reviewed-item {
margin: $padding;
display: flex;
flex-direction: row;
align-items: center;
justify-content: flex-start;
box-sizing: border-box;
border-bottom: solid 1rpx #f9f9f9;
font-size: $title-size-m;
padding-bottom: 20rpx;
color: $text-gray;
.add-icon {
background-color: $main-color;
padding: 10rpx;
border-radius: 6rpx;
margin-right: 20rpx;
}
.sure {
// width: 140rpx;
// background-color: $main-color;
color: $main-color;
text-align: center;
font-size: $title-size-m;
padding: 6rpx 20rpx;
border-radius: 10rpx;
}
}
}
</style>

View File

@@ -19,7 +19,7 @@
</view> </view>
</view> </view>
<!-- content --> <!-- content -->
<view v-if="$store.state.token !== ''"> <view v-if="$store.state.token !== ''">
<connection-status :connection="connection" /> <connection-status :connection="connection" />
<conversation-list @refresh="getConversationList()" :conversations="conversations" /> <conversation-list @refresh="getConversationList()" :conversations="conversations" />
</view> </view>
@@ -76,13 +76,7 @@
onHide() { onHide() {
uni.$off('onReceiveMessage') uni.$off('onReceiveMessage')
}, },
methods: { methods: {
onDemo(){
console.log('1111')
uni.navigateTo({
url: '/pages/im/chatDemo'
})
},
checkNewFriendPending() { checkNewFriendPending() {
im.getPendingList((pendings) => { im.getPendingList((pendings) => {
this.hasNewFriends = pendings.length this.hasNewFriends = pendings.length

View File

@@ -1,27 +1,30 @@
<template> <template>
<view class="call"> <view class="call">
<view class="video"> <view class="video">
<RongCloud-Call-RCUniCallView ref="bigVideoView" :style="{width:windowWidth+'px',height:windowHeight+'px'}" <RongCloud-Call-RCUniCallView ref="bigVideoView" :style="bigVideoStyle" class="bigVideoView">
class="bigVideoView">
</RongCloud-Call-RCUniCallView>
<RongCloud-Call-RCUniCallView ref="smallVideoView" class="smallVideoView">
</RongCloud-Call-RCUniCallView> </RongCloud-Call-RCUniCallView>
<movable-area class="movableArea" :style="movableAreaStyle">
<movable-view class="movableView" direction="all" :x="50" :y="50" v-if="mediaType == 1 && connected">
<RongCloud-Call-RCUniCallView ref="smallVideoView" class="smallVideoView" @click="changeMine">
</RongCloud-Call-RCUniCallView>
</movable-view>
</movable-area>
</view> </view>
<view class="status" v-if="!connected || mediaType == 0"> <view class="status" v-if="!connected">
<view class="remote"> <view class="remote">
<u-avatar :src="contact(targetId).portraitUrl" shape="square" size="96" bgColor="#fff" /> <u-avatar :src="contact(targetId).portraitUrl" shape="square" :size="avatarSize" bgColor="#fff" />
<view><text class="nickname">{{ contact(targetId).name }}</text></view> <view><text class="nickname">{{ contact(targetId).name }}</text></view>
<view v-if="remoteRinging"><text class="mediaType">等待对方接听</text></view> <view v-if="remoteRinging"><text class="mediaType">等待对方接听</text></view>
<view v-if="connected"><text class="mediaType">已接通</text></view> <view v-if="connected"><text class="mediaType">已接通</text></view>
<view v-else><text class="mediaType">{{ mediaType == 0 ? '邀请您语音通话' : '邀请您视频通话' }}</text></view>
</view> </view>
</view> </view>
<view class="buttons"> <view class="buttons">
<view class="btn" v-if="connected" @click="changeMicrophone"> <view class="btn" v-if="connected" @click="changeMicrophone">
<view class="icon"> <view class="icon">
<u-icon name="mic" color="#ffffff" size="30" /> <u-icon name="mic-off" color="#ffffff" size="30" v-if="micOff" />
<u-icon name="mic-off" color="#ffffff" size="30" /> <u-icon name="mic" color="#ffffff" size="30" v-else />
</view> </view>
<text class="text">麦克风</text> <text class="text">麦克风</text>
</view> </view>
@@ -31,7 +34,7 @@
</view> </view>
<text class="text">挂断</text> <text class="text">挂断</text>
</view> </view>
<view class="btn" v-if="!connected" @click="accept"> <view class="btn" v-if="!connected && this.isCall == false" @click="accept">
<view class="icon"> <view class="icon">
<u-icon name="checkmark" color="#ffffff" size="30" /> <u-icon name="checkmark" color="#ffffff" size="30" />
</view> </view>
@@ -39,8 +42,8 @@
</view> </view>
<view class="btn" v-if="connected" @click="changeSpeaker"> <view class="btn" v-if="connected" @click="changeSpeaker">
<view class="icon"> <view class="icon">
<u-icon name="volume-fill" color="#ffffff" size="27" /> <u-icon name="volume-off-fill" color="#ffffff" size="27" v-if="volumeOff" />
<u-icon name="volume-off-fill" color="#ffffff" size="27" /> <u-icon name="volume-fill" color="#ffffff" size="27" v-else />
</view> </view>
<text class="text">扬声器</text> <text class="text">扬声器</text>
</view> </view>
@@ -51,25 +54,46 @@
<script> <script>
import * as CallLib from '@/uni_modules/RongCloud-CallWrapper/lib/index' import * as CallLib from '@/uni_modules/RongCloud-CallWrapper/lib/index'
import * as IMLib from '@/uni_modules/RongCloud-IMWrapper/js_sdk/index' import * as IMLib from '@/uni_modules/RongCloud-IMWrapper/js_sdk/index'
import utils from '@/utils/index.js'
export default { export default {
data() { data() {
return { return {
targetId: '', targetId: '',
mediaType: 0, // 0 语音 1 视频 mediaType: 0, // 0 语音 1 视频
isOut: false,
connected: false, connected: false,
micStatus: false, micStatus: false,
speStatus: false, speStatus: false,
remoteRinging: false, remoteRinging: false,
ring: null ring: null,
isCall: false,
avatarSize: 96,
bigVideoStyle: {},
movableAreaStyle: {},
// 关闭麦克风
micOff: false,
// 关闭扬声器
volumeOff: false,
// 通话时长
duration: 0,
interval: null
} }
}, },
onLoad(e) { onLoad(e) {
this.avatarSize = utils.rpx2px(200)
this.targetId = e.targetId this.targetId = e.targetId
this.mediaType = e.mediaType this.mediaType = e.mediaType
this.isCall = Boolean(e.isCall)
// 进入页面开启外呼 // 进入页面开启外呼
CallLib.startSingleCall(this.targetId, this.mediaType, ''); if (this.isCall) {
CallLib.startSingleCall(this.targetId, this.mediaType, '');
if (this.mediaType == 1) {
const session = CallLib.getCurrentCallSession()
setTimeout(() => {
CallLib.setVideoView(session.mine.userId, this.$refs.bigVideoView.ref, 0, false)
}, 200)
}
}
// 响铃 // 响铃
this.startRing() this.startRing()
// 监听通话链接状态 // 监听通话链接状态
@@ -81,6 +105,14 @@
uni.$once('onRemoteUserJoined', () => { uni.$once('onRemoteUserJoined', () => {
this.remoteRinging = false this.remoteRinging = false
}) })
this.bigVideoStyle = {
width: this.windowWidth + 'px',
height: this.windowHeight + 'px',
}
this.movableAreaStyle = {
width: this.windowWidth + 'px',
height: this.windowHeight + 'px',
}
}, },
beforeDestroy() { beforeDestroy() {
@@ -99,11 +131,36 @@
} }
}, },
methods: { methods: {
afterHangup() {
clearInterval(this.interval)
const targetId = this.targetId
const sentStatus = 30
const messageContent = {
objectName: 'RC:InfoNtf',
userInfo: this.$store.getters.sender,
message: JSON.stringify({
mediaType: this.mediaType,
connected: this.connected,
duration: this.duration
})
}
const sentTime = 0
if (this.isCall) {
IMLib.insertOutgoingMessage(1, targetId, sentStatus, messageContent, sentTime)
} else {
IMLib.insertIncomingMessage(1, targetId, targetId, sentStatus, messageContent, sentTime)
}
uni.$emit('onReceiveMessage', {
targetId: this.targetId
})
},
changeMicrophone() { changeMicrophone() {
this.micOff = !this.micOff
CallLib.enableMicrophone(this.micStatus) CallLib.enableMicrophone(this.micStatus)
this.micStatus = !this.micStatus this.micStatus = !this.micStatus
}, },
changeSpeaker() { changeSpeaker() {
this.volumeOff = !this.volumeOff
CallLib.enableSpeaker(this.speStatus) CallLib.enableSpeaker(this.speStatus)
this.speStatus = !this.speStatus this.speStatus = !this.speStatus
}, },
@@ -122,10 +179,31 @@
CallLib.setVideoView(session.targetId, this.$refs.bigVideoView.ref, 0, false) CallLib.setVideoView(session.targetId, this.$refs.bigVideoView.ref, 0, false)
CallLib.setVideoView(session.mine.userId, this.$refs.smallVideoView.ref, 0, true) CallLib.setVideoView(session.mine.userId, this.$refs.smallVideoView.ref, 0, true)
}, 200) }, 200)
} }
this.interval = setInterval(() => {
this.duration++
}, 1000)
},
// 切换主屏显示人
changeMine() {
// if (this.isCall) {
// const session = CallLib.getCurrentCallSession()
// setTimeout(() => {
// CallLib.setVideoView(session.targetId, this.$refs.bigVideoView.ref, 0, false)
// CallLib.setVideoView(session.mine.userId, this.$refs.smallVideoView.ref, 0, true)
// }, 200)
// } else {
// const session = CallLib.getCurrentCallSession()
// setTimeout(() => {
// CallLib.setVideoView(session.targetId, this.$refs.smallVideoView.ref, 0, true)
// CallLib.setVideoView(session.mine.userId, this.$refs.bigVideoView.ref, 0, false)
// }, 200)
// }
// this.isCall = !this.isCall
}, },
hangup() { hangup() {
CallLib.hangup() CallLib.hangup()
this.afterHangup()
this.stopRing() this.stopRing()
setTimeout(() => { setTimeout(() => {
@@ -171,23 +249,33 @@
position: relative; position: relative;
.video { .video {
.bigVideoView { .movableArea {
background: #000; position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
.movableView {
width: 180rpx;
height: 320rpx;
position: relative;
.smallVideoView {
width: 180rpx;
height: 320rpx;
background-color: #666;
}
}
} }
.smallVideoView { .bigVideoView {
background: blue; background-color: #666;
position: absolute;
right: 100rpx;
top: 100rpx;
width: 180rpx;
height: 320rpx;
} }
} }
.status { .status {
flex: 1; flex: 1;
background: #666;
width: 750rpx; width: 750rpx;
position: fixed; position: fixed;
bottom: 0; bottom: 0;
@@ -226,10 +314,6 @@
.btn { .btn {
align-items: center; align-items: center;
&.hangup {
background: $text-price;
}
.icon { .icon {
background: $main-color; background: $main-color;
width: 132rpx; width: 132rpx;
@@ -238,6 +322,10 @@
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
&.hangup {
background-color: $text-price;
}
} }
.text { .text {

View File

@@ -4,43 +4,25 @@
<!-- chat --> <!-- chat -->
<view class="body"> <view class="body">
<view class="scroll"> <view class="scroll">
<view class="cell" v-for="(item, index) in messages" :key="index"> <view class="cell" v-for="(message, index) in messages" :key="index">
<view class="time">{{ item.sentTime|timeCustomCN }}</view> <show-message-cell :message="message" />
<view :class="['cell-item', item.messageDirection == 1 ? 'right' : 'left']">
<u-avatar class="avatar" size="40" shape="square"
@click="showUser(item.senderUserId, item.messageDirection)"
:src="contact(item.senderUserId).portraitUrl" />
<view class="msg">
<show-voice v-if="item.objectName === 'RC:HQVCMsg'" :guest="item.messageDirection == 1"
:msg="item.content" />
<show-image v-if="item.objectName === 'RC:ImgMsg'" :guest="item.messageDirection == 1"
:msg="item.content" />
<show-text v-if="item.objectName === 'RC:TxtMsg'" :guest="item.messageDirection == 1"
:msg="item.content" />
<view class="state" v-if="item.messageDirection == 1">
<text
:class="item.sentStatus === 50?'state-text':'state-text-active'">{{ item.sentStatus == 50 ? '已读': '未读'}}</text>
</view>
</view>
</view>
</view> </view>
</view> </view>
</view> </view>
</view> </view>
</template> </template>
<script> <script>
import * as RongIMLib from '@/uni_modules/RongCloud-IMWrapper/js_sdk/index' import * as RongIMLib from '@/uni_modules/RongCloud-IMWrapper/js_sdk/index'
import im from '@/utils/im/index.js' import im from '@/utils/im/index.js'
import showVoice from '../components/showVoice'
import showImage from '../components/showImage'
import showText from '../components/showText'
import sentMessageBar from '../components/sentMessageBar' import sentMessageBar from '../components/sentMessageBar'
import showMessageCell from '../components/showMessageCell'
import utils from '@/utils/index.js'
export default { export default {
components: { components: {
sentMessageBar, sentMessageBar,
showVoice, showMessageCell
showImage,
showText
}, },
data() { data() {
return { return {
@@ -95,9 +77,21 @@
if (msg.targetId == this.targetId) { if (msg.targetId == this.targetId) {
this.getNewMessage() this.getNewMessage()
} }
})
uni.$on('onRecallMessage', (res) => {
if (res.targetId == this.targetId) {
this.messages = this.messages.map(item => {
if (res.messageId == item.messageId) {
return res
} else {
return item
}
})
}
}) })
}, },
onUnload() { onUnload() {
uni.$off('onRecallMessage')
uni.$off('onReadReceiptReceived') uni.$off('onReadReceiptReceived')
}, },
methods: { methods: {
@@ -126,13 +120,6 @@
this.scrollBottom() this.scrollBottom()
}) })
}, },
// 展示好友信息, type 1 是自己, 2 是对方
showUser(targetId, type) {
uni.navigateTo({
url: type === 1 ? '/pages/im/friends/mine?targetId=' + targetId :
'/pages/im/friends/info?targetId=' + targetId
})
},
// 滚动到底部 // 滚动到底部
scrollBottom(type) { scrollBottom(type) {
if (this.latestMessage) { if (this.latestMessage) {
@@ -147,7 +134,7 @@
} }
} }
} }
</script> </script>
<style scoped lang="scss"> <style scoped lang="scss">
/* 窗口 */ /* 窗口 */
@@ -170,17 +157,18 @@
justify-content: flex-end; justify-content: flex-end;
.cell { .cell {
padding: 10rpx 30rpx; padding: 10rpx 20rpx;
.time { .time {
text-align: center; text-align: center;
font-size: 24rpx; font-size: 24rpx;
color: #666; color: #666;
margin-bottom: 10rpx;
} }
.cell-item { .cell-item {
display: flex; display: flex;
width: 690rpx; width: 710rpx;
justify-content: flex-start; justify-content: flex-start;
&.left { &.left {
@@ -189,23 +177,14 @@
&.right { &.right {
flex-direction: row-reverse; flex-direction: row-reverse;
.state { .state {
text-align: right; text-align: right;
} }
} }
.msg { .msg {
margin: 0 20rpx; margin: 0 20rpx;
.state {
padding-top: 10rpx;
.state-text {
font-size: $title-size-m - 2;
color: rgba($color: $main-color, $alpha: 0.3)
}
.state-text-active {
font-size: $title-size-m - 2;
color: #cecece;
}
}
} }
} }

View File

@@ -4,7 +4,7 @@
<view class="info-box"> <view class="info-box">
<image src="@/static/user/user_back.png" mode="aspectFill" /> <image src="@/static/user/user_back.png" mode="aspectFill" />
<view class="user-flex"> <view class="user-flex">
<image class="cover" @click="$Router.push({ name: 'Setting' })" <image class="cover" @click="goSetting"
:src="userInfo.avatar || require('@/static/user/cover.png')" mode="aspectFill" /> :src="userInfo.avatar || require('@/static/user/cover.png')" mode="aspectFill" />
<view class="user-content"> <view class="user-content">
<block v-if="$store.state.token != ''"> <block v-if="$store.state.token != ''">
@@ -233,6 +233,11 @@
params params
}); });
} }
},
goSetting(){
if (this.isLogin()) {
this.$Router.push({ name: 'Setting' })
}
}, },
// 检查登录 // 检查登录
isLogin() { isLogin() {

View File

@@ -41,7 +41,7 @@ const notifyMsgTypes = [
const imLibListeners = () => { const imLibListeners = () => {
// 添加连接状态监听函数 // 添加连接状态监听函数
IMLib.addConnectionStatusListener((res) => { IMLib.addConnectionStatusListener((res) => {
console.log('连接状态监听', res.data.status) console.error('连接状态监听', res.data.status)
uni.$emit('onConnectionStatusChange', res.data.status) uni.$emit('onConnectionStatusChange', res.data.status)
}) })
// 添加消息监听函数 // 添加消息监听函数
@@ -69,7 +69,7 @@ const imLibListeners = () => {
store.dispatch('updateContact', JSON.parse(message.content.data)) store.dispatch('updateContact', JSON.parse(message.content.data))
// 调用完更新之后,删除这条消息 // 调用完更新之后,删除这条消息
IMLib.deleteMessagesByIds([message.messageId]) IMLib.deleteMessagesByIds([message.messageId])
} else if (message.objectName === IMLib.ObjectName.ContactNotification) { } else if (message.objectName === IMLib.ObjectName.ContactNotification) {
console.error('触发一个新好友的通知事件', message); console.error('触发一个新好友的通知事件', message);
// 触发一个新好友的通知事件 // 触发一个新好友的通知事件
uni.$emit('onContactNotification', message) uni.$emit('onContactNotification', message)
@@ -85,13 +85,45 @@ const imLibListeners = () => {
uni.$emit('onReceiveMessage', message) uni.$emit('onReceiveMessage', message)
} }
}) })
// 监听私聊消息已读回执
// 监听消息回执
IMLib.addReadReceiptReceivedListener(({ IMLib.addReadReceiptReceivedListener(({
data data
}) => { }) => {
console.error("监听私聊消息已读回执: ", data);
uni.$emit('onReadReceiptReceived', data) uni.$emit('onReadReceiptReceived', data)
}) })
// 监听消息撤回操作
IMLib.addRecallMessageListener((res) => {
IMLib.getMessage(res.data.messageId, (res) => {
console.error("消息撤回: ", res.message);
uni.$emit('onRecallMessage', res.message)
})
})
// 监听需要群聊消息回执
IMLib.addReceiptRequestListener(({
data
}) => {
uni.$emit('onReceiptRequest', data)
})
// 群消息已读的回执
IMLib.addReceiptResponseListener(({
data
}) => {
// 获取本地消息
IMLib.getMessageByUId(data.messageUId, ({
message
}) => {
const readers = Object.keys(data.users).length
const extra = JSON.stringify({
readers
})
// 在消息的扩展数据中,设置已读数量
IMLib.setMessageExtra(message.messageId, extra, (result) => {
message.extra = extra
uni.$emit('onReceiptResponse', message)
})
})
})
} }
const callLibListeners = () => { const callLibListeners = () => {
@@ -100,7 +132,7 @@ const callLibListeners = () => {
CallLib.onCallReceived(({ CallLib.onCallReceived(({
data data
}) => { }) => {
console.log('onCallReceived'); console.error('onCallReceived');
uni.navigateTo({ uni.navigateTo({
url: '/pages/im/private/call?targetId=' + data.targetId + '&mediaType=' + url: '/pages/im/private/call?targetId=' + data.targetId + '&mediaType=' +
data.mediaType data.mediaType
@@ -112,27 +144,27 @@ const callLibListeners = () => {
}) })
// 外呼 // 外呼
CallLib.onCallOutgoing((res) => { CallLib.onCallOutgoing((res) => {
console.log('onCallOutgoing', res); console.error('onCallOutgoing', res);
uni.$emit('onCallOutgoing') uni.$emit('onCallOutgoing')
}) })
// 远端响铃 // 远端响铃
CallLib.onRemoteUserRinging((res) => { CallLib.onRemoteUserRinging((res) => {
console.log('onRemoteUserRinging', res); console.error('onRemoteUserRinging', res);
uni.$emit('onRemoteUserRinging') uni.$emit('onRemoteUserRinging')
}) })
// 远端加入 // 远端加入
CallLib.onRemoteUserJoined((res) => { CallLib.onRemoteUserJoined((res) => {
console.log('远端接听'); console.error('远端接听');
uni.$emit('onRemoteUserJoined') uni.$emit('onRemoteUserJoined')
}) })
// 断开链接 // 断开链接
CallLib.onCallDisconnected((res) => { CallLib.onCallDisconnected((res) => {
console.log('断开链接', res) console.error('断开链接', res)
uni.$emit('onCallDisconnected') uni.$emit('onCallDisconnected')
}) })
// 远端挂断 // 远端挂断
CallLib.onRemoteUserLeft((res) => { CallLib.onRemoteUserLeft((res) => {
console.log('远端离开', res) console.error('远端离开', res)
uni.$emit('onRemoteUserLeft') uni.$emit('onRemoteUserLeft')
}) })
} }

View File

@@ -16,7 +16,9 @@ const getMessageList = (conversationType, targetId, timeStamp, count, isForward,
'RC:SightMsg', 'RC:SightMsg',
'RC:ReferenceMsg', 'RC:ReferenceMsg',
'RC:CombineMsg', 'RC:CombineMsg',
'RC:GrpNtf' 'RC:GrpNtf',
'RC:InfoNtf',
'RC:RcNtf'
] ]
RongIMLib.getHistoryMessagesByTimestamp( RongIMLib.getHistoryMessagesByTimestamp(
@@ -59,18 +61,16 @@ const getPendingList = (callback, total) => {
// 群组申请列表,邀请列表 // 群组申请列表,邀请列表
const getGroupPendinglist = (targetId, callback) => { const getGroupPendinglist = (targetId, callback) => {
total = total || 100 const conversationType = RongIMLib.ConversationType.SYSTEM
RongIMLib.getConversationList([RongIMLib.ConversationType.SYSTEM], total, 0, (res) => { const objectNames = ['RC:ContactNtf']
if (res.code === 0) {
const pendings = res.conversations.filter((item) => {
return item.targetId == targetId &&
item.objectName == RongIMLib.ObjectName.ContactNotification &&
item.latestMessage.operation === 'GroupPending'
})
callback(pendings) RongIMLib.getHistoryMessagesByTimestamp(conversationType, targetId, objectNames, 0, 1000, true,
({
messages
}) => {
callback(messages)
} }
}) )
} }
/** /**
@@ -96,6 +96,11 @@ const sentText = (conversationType, targetId, content, user, callback) => {
messageId messageId
}) => { }) => {
if (code === 0) { if (code === 0) {
if (conversationType == 3) {
RongIMLib.sendReadReceiptRequest(messageId, (res) => {
console.log('发送回执请求', res);
})
}
callback(messageId) callback(messageId)
} else { } else {
console.log('发送失败', msg); console.log('发送失败', msg);

View File

@@ -17,12 +17,7 @@ uni-simple-router@^2.0.7:
resolved "https://registry.npmjs.org/uni-simple-router/-/uni-simple-router-2.0.7.tgz" resolved "https://registry.npmjs.org/uni-simple-router/-/uni-simple-router-2.0.7.tgz"
integrity sha512-8FKv5dw7Eoonm0gkO8udprrxzin0fNUI0+AvIphFkFRH5ZmP5ZWJ2pvnWzb2NiiqQSECTSU5VSB7HhvOSwD5eA== integrity sha512-8FKv5dw7Eoonm0gkO8udprrxzin0fNUI0+AvIphFkFRH5ZmP5ZWJ2pvnWzb2NiiqQSECTSU5VSB7HhvOSwD5eA==
uview-ui@^2.0.19: uview-ui@^2.0.27:
version "2.0.19" version "2.0.27"
resolved "https://registry.npmjs.org/uview-ui/-/uview-ui-2.0.19.tgz" resolved "https://registry.yarnpkg.com/uview-ui/-/uview-ui-2.0.27.tgz#1a7dde9c6246e851d768f3efd44b5fb26774a2e1"
integrity sha512-ddZiaP7R9wsUxMzAuhuXgh5OswgCm2lKuulTqjnRXFr0uUWsgL1iBifU3GbOwpwP0LtTHKJOo9rYv1LP0WXmzA== integrity sha512-fl35rlguNPfXnwNoVv0w4zS1blFFxxSPuGR1+9SbpFGC33aiTBaoFWs/4Fppj0foS/kDCqSWcJiymNmQjPBD4g==
vuex@^3.6.2:
version "3.6.2"
resolved "https://registry.npmjs.org/vuex/-/vuex-3.6.2.tgz"
integrity sha512-ETW44IqCgBpVomy520DT5jf8n0zoCac+sxWnn+hMe/CzaSejb/eVw2YToiXYX+Ex/AuHHia28vWTq4goAexFbw==