Browse Source

Merge branch 'dev' of https://git.citupro.com/zhengnaiwen_citu/menduner into dev

Xiao_123 10 months ago
parent
commit
48582ef42d
5 changed files with 408 additions and 47 deletions
  1. 146 12
      pnpm-lock.yaml
  2. 8 1
      src/api/common/index.js
  3. 140 0
      src/hooks/web/useIM.js
  4. 33 5
      src/store/user.js
  5. 81 29
      src/views/recruit/personal/message/index.vue

+ 146 - 12
pnpm-lock.yaml

@@ -11,12 +11,39 @@ importers:
       '@mdi/font':
         specifier: 7.0.96
         version: 7.0.96
+      '@vuepic/vue-datepicker':
+        specifier: ^8.7.0
+        version: 8.8.1(vue@3.4.25)
       axios:
         specifier: ^1.6.8
         version: 1.6.8
+      bignumber.js:
+        specifier: ^9.1.2
+        version: 9.1.2
+      buffer:
+        specifier: ^6.0.3
+        version: 6.0.3
+      crypto-js:
+        specifier: ^4.2.0
+        version: 4.2.0
+      curve25519-js:
+        specifier: ^0.0.4
+        version: 0.0.4
+      echarts:
+        specifier: ^5.4.3
+        version: 5.5.1
+      js-base64:
+        specifier: ^3.7.7
+        version: 3.7.7
       js-cookie:
         specifier: ^3.0.5
         version: 3.0.5
+      lodash:
+        specifier: ^4.17.21
+        version: 4.17.21
+      md5-typescript:
+        specifier: ^1.0.5
+        version: 1.0.5
       nprogress:
         specifier: ^0.2.0
         version: 0.2.0
@@ -45,8 +72,11 @@ importers:
         specifier: ^4.3.0
         version: 4.3.2(vue@3.4.25)
       vuetify:
-        specifier: ^3.5.0
-        version: 3.5.17(vite-plugin-vuetify@2.0.3)(vue-i18n@9.13.1(vue@3.4.25))(vue@3.4.25)
+        specifier: ^3.6.0
+        version: 3.6.13(vite-plugin-vuetify@2.0.3)(vue-i18n@9.13.1(vue@3.4.25))(vue@3.4.25)
+      wukongimjssdk:
+        specifier: ^1.2.10
+        version: 1.2.10
     devDependencies:
       '@rushstack/eslint-patch':
         specifier: ^1.8.0
@@ -83,7 +113,7 @@ importers:
         version: 5.2.10(sass@1.75.0)
       vite-plugin-vuetify:
         specifier: ^2.0.3
-        version: 2.0.3(vite@5.2.10(sass@1.75.0))(vue@3.4.25)(vuetify@3.5.17)
+        version: 2.0.3(vite@5.2.10(sass@1.75.0))(vue@3.4.25)(vuetify@3.6.13)
 
 packages:
 
@@ -400,6 +430,13 @@ packages:
   '@rushstack/eslint-patch@1.10.2':
     resolution: {integrity: sha512-hw437iINopmQuxWPSUEvqE56NCPsiU8N4AYtfHmJFckclktzK9YQJieD3XkDCDH4OjL+C7zgPUh73R/nrcHrqw==}
 
+  '@types/bignumber.js@5.0.0':
+    resolution: {integrity: sha512-0DH7aPGCClywOFaxxjE6UwpN2kQYe9LwuDQMv+zYA97j5GkOMo8e66LYT+a8JYU7jfmUFRZLa9KycxHDsKXJCA==}
+    deprecated: This is a stub types definition for bignumber.js (https://github.com/MikeMcl/bignumber.js/). bignumber.js provides its own type definitions, so you don't need @types/bignumber.js installed!
+
+  '@types/crypto-js@4.2.2':
+    resolution: {integrity: sha512-sDOLlVbHhXpAUAL0YHDUUwDZf3iN4Bwi4W6a0W0b+QcAezUbRtH4FVb+9J4h+XFPW7l/gQ9F8qC7P+Ec4k8QVQ==}
+
   '@types/estree@1.0.5':
     resolution: {integrity: sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==}
 
@@ -451,6 +488,11 @@ packages:
   '@vue/shared@3.4.25':
     resolution: {integrity: sha512-k0yappJ77g2+KNrIaF0FFnzwLvUBLUYr8VOwz+/6vLsmItFp51AcxLL7Ey3iPd7BIRyWPOcqUjMnm7OkahXllA==}
 
+  '@vuepic/vue-datepicker@8.8.1':
+    resolution: {integrity: sha512-8ehfUz1m69Vuc16Pm4ukgb3Mg1VT14x4EsG1ag4O/qbSNRWztTo+pUV4JnFt0FGLl5gGb6NXlxIvR7EjLgD7Gg==}
+    peerDependencies:
+      vue: '>=3.2.0'
+
   '@vuetify/loader-shared@2.0.3':
     resolution: {integrity: sha512-Ss3GC7eJYkp2SF6xVzsT7FAruEmdihmn4OCk2+UocREerlXKWgOKKzTN5PN3ZVN5q05jHHrsNhTuWbhN61Bpdg==}
     peerDependencies:
@@ -498,6 +540,12 @@ packages:
   balanced-match@1.0.2:
     resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==}
 
+  base64-js@1.5.1:
+    resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==}
+
+  bignumber.js@9.1.2:
+    resolution: {integrity: sha512-2/mKyZH9K85bzOEfhXDBFZTGd1CTs+5IHpeFQo9luiBG7hghdC851Pj2WAhb6E3R6b9tZj/XKhbg4fum+Kepug==}
+
   binary-extensions@2.3.0:
     resolution: {integrity: sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==}
     engines: {node: '>=8'}
@@ -515,6 +563,9 @@ packages:
     resolution: {integrity: sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==}
     engines: {node: '>=8'}
 
+  buffer@6.0.3:
+    resolution: {integrity: sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==}
+
   call-bind@1.0.7:
     resolution: {integrity: sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==}
     engines: {node: '>= 0.4'}
@@ -549,6 +600,9 @@ packages:
     resolution: {integrity: sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==}
     engines: {node: '>= 8'}
 
+  crypto-js@4.2.0:
+    resolution: {integrity: sha512-KALDyEYgpY+Rlob/iriUtjV6d5Eq+Y191A5g4UqLAi8CyGP9N1+FdVbkc1SxKc2r4YAYqG8JzO2KGL+AizD70Q==}
+
   cssesc@3.0.0:
     resolution: {integrity: sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==}
     engines: {node: '>=4'}
@@ -561,10 +615,16 @@ packages:
   csstype@3.1.3:
     resolution: {integrity: sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==}
 
+  curve25519-js@0.0.4:
+    resolution: {integrity: sha512-axn2UMEnkhyDUPWOwVKBMVIzSQy2ejH2xRGy1wq81dqRwApXfIzfbE3hIX0ZRFBIihf/KDqK158DLwESu4AK1w==}
+
   data-urls@5.0.0:
     resolution: {integrity: sha512-ZYP5VBHshaDAiVZxjbRVcFJpc+4xGgT0bK3vzy1HLN8jTO975HEbuYzZJcHoQEY5K1a0z8YayJkyVETa08eNTg==}
     engines: {node: '>=18'}
 
+  date-fns@3.6.0:
+    resolution: {integrity: sha512-fRHTG8g/Gif+kSh50gaGEdToemgfj74aRX3swtiouboip5JDLAyDE9F11nHMIcvOaXeOC6D7SpNhi7uFyB7Uww==}
+
   debug@4.3.4:
     resolution: {integrity: sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==}
     engines: {node: '>=6.0'}
@@ -592,6 +652,9 @@ packages:
     resolution: {integrity: sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==}
     engines: {node: '>=6.0.0'}
 
+  echarts@5.5.1:
+    resolution: {integrity: sha512-Fce8upazaAXUVUVsjgV6mBnGuqgO+JNDlcgF79Dksy4+wgGpQB2lmYoO4TSweFg/mZITdpGHomw/cNBJZj1icA==}
+
   entities@4.5.0:
     resolution: {integrity: sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==}
     engines: {node: '>=0.12'}
@@ -797,6 +860,9 @@ packages:
     resolution: {integrity: sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==}
     engines: {node: '>=0.10.0'}
 
+  ieee754@1.2.1:
+    resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==}
+
   ignore@5.3.1:
     resolution: {integrity: sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw==}
     engines: {node: '>= 4'}
@@ -847,6 +913,9 @@ packages:
   isexe@2.0.0:
     resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==}
 
+  js-base64@3.7.7:
+    resolution: {integrity: sha512-7rCnleh0z2CkXhH67J8K1Ytz0b2Y+yxTPL+/KOJoa20hfnVQ/3/T6W/KflYI4bRHRagNeXeU2bkNGI3v1oS/lw==}
+
   js-cookie@3.0.5:
     resolution: {integrity: sha512-cEiJEAEoIbWfCZYKWhVwFuvPX1gETRYPw6LlaTKoxD3s2AkXzkCjnp6h0V77ozyqj0jakteJ4YqDJT830+lVGw==}
     engines: {node: '>=14'}
@@ -901,6 +970,9 @@ packages:
   magic-string@0.30.10:
     resolution: {integrity: sha512-iIRwTIf0QKV3UAnYK4PU8uiEc4SRh5jX0mwpIwETPpHdhVM4f53RSwS/vXvN1JhGX+Cs7B8qIq3d6AH49O5fAQ==}
 
+  md5-typescript@1.0.5:
+    resolution: {integrity: sha512-ovAc4EtiNt2dY8JPhPr/wkC9h4U5k/nuClNVcG0Ga3V1rMlYpAY24ZaaymFXJlz+ccJ6UMPo3FSaVKe7czBsXw==}
+
   merge2@1.4.1:
     resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==}
     engines: {node: '>= 8'}
@@ -1174,6 +1246,9 @@ packages:
     resolution: {integrity: sha512-tk2G5R2KRwBd+ZN0zaEXpmzdKyOYksXwywulIX95MBODjSzMIuQnQ3m8JxgbhnL1LeVo7lqQKsYa1O3Htl7K5g==}
     engines: {node: '>=18'}
 
+  tslib@2.3.0:
+    resolution: {integrity: sha512-N82ooyxVNm6h1riLCoyS9e3fuJ3AMG2zIZs2Gd1ATcSFjSA23Q0fzjjZeh0jbJvWVDZ0cJT8yaNNaaXHzueNjg==}
+
   tslib@2.6.2:
     resolution: {integrity: sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==}
 
@@ -1300,8 +1375,8 @@ packages:
       typescript:
         optional: true
 
-  vuetify@3.5.17:
-    resolution: {integrity: sha512-/Veklxxyu/l63q7QQOqJZeZukIKI2sBxY7FKMDcNup2KSGMjyjT+oYXy1DOdl7wlU3c3fKGQMFHqVWb0HDsyDw==}
+  vuetify@3.6.13:
+    resolution: {integrity: sha512-Gz7jxXAkmff2m6CM0EUWOo/72TM322/3I6aDna++k1nPOW1/hNx4td1MZG4u75fzdn3r+uIe0dbF7SWuhu6DWA==}
     engines: {node: ^12.20 || >=14.13}
     peerDependencies:
       typescript: '>=4.7'
@@ -1370,6 +1445,9 @@ packages:
       utf-8-validate:
         optional: true
 
+  wukongimjssdk@1.2.10:
+    resolution: {integrity: sha512-MX4NJoXGV+KnxZ6kK8UwsjLWEewGQudmCGV2d4/vrtI99Z78EkfWARPyVGX3jkqX0vwDzxid2JrcQewuo3vXGA==}
+
   xml-name-validator@4.0.0:
     resolution: {integrity: sha512-ICP2e+jsHvAj2E2lIHxa5tjXRlKDJo4IdvPvCXbXQGdzSfmSpNVyIKMvoZHjDY9DP0zV17iI85o90vRFXNccRw==}
     engines: {node: '>=12'}
@@ -1388,6 +1466,9 @@ packages:
     resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==}
     engines: {node: '>=10'}
 
+  zrender@5.6.0:
+    resolution: {integrity: sha512-uzgraf4njmmHAbEUxMJ8Oxg+P3fT04O+9p7gY+wJRVxo8Ge+KmYv0WJev945EH4wFuc4OY2NLXz46FZrWS9xJg==}
+
 snapshots:
 
   '@antfu/utils@0.7.7': {}
@@ -1598,6 +1679,12 @@ snapshots:
 
   '@rushstack/eslint-patch@1.10.2': {}
 
+  '@types/bignumber.js@5.0.0':
+    dependencies:
+      bignumber.js: 9.1.2
+
+  '@types/crypto-js@4.2.2': {}
+
   '@types/estree@1.0.5': {}
 
   '@ungap/structured-clone@1.2.0': {}
@@ -1671,11 +1758,16 @@ snapshots:
 
   '@vue/shared@3.4.25': {}
 
-  '@vuetify/loader-shared@2.0.3(vue@3.4.25)(vuetify@3.5.17(vite-plugin-vuetify@2.0.3)(vue-i18n@9.13.1(vue@3.4.25))(vue@3.4.25))':
+  '@vuepic/vue-datepicker@8.8.1(vue@3.4.25)':
+    dependencies:
+      date-fns: 3.6.0
+      vue: 3.4.25
+
+  '@vuetify/loader-shared@2.0.3(vue@3.4.25)(vuetify@3.6.13(vite-plugin-vuetify@2.0.3)(vue-i18n@9.13.1(vue@3.4.25))(vue@3.4.25))':
     dependencies:
       upath: 2.0.1
       vue: 3.4.25
-      vuetify: 3.5.17(vite-plugin-vuetify@2.0.3)(vue-i18n@9.13.1(vue@3.4.25))(vue@3.4.25)
+      vuetify: 3.6.13(vite-plugin-vuetify@2.0.3)(vue-i18n@9.13.1(vue@3.4.25))(vue@3.4.25)
 
   acorn-jsx@5.3.2(acorn@8.11.3):
     dependencies:
@@ -1721,6 +1813,10 @@ snapshots:
 
   balanced-match@1.0.2: {}
 
+  base64-js@1.5.1: {}
+
+  bignumber.js@9.1.2: {}
+
   binary-extensions@2.3.0: {}
 
   boolbase@1.0.0: {}
@@ -1738,6 +1834,11 @@ snapshots:
     dependencies:
       fill-range: 7.0.1
 
+  buffer@6.0.3:
+    dependencies:
+      base64-js: 1.5.1
+      ieee754: 1.2.1
+
   call-bind@1.0.7:
     dependencies:
       es-define-property: 1.0.0
@@ -1783,6 +1884,8 @@ snapshots:
       shebang-command: 2.0.0
       which: 2.0.2
 
+  crypto-js@4.2.0: {}
+
   cssesc@3.0.0: {}
 
   cssstyle@4.0.1:
@@ -1791,11 +1894,15 @@ snapshots:
 
   csstype@3.1.3: {}
 
+  curve25519-js@0.0.4: {}
+
   data-urls@5.0.0:
     dependencies:
       whatwg-mimetype: 4.0.0
       whatwg-url: 14.0.0
 
+  date-fns@3.6.0: {}
+
   debug@4.3.4:
     dependencies:
       ms: 2.1.2
@@ -1816,6 +1923,11 @@ snapshots:
     dependencies:
       esutils: 2.0.3
 
+  echarts@5.5.1:
+    dependencies:
+      tslib: 2.3.0
+      zrender: 5.6.0
+
   entities@4.5.0: {}
 
   es-define-property@1.0.0:
@@ -2076,6 +2188,8 @@ snapshots:
     dependencies:
       safer-buffer: 2.1.2
 
+  ieee754@1.2.1: {}
+
   ignore@5.3.1: {}
 
   immutable@4.3.5: {}
@@ -2116,6 +2230,8 @@ snapshots:
 
   isexe@2.0.0: {}
 
+  js-base64@3.7.7: {}
+
   js-cookie@3.0.5: {}
 
   js-yaml@4.1.0:
@@ -2183,6 +2299,8 @@ snapshots:
     dependencies:
       '@jridgewell/sourcemap-codec': 1.4.15
 
+  md5-typescript@1.0.5: {}
+
   merge2@1.4.1: {}
 
   micromatch@4.0.5:
@@ -2436,6 +2554,8 @@ snapshots:
     dependencies:
       punycode: 2.3.1
 
+  tslib@2.3.0: {}
+
   tslib@2.6.2: {}
 
   type-check@0.4.0:
@@ -2491,14 +2611,14 @@ snapshots:
 
   util-deprecate@1.0.2: {}
 
-  vite-plugin-vuetify@2.0.3(vite@5.2.10(sass@1.75.0))(vue@3.4.25)(vuetify@3.5.17):
+  vite-plugin-vuetify@2.0.3(vite@5.2.10(sass@1.75.0))(vue@3.4.25)(vuetify@3.6.13):
     dependencies:
-      '@vuetify/loader-shared': 2.0.3(vue@3.4.25)(vuetify@3.5.17(vite-plugin-vuetify@2.0.3)(vue-i18n@9.13.1(vue@3.4.25))(vue@3.4.25))
+      '@vuetify/loader-shared': 2.0.3(vue@3.4.25)(vuetify@3.6.13(vite-plugin-vuetify@2.0.3)(vue-i18n@9.13.1(vue@3.4.25))(vue@3.4.25))
       debug: 4.3.4
       upath: 2.0.1
       vite: 5.2.10(sass@1.75.0)
       vue: 3.4.25
-      vuetify: 3.5.17(vite-plugin-vuetify@2.0.3)(vue-i18n@9.13.1(vue@3.4.25))(vue@3.4.25)
+      vuetify: 3.6.13(vite-plugin-vuetify@2.0.3)(vue-i18n@9.13.1(vue@3.4.25))(vue@3.4.25)
     transitivePeerDependencies:
       - supports-color
 
@@ -2548,11 +2668,11 @@ snapshots:
       '@vue/server-renderer': 3.4.25(vue@3.4.25)
       '@vue/shared': 3.4.25
 
-  vuetify@3.5.17(vite-plugin-vuetify@2.0.3)(vue-i18n@9.13.1(vue@3.4.25))(vue@3.4.25):
+  vuetify@3.6.13(vite-plugin-vuetify@2.0.3)(vue-i18n@9.13.1(vue@3.4.25))(vue@3.4.25):
     dependencies:
       vue: 3.4.25
     optionalDependencies:
-      vite-plugin-vuetify: 2.0.3(vite@5.2.10(sass@1.75.0))(vue@3.4.25)(vuetify@3.5.17)
+      vite-plugin-vuetify: 2.0.3(vite@5.2.10(sass@1.75.0))(vue@3.4.25)(vuetify@3.6.13)
       vue-i18n: 9.13.1(vue@3.4.25)
 
   w3c-xmlserializer@5.0.0:
@@ -2586,6 +2706,16 @@ snapshots:
 
   ws@8.17.0: {}
 
+  wukongimjssdk@1.2.10:
+    dependencies:
+      '@types/bignumber.js': 5.0.0
+      '@types/crypto-js': 4.2.2
+      bignumber.js: 9.1.2
+      buffer: 6.0.3
+      crypto-js: 4.2.0
+      curve25519-js: 0.0.4
+      md5-typescript: 1.0.5
+
   xml-name-validator@4.0.0: {}
 
   xml-name-validator@5.0.0: {}
@@ -2595,3 +2725,7 @@ snapshots:
   yallist@4.0.0: {}
 
   yocto-queue@0.1.0: {}
+
+  zrender@5.6.0:
+    dependencies:
+      tslib: 2.3.0

+ 8 - 1
src/api/common/index.js

@@ -218,7 +218,14 @@ export const getUserAccount = async () => {
 // 获取聊天秘钥信息
 export const getChatKey = async (data) => {
   return await request.post({
-    url: 'admin-api/im/user/get',
+    url: '/app-api/im/user/get',
+    data
+  })
+}
+// 同步最近会话
+export const getConversationSync = async (data) => {
+  return await request.post({
+    url: '/app-api/im/conversation/sync',
     data
   })
 }

+ 140 - 0
src/hooks/web/useIM.js

@@ -0,0 +1,140 @@
+
+
+
+import { ref, onMounted, onUnmounted } from 'vue';
+import { getConversationSync } from '@/api/common'
+
+// 配置悟空IM
+import {
+  MessageText,
+  Channel,
+  WKSDK,
+  ChannelTypePerson,
+  // ChannelTypeGroup
+} from "wukongimjssdk"
+import Snackbar from '@/plugins/snackbar'
+
+import { useUserStore } from '@/store/user'
+
+const userStore = useUserStore()
+
+const ConnectStatus = {
+  Disconnect: 0, // 断开连接
+  Connected: 1, // 连接成功
+  Connecting: 2, // 连接中
+  ConnectFail: 3, // 连接错误
+  ConnectKick: 4, // 连接被踢,服务器要求客户端断开(一般是账号在其他地方登录,被踢)
+}
+
+
+initDataSource()
+// api 接入
+function initDataSource () {
+  // 最近会话数据源
+  WKSDK.shared().config.provider.syncConversationsCallback  = async () => {
+    const res = await getConversationSync({ msg_count: 100 })
+    return res
+  }
+}
+export function initKey () {
+  return new Promise((resolve) => { 
+    userStore.getChatKey().then(() => {
+      resolve()
+    }).catch((error) => {
+      // 报错重连
+      console.log(error.msg)
+      setTimeout(() => {
+        initKey()
+      }, 3000)
+    })
+  })
+}
+
+export function initConnect () {
+  const connected = ref(false)
+  const conversationList = ref([])
+  // 单机模式可以直接设置地址
+  WKSDK.shared().config.addr = 'ws://' + userStore.IMConfig.wsUrl // 默认端口为5200
+  // 认证信息
+  WKSDK.shared().config.uid = userStore.IMConfig.uid // 用户uid(需要在悟空通讯端注册过)
+  WKSDK.shared().config.token = userStore.IMConfig.token // 用户token (需要在悟空通讯端注册过)
+  // 连接
+  onMounted(() => {
+    // 连接状态监听
+    WKSDK.shared().connectManager.addConnectStatusListener(
+      async (status, reasonCode) => {
+        if (status === ConnectStatus.Connected) {
+          console.log('连接成功')
+          connected.value = true
+          // 获取列表
+          const res = await syncConversation()
+          conversationList.value = [...res]
+        } else {
+          console.log('reasonCode', reasonCode)
+          connected.value = false
+          conversationList.value = []
+        }
+      }
+    )
+
+    // 消息发送状态监听
+    WKSDK.shared().chatManager.addMessageStatusListener(statusListen)
+    // 常规消息监听
+    WKSDK.shared().chatManager.addMessageListener(messageListen)
+    
+    connect()
+  })
+  onUnmounted(() => {
+    // 连接状态监听移除
+    WKSDK.shared().connectManager.disconnect()
+    // 消息发送状态监听移除
+    WKSDK.shared().chatManager.removeMessageStatusListener(statusListen)
+    // 常规消息监听移除
+    WKSDK.shared().chatManager.removeMessageListener(messageListen)
+  })
+  return { connected, conversationList }
+}
+
+// 消息发送状态监听
+function statusListen (packet) {
+  if (packet.reasonCode === 1) {
+    // 发送成功
+  } else {
+    // 发送失败
+  }
+}
+
+// 常规消息监听
+function messageListen (message) {
+  console.log('收到消息', message)
+  // message.content // 消息内容
+  // message.channel // 消息频道
+  // message.fromUID // 消息发送者
+}
+
+
+export function connect () {
+  WKSDK.shared().connectManager.connect()
+}
+
+export function send (user, text) {
+  // 例如发送文本消息hello给用户u10001
+  const _text = new MessageText(text) // 文本消息
+  WKSDK.shared().chatManager.send(_text, new Channel(user, ChannelTypePerson))
+
+  // 例如发送文本消息hello给群频道g10001
+  // WKSDK.shared().chatManager.send(_text, new Channel(user,ChannelTypeGroup))
+}
+
+// 同步最近会话
+export async function syncConversation () {
+  return new Promise((resolve) => {
+    WKSDK.shared().conversationManager.sync().then(res => {
+      resolve(res)
+    }).catch(error => {
+      Snackbar.error(error.msg)
+    })
+  })
+}
+
+

+ 33 - 5
src/store/user.js

@@ -1,12 +1,24 @@
 import { defineStore } from 'pinia'
 import { setToken, removeToken, setRefreshToken, getToken } from '@/utils/auth'
-import { smsLogin, passwordLogin, getBaseInfo, passwordLoginOfEnterprise, smsLoginOfEnterprise, switchLoginOfEnterprise, getEnterprisingUserInfo, logoutToken, logout } from '@/api/common'
+import {
+  smsLogin,
+  passwordLogin, 
+  getBaseInfo, 
+  passwordLoginOfEnterprise, 
+  smsLoginOfEnterprise, 
+  switchLoginOfEnterprise, 
+  getEnterprisingUserInfo, 
+  logoutToken, 
+  logout 
+} from '@/api/common'
 import { getUserInfo } from '@/api/personal/user'
 import { getEnterpriseUserAccount, getUserAccount } from '@/api/common'
 import Snackbar from '@/plugins/snackbar'
 import { timesTampChange } from '@/utils/date'
 import { updateEventList } from '@/utils/eventList'
 import { getBaseInfoDictOfName } from '@/utils/getText'
+import { getChatKey } from '@/api/common'
+
 
 
 export const useUserStore = defineStore('user',
@@ -14,14 +26,15 @@ export const useUserStore = defineStore('user',
     state: () => ({
       // loginType: null, // 登录类型 // 330为企业登录
       accountInfo: {}, // 登录返回的信息
-      userInfo: {}, // 当前登录账号信息
+      userInfo: localStorage.getItem('userInfo') ? JSON.parse(localStorage.getItem('userInfo')) : {}, // 当前登录账号信息
       baseInfo: {}, // 人才信息
       userAccount: {}, // 用户账户信息
       enterpriseUserAccount: {}, // 企业账户信息
+      IMConfig: localStorage.getItem('IMConfig') ? JSON.parse(localStorage.getItem('IMConfig')) : {} // IM聊天密钥
     }),
     actions: {
       // 短信登录
-      async handleSmsLogin (data) {
+      handleSmsLogin (data) {
         return new Promise((resolve, reject) => {
           const loginApi = data.loginType === 330 ? smsLoginOfEnterprise : smsLogin
           loginApi(data).then(res => {
@@ -38,7 +51,20 @@ export const useUserStore = defineStore('user',
           }).catch(err => { reject(err) })
         })
       },
-      // // 密码登录
+      // 获取聊天密钥
+      getChatKey () {
+        return new Promise((resolve, reject) => {
+          getChatKey({ userId: this.userInfo.id })
+          .then(res => {
+            this.IMConfig = res
+            localStorage.setItem('IMConfig', JSON.stringify(res))
+            resolve()
+          }).catch(error => {
+            reject(error)
+          })
+        })
+      },
+      // 密码登录
       async handlePasswordLogin(data) {
         return new Promise((resolve, reject) => {
           const loginApi = data.loginType === 330 ? passwordLoginOfEnterprise : passwordLogin
@@ -62,6 +88,8 @@ export const useUserStore = defineStore('user',
           const data = await api({ id: this.accountInfo.userId })
           this.userInfo = data
           localStorage.setItem('userInfo', JSON.stringify(data))
+          // 获取密钥
+          this.getChatKey()
           updateEventList(true) // 获取规则配置跟踪列表
           this.getUserAccountInfo()
         } catch (error) {
@@ -150,7 +178,7 @@ export const useUserStore = defineStore('user',
         localStorage.setItem('userAccount', JSON.stringify(data))
       }
     }
-   },
+  },
   {
     persist: true,
     devtools: true

+ 81 - 29
src/views/recruit/personal/message/index.vue

@@ -2,11 +2,53 @@
   <div class="default-width message pa-3">
     <div class="message-left">
       <div class="message-left-search d-flex align-center justify-center">
+        <!-- {{ connected ? '连接成功': '连接失败' }} -->
         <TextInput v-model="searchInputVal" :item="textItem" @appendInnerClick="handleSearch" @enter="handleSearch"></TextInput>
       </div>
       <div class="message-chat-box mt-5">
-        <div v-if="chatList.length">
-          <div class="chat-item d-flex align-center" v-for="(val, i) in chatList" :key="i">
+        <v-overlay
+          :model-value="!connected"
+          contained
+          class="align-center justify-center"
+        >
+          <v-progress-circular
+            color="primary"
+            size="64"
+            indeterminate
+          ></v-progress-circular>
+        </v-overlay>
+        <div v-if="conversationList.length">
+          <v-list density="compact">
+            <v-list-item
+              v-for="(val, i) in conversationList"
+              :key="i"
+              :value="val"
+              color="primary"
+              :title="val.name + val.enterpriseName + val.postName"
+              :subtitle="val.tip"
+            >
+              <template v-slot:prepend>
+                <v-avatar :image="val.avatar || 'https://minio.citupro.com/dev/menduner/7.png'"></v-avatar>
+              </template>
+              <template v-slot:append>
+                <v-btn
+                  color="grey-lighten-1"
+                  icon="mdi-information"
+                  variant="text"
+                ></v-btn>
+              </template>
+
+
+              <!-- <v-list-item-title>
+                <span class="font-size-15">{{ val.name }}</span>
+                <span class="ml-3 title-box">{{ val.enterpriseName }}</span>
+                <span class="septal-line"></span>
+                <span>{{ val.postName }}</span>
+                <span>17.25</span>
+              </v-list-item-title> -->
+            </v-list-item>
+          </v-list>
+          <!-- <div class="chat-item d-flex align-center" v-for="(val, i) in chatList" :key="i">
             <v-avatar :image="val.avatar || 'https://minio.citupro.com/dev/menduner/7.png'"></v-avatar>
             <div class="ml-3 font-size-13">
               <div class="chat-item-time color-999">17.25</div>
@@ -18,7 +60,7 @@
               </div>
               <div class="color-999 mt-1">{{ val.tip }}</div>
             </div>
-          </div>
+          </div> -->
           <div class="message-no-more-text mt-3">没有更多了</div>
         </div>
         <div v-else class="left-noData">
@@ -40,13 +82,23 @@
 defineOptions({ name: 'personal-message-index'})
 import { ref } from 'vue'
 import Chatting from './components/chatting.vue'
-// import { getChatKey } from '@/api/common'
+import { initKey, initConnect } from '@/hooks/web/useIM'
+// 实例
+
+import { useUserStore } from '@/store/user'
+
+const userStore = useUserStore()
+
+if (Object.keys(userStore.IMConfig).length === 0) {
+  await initKey()
+}
+
+const { connected, conversationList } = initConnect()
+
+console.log('connected.value', connected.value)
+
+// const IMStatus = ref(isConnected)
 
-// const getKey = async () => {
-//   const data = await getChatKey({ userId: '1' })
-//   console.log(data, 'key')
-// }
-// getKey()
 
 const showRightNoData = ref(false)
 const searchInputVal = ref()
@@ -61,26 +113,26 @@ const textItem = ref({
 })
 
 // 左侧聊天列表
-const chatList = ref([
-  {
-    id: 1,
-    name: '钟女士',
-    avatar: 'https://minio.citupro.com/dev/menduner/tx1.jpg',
-    enterpriseName: '泰康泰康泰康泰康泰康泰康',
-    postName: '人事HR',
-    updateTime: 1715337950000,
-    tip: '你好'
-  },
-  {
-    id: 2,
-    name: '林先生',
-    avatar: 'https://minio.citupro.com/dev/menduner/tx1.jpg',
-    enterpriseName: '众宝联合',
-    postName: '人力资源主管',
-    updateTime: 1715337950000,
-    tip: '你好'
-  }
-])
+// const chatList = ref([
+//   {
+//     id: 1,
+//     name: '钟女士',
+//     avatar: 'https://minio.citupro.com/dev/menduner/tx1.jpg',
+//     enterpriseName: '泰康泰康泰康泰康泰康泰康',
+//     postName: '人事HR',
+//     updateTime: 1715337950000,
+//     tip: '你好'
+//   },
+//   {
+//     id: 2,
+//     name: '林先生',
+//     avatar: 'https://minio.citupro.com/dev/menduner/tx1.jpg',
+//     enterpriseName: '众宝联合',
+//     postName: '人力资源主管',
+//     updateTime: 1715337950000,
+//     tip: '你好'
+//   }
+// ])
 
 const handleSearch = () => {
   console.log(searchInputVal.value, 'search')