jim-util.js 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385
  1. /**
  2. * 极光操作库 https://docs.jiguang.cn/jmessage/client/im_sdk_js_v2#%E6%A6%82%E8%BF%B0
  3. * 极光会话未读数需要自己维护
  4. * 极光多端消息多端在线 https://docs.jiguang.cn/jmessage/client/im_sdk_js_v2#%E4%BC%9A%E8%AF%9D%E6%9C%AA%E8%AF%BB%E6%95%B0%E5%8F%98%E6%9B%B4%E7%9B%91%E5%90%AC%EF%BC%88%E5%A4%9A%E7%AB%AF%E5%9C%A8%E7%BA%BF%EF%BC%89
  5. */
  6. import api from '@/utils/api'
  7. import moment from '@/public/moment/moment.js' //时间日期js处理库
  8. //极光IM jsSDK APP非常容易掉线,所以增加重连机制
  9. const initJIM = (config) => {
  10. return new Promise((resolve, reject) => {
  11. let JIM = getApp().globalData.JIM
  12. console.log('<<<----------JIM初始化开始---------->>>');
  13. if (!JIM.isInit()) {
  14. // 重新进行初始化登录,超过 次就不在继续
  15. JIM.init(config).onSuccess(function (data) {
  16. getApp().globalData.JIM = JIM
  17. console.log('<<<----------JIM初始化成功---------->>>');
  18. resolve(data)
  19. }).onFail(function (data) {
  20. console.log('<<<----------JIM初始化失败---------->>>');
  21. // reject(data)
  22. uni.$emit('JIMDisconnect')
  23. reject()
  24. }).onTimeout(function (data) {
  25. console.log('<<<----------JIM初始化超时---------->>>');
  26. uni.$emit('JIMDisconnect')
  27. // initJIM(config) //重连
  28. reject(data)
  29. })
  30. } else {
  31. resolve()
  32. }
  33. })
  34. }
  35. //极光登录
  36. const loginJIM = () => {
  37. return new Promise((resolve, reject) => {
  38. let JIM = getApp().globalData.JIM
  39. //获取用户信息
  40. let userInfo = uni.getStorageSync('wx_login_user_info')
  41. let thirdSession = uni.getStorageSync('third_session')
  42. //还不是点餐平台用户,不登录极光
  43. if (!userInfo || !userInfo.id || !thirdSession) {
  44. console.log("还不是点餐平台用户,不登录极光")
  45. resolve("success");
  46. return
  47. }
  48. let username = userInfo.id
  49. let password = userInfo.id
  50. if (JIM.isLogin() && JIM.isConnect()) {
  51. console.log("极光IM已经登录,无需再登录");
  52. resolve("success");
  53. return
  54. }
  55. ;
  56. JIM.login({
  57. 'username': username,
  58. 'password': password
  59. }).onSuccess(function (data) {
  60. console.log("极光IM登录成功");
  61. uni.$emit('JIMLogin')
  62. // 刷新会话未读数
  63. refreshConversationUnreadCount(username).then(() => {
  64. // 获取离线消息
  65. refreshOfflineMsg()
  66. // 极光1分钟内最新的消息数据经常会获取不到,所以登录1分钟后再获取一次
  67. setTimeout(() => {
  68. refreshOfflineMsg()
  69. }, 1000 * 60)
  70. })
  71. updateJIMUserInfo(userInfo).then(res => {
  72. resolve("success");
  73. });
  74. }).onFail(function (data) {
  75. //如果用户不存在,则注册账号
  76. if (data.code == 880103) {
  77. let nickname = userInfo.nickName
  78. JIM.register({
  79. 'username': username,
  80. 'password': password,
  81. 'nickname': nickname,
  82. 'extras': {
  83. 'avatar': userInfo.headimgUrl
  84. }
  85. }).onSuccess(function (data) {
  86. console.log("极光IM注册成功");
  87. //登录
  88. JIM.login({
  89. 'username': username,
  90. 'password': password
  91. }).onSuccess(function (data) {
  92. console.log("极光IM登录成功");
  93. uni.$emit('JIMLogin')
  94. // 刷新会话未读数
  95. refreshConversationUnreadCount(username).then(() => {
  96. // 获取离线消息
  97. refreshOfflineMsg()
  98. // 极光1分钟内最新的消息数据经常会获取不到,所以登录1分钟后再获取一次
  99. setTimeout(() => {
  100. refreshOfflineMsg()
  101. }, 1000 * 60)
  102. })
  103. updateJIMUserInfo(userInfo).then(res => {
  104. resolve("success");
  105. });
  106. }).onFail(function (data) {
  107. // 极光IM登录失败
  108. console.log(data)
  109. resolve("success");
  110. });
  111. }).onFail(function (data) {
  112. console.log('JIM -注册失败')
  113. console.log(data)
  114. resolve("success");
  115. });
  116. } else if (data.code == 880109 || data.code == 880107) {
  117. console.log(data)
  118. } else {
  119. console.log('极光IM登录失败')
  120. console.log(data)
  121. resolve("success");
  122. }
  123. });
  124. });
  125. }
  126. // 保存消息到本地
  127. const saveJIMMsg = (messages, isOffline) => {
  128. let userInfo = uni.getStorageSync('wx_login_user_info')
  129. let localMsgObj = {} // 本地聊天消息,value为聊天记录Array
  130. for (var i = 0; i < messages.length; i++) { // 极光服务器记录与本地保存的记录比对 保存到本地
  131. // 极光服务器记录与本地保存的记录比对
  132. // 云端的记录 时间1 时间2
  133. // 本地 时间0 时间3
  134. // 保证记录完整,聊天界面查看时以本地数据为准
  135. let curMsg = messages[i]
  136. curMsg.timess = moment(curMsg.ctime_ms).format('HH:mm')
  137. let chatRecordLocalSaveKey = "chat_record_" + userInfo.tenantId + '_' + userInfo.id + '_';
  138. let fromId = ''//用一对一聊天的id作为key,
  139. if (curMsg.from_id == userInfo.id) {
  140. fromId = curMsg.target_id
  141. } else {
  142. fromId = curMsg.from_id
  143. }
  144. chatRecordLocalSaveKey = chatRecordLocalSaveKey + fromId
  145. let localMsgArray = localMsgObj[chatRecordLocalSaveKey]
  146. if (!localMsgArray) {
  147. let localMsgStr = uni.getStorageSync(chatRecordLocalSaveKey) // 本地消息
  148. localMsgObj[chatRecordLocalSaveKey] = localMsgStr ? JSON.parse(localMsgStr) : [];
  149. localMsgArray = localMsgObj[chatRecordLocalSaveKey]
  150. }
  151. let localMsgIds = []
  152. localMsgIds = localMsgArray.map(itemId => {
  153. return itemId.msgid
  154. })
  155. let curIndex = -1;
  156. let localMsgArrayLength = localMsgArray.length - 1;
  157. if (localMsgArray.length > 0 && localMsgIds.indexOf(curMsg.msgid) == -1) { //当前消息是否存在,如果不存在就插入
  158. if (curMsg.msg_ctime < localMsgArray[0].msg_ctime) { //插入到最前面
  159. curIndex = 0
  160. } else {
  161. localMsgArray.map((itemMsg, index) => {
  162. if (localMsgArrayLength == index) {
  163. curIndex = index
  164. } else if (curMsg.msg_ctime > itemMsg.msg_ctime && curMsg.msg_ctime <
  165. localMsgArray[index + 1].msg_ctime) {
  166. curIndex = index //插入到指定位置
  167. return
  168. }
  169. })
  170. }
  171. }
  172. if (localMsgArray.length > 0) {
  173. if (curIndex > -1) {
  174. if (localMsgArrayLength == curIndex) {
  175. localMsgArray.push(curMsg)
  176. if (isOffline) {
  177. // 会话数+1
  178. // 刷新会话未读数
  179. // 存储的会话数据
  180. let conversationDB = uni.getStorageSync("conversation_unread_count_data" + userInfo.id)
  181. // 使用对象存储会话未读数,方便更新未读数
  182. let conversationsObj = conversationDB ? JSON.parse(conversationDB) : {};
  183. // 会话未读数
  184. if (conversationsObj[fromId]) {
  185. conversationsObj[fromId] = conversationsObj[fromId] + 1
  186. } else {
  187. conversationsObj[fromId] = 1
  188. }
  189. uni.setStorageSync("conversation_unread_count_data" + userInfo.id, JSON.stringify(
  190. conversationsObj)) //保存会话
  191. }
  192. } else {
  193. localMsgArray.splice(curIndex, 0, curMsg)
  194. }
  195. }
  196. } else {
  197. localMsgArray.push(curMsg)
  198. if (isOffline) {
  199. // 会话数+1
  200. // 刷新会话未读数
  201. // 存储的会话数据
  202. let conversationDB = uni.getStorageSync("conversation_unread_count_data" + userInfo.id)
  203. // 使用对象存储会话未读数,方便更新未读数
  204. let conversationsObj = conversationDB ? JSON.parse(conversationDB) : {};
  205. // 会话未读数
  206. if (conversationsObj[fromId]) {
  207. conversationsObj[fromId] = conversationsObj[fromId] + 1
  208. } else {
  209. conversationsObj[fromId] = 1
  210. }
  211. uni.setStorageSync("conversation_unread_count_data" + userInfo.id, JSON.stringify(conversationsObj)) //保存会话
  212. }
  213. }
  214. }
  215. // 保存聊天数据
  216. for (let key in localMsgObj) {
  217. uni.setStorageSync(key, JSON.stringify(localMsgObj[key]));
  218. // uni.removeStorageSync(key) //清空聊天消息
  219. }
  220. console.log('保存消息成功')
  221. }
  222. const refreshOfflineMsg = () => {
  223. // 获取离线消息
  224. getJIMOfflineMsg().then(() => {
  225. // 更新消息未读数
  226. getJIMUnreadMsgCnt()
  227. // 消息接收通知
  228. uni.$emit('msg_ol')
  229. })
  230. }
  231. // 获取极光离线消息保存到本地【注意:这个接口2分钟内的消息数据是没有的】
  232. const getJIMOfflineMsg = () => {
  233. return new Promise((resolve, reject) => {
  234. //获取用户信息
  235. let userInfo = uni.getStorageSync('wx_login_user_info')
  236. // 拉取极光服务器消息数据
  237. let end_time = moment().format('YYYY-MM-DD HH:mm:ss');
  238. // 极光免费版只能获取7天内的聊天记录
  239. let begin_time = moment().subtract(7, "days").format('YYYY-MM-DD HH:mm:ss');
  240. api.getJiguangMessages({
  241. userName: userInfo.id,
  242. beginTime: begin_time,
  243. endTime: end_time
  244. }).then(res => {
  245. let lszs = JSON.parse(res.data).messages; // 极光的聊天记录,包含了所有人的
  246. console.log("离线消息")
  247. // console.log(lszs)
  248. if (lszs) {
  249. saveJIMMsg(lszs, true)
  250. console.log('保存离线消息成功')
  251. resolve()
  252. } else {
  253. reject()
  254. }
  255. }).catch(() => {
  256. console.log('保存离线消息失败')
  257. reject()
  258. })
  259. })
  260. }
  261. // 刷新会话未读数
  262. const refreshConversationUnreadCount = (userId) => {
  263. return new Promise((resolve, reject) => {
  264. // 会话未读数需要开发者自己维护 https://community.jiguang.cn/question/248440
  265. // 如果极光的未读数有值那么就用极光的,否则就用本地的未读数的值表示本地的消息未读过
  266. let JIM = getApp().globalData.JIM
  267. JIM.getConversation().onSuccess(function (data) {
  268. // 极光的会话数据
  269. let conversation = data.conversations.reverse()
  270. console.log('获取极光的会话数据成功')
  271. // 本地存储的会话数据
  272. // let conversationUnreadDB = uni.getStorageSync("conversation_unread_count_data")
  273. let conversationsObj = {};
  274. conversation.map((item) => {
  275. conversationsObj[item.username] = 0
  276. })
  277. uni.setStorageSync("conversation_unread_count_data" + userId, JSON.stringify(
  278. conversationsObj)) //保存会话
  279. // uni.setStorageSync("conversation_unread_count_data","") //清空会话
  280. resolve(conversation)
  281. }).onFail(function (data) {
  282. console.log('JIM fail:' + data)
  283. reject()
  284. });
  285. })
  286. }
  287. //刷新会话未读数
  288. const getJIMUnreadMsgCnt = () => {
  289. //获取用户信息
  290. let userInfo = uni.getStorageSync('wx_login_user_info')
  291. let count = 0
  292. if (userInfo) {
  293. // 存储的会话数据
  294. let conversationUnreadDB = uni.getStorageSync("conversation_unread_count_data" + userInfo.id)
  295. let conversationsObj = conversationUnreadDB ? JSON.parse(conversationUnreadDB) : {};
  296. for (const key in conversationsObj) {
  297. count = count + conversationsObj[key]
  298. }
  299. }
  300. // 设置tabbar未读数量
  301. uni.setTabBarBadge({
  302. index: 2,
  303. text: count + ''
  304. });
  305. }
  306. //更新极光IM用户信息
  307. const updateJIMUserInfo = (userInfo) => {
  308. let username = userInfo.id
  309. return new Promise((resolve, reject) => {
  310. let JIM = getApp().globalData.JIM;
  311. JIM.getUserInfo({
  312. 'username': username,
  313. }).onSuccess(function (data) {
  314. console.log('获取IM用户信息成功')
  315. let nickname = userInfo.nickName
  316. if (data.user_info.nickname != nickname || data.user_info.extras.avatar != userInfo
  317. .headimgUrl) {
  318. console.log('更新JIM用户信息')
  319. JIM.updateSelfInfo({
  320. 'nickname': nickname,
  321. 'extras': {
  322. 'avatar': userInfo.headimgUrl
  323. }
  324. }).onSuccess(function (data) {
  325. //data.code 返回码
  326. //data.message 描述
  327. resolve("success");
  328. }).onFail(function (data) {
  329. console.log('updataJIMUserInfo fail:' + data)
  330. resolve("success");
  331. });
  332. } else {
  333. resolve("success");
  334. }
  335. }).onFail(function (data) {
  336. //data.code 返回码
  337. //data.message 描述
  338. resolve("success");
  339. });
  340. });
  341. }
  342. const clearConversationMsgUnread = (chatId) => {
  343. //获取用户信息
  344. let userInfo = uni.getStorageSync('wx_login_user_info')
  345. if (userInfo) {
  346. // 会话未读数数清零
  347. let conversationUnreadDB = uni.getStorageSync("conversation_unread_count_data" + userInfo.id)
  348. if (conversationUnreadDB) {
  349. let conversationsObj = conversationUnreadDB ? JSON.parse(conversationUnreadDB) : {};
  350. conversationsObj[chatId] = 0;
  351. uni.setStorageSync("conversation_unread_count_data" + userInfo.id, JSON.stringify(conversationsObj)) //保存会话
  352. }
  353. }
  354. }
  355. // 创建一条消息,用于本地缓存消息
  356. const createLocalMessage = (msgid, msg_ctime, msgContent) => {
  357. return {
  358. ...msgContent,
  359. msgid,
  360. msg_ctime,
  361. is_local_msg: true //是否是本地缓存的消息
  362. }
  363. }
  364. module.exports = {
  365. initJIM,
  366. loginJIM,
  367. saveJIMMsg,
  368. refreshOfflineMsg,
  369. getJIMOfflineMsg,
  370. refreshConversationUnreadCount,
  371. getJIMUnreadMsgCnt,
  372. updateJIMUserInfo,
  373. clearConversationMsgUnread,
  374. createLocalMessage,
  375. }