useIM.js 11 KB

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