useIM.js 12 KB

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