useIM.js 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447
  1. import { ref, onMounted, onUnmounted, watch } from 'vue';
  2. import { getConversationSync, getMessageSync, getChatKey, setUnread, deleteConversation } from '@/api/common'
  3. import { Base64 } from 'js-base64'
  4. import { userStore } from '@/store/user'
  5. import { useIMStore } from '@/store/im'
  6. // 配置悟空IM
  7. import {
  8. MessageText,
  9. Channel,
  10. WKSDK,
  11. ChannelTypePerson,
  12. MessageContent,
  13. } from "wukongimjssdk"
  14. // 默认招呼语
  15. export const defaultText = '您好,关注到您发布该职位信息,请问有机会与您进一步沟通吗?'
  16. // 企业默认招呼语
  17. // export const defaultTextEnt = '您好,我们正在寻找充满激情、勇于挑战的您,快来和我聊一聊吧~'
  18. const { ObjectContent } = initRegister(101)
  19. const { ObjectContent: ObjectContent2 } = initRegister(102)
  20. const { ObjectContent: ObjectContent3 } = initRegister(103)
  21. const { ObjectContent: ObjectContent4 } = initRegister(104)
  22. const { ObjectContent: ObjectContent5 } = initRegister(105) // 发送简历
  23. const contentType = {
  24. 101: ObjectContent,
  25. 102: ObjectContent2,
  26. 103: ObjectContent3,
  27. 104: ObjectContent4,
  28. 105: ObjectContent5, // 发送简历
  29. }
  30. // 注册消息体
  31. function initRegister (type) {
  32. class ObjectContent extends MessageContent {
  33. constructor(text) {
  34. super();
  35. this.content = text
  36. }
  37. get conversationDigest() {
  38. // 这里需要实现具体的逻辑
  39. return this.content
  40. }
  41. get contentType() {
  42. // 这里需要实现具体的逻辑
  43. return type; // 示例实现
  44. }
  45. decodeJSON(content) {
  46. this.content = content.text;
  47. }
  48. encodeJSON() {
  49. return {
  50. content: this.content
  51. };
  52. }
  53. }
  54. // 注册101类型为面试
  55. WKSDK.shared().register(type, () => new ObjectContent(''))
  56. return {
  57. ObjectContent
  58. }
  59. }
  60. const HISTORY_QUERY = {
  61. limit: 20,
  62. startMessageSeq: 0,
  63. endMessageSeq: 0,
  64. pullMode: 1
  65. }
  66. const ConnectStatus = {
  67. Disconnect: 0, // 断开连接
  68. Connected: 1, // 连接成功
  69. Connecting: 2, // 连接中
  70. ConnectFail: 3, // 连接错误
  71. ConnectKick: 4, // 连接被踢,服务器要求客户端断开(一般是账号在其他地方登录,被踢)
  72. }
  73. // api 接入
  74. export function useDataSource () {
  75. // 最近会话数据源
  76. WKSDK.shared().config.provider.syncConversationsCallback = async () => {
  77. const query = {
  78. msg_count: 1
  79. }
  80. const resultConversations = []
  81. const resp = await getConversationSync(query)
  82. const { data:conversationList } = resp
  83. if (conversationList) {
  84. conversationList.forEach(conversation => {
  85. conversation.channel = new Channel(conversation.channel_id, conversation.channel_type)
  86. conversation.unread = +(conversation.unread || 0)
  87. resultConversations.push(conversation)
  88. })
  89. }
  90. return resultConversations
  91. }
  92. // 同步频道消息数据源
  93. WKSDK.shared().config.provider.syncMessagesCallback = async function(channel) {
  94. // 后端提供的获取频道消息列表的接口数据 然后构建成 Message对象数组返回
  95. let resultMessages = new Array()
  96. const {
  97. startMessageSeq: start_message_seq,
  98. endMessageSeq: end_message_seq,
  99. limit,
  100. pullMode: pull_mode
  101. } = HISTORY_QUERY
  102. const query = {
  103. channel_id: channel.channelID,
  104. channel_type: channel.channelType,
  105. start_message_seq,
  106. end_message_seq,
  107. limit,
  108. pull_mode,
  109. }
  110. const { data } = await getMessageSync(query)
  111. const resp = data
  112. const messageList = resp && resp["messages"]
  113. if (messageList) {
  114. messageList.forEach((msg) => {
  115. // const message = Convert.toMessage(msg);
  116. // msg.channel = new Channel(msg.channel_id, msg.channel_type)
  117. msg.payload = JSON.parse(Base64.decode(msg.payload))
  118. if (contentType[msg.payload.type]) {
  119. msg.payload.content = JSON.parse(msg.payload.content ?? '{}')
  120. }
  121. resultMessages.push(msg)
  122. })
  123. }
  124. // console.log(resultMessages)
  125. const more = resp.more === 1
  126. return {
  127. more,
  128. resultMessages
  129. }
  130. }
  131. }
  132. async function getKey () {
  133. const useUserStore = userStore()
  134. const keyQuery = {
  135. userId: useUserStore.accountInfo?.userId
  136. }
  137. const { data } = await getChatKey(keyQuery)
  138. return {
  139. ...data
  140. }
  141. }
  142. export const useIM = () => {
  143. useDataSource()
  144. const key = ref(0)
  145. const IM = useIMStore()
  146. onMounted( async () => {
  147. await resetConfig()
  148. // 连接状态监听
  149. WKSDK.shared().connectManager.addConnectStatusListener(connectStatusListener)
  150. // 常规消息监听
  151. WKSDK.shared().chatManager.addMessageListener(messageListen)
  152. // 连接
  153. WKSDK.shared().connectManager.connect()
  154. })
  155. onUnmounted(() => {
  156. WKSDK.shared().connectManager.removeConnectStatusListener(connectStatusListener)
  157. // 常规消息监听移除
  158. WKSDK.shared().chatManager.removeMessageListener(messageListen)
  159. // 连接状态监听移除
  160. WKSDK.shared().connectManager.disconnect()
  161. })
  162. async function messageListen (message) {
  163. // console.log('收到消息', message)
  164. IM.setFromChannel(message.channel.channelID)
  165. setUnreadCount()
  166. }
  167. async function connectStatusListener (status) {
  168. // console.log('连接状态', status === ConnectStatus.Connected)
  169. // 连接成功 获取点击数
  170. const connected = status === ConnectStatus.Connected
  171. IM.setConnected(connected)
  172. if (connected) {
  173. // 必须同步最近会话才能获取未读总数
  174. await syncConversation()
  175. setUnreadCount()
  176. }
  177. }
  178. function setUnreadCount () {
  179. const count = WKSDK.shared().conversationManager.getAllUnreadCount()
  180. key.value++
  181. IM.setNewMsg(key.value)
  182. IM.setUnreadCount(count)
  183. console.log('未读消息总数', count)
  184. }
  185. async function resetConfig () {
  186. try {
  187. const { uid, wssUrl, token } = await getKey()
  188. if (!wssUrl) {
  189. return
  190. }
  191. IM.setUid(uid)
  192. // 单机模式可以直接设置地址
  193. WKSDK.shared().config.addr = 'wss://' + wssUrl// 默认端口为5200 + wsUrl
  194. // 认证信息
  195. WKSDK.shared().config.uid = uid // 用户uid(需要在悟空通讯端注册过)
  196. WKSDK.shared().config.token = token // 用户token (需要在悟空通讯端注册过)
  197. } catch (error) {
  198. console.log(error)
  199. }
  200. }
  201. return {
  202. resetConfig
  203. }
  204. }
  205. export function initConnect (callback = () => {}, mounted = () => {}) {
  206. useDataSource()
  207. const IM = useIMStore()
  208. const conversationList = ref([])
  209. const messageItems = ref([])
  210. watch(
  211. () => IM.newMsg,
  212. async () => {
  213. // 未读消息变化
  214. updateConversation()
  215. // 拉取最新消息 查看是否是自己的数据
  216. },
  217. {
  218. deep: true,
  219. immediate: true
  220. }
  221. )
  222. onMounted(async () => {
  223. // 消息发送状态监听
  224. WKSDK.shared().chatManager.addMessageStatusListener(statusListen)
  225. // 常规消息监听
  226. // WKSDK.shared().chatManager.addMessageListener(messageListen)
  227. mounted()
  228. })
  229. onUnmounted(() => {
  230. // 消息发送状态监听移除
  231. WKSDK.shared().chatManager.removeMessageStatusListener(statusListen)
  232. // 常规消息监听移除
  233. // WKSDK.shared().chatManager.removeMessageListener(messageListen)
  234. })
  235. // 消息发送状态监听
  236. function statusListen (packet) {
  237. console.log('发送状态', packet)
  238. if (packet.reasonCode === 1) {
  239. // 发送成功
  240. console.log('发送成功')
  241. // 添加一组成功数据
  242. callback(true)
  243. } else {
  244. // 发送失败
  245. console.log('发送失败')
  246. // 添加一组失败数据
  247. callback(false)
  248. }
  249. }
  250. async function updateConversation () {
  251. const res = await syncConversation()
  252. conversationList.value = res
  253. }
  254. function updateUnreadCount () {
  255. const count = WKSDK.shared().conversationManager.getAllUnreadCount()
  256. IM.setUnreadCount(count)
  257. }
  258. async function deleteConversations (channel, enterpriseId) {
  259. const query = {
  260. channel_id: channel.channelID,
  261. channel_type: channel.channelType,
  262. enterpriseId
  263. }
  264. await deleteConversation(query)
  265. }
  266. async function resetUnread (channel, enterpriseId) {
  267. const query = {
  268. channel_id: channel.channelID,
  269. channel_type: channel.channelType,
  270. enterpriseId,
  271. unread: 0
  272. }
  273. const res = await setUnread(query)
  274. return res
  275. }
  276. return {
  277. resetUnread,
  278. deleteConversations,
  279. updateConversation,
  280. updateUnreadCount,
  281. conversationList,
  282. messageItems,
  283. // channel
  284. }
  285. }
  286. // 同步最近会话
  287. async function syncConversation () {
  288. const res = await WKSDK.shared().conversationManager.sync()
  289. return res
  290. }
  291. // 发起聊天
  292. export async function initChart (userId, enterpriseId) {
  293. const channel = ref()
  294. // const list = ref([])
  295. const query = {
  296. userId,
  297. enterpriseId
  298. }
  299. // 创建聊天频道
  300. const { data } = await getChatKey(query)
  301. const { uid } = data
  302. const _channel = new Channel(uid, ChannelTypePerson)
  303. channel.value = _channel
  304. const conversation = WKSDK.shared().conversationManager.findConversation(_channel)
  305. if(!conversation) {
  306. // 如果最近会话不存在,则创建一个空的会话
  307. WKSDK.shared().conversationManager.createEmptyConversation(_channel)
  308. }
  309. const res = await getMoreMessages(1, _channel)
  310. return {
  311. channel,
  312. ...res
  313. }
  314. }
  315. // 翻页
  316. export async function getMoreMessages (pageSize, channel) {
  317. const list = ref([])
  318. Object.assign(HISTORY_QUERY, {
  319. startMessageSeq: (pageSize - 1) * HISTORY_QUERY.limit
  320. })
  321. const { resultMessages, more } = await WKSDK.shared().chatManager.syncMessages(channel)
  322. list.value = resultMessages
  323. return {
  324. list,
  325. more
  326. }
  327. }
  328. /**
  329. *
  330. * @param {*} text
  331. * @param {*} _channel
  332. * @param { Number } type : 101 面试主体
  333. * @returns
  334. */
  335. // 发送职位使用101
  336. export function send (text, _channel, type) {
  337. let _text
  338. if (contentType[type]) {
  339. _text = new contentType[type](text)
  340. WKSDK.shared().chatManager.send(_text, _channel)
  341. return
  342. }
  343. // if (type === 101) {
  344. // _text = new ObjectContent(text)
  345. // WKSDK.shared().chatManager.send(_text, _channel)
  346. // // console.log(_text)
  347. // return
  348. // }
  349. // if (type === 102) {
  350. // _text = new ObjectContent2(text)
  351. // WKSDK.shared().chatManager.send(_text, _channel)
  352. // // console.log(_text)
  353. // return
  354. // }
  355. // // 求职者拒绝面试邀请
  356. // if (type === 103) {
  357. // _text = new ObjectContent3(text)
  358. // WKSDK.shared().chatManager.send(_text, _channel)
  359. // return
  360. // }
  361. // // 求职者接受面试邀请
  362. // if (type === 104) {
  363. // _text = new ObjectContent4(text)
  364. // WKSDK.shared().chatManager.send(_text, _channel)
  365. // return
  366. // }
  367. _text = new MessageText(text)
  368. // console.log(_text)
  369. WKSDK.shared().chatManager.send(_text, _channel)
  370. }
  371. // 对话开场白 用户 to 企业
  372. export async function prologue ({userId, enterpriseId, text}) {
  373. const { channel } = await checkConversation(userId, enterpriseId)
  374. send(text, channel, 102)
  375. return channel
  376. }
  377. // 企业 to 用户
  378. export async function talkToUser ({userId, text}) {
  379. const { channel, isNewTalk } = await checkConversation(userId)
  380. if (!isNewTalk) send(text, channel)
  381. }
  382. // 检测是否存在频道
  383. export async function checkConversation (userId, enterpriseId) {
  384. const query = {
  385. userId,
  386. enterpriseId
  387. }
  388. // 创建聊天频道
  389. const { data } = await getChatKey(query)
  390. const { uid } = data
  391. const _channel = new Channel(uid, ChannelTypePerson)
  392. console.log('生成channel', _channel)
  393. const conversation = WKSDK.shared().conversationManager.findConversation(_channel)
  394. const isNewTalk = ref(false)
  395. if(!conversation) {
  396. // 如果最近会话不存在,则创建一个空的会话
  397. WKSDK.shared().conversationManager.createEmptyConversation(_channel)
  398. isNewTalk.value = true
  399. }
  400. return {
  401. channel: _channel,
  402. isNewTalk: isNewTalk.value
  403. }
  404. }