15376779826 1 mese fa
parent
commit
1496965236
74 ha cambiato i file con 4580 aggiunte e 2258 eliminazioni
  1. 7 4
      package.json
  2. 2 1
      public/index.html
  3. BIN
      public/openIM.wasm
  4. BIN
      public/sql-wasm.wasm
  5. 561 0
      public/wasm_exec.js
  6. 7 0
      src/api/doctor.js
  7. 14 1
      src/api/inquiryOrder.js
  8. BIN
      src/assets/audio/beCalled.mp3
  9. 48 0
      src/assets/doctor.svg
  10. 14 0
      src/assets/guanjia.svg
  11. 19 6
      src/components/avatar.vue
  12. 180 91
      src/components/conversation/conversation-item.vue
  13. 12 2
      src/components/conversation/conversation-list.vue
  14. 3 3
      src/components/conversation/conversation-profile.vue
  15. 13 15
      src/components/conversation/conversation-selected-list.vue
  16. 2 2
      src/components/conversation/conversationProfile/group-member-info.vue
  17. 11 11
      src/components/conversation/conversationProfile/group-profile.vue
  18. 5 5
      src/components/conversation/conversationProfile/user-profile.vue
  19. 29 24
      src/components/conversation/current-conversation.vue
  20. 8 4
      src/components/friend/friend-application/application-item.vue
  21. 274 214
      src/components/friend/friend-container.vue
  22. 94 45
      src/components/friend/friend-item.vue
  23. 64 8
      src/components/friend/friend-list.vue
  24. 3 3
      src/components/group-live/components/live-chat.vue
  25. 3 3
      src/components/group-live/components/live-pusher.vue
  26. 6 6
      src/components/group/create-group.vue
  27. 6 6
      src/components/group/group-list.vue
  28. 16 10
      src/components/layout/side-bar.vue
  29. 170 111
      src/components/message/merger-message/mergerMessage-item.vue
  30. 7 6
      src/components/message/merger-message/message-merger.vue
  31. 130 62
      src/components/message/merger-message/message-relay.vue
  32. 30 14
      src/components/message/message-bubble.vue
  33. 32 15
      src/components/message/message-elements/custom-element.vue
  34. 28 20
      src/components/message/message-elements/file-element.vue
  35. 1 1
      src/components/message/message-elements/group-system-notice-element.vue
  36. 7 7
      src/components/message/message-elements/group-tip-element.vue
  37. 4 3
      src/components/message/message-elements/image-element.vue
  38. 1 1
      src/components/message/message-elements/merger-element.vue
  39. 119 74
      src/components/message/message-elements/sound-element.vue
  40. 3 1
      src/components/message/message-elements/text-element.vue
  41. 6 4
      src/components/message/message-footer.vue
  42. 3 3
      src/components/message/message-header.vue
  43. 88 66
      src/components/message/message-item.vue
  44. 427 146
      src/components/message/message-send-box.vue
  45. 637 607
      src/components/message/trtc-calling/calling-index.vue
  46. 6 1
      src/components/message/trtc-calling/group-member-list.vue
  47. 11 10
      src/components/my-profile.vue
  48. 4 4
      src/components/profile-card.vue
  49. 215 33
      src/components/user/login.vue
  50. 10 14
      src/main.js
  51. 3 3
      src/router/index.js
  52. 1 1
      src/store/modules/blacklist.js
  53. 208 62
      src/store/modules/conversation.js
  54. 7 16
      src/store/modules/friend.js
  55. 3 3
      src/store/modules/group.js
  56. 7 5
      src/store/modules/imuser.js
  57. 3 3
      src/store/modules/user.js
  58. 13 13
      src/tim.js
  59. 11 11
      src/trtc-calling.js
  60. 55 55
      src/utils/common.js
  61. 1 1
      src/utils/decodeText.js
  62. 215 1
      src/utils/emojiMap.js
  63. 36 4
      src/utils/im.js
  64. 1 0
      src/utils/request.js
  65. 23 23
      src/utils/rtc-client.js
  66. 13 0
      src/views/components/drugReport/addDrugReport.vue
  67. 1 2
      src/views/components/drugReport/drugReportDetails.vue
  68. 140 140
      src/views/components/msg/followMsgDetails.vue
  69. 141 141
      src/views/components/msg/msgDetails.vue
  70. 37 9
      src/views/components/order/inquiryOrderDetails.vue
  71. 50 3
      src/views/components/order/inquiryOrderList.vue
  72. 3 0
      src/views/components/order/inquiryOrderReportDetails.vue
  73. 230 65
      src/views/im/index.vue
  74. 38 30
      vue.config.js

+ 7 - 4
package.json

@@ -37,6 +37,7 @@
   ],
   "dependencies": {
     "@amap/amap-jsapi-loader": "^1.0.1",
+    "@openim/wasm-client-sdk": "^3.8.3-patch.10",
     "@riophae/vue-treeselect": "0.4.0",
     "axios": "0.21.0",
     "chart.js": "^2.9.4",
@@ -51,12 +52,12 @@
     "js-beautify": "1.13.0",
     "js-cookie": "2.2.1",
     "jsencrypt": "3.0.0-rc.1",
+    "livekit-client": "^2.15.4",
     "mta-h5-analysis": "^2.0.15",
     "nprogress": "0.2.0",
     "quill": "1.3.7",
     "screenfull": "5.0.2",
     "sortablejs": "1.10.2",
-    "tim-js-sdk": "^2.14.0",
     "tim-upload-plugin": "^1.0.4",
     "trtc-calling-js": "^1.0.0",
     "trtc-js-sdk": "^4.7.1",
@@ -84,14 +85,16 @@
     "eslint": "7.15.0",
     "eslint-plugin-vue": "7.2.0",
     "lint-staged": "10.5.3",
-    "runjs": "4.4.2",
     "node-sass": "4.14.1",
+    "runjs": "4.4.2",
     "sass-loader": "8.0.2",
     "script-ext-html-webpack-plugin": "2.1.5",
+    "stylus": "^0.54.7",
+    "stylus-loader": "^3.0.2",
     "svg-sprite-loader": "5.1.1",
     "vue-template-compiler": "2.6.12",
-    "stylus": "^0.54.7",
-    "stylus-loader": "^3.0.2"
+    "worker-loader": "^3.0.8",
+    "worker-plugin": "^5.0.1"
   },
   "engines": {
     "node": ">=8.9",

+ 2 - 1
public/index.html

@@ -1,6 +1,7 @@
 <!DOCTYPE html>
 <html>
   <head>
+    <script src="/wasm_exec.js"></script>
     <meta charset="utf-8">
     <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
     <meta name="renderer" content="webkit">
@@ -205,6 +206,6 @@
 		    <div class="load_title">正在加载系统资源,请耐心等待</div>
         </div>
 	</div>
- 
+
   </body>
 </html>

BIN
public/openIM.wasm


BIN
public/sql-wasm.wasm


+ 561 - 0
public/wasm_exec.js

@@ -0,0 +1,561 @@
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+"use strict";
+
+(() => {
+	const enosys = () => {
+		const err = new Error("not implemented");
+		err.code = "ENOSYS";
+		return err;
+	};
+
+	if (!globalThis.fs) {
+		let outputBuf = "";
+		globalThis.fs = {
+			constants: { O_WRONLY: -1, O_RDWR: -1, O_CREAT: -1, O_TRUNC: -1, O_APPEND: -1, O_EXCL: -1 }, // unused
+			writeSync(fd, buf) {
+				outputBuf += decoder.decode(buf);
+				const nl = outputBuf.lastIndexOf("\n");
+				if (nl != -1) {
+					console.log(outputBuf.substring(0, nl));
+					outputBuf = outputBuf.substring(nl + 1);
+				}
+				return buf.length;
+			},
+			write(fd, buf, offset, length, position, callback) {
+				if (offset !== 0 || length !== buf.length || position !== null) {
+					callback(enosys());
+					return;
+				}
+				const n = this.writeSync(fd, buf);
+				callback(null, n);
+			},
+			chmod(path, mode, callback) { callback(enosys()); },
+			chown(path, uid, gid, callback) { callback(enosys()); },
+			close(fd, callback) { callback(enosys()); },
+			fchmod(fd, mode, callback) { callback(enosys()); },
+			fchown(fd, uid, gid, callback) { callback(enosys()); },
+			fstat(fd, callback) { callback(enosys()); },
+			fsync(fd, callback) { callback(null); },
+			ftruncate(fd, length, callback) { callback(enosys()); },
+			lchown(path, uid, gid, callback) { callback(enosys()); },
+			link(path, link, callback) { callback(enosys()); },
+			lstat(path, callback) { callback(enosys()); },
+			mkdir(path, perm, callback) { callback(enosys()); },
+			open(path, flags, mode, callback) { callback(enosys()); },
+			read(fd, buffer, offset, length, position, callback) { callback(enosys()); },
+			readdir(path, callback) { callback(enosys()); },
+			readlink(path, callback) { callback(enosys()); },
+			rename(from, to, callback) { callback(enosys()); },
+			rmdir(path, callback) { callback(enosys()); },
+			stat(path, callback) { callback(enosys()); },
+			symlink(path, link, callback) { callback(enosys()); },
+			truncate(path, length, callback) { callback(enosys()); },
+			unlink(path, callback) { callback(enosys()); },
+			utimes(path, atime, mtime, callback) { callback(enosys()); },
+		};
+	}
+
+	if (!globalThis.process) {
+		globalThis.process = {
+			getuid() { return -1; },
+			getgid() { return -1; },
+			geteuid() { return -1; },
+			getegid() { return -1; },
+			getgroups() { throw enosys(); },
+			pid: -1,
+			ppid: -1,
+			umask() { throw enosys(); },
+			cwd() { throw enosys(); },
+			chdir() { throw enosys(); },
+		}
+	}
+
+	if (!globalThis.crypto) {
+		throw new Error("globalThis.crypto is not available, polyfill required (crypto.getRandomValues only)");
+	}
+
+	if (!globalThis.performance) {
+		throw new Error("globalThis.performance is not available, polyfill required (performance.now only)");
+	}
+
+	if (!globalThis.TextEncoder) {
+		throw new Error("globalThis.TextEncoder is not available, polyfill required");
+	}
+
+	if (!globalThis.TextDecoder) {
+		throw new Error("globalThis.TextDecoder is not available, polyfill required");
+	}
+
+	const encoder = new TextEncoder("utf-8");
+	const decoder = new TextDecoder("utf-8");
+
+	globalThis.Go = class {
+		constructor() {
+			this.argv = ["js"];
+			this.env = {};
+			this.exit = (code) => {
+				if (code !== 0) {
+					console.warn("exit code:", code);
+				}
+			};
+			this._exitPromise = new Promise((resolve) => {
+				this._resolveExitPromise = resolve;
+			});
+			this._pendingEvent = null;
+			this._scheduledTimeouts = new Map();
+			this._nextCallbackTimeoutID = 1;
+
+			const setInt64 = (addr, v) => {
+				this.mem.setUint32(addr + 0, v, true);
+				this.mem.setUint32(addr + 4, Math.floor(v / 4294967296), true);
+			}
+
+			const setInt32 = (addr, v) => {
+				this.mem.setUint32(addr + 0, v, true);
+			}
+
+			const getInt64 = (addr) => {
+				const low = this.mem.getUint32(addr + 0, true);
+				const high = this.mem.getInt32(addr + 4, true);
+				return low + high * 4294967296;
+			}
+
+			const loadValue = (addr) => {
+				const f = this.mem.getFloat64(addr, true);
+				if (f === 0) {
+					return undefined;
+				}
+				if (!isNaN(f)) {
+					return f;
+				}
+
+				const id = this.mem.getUint32(addr, true);
+				return this._values[id];
+			}
+
+			const storeValue = (addr, v) => {
+				const nanHead = 0x7FF80000;
+
+				if (typeof v === "number" && v !== 0) {
+					if (isNaN(v)) {
+						this.mem.setUint32(addr + 4, nanHead, true);
+						this.mem.setUint32(addr, 0, true);
+						return;
+					}
+					this.mem.setFloat64(addr, v, true);
+					return;
+				}
+
+				if (v === undefined) {
+					this.mem.setFloat64(addr, 0, true);
+					return;
+				}
+
+				let id = this._ids.get(v);
+				if (id === undefined) {
+					id = this._idPool.pop();
+					if (id === undefined) {
+						id = this._values.length;
+					}
+					this._values[id] = v;
+					this._goRefCounts[id] = 0;
+					this._ids.set(v, id);
+				}
+				this._goRefCounts[id]++;
+				let typeFlag = 0;
+				switch (typeof v) {
+					case "object":
+						if (v !== null) {
+							typeFlag = 1;
+						}
+						break;
+					case "string":
+						typeFlag = 2;
+						break;
+					case "symbol":
+						typeFlag = 3;
+						break;
+					case "function":
+						typeFlag = 4;
+						break;
+				}
+				this.mem.setUint32(addr + 4, nanHead | typeFlag, true);
+				this.mem.setUint32(addr, id, true);
+			}
+
+			const loadSlice = (addr) => {
+				const array = getInt64(addr + 0);
+				const len = getInt64(addr + 8);
+				return new Uint8Array(this._inst.exports.mem.buffer, array, len);
+			}
+
+			const loadSliceOfValues = (addr) => {
+				const array = getInt64(addr + 0);
+				const len = getInt64(addr + 8);
+				const a = new Array(len);
+				for (let i = 0; i < len; i++) {
+					a[i] = loadValue(array + i * 8);
+				}
+				return a;
+			}
+
+			const loadString = (addr) => {
+				const saddr = getInt64(addr + 0);
+				const len = getInt64(addr + 8);
+				return decoder.decode(new DataView(this._inst.exports.mem.buffer, saddr, len));
+			}
+
+			const timeOrigin = Date.now() - performance.now();
+			this.importObject = {
+				_gotest: {
+					add: (a, b) => a + b,
+				},
+				gojs: {
+					// Go's SP does not change as long as no Go code is running. Some operations (e.g. calls, getters and setters)
+					// may synchronously trigger a Go event handler. This makes Go code get executed in the middle of the imported
+					// function. A goroutine can switch to a new stack if the current stack is too small (see morestack function).
+					// This changes the SP, thus we have to update the SP used by the imported function.
+
+					// func wasmExit(code int32)
+					"runtime.wasmExit": (sp) => {
+						sp >>>= 0;
+						const code = this.mem.getInt32(sp + 8, true);
+						this.exited = true;
+						delete this._inst;
+						delete this._values;
+						delete this._goRefCounts;
+						delete this._ids;
+						delete this._idPool;
+						this.exit(code);
+					},
+
+					// func wasmWrite(fd uintptr, p unsafe.Pointer, n int32)
+					"runtime.wasmWrite": (sp) => {
+						sp >>>= 0;
+						const fd = getInt64(sp + 8);
+						const p = getInt64(sp + 16);
+						const n = this.mem.getInt32(sp + 24, true);
+						fs.writeSync(fd, new Uint8Array(this._inst.exports.mem.buffer, p, n));
+					},
+
+					// func resetMemoryDataView()
+					"runtime.resetMemoryDataView": (sp) => {
+						sp >>>= 0;
+						this.mem = new DataView(this._inst.exports.mem.buffer);
+					},
+
+					// func nanotime1() int64
+					"runtime.nanotime1": (sp) => {
+						sp >>>= 0;
+						setInt64(sp + 8, (timeOrigin + performance.now()) * 1000000);
+					},
+
+					// func walltime() (sec int64, nsec int32)
+					"runtime.walltime": (sp) => {
+						sp >>>= 0;
+						const msec = (new Date).getTime();
+						setInt64(sp + 8, msec / 1000);
+						this.mem.setInt32(sp + 16, (msec % 1000) * 1000000, true);
+					},
+
+					// func scheduleTimeoutEvent(delay int64) int32
+					"runtime.scheduleTimeoutEvent": (sp) => {
+						sp >>>= 0;
+						const id = this._nextCallbackTimeoutID;
+						this._nextCallbackTimeoutID++;
+						this._scheduledTimeouts.set(id, setTimeout(
+							() => {
+								this._resume();
+								while (this._scheduledTimeouts.has(id)) {
+									// for some reason Go failed to register the timeout event, log and try again
+									// (temporary workaround for https://github.com/golang/go/issues/28975)
+									console.warn("scheduleTimeoutEvent: missed timeout event");
+									this._resume();
+								}
+							},
+							getInt64(sp + 8),
+						));
+						this.mem.setInt32(sp + 16, id, true);
+					},
+
+					// func clearTimeoutEvent(id int32)
+					"runtime.clearTimeoutEvent": (sp) => {
+						sp >>>= 0;
+						const id = this.mem.getInt32(sp + 8, true);
+						clearTimeout(this._scheduledTimeouts.get(id));
+						this._scheduledTimeouts.delete(id);
+					},
+
+					// func getRandomData(r []byte)
+					"runtime.getRandomData": (sp) => {
+						sp >>>= 0;
+						crypto.getRandomValues(loadSlice(sp + 8));
+					},
+
+					// func finalizeRef(v ref)
+					"syscall/js.finalizeRef": (sp) => {
+						sp >>>= 0;
+						const id = this.mem.getUint32(sp + 8, true);
+						this._goRefCounts[id]--;
+						if (this._goRefCounts[id] === 0) {
+							const v = this._values[id];
+							this._values[id] = null;
+							this._ids.delete(v);
+							this._idPool.push(id);
+						}
+					},
+
+					// func stringVal(value string) ref
+					"syscall/js.stringVal": (sp) => {
+						sp >>>= 0;
+						storeValue(sp + 24, loadString(sp + 8));
+					},
+
+					// func valueGet(v ref, p string) ref
+					"syscall/js.valueGet": (sp) => {
+						sp >>>= 0;
+						const result = Reflect.get(loadValue(sp + 8), loadString(sp + 16));
+						sp = this._inst.exports.getsp() >>> 0; // see comment above
+						storeValue(sp + 32, result);
+					},
+
+					// func valueSet(v ref, p string, x ref)
+					"syscall/js.valueSet": (sp) => {
+						sp >>>= 0;
+						Reflect.set(loadValue(sp + 8), loadString(sp + 16), loadValue(sp + 32));
+					},
+
+					// func valueDelete(v ref, p string)
+					"syscall/js.valueDelete": (sp) => {
+						sp >>>= 0;
+						Reflect.deleteProperty(loadValue(sp + 8), loadString(sp + 16));
+					},
+
+					// func valueIndex(v ref, i int) ref
+					"syscall/js.valueIndex": (sp) => {
+						sp >>>= 0;
+						storeValue(sp + 24, Reflect.get(loadValue(sp + 8), getInt64(sp + 16)));
+					},
+
+					// valueSetIndex(v ref, i int, x ref)
+					"syscall/js.valueSetIndex": (sp) => {
+						sp >>>= 0;
+						Reflect.set(loadValue(sp + 8), getInt64(sp + 16), loadValue(sp + 24));
+					},
+
+					// func valueCall(v ref, m string, args []ref) (ref, bool)
+					"syscall/js.valueCall": (sp) => {
+						sp >>>= 0;
+						try {
+							const v = loadValue(sp + 8);
+							const m = Reflect.get(v, loadString(sp + 16));
+							const args = loadSliceOfValues(sp + 32);
+							const result = Reflect.apply(m, v, args);
+							sp = this._inst.exports.getsp() >>> 0; // see comment above
+							storeValue(sp + 56, result);
+							this.mem.setUint8(sp + 64, 1);
+						} catch (err) {
+							sp = this._inst.exports.getsp() >>> 0; // see comment above
+							storeValue(sp + 56, err);
+							this.mem.setUint8(sp + 64, 0);
+						}
+					},
+
+					// func valueInvoke(v ref, args []ref) (ref, bool)
+					"syscall/js.valueInvoke": (sp) => {
+						sp >>>= 0;
+						try {
+							const v = loadValue(sp + 8);
+							const args = loadSliceOfValues(sp + 16);
+							const result = Reflect.apply(v, undefined, args);
+							sp = this._inst.exports.getsp() >>> 0; // see comment above
+							storeValue(sp + 40, result);
+							this.mem.setUint8(sp + 48, 1);
+						} catch (err) {
+							sp = this._inst.exports.getsp() >>> 0; // see comment above
+							storeValue(sp + 40, err);
+							this.mem.setUint8(sp + 48, 0);
+						}
+					},
+
+					// func valueNew(v ref, args []ref) (ref, bool)
+					"syscall/js.valueNew": (sp) => {
+						sp >>>= 0;
+						try {
+							const v = loadValue(sp + 8);
+							const args = loadSliceOfValues(sp + 16);
+							const result = Reflect.construct(v, args);
+							sp = this._inst.exports.getsp() >>> 0; // see comment above
+							storeValue(sp + 40, result);
+							this.mem.setUint8(sp + 48, 1);
+						} catch (err) {
+							sp = this._inst.exports.getsp() >>> 0; // see comment above
+							storeValue(sp + 40, err);
+							this.mem.setUint8(sp + 48, 0);
+						}
+					},
+
+					// func valueLength(v ref) int
+					"syscall/js.valueLength": (sp) => {
+						sp >>>= 0;
+						setInt64(sp + 16, parseInt(loadValue(sp + 8).length));
+					},
+
+					// valuePrepareString(v ref) (ref, int)
+					"syscall/js.valuePrepareString": (sp) => {
+						sp >>>= 0;
+						const str = encoder.encode(String(loadValue(sp + 8)));
+						storeValue(sp + 16, str);
+						setInt64(sp + 24, str.length);
+					},
+
+					// valueLoadString(v ref, b []byte)
+					"syscall/js.valueLoadString": (sp) => {
+						sp >>>= 0;
+						const str = loadValue(sp + 8);
+						loadSlice(sp + 16).set(str);
+					},
+
+					// func valueInstanceOf(v ref, t ref) bool
+					"syscall/js.valueInstanceOf": (sp) => {
+						sp >>>= 0;
+						this.mem.setUint8(sp + 24, (loadValue(sp + 8) instanceof loadValue(sp + 16)) ? 1 : 0);
+					},
+
+					// func copyBytesToGo(dst []byte, src ref) (int, bool)
+					"syscall/js.copyBytesToGo": (sp) => {
+						sp >>>= 0;
+						const dst = loadSlice(sp + 8);
+						const src = loadValue(sp + 32);
+						if (!(src instanceof Uint8Array || src instanceof Uint8ClampedArray)) {
+							this.mem.setUint8(sp + 48, 0);
+							return;
+						}
+						const toCopy = src.subarray(0, dst.length);
+						dst.set(toCopy);
+						setInt64(sp + 40, toCopy.length);
+						this.mem.setUint8(sp + 48, 1);
+					},
+
+					// func copyBytesToJS(dst ref, src []byte) (int, bool)
+					"syscall/js.copyBytesToJS": (sp) => {
+						sp >>>= 0;
+						const dst = loadValue(sp + 8);
+						const src = loadSlice(sp + 16);
+						if (!(dst instanceof Uint8Array || dst instanceof Uint8ClampedArray)) {
+							this.mem.setUint8(sp + 48, 0);
+							return;
+						}
+						const toCopy = src.subarray(0, dst.length);
+						dst.set(toCopy);
+						setInt64(sp + 40, toCopy.length);
+						this.mem.setUint8(sp + 48, 1);
+					},
+
+					"debug": (value) => {
+						console.log(value);
+					},
+				}
+			};
+		}
+
+		async run(instance) {
+			if (!(instance instanceof WebAssembly.Instance)) {
+				throw new Error("Go.run: WebAssembly.Instance expected");
+			}
+			this._inst = instance;
+			this.mem = new DataView(this._inst.exports.mem.buffer);
+			this._values = [ // JS values that Go currently has references to, indexed by reference id
+				NaN,
+				0,
+				null,
+				true,
+				false,
+				globalThis,
+				this,
+			];
+			this._goRefCounts = new Array(this._values.length).fill(Infinity); // number of references that Go has to a JS value, indexed by reference id
+			this._ids = new Map([ // mapping from JS values to reference ids
+				[0, 1],
+				[null, 2],
+				[true, 3],
+				[false, 4],
+				[globalThis, 5],
+				[this, 6],
+			]);
+			this._idPool = [];   // unused ids that have been garbage collected
+			this.exited = false; // whether the Go program has exited
+
+			// Pass command line arguments and environment variables to WebAssembly by writing them to the linear memory.
+			let offset = 4096;
+
+			const strPtr = (str) => {
+				const ptr = offset;
+				const bytes = encoder.encode(str + "\0");
+				new Uint8Array(this.mem.buffer, offset, bytes.length).set(bytes);
+				offset += bytes.length;
+				if (offset % 8 !== 0) {
+					offset += 8 - (offset % 8);
+				}
+				return ptr;
+			};
+
+			const argc = this.argv.length;
+
+			const argvPtrs = [];
+			this.argv.forEach((arg) => {
+				argvPtrs.push(strPtr(arg));
+			});
+			argvPtrs.push(0);
+
+			const keys = Object.keys(this.env).sort();
+			keys.forEach((key) => {
+				argvPtrs.push(strPtr(`${key}=${this.env[key]}`));
+			});
+			argvPtrs.push(0);
+
+			const argv = offset;
+			argvPtrs.forEach((ptr) => {
+				this.mem.setUint32(offset, ptr, true);
+				this.mem.setUint32(offset + 4, 0, true);
+				offset += 8;
+			});
+
+			// The linker guarantees global data starts from at least wasmMinDataAddr.
+			// Keep in sync with cmd/link/internal/ld/data.go:wasmMinDataAddr.
+			const wasmMinDataAddr = 4096 + 8192;
+			if (offset >= wasmMinDataAddr) {
+				throw new Error("total length of command line and environment variables exceeds limit");
+			}
+
+			this._inst.exports.run(argc, argv);
+			if (this.exited) {
+				this._resolveExitPromise();
+			}
+			await this._exitPromise;
+		}
+
+		_resume() {
+			if (this.exited) {
+				throw new Error("Go program has already exited");
+			}
+			this._inst.exports.resume();
+			if (this.exited) {
+				this._resolveExitPromise();
+			}
+		}
+
+		_makeFuncWrapper(id) {
+			const go = this;
+			return function () {
+				const event = { id: id, this: this, args: arguments };
+				go._pendingEvent = event;
+				go._resume();
+				return event.result;
+			};
+		}
+	}
+})();

+ 7 - 0
src/api/doctor.js

@@ -14,6 +14,13 @@ export function login(account, password,type,code,uuid) {
     data: data
   })
 }
+export function accountCheck(userId) {
+  return request({
+    url: '/app/doctor/accountCheck',
+    method: 'post',
+    data: { userId: userId }
+  })
+}
 export function getDoctorDetails() {
   return request({
     url: '/app/doctor/getDoctorDetails',

+ 14 - 1
src/api/inquiryOrder.js

@@ -9,6 +9,13 @@ export function getInquiryOrderList(query) {
     params: query
   })
 }
+export function getInquiryOrderListByUser(query) {
+  return request({
+    url: '/app/inquiryOrder/getInquiryOrderListByUser',
+    method: 'get',
+    params: query
+  })
+}
 export function getCompanyList() {
   return request({
     url: '/app/inquiryOrder/getCompanyList',
@@ -52,7 +59,13 @@ export function getInquiryOrderReport(orderId) {
     }
   })
 }
-
+export function exportOrder(query) {
+  return request({
+    url: '/app/inquiryOrder/export',
+    method: 'get',
+    params: query
+  })
+}
 //接单
 export function receiveOrder(data) {
   return request({

BIN
src/assets/audio/beCalled.mp3


+ 48 - 0
src/assets/doctor.svg

@@ -0,0 +1,48 @@
+<svg width="60" height="61" viewBox="0 0 60 61" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g id="&#229;&#140;&#187;&#231;&#148;&#159;">
+<path id="Vector" d="M30 60C13.43 60 0 46.57 0 30C0 13.43 13.43 0 30 0C46.57 0 60 13.43 60 30C60 46.57 46.57 60 30 60ZM30 4C15.64 4 4 15.64 4 30C4 44.36 15.64 56 30 56C44.36 56 56 44.36 56 30C56 15.64 44.36 4 30 4Z" fill="url(#paint0_linear_2111_3396)"/>
+<g id="Vector_2">
+<mask id="path-2-inside-1_2111_3396" fill="white">
+<path d="M59 30C59 13.98 46.02 1 30 1C13.98 1 1 13.98 1 30C1 46.02 13.98 59 30 59V60C13.43 60 0 46.57 0 30C0 13.43 13.43 0 30 0C46.57 0 60 13.43 60 30C60 46.57 46.57 60 30 60V59C46.02 59 59 46.02 59 30Z"/>
+</mask>
+<path d="M59 30C59 13.98 46.02 1 30 1C13.98 1 1 13.98 1 30C1 46.02 13.98 59 30 59V60C13.43 60 0 46.57 0 30C0 13.43 13.43 0 30 0C46.57 0 60 13.43 60 30C60 46.57 46.57 60 30 60V59C46.02 59 59 46.02 59 30Z" fill="url(#paint1_linear_2111_3396)"/>
+<path d="M30 59H29.5V60H30H30.5V59H30ZM59 30H60C60 13.4277 46.5723 0 30 0V1V2C45.4677 2 58 14.5323 58 30H59ZM30 1V0C13.4277 0 0 13.4277 0 30H1H2C2 14.5323 14.5323 2 30 2V1ZM1 30H0C0 46.5723 13.4277 60 30 60V59V58C14.5323 58 2 45.4677 2 30H1ZM30 60V59C13.9823 59 1 46.0177 1 30H0H-1C-1 47.1223 12.8777 61 30 61V60ZM0 30H1C1 13.9823 13.9823 1 30 1V0V-1C12.8777 -1 -1 12.8777 -1 30H0ZM30 0V1C46.0177 1 59 13.9823 59 30H60H61C61 12.8777 47.1223 -1 30 -1V0ZM60 30H59C59 46.0177 46.0177 59 30 59V60V61C47.1223 61 61 47.1223 61 30H60ZM30 59V60C46.5723 60 60 46.5723 60 30H59H58C58 45.4677 45.4677 58 30 58V59Z" fill="url(#paint2_linear_2111_3396)" mask="url(#path-2-inside-1_2111_3396)"/>
+</g>
+<path id="Vector_3" d="M30 58C14.54 58 2 45.46 2 30C2 14.54 14.54 2 30 2C45.46 2 58 14.54 58 30C58 45.46 45.46 58 30 58ZM30 4C15.64 4 4 15.64 4 30C4 44.36 15.64 56 30 56C44.36 56 56 44.36 56 30C56 15.64 44.36 4 30 4Z" fill="url(#paint3_linear_2111_3396)"/>
+<path id="Vector_4" d="M57 30C57 15.09 44.91 3 30 3C15.09 3 3 15.09 3 30C3 44.91 15.09 57 30 57V58C14.54 58 2 45.46 2 30C2 14.54 14.54 2 30 2C45.46 2 58 14.54 58 30C58 45.46 45.46 58 30 58V57C44.91 57 57 44.91 57 30Z" fill="url(#paint4_linear_2111_3396)"/>
+<path id="Vector_5" d="M18.8499 46H39.0899C39.9999 46 40.8299 46.49 41.2699 47.28L41.3499 47.44L45.5499 56.44C46.3199 58.1 45.1099 60 43.2799 60H15.3699C13.6099 60 12.4099 58.24 13.0399 56.6L16.5099 47.6C16.8799 46.64 17.8099 46 18.8399 46H18.8499Z" fill="url(#paint5_linear_2111_3396)" stroke="url(#paint6_linear_2111_3396)"/>
+<path id="Vector_6" d="M24.6502 51.9299C24.4202 52.2899 24.1602 52.5899 23.8802 52.8399L23.2402 52.2499C23.8202 51.7299 24.2402 51.0999 24.4902 50.3599L25.2602 50.5799C25.1902 50.7899 25.1202 50.9799 25.0402 51.1599H28.4802V51.9299H26.6202V52.3299C26.6002 52.5499 26.5802 52.7599 26.5602 52.9599H29.0202V53.7599H26.3902C26.2602 54.1699 26.0802 54.5299 25.8602 54.8399C25.4102 55.4099 24.6802 55.8499 23.6602 56.1699L23.2002 55.4499C24.1902 55.1399 24.8602 54.7499 25.2302 54.2799C25.3402 54.1199 25.4402 53.9399 25.5102 53.7599H23.2502V52.9599H25.7302C25.7702 52.7499 25.7802 52.5499 25.7902 52.3299V51.9299H24.6502ZM26.7002 54.0999C27.5402 54.4599 28.3002 54.9099 29.0002 55.4399L28.5302 56.1599C27.7902 55.5499 27.0402 55.0699 26.2602 54.7199L26.6902 54.0999H26.7002ZM21.9502 49.4199H29.1602V50.2199H22.7702V56.2999H29.4502V57.1199H21.9502V49.4199ZM32.2602 51.5399C31.9002 52.3499 31.4502 53.0199 30.9002 53.5599L30.3402 52.8499C31.1502 51.9999 31.7002 50.8399 31.9902 49.3899L32.8602 49.5399C32.7702 49.9499 32.6702 50.3399 32.5602 50.6999H34.2302V49.1899H35.0802V50.6999H37.9702V51.5299H35.0802V53.3899H37.7902V54.2199H35.0802V56.2699H38.5502V57.1199H30.5702V56.2699H34.2302V54.2199H31.6602V53.3899H34.2302V51.5299H32.2502L32.2602 51.5399Z" fill="#D38307"/>
+</g>
+<defs>
+<linearGradient id="paint0_linear_2111_3396" x1="21.91" y1="1.82" x2="37.95" y2="57.72" gradientUnits="userSpaceOnUse">
+<stop stop-color="#FFC737"/>
+<stop offset="0.5" stop-color="#FFDD64"/>
+<stop offset="0.98" stop-color="#CF7C00"/>
+</linearGradient>
+<linearGradient id="paint1_linear_2111_3396" x1="13.9568" y1="4.10072" x2="30" y2="60" gradientUnits="userSpaceOnUse">
+<stop stop-color="#FFC737"/>
+<stop offset="0.501018" stop-color="#FFDD64"/>
+<stop offset="0.979167" stop-color="#CF7C00"/>
+</linearGradient>
+<linearGradient id="paint2_linear_2111_3396" x1="30" y1="0" x2="30" y2="60" gradientUnits="userSpaceOnUse">
+<stop stop-color="#FFF5DA"/>
+<stop offset="0.245067" stop-color="white" stop-opacity="0"/>
+</linearGradient>
+<linearGradient id="paint3_linear_2111_3396" x1="21.91" y1="1.82" x2="37.95" y2="57.72" gradientUnits="userSpaceOnUse">
+<stop stop-color="#FFB800"/>
+<stop offset="1" stop-color="#FFE195"/>
+</linearGradient>
+<linearGradient id="paint4_linear_2111_3396" x1="30" y1="2" x2="30" y2="58" gradientUnits="userSpaceOnUse">
+<stop stop-color="#FFD874"/>
+<stop offset="1" stop-color="#FFEDBF"/>
+</linearGradient>
+<linearGradient id="paint5_linear_2111_3396" x1="15.8799" y1="48.99" x2="55.5699" y2="63" gradientUnits="userSpaceOnUse">
+<stop stop-color="#FFE6A8"/>
+<stop offset="1" stop-color="#FFBA08"/>
+</linearGradient>
+<linearGradient id="paint6_linear_2111_3396" x1="34.9999" y1="39.11" x2="30.3899" y2="54.08" gradientUnits="userSpaceOnUse">
+<stop stop-color="white" stop-opacity="0.55"/>
+<stop offset="1" stop-color="white" stop-opacity="0"/>
+</linearGradient>
+</defs>
+</svg>

File diff suppressed because it is too large
+ 14 - 0
src/assets/guanjia.svg


+ 19 - 6
src/components/avatar.vue

@@ -6,18 +6,31 @@
 
 <script>
 import systemAvatar from '@/assets/image/system.png'
+import { getOpenIM } from '@/utils/openIM';
 export default {
+  data:{
+    return:{
+      OpenIM: null,
+    }
+  },
   props: {
     src: String,
     type: {
       type: String,
-      default: 'C2C'
+      default: '1'
     },
     shape: {
       type: String,
       default: 'circle'
     }
   },
+  async created() {
+    try {
+      this.OpenIM = getOpenIM()
+    } catch (e) {
+      console.error('OpenIM 获取失败', e)
+    }
+  },
   computed: {
     avatarSrc: function () {
       let src = this.src
@@ -29,13 +42,13 @@ export default {
     },
     defaultSrc: function () {
       switch(this.type) {
-        case 'C2C':
+        case 1:
           // 个人头像
           return 'https://imgcache.qq.com/open/qcloud/video/act/webim-avatar/avatar-2.png'
-        case 'GROUP':
+        case 3:
           // 群默认头像
           return 'https://imgcache.qq.com/open/qcloud/video/act/webim-avatar/avatar-3.png'
-        case this.TIM.TYPES.CONV_SYSTEM:
+        case 4:
           return systemAvatar
         default:
           // 默认头像
@@ -47,13 +60,13 @@ export default {
 </script>
 
 <style lang="stylus" scoped>
-.avatar 
+.avatar
   background-color $first
   text-align center
   width 100%
   height 100%
   overflow hidden
-  img 
+  img
     width 100%
     height 100%
 .shape-circle

+ 180 - 91
src/components/conversation/conversation-item.vue

@@ -8,21 +8,24 @@
         <span class="tim-icon-close" title="删除会话" @click="deleteConversation"></span>
       </div>
       <div class="warp">
-        <avatar :src="avatar" :type="conversation.type" />
+        <div class="avatar-wrapper">
+          <avatar :src="avatar" :type="conversation.faceURL" class="avatar" />
+          <img v-if="avatarBorder" :src="avatarBorder" class="avatar-border" />
+        </div>
         <div class="c-content">
           <div class="row-1">
             <div class="name">
               <div class="text-ellipsis">
-                <span :title="conversation.userProfile.nick || conversation.userProfile.userID"
-                  v-if="conversation.type ===  TIM.TYPES.CONV_C2C"
-                  >{{conversation.remark || conversation.userProfile.nick || conversation.userProfile.userID}}
+                <span :title="conversation.showName || conversation.userID"
+                      v-if="conversation.conversationType ===  1"
+                >{{conversation.remark || conversation.showName || conversation.userID}}
                 </span>
-                <span :title="conversation.groupProfile.name || conversation.groupProfile.groupID"
+<!--                <span :title="conversation.groupProfile.name || conversation.groupProfile.groupID"
                   v-else-if="conversation.type ===  TIM.TYPES.CONV_GROUP"
                   >{{conversation.groupProfile.name || conversation.groupProfile.groupID}}
-                </span>
+                </span>-->
                 <span
-                  v-else-if="conversation.type === TIM.TYPES.CONV_SYSTEM"
+                  v-else-if="conversation.conversationType === 4"
                   >系统通知
                 </span>
               </div>
@@ -35,10 +38,10 @@
           </div>
           <div class="row-2">
             <div class="summary">
-              <div v-if="conversation.lastMessage" class="text-ellipsis">
-                <span class="remind"  v-if="hasMessageAtMe">{{messageAtMeText}}</span>
-                <span class="text" :title="conversation.lastMessage.messageForShow">
-                  {{messageForShow}}
+              <div v-if="conversation.conversationID" class="text-ellipsis">
+                <span class="remind" v-if="hasMessageAtMe">{{ messageAtMeText }}</span>
+                <span class="text" :title="messageForShow">
+                  {{ messageForShow }}
                 </span>
               </div>
             </div>
@@ -55,16 +58,30 @@
 <script>
 import { mapGetters, mapState } from 'vuex'
 import { isToday, getDate, getTime } from '../../utils/date'
+import { getOpenIM } from '@/utils/openIM';
+import doctorBorder from '@/assets/doctor.svg'
+import guanjiaBorder from '@/assets/guanjia.svg'
+
 export default {
   name: 'conversation-item',
   props: ['conversation'],
   data() {
     return {
       popoverVisible: false,
-      showMessageAtMe_text:''
+      showMessageAtMe_text:'',
+      OpenIM: null,
+      lastMsg : {},
     }
   },
   computed: {
+    avatarBorder() {
+      if (this.conversation.userID?.startsWith('D')) {
+        return doctorBorder
+      } else if (this.conversation.userID?.startsWith('C')) {
+        return guanjiaBorder
+      }
+      return null
+    },
     hasMessageAtMe() {
       return (
               this.currentConversation.conversationID !==
@@ -75,13 +92,13 @@ export default {
       let text = ''
       if (this.conversation.groupAtInfoList.length > 0) {
         this.conversation.groupAtInfoList.forEach((item) => {
-          if (item.atTypeArray[0] === this.TIM.TYPES.CONV_AT_ME) {
+          if (item.atTypeArray[0] === 1) {
             text.indexOf('[@所有人]') !== -1 ? text = '[@所有人][有人@我]' : text = '[有人@我]'
           }
-          if (item.atTypeArray[0] === this.TIM.TYPES.CONV_AT_ALL) {
+          if (item.atTypeArray[0] === 2) {
             text.indexOf('[有人@我]') !== -1 ? text = '[有人@我][@所有人]' : text = '[@所有人]'
           }
-          if (item.atTypeArray[0] === this.TIM.TYPES.CONV_AT_ALL_AT_ME) {
+          if (item.atTypeArray[0] === 3) {
             text = '[@所有人][有人@我]'
           }
         })
@@ -100,41 +117,41 @@ export default {
     },
     date() {
       if (
-        !this.conversation.lastMessage ||
-        !this.conversation.lastMessage.lastTime
+        !this.conversation.latestMsg ||
+        !this.conversation.latestMsgSendTime
       ) {
         return ''
       }
-      const date = new Date(this.conversation.lastMessage.lastTime * 1000)
+      const date = new Date(this.conversation.latestMsgSendTime)
       if (isToday(date)) {
         return getTime(date)
       }
       return getDate(date)
     },
     avatar: function() {
-      switch (this.conversation.type) {
-        case 'GROUP':
-          return this.conversation.groupProfile.avatar
-        case 'C2C':
-          return this.conversation.userProfile.avatar
+      switch (this.conversation.conversationType) {
+        case 3:
+          return this.conversation.faceURL
+        case 1:
+          return this.conversation.faceURL
         default:
           return ''
       }
     },
     conversationName: function() {
-      if (this.conversation.type === this.TIM.TYPES.CONV_C2C) {
-        return this.conversation.userProfile.nick || this.conversation.userProfile.userID
+      if (this.conversation.conversationType === 1) {
+        return this.conversation.showName || this.conversation.userID
       }
-      if (this.conversation.type === this.TIM.TYPES.CONV_GROUP) {
+      if (this.conversation.conversationType === 3) {
         return this.conversation.groupProfile.name || this.conversation.groupProfile.groupID
       }
-      if (this.conversation.type === this.TIM.TYPES.CONV_SYSTEM) {
+      if (this.conversation.conversationType === 4) {
         return '系统通知'
       }
       return ''
     },
     showGrayBadge() {
-      if (this.conversation.type !== this.TIM.TYPES.CONV_GROUP) {
+      if (this.conversation.conversationType !== 4) {
         return false
       }
       return (
@@ -143,40 +160,82 @@ export default {
       )
     },
     messageForShow() {
-      if (this.conversation.lastMessage.isRevoked) {
-        // if (this.conversation.lastMessage.fromAccount === this.currentUserProfile.userID) {
-        //   return '你撤回了一条消息'
-        // }
-        if (this.conversation.type === this.TIM.TYPES.CONV_C2C) {
+      this.lastMsg = JSON.parse(this.conversation.latestMsg)
+      /*if (this.lastMsg.contentType === 2101) {
+        if (this.lastMsg.sendID === this.$store.getters.userID) {
+          return '你撤回了一条消息'
+        }
+        if (this.lastMsg.sessionType === 1) {
           return '对方撤回了一条消息'
         }
-        return `${this.conversation.lastMessage.fromAccount}撤回了一条消息`
+        return `${this.lastMsg.sendID}撤回了一条消息`
+      }*/
+      let text = ''
+      switch (this.lastMsg.contentType) {
+        case 2101:
+          if (this.lastMsg.sendID === this.$store.getters.userID) {
+            return '你撤回了一条消息'
+          }
+          if (this.lastMsg.sessionType === 1) {
+            return '对方撤回了一条消息'
+          }
+          return `${this.lastMsg.sendID}撤回了一条消息`
+        case 101:
+          text = this.lastMsg.textElem.content || ''
+          if (text.length > 20) {
+            text = text.slice(0, 20)
+          }
+          return text
+        case 107:
+          return '[聊天记录]'
+        case 102:
+          return '[图片]'
+        case 103:
+          return '[音频]'
+        case 104:
+          return '[视频]'
+        case 110:
+          return '[自定义消息]'
+        case 105:
+          return '[文件]'
+        case 115:
+          return '[动画表情]'
+        case 1701:
+          return '[阅后即焚]'
+        case 1201:
+          return '[成为好友通知]'
+        case 114:
+          return '[引用消息]'
       }
-      return this.conversation.lastMessage.messageForShow
+      //return  this.lastMsg.textElem.content
     },
     ...mapState({
       currentConversation: state => state.conversation.currentConversation,
-      currentUserProfile: state => state.user.currentUserProfile
+      currentUserProfile: state => state.user.currentUserProfile,
+      userID: state => state.imuser.userID,
     }),
     ...mapGetters(['toAccount'])
   },
   mounted() {
-
+    this.OpenIM = getOpenIM()
   },
   methods: {
     selectConversation() {
+      //console.log("this.currentConversation.conversationID"+this.currentConversation.conversationID)
       if (this.conversation.conversationID !== this.currentConversation.conversationID) {
+        console.log("用户id"+this.conversation.userID)
+        console.log("会话类型"+this.conversation.conversationType)
         this.$store.dispatch(
           'checkoutConversation',
-          this.conversation.conversationID
+          this.conversation,
         )
       }
     },
     deleteConversation(event) {
       // 停止冒泡,避免和点击会话的事件冲突
       event.stopPropagation()
-      this.tim
-        .deleteConversation(this.conversation.conversationID)
+      this.OpenIM
+        .deleteConversationAndDeleteAllMsg(this.conversation.conversationID)
         .then(() => {
           this.$store.commit('showMessage', {
             message: `会话【${this.conversationName}】删除成功!`,
@@ -201,28 +260,50 @@ export default {
 </script>
 
 <style lang="stylus" scoped>
-.conversation-item-container
-  padding 15px 20px
-  cursor pointer
-  position relative
-  overflow hidden
-  transition .2s
-  // &:first-child
-  //   padding-top 30px
-  &:hover
-    background-color $background
-    .close-btn
-      right 3px
+  .avatar-wrapper
+    position relative
+    width 40px
+    height 40px
+    margin-right 10px
+    flex-shrink 0
+
+  .avatar
+    width 100%
+    height 100%
+    border-radius 50%
+    display block
+
+  .avatar-border
+    position absolute
+    top 0
+    left 0
+    width 100%
+    height 100%
+    pointer-events none
+
+  .conversation-item-container
+    padding 15px 20px
+    cursor pointer
+    position relative
+    overflow hidden
+    transition .2s
+    &:hover
+      background-color $background
+      .close-btn
+        right 3px
+
   .close-btn
     position absolute
     right -20px
     top 3px
     color $font-dark
-    transition: all .2s ease;
-    &:hover
-      color $danger
+    transition all .2s ease
+     &:hover
+       color $danger
+
   .warp
     display flex
+
   .avatar
     width 40px
     height 40px
@@ -233,53 +314,61 @@ export default {
     flex 1
     height 40px
     overflow hidden
+
     .row-1
       display flex
       line-height 21px
-      .name
-        color $font-light
-        flex 1
-        min-width 0px
-      .unread-count
-        padding-left 10px
-        flex-shrink 0
-        color $font-dark
-        font-size 12px
-        .badge
-          vertical-align bottom
-          background-color $danger
-          border-radius 10px
-          color #FFF
-          display inline-block
-          font-size 12px
-          height 18px
-          max-width 40px
-          line-height 18px
-          padding 0 6px
-          text-align center
-          white-space nowrap
+
+       .name
+         color $font-light
+         flex 1
+         min-width 0px
+
+       .unread-count
+         padding-left 10px
+         flex-shrink 0
+         color $font-dark
+         font-size 12px
+
+         .badge
+           vertical-align bottom
+           background-color $danger
+           border-radius 10px
+           color #FFF
+           display inline-block
+           font-size 12px
+           height 18px
+           max-width 40px
+           line-height 18px
+           padding 0 6px
+           text-align center
+           white-space nowrap
+
     .row-2
       display flex
       font-size 12px
       padding-top 3px
+
       .summary
         flex 1
         overflow hidden
         min-width 0px
-        color: $secondary
+        color $secondary
+
         .remind
           color $danger
-      .date
-        padding-left 10px
-        flex-shrink 0
-        text-align right
-        color $font-dark
-.choose {
-  background-color: $background;
-}
-.context-menu-button {
-  padding: 10px
-  border: 2px solid $primary;
-  border-radius: 8px;
-}
+
+        .date
+          padding-left 10px
+          flex-shrink 0
+          text-align right
+          color $font-dark
+
+    .choose
+     background-color $background
+
+    .context-menu-button
+      padding 10px
+      border 2px solid $primary
+      border-radius 8px
 </style>

+ 12 - 2
src/components/conversation/conversation-list.vue

@@ -28,6 +28,7 @@
 <script>
 import ConversationItem from './conversation-item'
 import { mapState } from 'vuex'
+import { getOpenIM } from '@/utils/openIM';
 export default {
   name: 'ConversationList',
   components: { ConversationItem },
@@ -36,7 +37,11 @@ export default {
       showDialog: false,
       userID: '',
       isCheckouting: false, // 是否正在切换会话
-      timeout: null
+      timeout: null,
+      OpenIM: null,
+      conversationList1:[
+
+      ]
     }
   },
   computed: {
@@ -51,6 +56,9 @@ export default {
   destroyed() {
     window.removeEventListener('keydown', this.handleKeydown)
   },
+  created() {
+    this.OpenIM = getOpenIM()
+  },
   methods: {
     handleRefresh() {
       this.refreshConversation()()
@@ -61,7 +69,9 @@ export default {
         if (!that.timeout) {
           that.timeout = setTimeout(() =>{
             that.timeout = null
-            that.tim.getConversationList().then(() => {
+            that.OpenIM.getAllConversationList().then(({data}) => {
+              console.log("分页获取会话",data)
+              that.$store.commit('updateConversationList', data)
               that.$store.commit('showMessage', {
                 message: '刷新成功',
                 type: 'success'

+ 3 - 3
src/components/conversation/conversation-profile.vue

@@ -1,11 +1,11 @@
 <template>
   <div class="conversation-profile-wrapper">
     <user-profile
-      v-if="currentConversation.type === TIM.TYPES.CONV_C2C"
+      v-if="currentConversation.type === 1"
       :userProfile="currentConversation.userProfile"
     />
     <group-profile
-      v-else-if="currentConversation.type === TIM.TYPES.CONV_GROUP"
+      v-else-if="currentConversation.type === 3"
       :groupProfile="currentConversation.groupProfile"
     />
   </div>
@@ -33,7 +33,7 @@ export default {
 </script>
 
 <style lang="stylus" scoped>
-.conversation-profile-wrapper 
+.conversation-profile-wrapper
   background-color $white
   height 100%
   overflow-y scroll

+ 13 - 15
src/components/conversation/conversation-selected-list.vue

@@ -15,18 +15,16 @@
                                     <div class="row-1">
                                         <div class="name">
                                             <div class="text-ellipsis">
-                <span :title="conversation.userProfile.nick || conversation.userProfile.userID"
-                      v-if="conversation.type ===  TIM.TYPES.CONV_C2C"
-                >{{conversation.userProfile.nick || conversation.userProfile.userID}}
+                <span :title="conversation.showName || conversation.userID"
+                      v-if="conversation.conversationType ===  1"
+                >{{conversation.showName || conversation.userID}}
                 </span>
-                                                <span :title="conversation.groupProfile.name || conversation.groupProfile.groupID"
-                                                      v-else-if="conversation.type ===  TIM.TYPES.CONV_GROUP"
-                                                >{{conversation.groupProfile.name || conversation.groupProfile.groupID}}
-                </span>
-                                                <span
-                                                        v-else-if="conversation.type === TIM.TYPES.CONV_SYSTEM"
-                                                >系统通知
+                <!--<span :title="conversation.groupProfile.name || conversation.groupProfile.groupID" v-else-if="conversation.conversationType === 3">
+                  {{conversation.groupProfile.name || conversation.groupProfile.groupID}}
                 </span>
+                <span v-else-if="conversation.conversationType === 4" >
+                  系统通知
+                </span>-->
                                             </div>
                                         </div>
                                     </div>
@@ -69,11 +67,11 @@
       },
       avatar() {
         return function (conversation) {
-          switch (conversation.type) {
-            case 'GROUP':
-              return conversation.groupProfile.avatar
-            case 'C2C':
-              return conversation.userProfile.avatar
+          switch (conversation.conversationType) {
+            case 3:
+              return conversation.faceURL
+            case 1:
+              return conversation.faceURL
             default:
               return ''
           }

+ 2 - 2
src/components/conversation/conversationProfile/group-member-info.vue

@@ -110,7 +110,7 @@ export default {
     showCancelBan() {
       if (
         this.showMuteUntil &&
-        this.currentConversation.type === this.TIM.TYPES.CONV_GROUP &&
+        this.currentConversation.type === 3 &&
         !this.isMine
       ) {
         return this.isOwner || this.isAdmin
@@ -119,7 +119,7 @@ export default {
     },
     // 是否显示禁言按钮
     showBan() {
-      if (this.currentConversation.type === this.TIM.TYPES.CONV_GROUP) {
+      if (this.currentConversation.type === 3) {
         return this.isOwner || this.isAdmin
       }
       return false

+ 11 - 11
src/components/conversation/conversationProfile/group-profile.vue

@@ -279,33 +279,33 @@ export default {
   computed: {
     editable() {
       return (
-        this.groupProfile.type === this.TIM.TYPES.GRP_WORK ||
-        [this.TIM.TYPES.GRP_MBR_ROLE_OWNER, this.TIM.TYPES.GRP_MBR_ROLE_ADMIN].includes(this.groupProfile.selfInfo.role)
+        this.groupProfile.type === this.OpenIM.TYPES.GRP_WORK ||
+        [this.OpenIM.TYPES.GRP_MBR_ROLE_OWNER, this.OpenIM.TYPES.GRP_MBR_ROLE_ADMIN].includes(this.groupProfile.selfInfo.role)
       )
     },
     isOwner() {
-      return this.groupProfile.selfInfo.role === this.TIM.TYPES.GRP_MBR_ROLE_OWNER
+      return this.groupProfile.selfInfo.role === this.OpenIM.TYPES.GRP_MBR_ROLE_OWNER
     },
     isAdmin() {
-      return this.groupProfile.selfInfo.role === this.TIM.TYPES.GRP_MBR_ROLE_ADMIN
+      return this.groupProfile.selfInfo.role === this.OpenIM.TYPES.GRP_MBR_ROLE_ADMIN
     },
     showDissmissGroup() {
       // 好友工作群不能解散
-      return this.isOwner && this.groupProfile.type !== this.TIM.TYPES.GRP_WORK
+      return this.isOwner && this.groupProfile.type !== this.OpenIM.TYPES.GRP_WORK
     },
     groupType() {
-      switch (this.groupProfile.type) {
-        case this.TIM.TYPES.GRP_WORK:
+      /*switch (this.groupProfile.type) {
+        case this.OpenIM.TYPES.GRP_WORK:
           return '好友工作群(Work)'
-        case this.TIM.TYPES.GRP_PUBLIC:
+        case this.OpenIM.TYPES.GRP_PUBLIC:
           return '陌生人社交群(Public)'
-        case this.TIM.TYPES.GRP_CHATROOM:
+        case this.OpenIM.TYPES.GRP_CHATROOM:
           return '临时会议群(Meeting)'
-        case this.TIM.TYPES.GRP_AVCHATROOM:
+        case this.OpenIM.TYPES.GRP_AVCHATROOM:
           return '直播群(AVChatRoom)'
         default:
           return ''
-      }
+      }*/
     }
   },
   watch: {

+ 5 - 5
src/components/conversation/conversationProfile/user-profile.vue

@@ -115,9 +115,9 @@ export default {
     },
     gender() {
       switch (this.userProfile.gender) {
-        case this.TIM.TYPES.GENDER_MALE:
+        case this.OpenIM.TYPES.GENDER_MALE:
           return '男'
-        case this.TIM.TYPES.GENDER_FEMALE:
+        case this.OpenIM.TYPES.GENDER_FEMALE:
           return '女'
         default:
           return '未设置'
@@ -125,9 +125,9 @@ export default {
     },
     genderClass() {
       switch (this.userProfile.gender) {
-        case this.TIM.TYPES.GENDER_MALE:
+        case this.OpenIM.TYPES.GENDER_MALE:
           return 'icon-male'
-        case this.TIM.TYPES.GENDER_FEMALE:
+        case this.OpenIM.TYPES.GENDER_FEMALE:
           return 'icon-female'
         default:
           return ''
@@ -183,7 +183,7 @@ export default {
     removeFromFriendList() {
       let options = {
         userIDList: [this.userProfile.userID],
-        type: this.TIM.TYPES.SNS_DELETE_TYPE_BOTH
+        type: this.OpenIM.TYPES.SNS_DELETE_TYPE_BOTH
       }
       this.tim.deleteFriend(options).then(() => {
       }).catch(error => {

+ 29 - 24
src/components/conversation/current-conversation.vue

@@ -21,11 +21,12 @@
           </div>
           <div class="no-more" v-else>没有更多了</div>
           <el-checkbox-group v-model="checkList" v-if="selectMessage">
-            <el-checkbox :label="message.ID" v-for="message in currentMessageList" :key="message.ID" :disabled="message.status==='fail'">
+            <el-checkbox :label="message.clientMsgID" v-for="message in currentMessageList" :key="message.clientMsgID" :disabled="message.status==='fail'">
               <message-item   :message="message"/>
             </el-checkbox>
           </el-checkbox-group>
-          <message-item v-else v-for="message in currentMessageList" :key="message.ID" :message="message"/>
+          <message-item v-else v-for="message in currentMessageList" :key="message.clientMsgID" :message="message">
+          </message-item>
         </div>
         <div v-show="isShowScrollButtomTips" class="newMessageTips" @click="scrollMessageListToButtom">回到最新位置</div>
       </div>
@@ -86,7 +87,7 @@ import MessageMerger from '../message/merger-message/message-merger'
 import MessageRelay from '../message/merger-message/message-relay'
 import FriendProfile from '../friend/friend-container'
 import close from '../../assets/image/close.png'
-
+import { getOpenIM } from '@/utils/openIM';
 export default {
   name: 'CurrentConversation',
   components: {
@@ -112,6 +113,7 @@ export default {
       mergerMessage: null,
       positionX: 0,
       positionY: 0,
+      OpenIM: null,
     }
   },
   computed: {
@@ -134,7 +136,7 @@ export default {
       return this.friendContent
     },
     name() {
-      if (this.currentConversation.type === 'C2C') {
+      if (this.currentConversation.conversationType === 1) {
         // let name = this.currentConversation.userProfile.nick || this.toAccount
         // let list = this.currentMessageList
         // let len = list.length
@@ -145,21 +147,22 @@ export default {
         //     break
         //   }
         // }
-        return this.currentConversation.remark || this.currentConversation.userProfile.nick || this.currentConversation.userProfile.userID
+        return this.currentConversation.remark || this.currentConversation.showName || this.currentConversation.userID
 
-      } else if (this.currentConversation.type === 'GROUP') {
-        return this.currentConversation.groupProfile.name || this.toAccount
-      } else if (this.currentConversation.conversationID === '@TIM#SYSTEM') {
+      } else if (this.currentConversation.conversationType === 3) {
+        return this.currentConversation.showName || this.toAccount
+      } else if (this.currentConversation.conversationType === 4) {
         return '系统通知'
       }
       return this.toAccount
     },
     showMessageSendBox() {
-      return this.currentConversation.type !== this.TIM.TYPES.CONV_SYSTEM
+      return this.currentConversation.type !== 4
     },
     mergerTitle() {
+      console.log("this.mergerMessage",this.mergerMessage)
       if (this.mergerMessage) {
-        return this.mergerMessage.payload.title || '聊天记录'
+        return this.mergerMessage.mergeElem.title || '聊天记录'
       } else {
         return  '聊天记录'
       }
@@ -176,7 +179,7 @@ export default {
     this.$bus.$on('mergerMessageShow', this.mergerShow)
 
 
-    if (this.currentConversation.conversationID === '@TIM#SYSTEM') {
+    if (this.currentConversation.conversationType === 4) {
       return false
     }
   },
@@ -190,23 +193,26 @@ export default {
     // 1. 系统会话隐藏右侧资料组件
     // 2. 没有当前会话时,隐藏右侧资料组件。
     //    背景:退出群组/删除会话时,会出现一处空白区域
-    if (this.currentConversation.conversationID === '@TIM#SYSTEM' ||
-        typeof this.currentConversation.conversationID === 'undefined') {
+    if (this.currentConversation.conversationType === 4 ||
+      typeof this.currentConversation.conversationType === 'undefined') {
       this.showConversationProfile = false
     }
   },
   watch: {
     currentUnreadCount(next) {
       if (!this.hidden && next > 0) {
-        this.tim.setMessageRead({ conversationID: this.currentConversation.conversationID })
+        this.OpenIM.markConversationMessageAsRead(this.currentConversation.conversationID)
       }
     },
     hidden(next) {
       if (!next && this.currentUnreadCount > 0) {
-        this.tim.setMessageRead({ conversationID: this.currentConversation.conversationID })
+        this.OpenIM.markConversationMessageAsRead(this.currentConversation.conversationID )
       }
     }
   },
+  created() {
+    this.OpenIM = getOpenIM();
+  },
   methods: {
     move(e) {
       let odiv = this.$refs.dropdown.$el.children[0]//e.target        //获取目标元素
@@ -261,15 +267,14 @@ export default {
       this.selectedMessage()
       this.$store.commit('setRelayType', 2)
     },
-    selectedMessage () {
-      let messageList = []
-      this.selectedMessageList = []
-      this.checkList.forEach((id) => {
-        messageList = this.currentMessageList.find((item) => {
-          return item.ID === id
-        })
-        this.selectedMessageList.push(messageList)
-      })
+    selectedMessage() {
+      this.selectedMessageList = this.checkList.map((id) => {
+        return this.currentMessageList.find((item) => item.clientMsgID === id)
+      }).filter(Boolean)
+
+      console.log("checkList:", this.checkList)
+      console.log("currentMessageList:", this.currentMessageList)
+      console.log("selectedMessageList:", this.selectedMessageList)
 
       this.$store.commit('showConversationList', true)
       //this.closeSelectMessage() // TODO

+ 8 - 4
src/components/friend/friend-application/application-item.vue

@@ -12,6 +12,7 @@
 
 <script>
 import { mapState } from 'vuex'
+import { getOpenIM} from '@/utils/openIM';
 export default {
   components: {
   },
@@ -25,6 +26,7 @@ export default {
         tag: '',
         type: 'Response_Action_AgreeAndAdd',
       },
+      OpenIm:null,
     }
   },
   computed: {
@@ -32,13 +34,14 @@ export default {
       applicationList: state => state.friend.applicationList
     }),
     comeInApplicationList() {
-      return this.applicationList.filter((item) => {return item.type === this.TIM.TYPES.SNS_APPLICATION_SENT_TO_ME})
+      return this.applicationList.filter((item) => {return item.type === this.OpenIM.TYPES.SNS_APPLICATION_SENT_TO_ME})
     },
     sendOutApplicationList() {
-      return this.applicationList.filter((item) => {return item.type === this.TIM.TYPES.SNS_APPLICATION_SENT_BY_ME})
+      return this.applicationList.filter((item) => {return item.type === this.OpenIM.TYPES.SNS_APPLICATION_SENT_BY_ME})
     }
   },
   created() {
+    this.OpenIm =getOpenIM()
     this.showApplicationList = this.comeInApplicationList
   },
   mounted() {
@@ -50,8 +53,9 @@ export default {
     },
     // 应答
     acceptFriendApplication(userID) {
-      this.tim.acceptFriendApplication({
-        userID: userID,
+      this.OpenIm.acceptFriendApplication({
+        toUserID: userID,
+        handleMsg:"",
         remark: this.acceptApplication.remark,
         tag: this.acceptApplication.tag,
         type: this.acceptApplication.type

+ 274 - 214
src/components/friend/friend-container.vue

@@ -1,232 +1,291 @@
 <template>
-    <div class="friend-content" v-if="showFriendContent || showApplicationContent" @click="closeHandler">
-        <div class="friend-box" v-if="showFriendContent">
-            <div class="profile-container" >
-                <div class="item-nick text-ellipsis">{{friendProfile.profile.nick||friendProfile.profile.userID}}</div>
-                <img
-                        class="avatar"
-                        :src="friendProfile.profile.avatar ? friendProfile.profile.avatar : 'https://imgcache.qq.com/open/qcloud/video/act/webim-avatar/avatar-2.png'"
-                />
-            </div>
-            <el-divider></el-divider>
-            <p class="content-box"><span class="content-title">userID</span><span class="content-text">{{friendProfile.userID}}</span></p>
-            <div class="content-box"><span class="content-title">备注名</span>
-                <div class="text-box"   v-if="!showEditRemark">
-                    <span class="content-text  content-width text-ellipsis">{{friendProfile.remark || '暂无'}}</span>
-                    <i
-                            class="el-icon-edit"
-                            @click.stop="
-                        showEditRemark = true
-                        inputFocus('showEditRemark')
+  <div class="friend-content" v-if="showFriendContent || showApplicationContent" @click="closeHandler">
+    <div class="friend-box" v-if="showFriendContent">
+      <div class="profile-container" >
+        <div class="item-nick text-ellipsis">{{friendProfile.nickname||friendProfile.userID}}</div>
+        <img
+          class="avatar"
+          :src="friendProfile.faceURL ? friendProfile.faceURL : 'https://imgcache.qq.com/open/qcloud/video/act/webim-avatar/avatar-2.png'"
+        />
+      </div>
+      <el-divider></el-divider>
+      <p class="content-box"><span class="content-title">userID</span><span class="content-text">{{friendProfile.userID}}</span></p>
+      <div class="content-box">
+        <span class="content-title">备注名</span>
 
-            "
-                            style="cursor:pointer; font-size:16px; margin-left: 6px"
-                    />
-                </div>
-                <el-input
-                        style="display: inline-block"
-                        ref="showEditRemark"
-                        v-else
-                        autofocus
-                        v-model="profileRemark"
-                        size="mini"
-                        @blur="blurHandler"
-                        @keydown.enter.native="editRemarkHandler"
-                />
-            </div>
+        <!-- 显示模式 -->
+        <div class="text-box" v-if="!showEditRemark">
+              <span class="content-text content-width text-ellipsis">
+                {{ friendProfile.remark || '暂无' }}
+              </span>
+          <i
+            class="el-icon-edit"
+            @click.stop="
+                showEditRemark = true,
+                inputFocus('remarkInput')"
+            style="cursor: pointer; font-size: 16px; margin-left: 6px"
+          />
+        </div>
 
-            <p class="content-box"><span class="content-title">来源</span><span class="content-text">{{getSource(friendProfile.source)}}</span></p>
-            <el-divider></el-divider>
-            <div class="content-box" v-show="friendType==='friendList'">
-                <span class="content-title" v-show="!showEdit" style="line-height: 35px">所在分组</span>
-                <span class="content-title" v-show="showEdit"  style="line-height: 35px">添加到分组</span>
-                <div class="text-content">
-                    <span class="content-text" v-show="!showEdit">{{groupName}}</span>
-                    <i class="el-icon-edit edit-icon" v-show="!showEdit"   @click.stop="showEditHandler"></i>
-                </div>
-                <el-select v-if="showEdit" v-model="addGroupName"  placeholder="选择分组" @change="addToFriendGroup">
-                    <el-option
-                            v-for="item in friendGroupList"
-                            @blur="showEdit = false"
-                            :key="item.name"
-                            :label="item.name"
-                            :value="item.name">
-                    </el-option>
-                </el-select>
-            </div>
-            <p class="content-box" v-show="friendType==='groupFriend'" style="height: 40px">
-                <span class="content-title" style="line-height: 35px">所在分组</span>
-                <span class="content-text" v-show="!showEdit" style="line-height: 35px">{{groupName}}</span>
-            </p>
-            <div class="sendBtn" @click.stop="checkoutConversation(friendProfile.userID)">发送消息</div>
-            <div class="delete-text" v-show="friendType==='groupFriend'" @click.stop="removeFromFriendGroup(friendProfile.userID)">从该群组中移除</div>
-            <div class="delete-text" v-show="friendType==='friendList'" @click.stop="removeFromFriendList(friendProfile.userID)">删除该好友</div>
+        <!-- 编辑模式 -->
+        <div v-else style="display: inline-flex; align-items: center;">
+          <el-input
+            ref="remarkInput"
+            v-model="profileRemark"
+            size="mini"
+            style="width: 200px; margin-right: 8px;"
+          />
+          <el-button type="primary" size="mini" @click="editRemarkHandler">
+            保存
+          </el-button>
+          <el-button size="mini" @click="showEditRemark = false" style="margin-left: 5px;">
+            取消
+          </el-button>
         </div>
-        <div class="friend-box" v-if="showApplicationContent">
-            <div class="profile-container" >
-                <div class="item-nick text-ellipsis">{{applicationContent.nick||applicationContent.userID}}</div>
-                <img
-                        class="avatar"
-                        :src="applicationContent.avatar ? applicationContent.avatar : 'http://imgcache.qq.com/open/qcloud/video/act/webim-avatar/avatar-2.png'"
-                />
-            </div>
-            <el-divider></el-divider>
-            <p class="content-box"><span class="content-title">userID</span><span class="content-text">{{applicationContent.userID}}</span></p>
-            <p class="content-box"><span class="content-title">来源</span><span class="content-text content-width text-ellipsis">{{getSource(applicationContent.source)}}</span></p>
-            <div class="content-box" v-if="showRemark"><span class="content-title">备注名</span>
-                <el-input
-                        style="display: inline-block"
-                        ref="showRemark"
-                        autofocus
-                        v-model="acceptApplication.remark"
-                        size="mini"
-                        @blur="remarkBlurHandler"
-                        @keydown.enter.native="editRemarkHandler"
-                />
-            </div>
-            <el-divider></el-divider>
-            <p class="content-box">
-                <span class="content-title">打招呼</span>
-                <el-tooltip class="item" effect="dark" :content="applicationContent.wording" placement="bottom-end">
-                    <span class="content-text content-width text-ellipsis">{{applicationContent.wording}}</span>
-                </el-tooltip>
-            </p>
-            <div class="application-box" v-if="!showRemark">
-                <p class="application-refuse" @click="acceptHandler">同意</p>
-                <p class="application-delete"  @click="refuseFriendApplication(applicationContent.userID)">拒绝</p>
-            </div>
-            <div class="application-box" v-else>
-                <p class="application-refuse" @click="acceptFriendApplication(applicationContent.userID)">确认</p>
-                <p class="application-delete"  @click="cancelHandler()">取消</p>
-            </div>
+      </div>
+
+      <p class="content-box"><span class="content-title">来源</span><span class="content-text">{{getSource(friendProfile.addSource)}}</span></p>
+      <el-divider></el-divider>
+      <div class="content-box" v-show="friendType==='friendList'">
+        <span class="content-title" v-show="!showEdit" style="line-height: 35px">所在分组</span>
+        <span class="content-title" v-show="showEdit"  style="line-height: 35px">添加到分组</span>
+        <div class="text-content">
+          <span class="content-text" v-show="!showEdit">{{groupName}}</span>
+          <i class="el-icon-edit edit-icon" v-show="!showEdit"   @click.stop="showEditHandler"></i>
         </div>
+        <el-select v-if="showEdit" v-model="addGroupName"  placeholder="选择分组" @change="addToFriendGroup">
+          <el-option
+            v-for="item in friendGroupList"
+            @blur="showEdit = false"
+            :key="item.name"
+            :label="item.name"
+            :value="item.name">
+          </el-option>
+        </el-select>
+      </div>
+      <p class="content-box" v-show="friendType==='groupFriend'" style="height: 40px">
+        <span class="content-title" style="line-height: 35px">所在分组</span>
+        <span class="content-text" v-show="!showEdit" style="line-height: 35px">{{groupName}}</span>
+      </p>
+      <div class="sendBtn" @click.stop="checkoutConversation(friendProfile.userID)">发送消息</div>
+      <div class="delete-text" v-show="friendType==='groupFriend'" @click.stop="removeFromFriendGroup(friendProfile.userID)">从该群组中移除</div>
+      <div class="delete-text" v-show="friendType==='friendList'" @click.stop="removeFromFriendList(friendProfile.userID)">删除该好友</div>
     </div>
+    <div class="friend-box" v-if="showApplicationContent">
+      <div class="profile-container" >
+        <div class="item-nick text-ellipsis">{{applicationContent.nick||applicationContent.userID}}</div>
+        <img
+          class="avatar"
+          :src="applicationContent.avatar ? applicationContent.avatar : 'http://imgcache.qq.com/open/qcloud/video/act/webim-avatar/avatar-2.png'"
+        />
+      </div>
+      <el-divider></el-divider>
+      <p class="content-box"><span class="content-title">userID</span><span class="content-text">{{applicationContent.userID}}</span></p>
+      <p class="content-box"><span class="content-title">来源</span><span class="content-text content-width text-ellipsis">{{getSource(applicationContent.addSource)}}</span></p>
+      <div class="content-box" v-if="showRemark"><span class="content-title">备注名</span>
+        <el-input
+          style="display: inline-block"
+          ref="showRemark"
+          autofocus
+          v-model="acceptApplication.remark"
+          size="mini"
+          @blur="remarkBlurHandler"
+          @keydown.enter.native="editRemarkHandler"
+        />
+      </div>
+      <el-divider></el-divider>
+      <p class="content-box">
+        <span class="content-title">打招呼</span>
+        <el-tooltip class="item" effect="dark" :content="applicationContent.wording" placement="bottom-end">
+          <span class="content-text content-width text-ellipsis">{{applicationContent.wording}}</span>
+        </el-tooltip>
+      </p>
+      <div class="application-box" v-if="!showRemark">
+        <p class="application-refuse" @click="acceptHandler">同意</p>
+        <p class="application-delete"  @click="refuseFriendApplication(applicationContent.userID)">拒绝</p>
+      </div>
+      <div class="application-box" v-else>
+        <p class="application-refuse" @click="acceptFriendApplication(applicationContent.userID)">确认</p>
+        <p class="application-delete"  @click="cancelHandler()">取消</p>
+      </div>
+    </div>
+  </div>
 </template>
 
 <script>
-  import { mapState } from 'vuex'
-  export default {
-    name: 'index',
-    data() {
-      return {
-        showEdit: false,
-        showEditRemark: false,
-        showRemark: false,
-        addGroupName: '',
-        profileRemark: '',
-        editGroupList: [],
-        isUpdate: false,
-        acceptApplication: {
-          remark: '',
-          type: 'Response_Action_AgreeAndAdd',
-        },
+import { mapState } from 'vuex'
+import ScrollPane from "../../layout/components/TagsView/ScrollPane";
+import { getOpenIM,getCbEvents } from '@/utils/openIM';
+export default {
+  name: 'index',
+  components: {ScrollPane},
+  data() {
+    return {
+      OpenIM:null,
+      showEdit: false,
+      showEditRemark: false,
+      showRemark: false,
+      addGroupName: '',
+      profileRemark: '',
+      editGroupList: [],
+      isUpdate: false,
+      acceptApplication: {
+        remark: '',
+        type: 'Response_Action_AgreeAndAdd',
+      },
+    }
+  },
+  computed: {
+    ...mapState({
+      friendContent: state => state.friend.friendContent,
+      applicationContent: state => state.friend.applicationContent,
+      friendGroupList: state => state.friend.friendGroupList,
+    }),
+    showFriendContent() {
+      if (JSON.stringify(this.friendContent) === '{}') {
+        return false
       }
+      return true
     },
-    computed: {
-      ...mapState({
-        friendContent: state => state.friend.friendContent,
-        applicationContent: state => state.friend.applicationContent,
-        friendGroupList: state => state.friend.friendGroupList,
-      }),
-      showFriendContent() {
-        if (JSON.stringify(this.friendContent) === '{}') {
-          return false
-        }
-        return true
-      },
-      showApplicationContent() {
-        if (JSON.stringify(this.applicationContent) === '{}') {
-          return false
-        }
-        return true
-      },
-      friendProfile() {
-        return this.friendContent.friend
-      },
-      groupName() {
-        if(this.friendProfile.groupList.length>0) {
-          return this.friendProfile.groupList.join(',')
-        }else {
-          return '暂无分组'
-        }
-      },
-      groupList:{
-        get() {
-          return this.friendProfile.groupList
-        },
-        set(value) {
-          this.editGroupList = value
-        }
-      },
-      friendType() {
-        return this.friendContent.type
-      },
-      getSource() {
-        return function (source) {
-          return source.substring(15)
-        }
-      },
+    showApplicationContent() {
+      if (JSON.stringify(this.applicationContent) === '{}') {
+        return false
+      }
+      return true
     },
-    methods: {
-      showEditHandler() {
-        this.showEdit = true
-        this.addGroupName = ''
-      },
-      inputFocus(ref) {
-        this.profileRemark = this.friendProfile.remark
-        this.$nextTick(() => {
-          this.$refs[ref].focus()
-        })
-      },
-      blurHandler() {
-        this.showEditRemark = false
-        this.isUpdate = true
-      },
-      remarkBlurHandler() {
-        // this.showEditRemark = false
-      },
-      acceptHandler() {
-        this.showRemark = true
-        this.acceptApplication.remark = ''
-        this.$nextTick(() => {
-          this.$refs.showRemark.focus()
-        })
-      },
-      cancelHandler() {
-        this.showRemark = false
+    friendProfile() {
+      console.log("this.friendContent",this.friendContent)
+      return this.friendContent.friend
+    },
+    groupName() {
+      /*console.log("this.friendProfile",this.friendProfile)
+      if(this.friendProfile.groupList.length>0) {
+        return this.friendProfile.groupList.join(',')
+      }else {
+        return '暂无分组'
+      }*/
+      return '暂无分组'
+    },
+    groupList:{
+      get() {
+        return this.friendProfile.groupList
       },
-      closeHandler() {
-        this.showEdit = false
-        if (this.isUpdate) {
-          this.editRemarkHandler()
+      set(value) {
+        this.editGroupList = value
+      }
+    },
+    friendType() {
+      return this.friendContent.type
+    },
+    getSource() {
+      return function (source) {
+        switch (source) {
+          case 1:
+            return '管理员导入添加'
+          case 2:
+            return '申请添加'
         }
-      },
-      editRemarkHandler() {
-        this.showEditRemark = false
-        // 更新好友备注
-        this.tim.updateFriend({
-          userID: this.friendProfile.userID,
-          remark: this.profileRemark
-        }).then(()=> {
-        }).catch((imError)=> {
-          console.warn('getFriendProfile error:', imError) // 更新失败
-        })
-        this.isUpdate = false
-      },
-      updateFriendGroup() {
-        this.profileRemark = this.friendProfile.remark
-        // 更新好友分组
-        this.tim.updateFriend({
-          userID: this.friendProfile.userID,
-          groupList: this.editGroupList
-        }).then(()=>{
-        }).catch((imError)=> {
-          console.warn('getFriendProfile error:', imError) // 更新失败
+      }
+    },
+  },
+  created() {
+    this.OpenIM = getOpenIM();
+  },
+  methods: {
+    showEditHandler() {
+      this.showEdit = true
+      this.addGroupName = ''
+    },
+    inputFocus(ref) {
+      this.profileRemark = this.friendProfile.remark
+      this.$nextTick(() => {
+        this.$refs[ref].focus()
+      })
+    },
+    blurHandler() {
+      this.showEditRemark = false
+      this.isUpdate = true
+    },
+    remarkBlurHandler() {
+      // this.showEditRemark = false
+    },
+    acceptHandler() {
+      this.showRemark = true
+      this.acceptApplication.remark = ''
+      this.$nextTick(() => {
+        this.$refs.showRemark.focus()
+      })
+    },
+    cancelHandler() {
+      this.showRemark = false
+    },
+    closeHandler() {
+      this.showEdit = false
+      if (this.isUpdate) {
+        this.editRemarkHandler()
+      }
+    },
+    editRemarkHandler() {
+      this.showEditRemark = false
+      console.log("this.OpenIM000",this.OpenIM)
+      // 更新好友备注
+
+      this.OpenIM.updateFriends({
+        friendUserIDs: [this.friendProfile.userID],
+        remark: this.profileRemark
+      })
+        .then(({ data }) => {
+          this.$store.commit('showMessage', {
+            message: '备注修改成功',
+            type: 'success',
+          });
+          // 更新 friendProfile.remark 本地显示
+          this.friendProfile.remark = this.profileRemark;
+          // 调用成功,冲新加载好友列表和会话列表
+          //查询会话列表
+          this.OpenIM.getAllConversationList()
+            .then(({ data }) => {
+              // 调用成功
+              console.log("获取到会话列表",data)
+              this.conversationList= data
+              this.$store.commit('updateConversationList', data)
+            })
+          //查询好友列表
+          this.OpenIM.getFriendListPage({ offset:0, count:100 })
+            .then(({ data }) => {
+              // 调用成功
+              console.log("获取到好友列表",data)
+              //this.conversationList= data
+              this.$store.commit('updateFriendList', data)
+            })
         })
-      },
-      checkoutConversation(userID) {
+        .catch(({ errCode, errMsg }) => {
+          // 调用失败
+        });
+      this.isUpdate = false
+    },
+    updateFriendGroup() {
+      this.profileRemark = this.friendProfile.remark
+      // 更新好友分组
+      this.tim.updateFriend({
+        userID: this.friendProfile.userID,
+        groupList: this.editGroupList
+      }).then(()=>{
+      }).catch((imError)=> {
+        console.warn('getFriendProfile error:', imError) // 更新失败
+      })
+    },
+    checkoutConversation(userID) {
+      console.log(userID)
+
+      //查询会话
+      this.OpenIM.getOneConversation({
+        sourceID: userID.toString(),
+        sessionType: 1,
+      }).then(({ data }) => {
+        console.log("查询单挑回话",data)
         this.$store
-          .dispatch('checkoutConversation', `C2C${userID}`)
+          .dispatch('checkoutConversation', data)
           .then(() => {
             this.showDialog = false
             this.$bus.$emit('checkoutConversation')
@@ -236,7 +295,8 @@
             type: 'warning'
           })
         })
-      },
+      })
+    },
       addToFriendGroup() {
         this.tim.addToFriendGroup({name: this.addGroupName, userIDList: [this.friendProfile.userID]}).then(() => {
           this.$store.commit('showMessage', {

+ 94 - 45
src/components/friend/friend-item.vue

@@ -1,11 +1,24 @@
 <template>
-  <div class="friendList-item-wrapper" :id="'friend-'+name+'-'+index" @click="selectedItem">
-    <avatar :src="friend.profile.avatar" />
-    <div class="item-nick text-ellipsis">{{friend.remark || friend.profile.nick||friend.profile.userID}}</div>
+  <div
+    class="friendList-item-wrapper"
+    :id="'friend-'+name+'-'+index"
+    @click="selectedItem"
+  >
+    <div class="avatar-wrapper">
+      <avatar :src="friend.faceURL" class="avatar" />
+      <img v-if="avatarBorder" :src="avatarBorder" class="avatar-border" />
+    </div>
+
+    <div class="item-nick text-ellipsis">
+      {{ friend.remark || friend.nickname || friend.userID }}
+    </div>
   </div>
 </template>
 
 <script>
+import {mapState} from "vuex";
+import doctorBorder from '@/assets/doctor.svg'
+import guanjiaBorder from '@/assets/guanjia.svg'
   export default {
   props: ['friend','friendGroupNameList','type','groupName','index'],
   data() {
@@ -16,18 +29,41 @@
       },
     }
   },
-  computed: {
-    name() {
-      if(this.groupName) {
-        return this.groupName
-      }else {
-        return ''
-      }
-    }
-  },
+    computed: {
+      avatarBorder() {
+        if (this.friend.userID?.startsWith('D')) {
+          return doctorBorder
+        } else if (this.friend.userID?.startsWith('C')) {
+          return guanjiaBorder
+        }
+        return null
+      },
+      name() {
+        if(this.groupName) {
+          return this.groupName
+        }else {
+          return ''
+        }
+      },
+      borderClass() {
+        // 判断 userID 第一个字母
+        const userID = this.friend?.friendInfo?.userID || '';
+        if (userID.startsWith('D')) {
+          return 'doctor-border';
+        } else if (userID.startsWith('C')) {
+          return 'guanjia-border';
+        } else {
+          return ''; // 默认不加边框
+        }
+      },
+      ...mapState({
+        friendList: state => state.friend.friendList,
+      }),
+    },
 
   methods:{
     selectedItem() {
+      console.log("this.friendList",this.friendList)
       this.$store.commit('resetCurrentConversation')
       this.$store.dispatch('setFriendContent', {
         friend: this.friend,
@@ -84,38 +120,60 @@
 </script>
 
 <style lang="stylus" scoped>
-  .item-nick {
-    padding-left: 20px;
-    width: 100%;
-    color: $white;
-    box-sizing: border-box;
-    word-wrap: break-word;
-    overflow: hidden;
-    text-overflow: ellipsis;
-    font-size 16px
-  }
+  .avatar-wrapper
+    position relative
+    width 40px
+    height 40px
+    margin-right 10px
+    flex-shrink 0
 
-  .friendList-item-wrapper {
+  .avatar
+    width 100%
+    eight 100%
+    border-radius 50%
+    display block
+  .avatar-border
+    position absolute
+    top 0
+    left 0
+    width 100%
+    height 100%
+    pointer-events none
+  .avatar
+    width 40px
+    height 40px
+    margin-right 10px
+    border-radius 50%
+    flex-shrink 0
+  .item-nick
+    padding-left 20px
+    width 100%
+    color #fff
+    box-sizing border-box
+    word-wrap break-word
+    overflow hidden
+    text-overflow ellipsis
+    font-size 16px
+  .friendList-item-wrapper
     cursor pointer
     padding 0 40px
-    padding-bottom: 15px;
-    display: flex;
-    align-items: center;
-    justify-content: flex-start;
-  }
-  .group-friend-btn {
+    padding-bottom 15px
+    display flex
+    align-items center
+    justify-content flex-start
+  .group-friend-btn
     position absolute
     right 13px
-  }
-  .unread-count {
+
+  .unread-count
     padding-left 10px
     flex-shrink 0
-    color $font-dark
+    color #666
     font-size 12px
-  }
-  .badge {
+
+  .badge
     vertical-align bottom
-    background-color $danger
+    background-color #f56c6c
     border-radius 10px
     color #FFF
     display inline-block
@@ -126,15 +184,6 @@
     padding 0 6px
     text-align center
     white-space nowrap
-    }
-  .avatar {
-    width: 40px;
-    height: 40px;
-    border-radius: 50%;
-    flex-shrink: 0
-    box-shadow: 0 5px 10px 0 rgba(0, 0, 0, 0.1);
-  }
-  .el-icon-chat-dot-round:before {
+  .el-icon-chat-dot-round:before
     color #dddddd
-  }
 </style>

+ 64 - 8
src/components/friend/friend-list.vue

@@ -1,9 +1,9 @@
 <template>
   <div class="friend-container">
-    <div class="add-friend" @click="handleAddButtonClick">
+<!--    <div class="add-friend" @click="handleAddButtonClick">
       <i class="tim-icon-friend-add" style="font-size: 28px"></i>
       <span style="margin-left: 6px">加好友</span>
-    </div>
+    </div>-->
     <el-dialog title="快速搜索好友" :visible.sync="showDialog" width="400px">
       <el-input placeholder="请输入用户ID" v-model="userID" @keydown.enter.native="addFriendConfirm">
         <el-button slot="append" icon="el-icon-search" @click="addFriendConfirm"></el-button>
@@ -63,13 +63,24 @@
     </el-dialog>
     <div class="scroll-container">
       <div class="menu-container">
+        <div style="padding: 10px; display: flex; gap: 6px;">
+          <el-input
+            v-model="searchKeyword"
+            placeholder="输入昵称/备注"
+            clearable
+            size="small"
+            style="flex: 1;"
+          />
+          <el-button type="primary" size="small" @click="searchFriendList">搜索</el-button>
+          <el-button size="small" @click="resetSearch">清空</el-button>
+        </div>
         <el-menu
                 default-active="application"
                 class="el-menu-vertical-demo"
                 :default-openeds="openeds"
                 @open="handleOpen"
                 @close="handleClose">
-          <el-submenu index="application" style="border-buttom:1px solid #1c2438">
+<!--          <el-submenu index="application" style="border-buttom:1px solid #1c2438">
             <template slot="title">
               <i :class="{'el-icon-arrow-right': !active['application'], 'el-icon-arrow-down': active['application']}"></i>
               <span>新的好友
@@ -116,14 +127,14 @@
                 </el-menu-item>
               </el-submenu>
             </el-menu-item-group>
-          </el-submenu>
+          </el-submenu>-->
           <el-submenu :hide-timeout="hideTimeOut"  index="friendList" style="border-buttom:1px solid #1c2438">
             <template slot="title">
               <i :class="{'el-icon-arrow-right': !active['friendList'], 'el-icon-arrow-down': active['friendList']}"></i>
               <span>联系人</span>
             </template>
             <el-menu-item-group>
-              <el-menu-item   :index="friend.userID" v-for="(friend,index) in friendList"  :key="friend.userID">
+              <el-menu-item   :index="friend.userID" v-for="(friend,index) in filteredList"  :key="friend.userID">
                 <friend-item  :index="index" :friend="friend"  :friendGroupNameList="friendGroupNameList" :type="'friendList'"/>
               </el-menu-item>
             </el-menu-item-group>
@@ -139,6 +150,7 @@
 import { mapState } from 'vuex'
 import FriendItem from './friend-item.vue'
 import FriendApplication from './friend-application/application-item.vue'
+import { getOpenIM,getCbEvents } from '@/utils/openIM';
 export default {
   components: {
     FriendItem,
@@ -146,6 +158,9 @@ export default {
   },
   data() {
     return {
+      searchKeyword: '',
+      filteredList: [],
+      OpenIM:null,
       active: {},
       hideTimeOut: 1000,
       openeds: ['friendList'],
@@ -163,7 +178,8 @@ export default {
         remark: '',
         groupName: '',
         wording: '',
-        type: this.TIM.TYPES.SNS_ADD_TYPE_BOTH
+        //type: this.OpenIM.TYPES.SNS_ADD_TYPE_BOTH
+        type: 1
       },
       addInfo: {
         groupName: '',
@@ -174,7 +190,7 @@ export default {
         nick: '',
         userID: '',
       },
-      formLabelWidth: '120px'
+      formLabelWidth: '120px',
     }
   },
   computed: {
@@ -192,7 +208,7 @@ export default {
       return this.friendGroupList.map((item) => {return item.name})
     },
     comeInApplicationList() {
-      return this.applicationList.filter((item) => {return item.type === this.TIM.TYPES.SNS_APPLICATION_SENT_TO_ME})
+      //return this.applicationList.filter((item) => {return item.type === this.OpenIM.TYPES.SNS_APPLICATION_SENT_TO_ME})
     },
     groupFriend() {
       return function (userIDList) {
@@ -205,8 +221,48 @@ export default {
   },
   mounted() {
     this.$set(this.active, 'friendList',  true)
+    this.filteredList = this.friendList;
+  },
+  created() {
+    this.OpenIM = getOpenIM();
+    this.searchFriendList();
   },
   methods: {
+    searchFriendList() {
+      const keyword = this.searchKeyword.trim().toLowerCase();
+      if (!keyword) {
+        this.OpenIM.getFriendListPage({ offset:0, count:100 })
+          .then(({ data }) => {
+            // 调用成功
+            //this.conversationList= data
+            this.$store.commit('updateFriendList', data)
+            this.filteredList = this.friendList;
+            return;
+          })
+          .catch(({ errCode, errMsg }) => {
+            // 调用失败
+          })
+
+      }
+      this.OpenIM.searchFriends({
+        keywordList: [keyword],
+        isSearchUserID: false,
+        isSearchNickname: true,
+        isSearchRemark: true,
+      })
+        .then(({data}) => {
+          // 调用成功
+          this.$store.commit('updateFriendList', data)
+          this.filteredList = this.friendList;
+        })
+        .catch(({ errCode, errMsg }) => {
+          // 调用失败
+        });
+    },
+    resetSearch() {
+      this.searchKeyword = '';
+      this.searchFriendList();
+    },
     handleOpen(key, keyPath) {
       if(keyPath.length ===1) {
         this.$set(this.active, keyPath[0], true)

+ 3 - 3
src/components/group-live/components/live-chat.vue

@@ -173,7 +173,7 @@ export default {
     this.$bus.$on('group-live-send-gift', (index)=> {
       const message = this.tim.createCustomMessage({
         to: this.groupLiveInfo.roomID,
-        conversationType: this.TIM.TYPES.CONV_GROUP,
+        conversationType: 3,
         payload: {
           data: JSON.stringify({version: '1.0.0' ,'message': `${index}`,'command':'6','action':301}),
           description: '',
@@ -217,7 +217,7 @@ export default {
         groupID: this.groupLiveInfo.roomID
       }).then((imResponse) => {
         const status = imResponse.data.status
-        if (status === this.TIM.TYPES.JOIN_STATUS_SUCCESS || status === this.TIM.TYPES.JOIN_STATUS_ALREADY_IN_GROUP) {
+        if (status === this.OpenIM.TYPES.JOIN_STATUS_SUCCESS || status === this.OpenIM.TYPES.JOIN_STATUS_ALREADY_IN_GROUP) {
           this.sendAvailable = true
         }
       }).catch(() => {})
@@ -244,7 +244,7 @@ export default {
       }
       const message = this.tim.createTextMessage({
         to: this.groupLiveInfo.roomID,
-        conversationType: this.TIM.TYPES.CONV_GROUP,
+        conversationType: 3,
         payload: { text: this.messageContent }
       })
       // 此处用JSON序列化和反序列化对message断链

+ 3 - 3
src/components/group-live/components/live-pusher.vue

@@ -184,7 +184,7 @@ export default {
       await this.tim.createGroup({
         name: this.roomName,
         groupID: this.roomID,
-        type: this.TIM.TYPES.GRP_AVCHATROOM,
+        type: this.OpenIM.TYPES.GRP_AVCHATROOM,
       })
       this.$bus.$emit('join-group-live-avchatroom')
     },
@@ -238,8 +238,8 @@ export default {
       }
       const message = this.tim.createCustomMessage({
         to: this.groupLiveInfo.groupID,
-        conversationType: this.TIM.TYPES.CONV_GROUP,
-        priority: this.TIM.TYPES.MSG_PRIORITY_NORMAL,
+        conversationType: 3,
+        priority: this.OpenIM.TYPES.MSG_PRIORITY_NORMAL,
         payload: {
           data: JSON.stringify(form),
           description: '',

+ 6 - 6
src/components/group/create-group.vue

@@ -38,7 +38,7 @@
           multiple
           filterable
           remote
-          :disabled="form.type === TIM.TYPES.GRP_AVCHATROOM"
+          :disabled="form.type === OpenIM.TYPES.GRP_AVCHATROOM"
           :remote-method="handleSearchUser"
           :loading="loading"
           placeholder="请输入群成员 userID"
@@ -79,7 +79,7 @@ export default {
       form: {
         groupID: '',
         name: '',
-        type: this.TIM.TYPES.GRP_WORK,
+        type: this.OpenIM.TYPES.GRP_WORK,
         avatar: '',
         introduction: '',
         notification: '',
@@ -96,9 +96,9 @@ export default {
   computed: {
     joinOptionDisabled() {
       return [
-        this.TIM.TYPES.GRP_WORK,
-        this.TIM.TYPES.GRP_MEETING,
-        this.TIM.TYPES.GRP_AVCHATROOM
+        this.OpenIM.TYPES.GRP_WORK,
+        this.OpenIM.TYPES.GRP_MEETING,
+        this.OpenIM.TYPES.GRP_AVCHATROOM
       ].includes(this.form.type)
     }
   },
@@ -134,7 +134,7 @@ export default {
         ...this.form,
         memberList: this.form.memberList.map(userID => ({ userID }))
       }
-      if ([this.TIM.TYPES.GRP_WORK, this.TIM.TYPES.GRP_AVCHATROOM].includes(this.form.type)) {
+      if ([this.OpenIM.TYPES.GRP_WORK, this.OpenIM.TYPES.GRP_AVCHATROOM].includes(this.form.type)) {
         delete options.joinOption
       }
       return options

+ 6 - 6
src/components/group/group-list.vue

@@ -66,7 +66,7 @@ export default {
     searchGroupByID(queryString, showInSearchResult) {
       if (queryString.trim().length > 0) {
         this.hideSearchLoading = false
-        this.tim
+        this.OpenIM
           .searchGroupByID(queryString)
           .then(({ data: { group } }) => {
             showInSearchResult([group])
@@ -85,17 +85,17 @@ export default {
       this.$store.commit('updateCreateGroupModelVisible', true)
     },
     applyJoinGroup(group) {
-      this.tim
+      this.OpenIM
         .joinGroup({ groupID: group.groupID })
         .then(async res => {
           switch(res.data.status) {
-            case this.TIM.TYPES.JOIN_STATUS_WAIT_APPROVAL:
+            case this.OpenIM.TYPES.JOIN_STATUS_WAIT_APPROVAL:
               this.$store.commit('showMessage', {
                 message: '申请成功,等待群管理员确认。',
                 type: 'info'
               })
               break
-            case this.TIM.TYPES.JOIN_STATUS_SUCCESS:
+            case this.OpenIM.TYPES.JOIN_STATUS_SUCCESS:
               await this.$store.dispatch(
                 'checkoutConversation',
                 `GROUP${res.data.group.groupID}`
@@ -105,7 +105,7 @@ export default {
                 type: 'success'
               })
               break
-            case this.TIM.TYPES.JOIN_STATUS_ALREADY_IN_GROUP:
+            case this.OpenIM.TYPES.JOIN_STATUS_ALREADY_IN_GROUP:
               this.$store.commit('showMessage', {
                 message: '您已经是群成员了,请勿重复加群哦!',
                 type: 'info'
@@ -131,7 +131,7 @@ export default {
   width 100%
   display flex
   flex-direction column
-  .group-container 
+  .group-container
     overflow-y scroll
   .header-bar
     display: flex;

+ 16 - 10
src/components/layout/side-bar.vue

@@ -14,12 +14,6 @@
             <template v-else>{{totalUnreadCount}}</template>
           </sup>
         </div>
-        <!-- <div
-          id="group-list"
-          class="iconfont icon-group"
-          :class="{ active: showGroupList }"
-          title="群组列表"
-        ></div>
         <div
           id="friend-list"
           class="iconfont icon-contact"
@@ -31,6 +25,13 @@
             <template v-else>{{applicationUnreadCount}}</template>
           </sup>
         </div>
+        <!-- <div
+          id="group-list"
+          class="iconfont icon-group"
+          :class="{ active: showGroupList }"
+          title="群组列表"
+        ></div>
+
         <div
           id="black-list"
           class="iconfont icon-blacklist"
@@ -63,7 +64,7 @@ import ConversationList from '../conversation/conversation-list'
 import GroupList from '../group/group-list'
 import FriendList from '../friend/friend-list'
 import BlackList from '../blacklist/blacklist'
-
+import { getOpenIM,getCbEvents } from '@/utils/openIM';
 const activeName = {
   CONVERSATION_LIST: 'conversation-list',
   GROUP_LIST: 'group-list',
@@ -83,7 +84,8 @@ export default {
   data() {
     return {
       active: activeName.CONVERSATION_LIST,
-      activeName: activeName
+      activeName: activeName,
+      OpenIM:null
     }
   },
   computed: {
@@ -116,6 +118,9 @@ export default {
     })
 
   },
+  created() {
+    this.OpenIM = getOpenIM();
+  },
   methods: {
     checkoutActive(name) {
       this.active = name
@@ -141,9 +146,10 @@ export default {
       }
     },
     handleRefresh() {
+      console.log("好友列表")
       switch (this.active) {
         case activeName.CONVERSATION_LIST:
-          this.tim.getConversationList().catch(error => {
+          this.OpenIM.getAllConversationList().catch(error => {
             this.$store.commit('showMessage', {
               type: 'error',
               message: error.message
@@ -175,7 +181,7 @@ export default {
         })
     },
     getFriendList() {
-      this.tim
+      this.OpenIM
         .getFriendList()
         .then(({ data: friendList }) => {
           this.$store.commit('upadteFriendList', friendList)

+ 170 - 111
src/components/message/merger-message/mergerMessage-item.vue

@@ -2,75 +2,75 @@
     <div class="message-wrapper col-2">
         <div class="content-wrapper">
 <!--文本消息-->
-            <div class="message-container" v-if="message.type === 'TIMTextElem'">
-                <div class="text-message" v-for="(item, index) in contentList" :key="index">
-                    <span  :key="index" v-if="item.name === 'text'">{{ item.text }}</span>
-                    <img v-else-if="item.name === 'img'" :src="item.src" width="20px" height="20px" :key="index"/>
-                </div>
-            </div>
+          <div class="message-container" v-if="message.contentType === 101">
+              <div class="text-message" v-for="(item, index) in contentList" :key="index">
+                  <span  :key="index" v-if="item.name === 'text'">{{ item.text }}</span>
+                  <img v-else-if="item.name === 'img'" :src="item.src" width="20px" height="20px" :key="index"/>
+              </div>
+          </div>
 <!--图片消息-->
-            <div class="message-container" v-else-if="message.type === 'TIMImageElem'">
-                <img class="image-element" :src="payload.imageInfoArray[0].url" @load="onImageLoaded" @click="handlePreview()" />
-            </div>
+          <div class="message-container" v-else-if="message.contentType === 102">
+            <img class="image-element" :src="message.pictureElem.sourcePicture.url" @load="onImageLoaded" @click="handlePreview()" />
+          </div>
 <!--文件消息-->
-            <div class="message-container" v-else-if="message.type === 'TIMFileElem'">
+            <div class="message-container" v-else-if="message.type === 105">
                 <div class="file-element-wrapper" title="单击下载" @click="downloadFile">
                     <div class="file-box">
                         <i class="el-icon-document file-icon"></i>
                         <div class="file-element">
-                            <span class="file-name">{{ payload.fileName }}</span>
-                            <span class="file-size">{{ fileSize }}</span>
+                          <span class="file-name">{{ message.fileElem.fileName }}</span>
+                          <span class="file-size">{{ message.fileElem.fileSize }}</span>
                         </div>
                     </div>
                 </div>
             </div>
 <!--表情消息-->
 
-            <div class="message-container" v-else-if="message.type === 'TIMFaceElem'">
-                <img :src="faceUrl"/>
+            <div class="message-container" v-else-if="message.type === 115">
+              <img :src="faceUrl"/>
             </div>
 <!--视频消息-->
-            <div class="message-container" v-else-if="message.type === TIM.TYPES.MSG_VIDEO">
-                <video
-                        :src="payload.videoUrl"
-                        controls
-                        class="merger-video"
-                        @error="videoError"
-                ></video>
-            </div>
+          <div class="message-container" v-else-if="message.contentType === 104">
+            <video
+              :src="message.videoElem.videoUrl"
+              controls
+              class="merger-video"
+              @error="videoError"
+            ></video>
+          </div>
 <!--音频消息-->
-            <div class="sound-element-wrapper"  v-else-if="message.type === TIM.TYPES.MSG_AUDIO" title="单击播放" @click="play">
-                <i class="iconfont icon-voice"></i>
-                {{ payload.second + '"' }}
-            </div>
- <!--自定义消息-->
-            <div class="message-container" v-else-if="message.type === 'TIMCustomElem'">
-                <div class="custom-element-wrapper">
-                    <div class="survey"  v-if="this.payload.data === 'survey'">
-                        <div class="title">对IM DEMO的评分和建议</div>
-                        <el-rate
-                                v-model="rate"
-                                disabled
-                                show-score
-                                text-color="#ff9900"
-                                score-template="{value}">
-                        </el-rate>
-                        <div class="suggestion">{{this.payload.extension}}</div>
-                    </div>
-                    <span class="text" title="您可以自行解析自定义消息" v-else>
+          <div class="sound-element-wrapper" v-else-if="message.contentType === 103" :title="playStatus === 'playing' ? '单击暂停' : '单击播放'" @click="handleClick">
+            <i class="iconfont icon-voice"></i>
+            {{ message.soundElem.duration}}
+          </div>
+          <!--自定义消息-->
+          <div class="message-container" v-else-if="message.contentType === 110">
+            <div class="custom-element-wrapper">
+              <div class="survey"  v-if="this.payload.data === 'survey'">
+                <div class="title">对IM DEMO的评分和建议</div>
+                <el-rate
+                  v-model="rate"
+                  disabled
+                  show-score
+                  text-color="#ff9900"
+                  score-template="{value}">
+                </el-rate>
+                <div class="suggestion">{{this.payload.extension}}</div>
+              </div>
+              <span class="text" title="您可以自行解析自定义消息" v-else>
                       <template >{{translateCustomMessage(this.payload)}}</template>
                     </span>
-                </div>
             </div>
-<!--合并的消息-->
-            <div class="message-container"  @click="mergerHandler(message)" v-else-if="message.type === TIM.TYPES.MSG_MERGER">
-                <div class="merger-item">
-                    <p class="merger-title">{{payload.title}}</p>
-                    <p class="merger-text" v-for="(item, index) in payload.abstractList" :key="index">
-                        {{item}}
-                    </p>
-                </div>
+          </div>
+          <!--合并的消息-->
+          <div class="message-container"  @click="mergerHandler(message)" v-else-if="message.contentType === 107">
+            <div class="merger-item">
+              <p class="merger-title">{{message.mergeElem.title}}</p>
+              <p class="merger-text" v-for="(item, index) in message.mergeElem.abstractList" :key="index">
+                {{item}}
+              </p>
             </div>
+          </div>
         </div>
 
     </div>
@@ -91,8 +91,8 @@
       },
       payload: {
         type: Object,
-        required: true
-      },
+        default: () => ({})
+      }
 
     },
     components: {
@@ -105,9 +105,19 @@
         relayMessage: {},
         selectedConversation: [],
         messageSelected:[],
+        amr: null,
+        audio: null,
+        isAMR: false,
+        playStatus: 'stopped' // 'playing' | 'paused' | 'stopped'
       }
     },
     computed: {
+      url() {
+        return this.message.soundElem.sourceUrl
+      },
+      second() {
+        return this.message.soundElem.duration
+      },
       ...mapState({
         currentConversation: state => state.conversation.currentConversation,
         currentUserProfile: state => state.imuser.currentUserProfile,
@@ -120,7 +130,7 @@
       },
       // 图片消息
       imageUrl() {
-        const url = this.payload.imageInfoArray[0].imageUrl
+        const url = this.message.pictureElem.sourcePicture.url
         if (typeof url !== 'string') {
           return ''
         }
@@ -149,7 +159,7 @@
 
       // 文件消息大小
       fileSize() {
-        const size = this.payload.fileSize
+        const size = this.message.fileElem.fileSize
         if (size > 1024) {
           if (size / 1024 > 1024) {
             return `${this.toFixed(size / 1024 / 1024)} Mb`
@@ -160,7 +170,7 @@
       },
       // 消息昵称
       from() {
-        const isC2C = this.currentConversation.type === this.TIM.TYPES.CONV_C2C
+        const isC2C = this.currentConversation.type === 1
         // 自己发送的用昵称渲染
         if (this.isMine) {
           return  this.currentUserProfile.nick || this.currentUserProfile.userID
@@ -195,6 +205,7 @@
         return this.message.flow === 'out'
       },
       contentList() {
+        console.log("this.payload",this.payload)
         return decodeText(this.payload)
       },
     },
@@ -227,7 +238,7 @@
       },
       handlePreview() {
         this.$bus.$emit('image-preview', {
-          url: this.payload.imageInfoArray[0].url,
+          url: this.message.pictureElem.sourcePicture.url,
           flag: true
         })
       },
@@ -264,19 +275,19 @@
         let type = ''
         let toUserId = ''
         this.selectedConversation.forEach((item) => {
-          if(item.indexOf(this.TIM.TYPES.CONV_C2C) !== -1) {
-            type = this.TIM.TYPES.CONV_C2C
+          if(item.indexOf(this.OpenIM.TYPES.CONV_C2C) !== -1) {
+            type = 1
             toUserId = item.substring(3,item.length)
           }
-          if(item.indexOf(this.TIM.TYPES.CONV_GROUP) !== -1) {
-            type = this.TIM.TYPES.CONV_GROUP
+          if(item.indexOf(3) !== -1) {
+            type = 3
             toUserId = item.substring(5,item.length)
           }
           const message = this.tim.createForwardMessage({
             to: toUserId,
             conversationType: type,
             payload: this.relayMessage,
-            priority: this.TIM.TYPES.MSG_PRIORITY_NORMAL
+            priority: this.OpenIM.TYPES.MSG_PRIORITY_NORMAL
           })
           this.tim.sendMessage(message).catch(imError => {
             this.$store.commit('showMessage', {
@@ -289,6 +300,7 @@
       },
       // 合并的消息
       mergerHandler(message) {
+        console.log("setMergerMessage",message)
         this.$store.commit('setMergerMessage', message)
         // this.$bus.$emit('mergerMessage', message)
       },
@@ -298,75 +310,122 @@
       },
       // 音频消息
       play() {
-        // 目前移动端的语音消息采用 aac 格式,以前用 amr 格式。默认先用 audio 标签播放,若无法播放则尝试 amr 格式播放。
-        const audio = document.createElement('audio')
-        audio.addEventListener('error', this.tryPlayAMR) // 播放出错,则尝试使用 AMR 播放
-        audio.src = this.payload.url
-        const promise = audio.play()
-        if (promise) {
-          promise.catch(() => {})
+        this.cleanup()
+
+        // 默认使用 HTML5 audio 播放
+        this.audio = new Audio(this.url)
+        console.log(this.audio)
+        this.audio.addEventListener('error', this.tryPlayAMR)
+        this.audio.addEventListener('ended', this.cleanup)
+        this.audio.play()
+          .then(() => {
+            this.playStatus = 'playing'
+          })
+          .catch(() => {
+            // 播放失败 fallback 到 tryPlayAMR
+          })
+      },
+      handleClick() {
+        console.log("this.message.soundElem.sourceUrl",this.message.soundElem.sourceUrl)
+        if (this.playStatus === 'playing') {
+          this.pause()
+        } else if (this.playStatus === 'paused') {
+          this.resume()
+        } else {
+          this.play()
         }
       },
+      pause() {
+        if (this.isAMR && this.amr) {
+          this.amr.pause()
+        } else if (this.audio) {
+          this.audio.pause()
+        }
+        this.playStatus = 'paused'
+      },
+      resume() {
+        if (this.isAMR && this.amr) {
+          this.amr.play()
+        } else if (this.audio) {
+          this.audio.play()
+        }
+        this.playStatus = 'playing'
+      },
       tryPlayAMR() {
-        try {
-          const isIE = /MSIE|Trident|Edge/.test(window.navigator.userAgent)
-          // amr 播放组件库在 IE 不支持
-          if (isIE) {
-            this.$store.commit('showMessage', {
-              message: '您的浏览器不支持该格式的语音消息播放,请尝试更换浏览器,建议使用:谷歌浏览器',
-              type: 'warning'
-            })
-            return
-          }
-          // 动态插入 amr 播放组件库
-          if (!window.BenzAMRRecorder) {
-            const script = document.createElement('script')
-            script.addEventListener('load', this.playAMR)
-            script.src = '/BenzAMRRecorder.js'
-            const firstScript = document.getElementsByTagName('script')[0]
-            firstScript.parentNode.insertBefore(script, firstScript)
-            return
-          }
-          this.playAMR()
-        } catch (error) {
+        this.isAMR = true
+        const isIE = /MSIE|Trident|Edge/.test(window.navigator.userAgent)
+        if (isIE) {
           this.$store.commit('showMessage', {
             message: '您的浏览器不支持该格式的语音消息播放,请尝试更换浏览器,建议使用:谷歌浏览器',
             type: 'warning'
           })
+          return
+        }
+
+        if (!window.BenzAMRRecorder) {
+          const script = document.createElement('script')
+          script.addEventListener('load', this.playAMR)
+          script.src = '/BenzAMRRecorder.js'
+          document.head.appendChild(script)
+          return
         }
+
+        this.playAMR()
       },
       playAMR() {
         if (!this.amr && window.BenzAMRRecorder) {
           this.amr = new window.BenzAMRRecorder()
+          this.amr.onEnded(() => {
+            this.cleanup()
+          })
         }
+
         if (this.amr.isInit()) {
           this.amr.play()
-          return
+          this.playStatus = 'playing'
+        } else {
+          this.amr.initWithUrl(this.url).then(() => {
+            this.amr.play()
+            this.playStatus = 'playing'
+          })
         }
-        this.amr.initWithUrl(this.url).then(() => {
-          this.amr.play()
-        })
+      },
+      cleanup() {
+        if (this.audio) {
+          this.audio.pause()
+          this.audio = null
+        }
+        if (this.amr) {
+          this.amr.stop()
+        }
+        this.playStatus = 'stopped'
       },
       // 文件消息
       downloadFile() {
-        // 浏览器支持fetch则用blob下载,避免浏览器点击a标签,跳转到新页面预览的行为
-        if (window.fetch) {
-          fetch(this.payload.fileUrl)
-            .then(res => res.blob())
-            .then(blob => {
-              let a = document.createElement('a')
-              let url = window.URL.createObjectURL(blob)
-              a.href = url
-              a.download = this.payload.fileName
-              a.click()
-            })
-        } else {
-          let a = document.createElement('a')
-          a.href = this.payload.fileUrl
-          a.target = '_blank'
-          a.download = this.filename
-          a.click()
-        }
+        const fileUrl = this.message.fileElem.sourceUrl;
+        const fileName = this.message.fileElem.fileName;
+        console.log(fileUrl)
+        fetch(fileUrl)
+          .then(response => {
+            if (!response.ok) throw new Error(`下载失败,状态码:${response.status}`);
+            return response.blob();
+          })
+          .then(blob => {
+            /*const mime = 'application/vnd.openxmlformats-officedocument.wordprocessingml.document';
+            const docBlob = new Blob([blob], { type: mime });*/ // 💡 明确指定 MIME 类型
+            const blobUrl = window.URL.createObjectURL(blob);
+
+            const a = document.createElement('a');
+            a.href = blobUrl;
+            a.download = fileName;
+            document.body.appendChild(a);
+            a.click();
+            document.body.removeChild(a);
+            window.URL.revokeObjectURL(blobUrl); // 释放资源
+          })
+          .catch(err => {
+            console.error('下载失败:', err);
+          });
       }
     }
   }

+ 7 - 6
src/components/message/merger-message/message-merger.vue

@@ -6,14 +6,14 @@
                     <div   v-for="(messageItem, index) in mergerList(mergerMessage)" :key="index">
                         <div class="message-item">
                             <div class="avatar-box">
-                                <avatar class="group-member-avatar" :src="messageItem.avatar"/>
+                                <avatar class="group-member-avatar" :src="messageItem.senderFaceUrl"/>
                             </div>
                             <div class="container-box">
                                 <div class="nick-date">
-                                    <div class="name text-ellipsis">{{messageItem.nick || messageItem.from || '小晨曦'}}</div>
-                                    <div class="date">{{ getDate(messageItem.time) }}</div>
+                                    <div class="name text-ellipsis">{{messageItem.senderNickname || messageItem.from || '小晨曦'}}</div>
+                                    <div class="date">{{ getDate(messageItem.sendTime) }}</div>
                                 </div>
-                                <merger-message-item v-for="(item,index) in messageItem.messageBody" :key="index" :message="item" :payload="item.payload"/>
+                                <merger-message-item  :message="messageItem" :payload="messageItem.textElem"/>
                             </div>
                         </div>
                         <el-divider></el-divider>
@@ -48,7 +48,8 @@
       }),
       mergerList() {
         return function(message) {
-          return message.payload.messageList
+          console.log(message)
+          return message.mergeElem.multiMessage
         }
       }
     },
@@ -65,7 +66,7 @@
     },
     methods: {
       getDate(time) {
-        return getFullDate(new Date(time * 1000))
+        return getFullDate(new Date(time))
       },
       onScroll({ target: { scrollTop } }) {
         let messageListNode = this.$refs['message-list']

+ 130 - 62
src/components/message/merger-message/message-relay.vue

@@ -13,7 +13,7 @@
 <script>
   import { mapState } from 'vuex'
   import ConversationSelectedList from '../../conversation/conversation-selected-list'
-
+  import { getOpenIM } from '@/utils/openIM';
   export default {
     name: 'MessageBubble',
     components: {
@@ -21,6 +21,7 @@
     },
     data() {
       return {
+        OpenIM:null,
         isTimeout: false,
         showConversationList: false,
         selectedConversation: [],
@@ -28,6 +29,7 @@
       }
     },
     created() {
+      this.OpenIM = getOpenIM();
     },
     mounted() {
       if (this.$refs.dropdown && this.$refs.dropdown.$el) {
@@ -58,14 +60,15 @@
 
       },
       sendSingleMessage(to, type, message) {
-        const _message = this.tim.createForwardMessage({
-          to: to,
-          conversationType: type,
-          payload: message,
-          priority: this.TIM.TYPES.MSG_PRIORITY_NORMAL
-        })
-        this.$store.commit('pushCurrentMessageList', _message)   // ??
-        return _message
+        return this.OpenIM.createForwardMessage(message)
+          .then(({ data }) => {
+            console.log("创建转发消息成功111", data);
+            this.$store.commit('pushCurrentMessageList', data);
+            return data
+          })
+          .catch(({ errCode, errMsg }) => {
+            console.error("创建转发消息失败", errCode, errMsg);
+          });
       },
       mergerSort() {
         this.selectedMessageList.sort((a, b) =>  {
@@ -76,42 +79,65 @@
           }
         })
       },
-      mergerMessage(to, type) {
-        let _abstractList = [], _count = 0, _title = ''
-        _count = this.selectedMessageList.length < 3 ? this.selectedMessageList.length : 3
-
-        for(let i = 0; i < _count; i++) {
-          _abstractList.push(this.setAbstractList(this.selectedMessageList[i]))
+      updateConversationList(){
+        this.OpenIM.getAllConversationList().then(({ data }) => {
+            // 调用成功
+            console.log(data,"147852")
+            this.$store.commit('updateConversationList', data)
+          })
+          .catch(({ errCode, errMsg }) => {
+            // 调用失败
+          })
+      },
+      mergerMessage(to, type, messageList) {
+        let _summaryList = [];
+        const _count = this.selectedMessageList.length < 3 ? this.selectedMessageList.length : 3;
+        for (let i = 0; i < _count; i++) {
+          _summaryList.push(this.setAbstractList(this.selectedMessageList[i]));
         }
-        _title = this.selectedMessageList[0].conversationType === 'GROUP' ? '群聊的聊天记录' : `${this.selectedMessageList[0].nick || this.selectedMessageList[0].from} 和 ${this.selectedMessageList[0].to} 的聊天记录`
-        let message = this.tim.createMergerMessage({
-          to: to,
-          conversationType: type,
-          payload: {
-            messageList: this.selectedMessageList ,
-            title: _title,
-            abstractList: _abstractList,
-            compatibleText: '请升级IMSDK到v2.10.1或更高版本查看此消息'
-          }
+
+        /*const _title = this.selectedMessageList[0].conversationType === 'GROUP'
+          ? '群聊的聊天记录'
+          : `${this.selectedMessageList[0].senderNickname || this.selectedMessageList[0].from} 和 ${this.selectedMessageList[0].to} 的聊天记录`;*/
+        const _title = "聊天记录"
+        console.log("创建合并转发消息参数",this.selectedMessageList)
+        return this.OpenIM.createMergerMessage({
+          messageList: this.selectedMessageList,
+          title: _title,
+          summaryList: _summaryList
         })
-        this.$store.commit('pushCurrentMessageList', message)   // ??
-        return message
+          .then(({ data }) => {
+            // 将返回的合并消息对象存入 Vuex 或其他状态管理
+            this.$store.commit('pushCurrentMessageList', data);
+            console.log("wwwwwwwwwww",data)
+            return data;  // 返回创建的合并消息对象
+          })
+          .catch(({ errCode, errMsg }) => {
+            console.error('合并消息创建失败:', errCode, errMsg);
+            throw new Error(errMsg || '合并消息创建失败');
+          });
       },
+
       async messageRelay() {
+
         let _type = '', _to = ''
+        const myId = this.$store.getters.userID
         for (let item of this.selectedConversation) {
-          if(item.indexOf(this.TIM.TYPES.CONV_C2C) !== -1) {
-            _type = this.TIM.TYPES.CONV_C2C
-            _to = item.substring(3, item.length)
+          if(item.startsWith("si")) {
+            _type = 1
+            _to = item.replace("si","").replace(myId,"").replaceAll("_","");
           }
-          if(item.indexOf(this.TIM.TYPES.CONV_GROUP) !== -1) {
-            _type = this.TIM.TYPES.CONV_GROUP
+          if(item.startsWith("sg")) {
+            _type = 3
             _to = item.substring(5, item.length)
           }
           // 排序
+          console.log(this.$store.state.conversation,"||||")
           this.mergerSort()
           if (this.relayType === 1) {
-            let message = this.sendSingleMessage(_to, _type, this.relayMessage)
+            this.relayMessage.recvID = _to
+            let message =await this.sendSingleMessage(_to, _type, this.relayMessage)
+            console.log(message,"message")
             this.sendMessageHandler(message)
           }
 
@@ -123,23 +149,44 @@
               })
               return
             }
+
             for (let selectedMessage of this.selectedMessageList) {
+              console.log("selectedMessage",selectedMessage)
+              selectedMessage.recvID = _to
               let message = await this.sendSingleMessage(_to, _type, selectedMessage)
-              await this.tim.sendMessage(message)
+              console.log("转发类型",message)
+              const sendText={
+                message:message,
+                recvID:message.recvID,
+                groupID:"",
+                offlinePushInfo : {
+                  title:message.senderNickname,
+                  desc:this.setAbstractList(message),
+                  iOSPushSound:"",
+                  iOSBadgeCount:true,
+                  operatorUserID:"",
+                  ex:""
+                }
+              }
+              console.log("this.OpenIM",this.OpenIM)
+              await this.OpenIM.sendMessage(sendText)
                 .then((res) => {
                   return res
                 })
-                .catch(imError => {
+                .catch(error => {
                   this.$store.commit('showMessage', {
-                    message: imError.message,
-                    type: 'error'
+                    type: 'error',
+                    message: error.message
                   })
                 })
 
             }
           }
           if (this.relayType === 3) {
-            let message = this.mergerMessage(_to, _type)
+            let message =await this.mergerMessage(_to, _type,this.selectedMessageList)
+
+            message.recvID = _to
+            console.log("wwwwwwwwwwwwwwwwww",message)
             this.sendMessageHandler(message)
           }
         }
@@ -148,37 +195,58 @@
       },
 
       sendMessageHandler(message) {
-        this.tim.sendMessage(message).catch(imError => {
-            this.$store.commit('showMessage', {
-              message: imError.message,
-              type: 'error'
-            })
+        console.log("this.OpenIM111",message)
+        const sendText={
+          message:message,
+          recvID:message.recvID,
+          groupID:"",
+          offlinePushInfo : {
+            title:message.senderNickname,
+            desc:this.setAbstractList(message),
+            iOSPushSound:"",
+            iOSBadgeCount:true,
+            operatorUserID:"",
+            ex:""
+          }
+        }
+        this.OpenIM.sendMessage(sendText).then(({ data }) => {
+          const msgList = Array.isArray(data) ? data : [data];
+          this.$store.commit('pushCurrentMessageList', msgList)
+          this.updateConversationList()
+          this.$bus.$emit('scroll-bottom')
+        }).catch(({ errCode, errMsg }) => {
+          // 调用失败
+          this.$store.commit('showMessage', {
+            message: errMsg.message,
+            type: 'error'
           })
+        });
       },
       setAbstractList(message) {
-        let nick = message.nick || message.from
+        console.log(message,"message1111111111111111111111")
+        let nickname = message.senderNickname || message.from
         let text = ''
-        switch (message.type) {
-          case this.TIM.TYPES.MSG_TEXT:
-            text = message.payload.text || ''
+        switch (message.contentType) {
+          case 101:
+            text = message.textElem.content || ''
             if (text.length > 20) {
               text = text.slice(0, 20)
             }
-            return `${nick}: ${text}`
-          case this.TIM.TYPES.MSG_MERGER:
-            return `${nick}: [聊天记录]`
-          case this.TIM.TYPES.MSG_IMAGE:
-            return `${nick}: [图片]`
-          case this.TIM.TYPES.MSG_AUDIO:
-            return `${nick}: [音频]`
-          case this.TIM.TYPES.MSG_VIDEO:
-            return `${nick}: [视频]`
-          case this.TIM.TYPES.MSG_CUSTOM:
-            return `${nick}: [自定义消息]`
-          case this.TIM.TYPES.MSG_FILE:
-            return `${nick}: [文件]`
-          case this.TIM.TYPES.MSG_FACE:
-            return `${nick}: [动画表情]`
+            return `${nickname}: ${text}`
+          case 107:
+            return `${nickname}: [聊天记录]`
+          case 102:
+            return `${nickname}: [图片]`
+          case 103:
+            return `${nickname}: [音频]`
+          case 104:
+            return `${nickname}: [视频]`
+          case 110:
+            return `${nickname}: [自定义消息]`
+          case 105:
+            return `${nickname}: [文件]`
+          case 115:
+            return `${nickname}: [动画表情]`
         }
       },
       handleDropDownMousedown(e) {

+ 30 - 14
src/components/message/message-bubble.vue

@@ -5,7 +5,7 @@
         <div v-if="isMine && messageReadByPeer" class="message-status">
           <span>{{messageReadByPeer}}</span>
         </div>
-        <div class="message-content" :class="bubbleStyle">
+        <div v-if="message.contentType!==2101" class="message-content" :class="bubbleStyle">
           <slot></slot>
         </div>
       </div>
@@ -15,7 +15,7 @@
         <el-dropdown-item command="merger" v-show="message.status !=='fail'">多选</el-dropdown-item>
       </el-dropdown-menu>
     </el-dropdown>
-    <div class="group-tip-element-wrapper" v-if="message.isRevoked">
+    <div class="group-tip-element-wrapper" v-if="isRevoked">
       {{text}}
       <el-button type="text" size="mini" class="edit-button" v-show="isEdit" @click="reEdit">&nbsp;重新编辑</el-button>
     </div>
@@ -23,18 +23,21 @@
 </template>
 
 <script>
-
+  import { getOpenIM } from '@/utils/openIM';
+  import {mapGetters, mapState} from "vuex";
   export default {
   name: 'MessageBubble',
   components: {
   },
   data() {
     return {
+      OpenIM:null,
       isTimeout: false,
       showConversationList: false,
       relayMessage: {},
       selectedConversation: [],
       testMergerMessage: {}
+
     }
   },
   props: {
@@ -50,6 +53,7 @@
     }
   },
   created() {
+    this.OpenIM = getOpenIM();
     this.isTimeoutHandler()
   },
   mounted() {
@@ -78,23 +82,28 @@
       return classString
     },
     text() {
-      if (this.message.conversationType === this.TIM.TYPES.CONV_C2C && !this.isMine) {
+      if (this.message.sessionType === 1 && !this.isMine) {
         return '对方撤回了一条消息'
       }
-      if (this.message.conversationType === this.TIM.TYPES.CONV_GROUP && !this.isMine) {
+      if (this.message.sessionType === 3 && !this.isMine) {
         return `${this.message.from}撤回了一条消息`
       }
       return '你撤回了一条消息'
     },
+    isRevoked() {
+      return this.message.contentType === 2101
+    },
     messageReadByPeer() {
-      if (this.message.status !== 'success') {
+      if (this.message.status !== 2) {
         return false
       }
-      if (this.message.conversationType === this.TIM.TYPES.CONV_C2C && this.message.isPeerRead) {
-        return '已读'
-      }
-      if (this.message.conversationType === this.TIM.TYPES.CONV_C2C && !this.message.isPeerRead) {
-        return '未读'
+      if (this.message.contentType!== 2101){
+        if (this.message.sessionType === 1 && this.message.isRead) {
+          return '已读'
+        }
+        if (this.message.sessionType === 1 && !this.message.isRead) {
+          return '未读'
+        }
       }
       return ''
     },
@@ -102,7 +111,7 @@
       if (!this.isMine) {
         return false
       }
-      if (this.message.type !== this.TIM.TYPES.MSG_TEXT) {
+      if (this.message.contentType !== 101) {
         return false
       }
       if (this.isTimeout) {
@@ -124,7 +133,14 @@
     handleCommand(command) {
       switch (command) {
         case 'revoke':
-          this.tim.revokeMessage(this.message).then(() => {
+          this.OpenIM.revokeMessage({
+            conversationID:this.$store.state.conversation.currentConversation.conversationID,
+            clientMsgID:this.message.clientMsgID
+          }).then(() => {
+            this.$store.dispatch(
+              'checkoutConversation',
+              this.$store.state.conversation.currentConversation,
+            )
             this.isTimeoutHandler()
           }).catch((err) => {
             this.$store.commit('showMessage', {
@@ -148,7 +164,7 @@
     },
     isTimeoutHandler() { // 从发送消息时间开始算起,两分钟内可以编辑
       let now = new Date()
-      if (parseInt(now.getTime() / 1000) - this.message.time > 2 * 60) {
+      if (parseInt(now.getTime()) - this.message.sendTime > 2 * 60*1000) {
         this.isTimeout = true
         return
       }

+ 32 - 15
src/components/message/message-elements/custom-element.vue

@@ -1,25 +1,32 @@
 <template>
 <message-bubble :isMine=isMine :message=message>
   <div class="custom-element-wrapper">
-    <span v-if="payload.data === 'startInquiry'" class="text"   >
+    <!--<span v-if="payload.customType === 200" class="text"  >
+      {{text}}
+    </span>-->
+    <span v-if="payload.payload.data === 'startInquiry'" class="text"   >
       {{text}}
     </span>
-    <span v-if="payload.data === 'finishInquiry'" class="text"   >
+    <span v-else-if="payload.payload.data === 'finishInquiry'" class="text"   >
       {{text}}
     </span>
-    <span v-if="payload.data === 'prescribe'" class="text"   >
-      处方单
+    <span v-else-if="payload.payload.data === 'prescribe'" class="text"   >
+      电子处方单
     </span>
-    <span v-if="payload.data === 'follow'" class="text" @click="openFollow(payload)"   >
+    <span v-else-if="payload.payload.data === 'follow'" class="text" @click="openFollow(payload.payload)"   >
       随访单
     </span>
-    <span v-if="payload.data === 'report'" class="text"   >
+    <span v-else-if="payload.payload.data === 'report'" class="text"   >
       问诊报告单
     </span>
-    <span v-if="payload.data === 'drugReport'" class="text" @click="openDrugReport(payload)"  >
+    <span v-else-if="payload.payload.data === 'drugReport'" class="text" @click="openDrugReport(payload.payload)"  >
       用药报告单
     </span>
-    <span v-else    >
+    <span v-else-if="payload.payload.data === 'order'" class="text"  >
+      问诊订单
+    </span>
+
+    <span v-else  >
       {{text}}
     </span>
     <el-drawer  :append-to-body="true" :with-header="false" size="75%" :title="show.title" :visible.sync="show.open">
@@ -32,7 +39,7 @@
 
 <script>
 import { mapState } from 'vuex'
-import MessageBubble from '../message-bubble'
+import MessageBubble from '@/components/message/message-bubble.vue'
 import followDetails from '@/views/components/follow/followDetails.vue';
 import drugReportDetails from '@/views/components/drugReport/drugReportDetails.vue';
 export default {
@@ -75,7 +82,7 @@ export default {
   methods: {
     openFollow(data){
       var that=this;
-      var followId=JSON.parse(data.extension).followId;
+      var followId=data.extension.followId;
       this.show.open=true;
       this.show.type=1;
       this.show.title="随访单"
@@ -84,6 +91,7 @@ export default {
       }, 500);
     },
     openDrugReport(data){
+      console.log("qwertttttttt",data)
       var that=this;
       var reportId=data.description;
       this.show.open=true;
@@ -95,7 +103,7 @@ export default {
     },
     translateCustomMessage(payload) {
       let videoPayload = {}
-      try{
+      /*try{
         videoPayload = JSON.parse(payload.data)
       } catch(e) {
         videoPayload = {}
@@ -107,12 +115,21 @@ export default {
         videoPayload.roomId = videoPayload.roomId.toString()
         videoPayload.isFromGroupLive = 1
         return videoPayload
+      }*/
+      /*console.log("qwerasdf",payload)
+      console.log("qwerasdf",payload.data.mediaType==='video')
+      if (payload.data.mediaType==='video'){
+        return '视频通话'
       }
-      if(payload.text) {
-        return payload.text
+      if (payload.data.mediaType==='audio'){
+        return '语音通话'
+      }*/
+      if(payload.payload.text) {
+        return payload.payload.text
       }else{
-        var obj=JSON.parse(payload.extension);
-        return obj.title
+        return payload.payload.extension.title
+        /*var obj=JSON.parse(payload.extension);
+        return obj.title*/
       }
     }
   }

+ 28 - 20
src/components/message/message-elements/file-element.vue

@@ -1,5 +1,5 @@
 <template>
-<message-bubble :isMine=isMine :message=message>  
+<message-bubble :isMine=isMine :message=message>
   <div class="file-element-wrapper" title="单击下载" @click="downloadFile">
     <div class="header">
       <i class="el-icon-document file-icon"></i>
@@ -44,7 +44,7 @@ export default {
       return this.payload.fileName
     },
     fileUrl() {
-      return this.payload.fileUrl
+      return this.payload.sourceUrl
     },
     size() {
       const size = this.payload.fileSize
@@ -68,24 +68,32 @@ export default {
       return number.toFixed(precision)
     },
     downloadFile() {
-      // 浏览器支持fetch则用blob下载,避免浏览器点击a标签,跳转到新页面预览的行为
-      if (window.fetch) {
-        fetch(this.fileUrl)
-          .then(res => res.blob())
-          .then(blob => {
-            let a = document.createElement('a')
-            let url = window.URL.createObjectURL(blob)
-            a.href = url
-            a.download = this.fileName
-            a.click()
-          })
-      } else {
-        let a = document.createElement('a')
-        a.href = this.fileUrl
-        a.target = '_blank'
-        a.download = this.filename
-        a.click()
-      }
+      console.log(this.payload)
+      console.log(this.message)
+      const fileUrl = this.fileUrl;
+      const fileName = this.fileName;
+      console.log(fileUrl)
+      fetch(fileUrl)
+        .then(response => {
+          if (!response.ok) throw new Error(`下载失败,状态码:${response.status}`);
+          return response.blob();
+        })
+        .then(blob => {
+          const mime = 'application/vnd.openxmlformats-officedocument.wordprocessingml.document';
+          const docBlob = new Blob([blob], { type: mime }); // 💡 明确指定 MIME 类型
+          const blobUrl = window.URL.createObjectURL(docBlob);
+
+          const a = document.createElement('a');
+          a.href = blobUrl;
+          a.download = fileName;
+          document.body.appendChild(a);
+          a.click();
+          document.body.removeChild(a);
+          window.URL.revokeObjectURL(blobUrl); // 释放资源
+        })
+        .catch(err => {
+          console.error('下载失败:', err);
+        });
     }
   }
 }

+ 1 - 1
src/components/message/message-elements/group-system-notice-element.vue

@@ -69,7 +69,7 @@ export default {
       return translateGroupSystemNotice(this.message)
     },
     title() {
-      if (this.message.type === this.TIM.TYPES.MSG_GRP_SYS_NOTICE) {
+       if (this.message.type === this.OpenIM.TYPES.MSG_GRP_SYS_NOTICE) {
         return '群系统通知'
       }
       return '系统通知'

+ 7 - 7
src/components/message/message-elements/group-tip-element.vue

@@ -37,17 +37,17 @@
       let nick = message.nick || ((message.from === this.userID) && this.currentUserProfile.nick) ||  message.from
       const userName = message.nick || message.payload.userIDList.join(',')
       switch (message.payload.operationType) {
-        case this.TIM.TYPES.GRP_TIP_MBR_JOIN:
+        case this.OpenIM.TYPES.GRP_TIP_MBR_JOIN:
           return `群成员:${userName} 加入群组`
-        case this.TIM.TYPES.GRP_TIP_MBR_QUIT:
+        case this.OpenIM.TYPES.GRP_TIP_MBR_QUIT:
           return `群成员:${userName} 退出群组`
-        case this.TIM.TYPES.GRP_TIP_MBR_KICKED_OUT:
+        case this.OpenIM.TYPES.GRP_TIP_MBR_KICKED_OUT:
           return `群成员:${userName} 被${message.payload.operatorID}踢出群组`
-        case this.TIM.TYPES.GRP_TIP_MBR_SET_ADMIN:
+        case this.OpenIM.TYPES.GRP_TIP_MBR_SET_ADMIN:
           return `群成员:${userName} 成为管理员`
-        case this.TIM.TYPES.GRP_TIP_MBR_CANCELED_ADMIN:
+        case this.OpenIM.TYPES.GRP_TIP_MBR_CANCELED_ADMIN:
           return `群成员:${userName} 被撤销管理员`
-        case this.TIM.TYPES.GRP_TIP_GRP_PROFILE_UPDATED:
+        case this.OpenIM.TYPES.GRP_TIP_GRP_PROFILE_UPDATED:
           return '群资料修改'
         case this.callTips:
           if(message.payload.text.indexOf('结束群聊')> -1) {
@@ -55,7 +55,7 @@
           }else {
             return  `"${nick}" ${message.payload.text}`
           }
-        case this.TIM.TYPES.GRP_TIP_MBR_PROFILE_UPDATED:
+        case this.OpenIM.TYPES.GRP_TIP_MBR_PROFILE_UPDATED:
           for (let member of message.payload.memberList) {
             if (member.muteTime > 0) {
               return `群成员:${member.userID}被禁言${member.muteTime}秒`

+ 4 - 3
src/components/message/message-elements/image-element.vue

@@ -8,7 +8,7 @@
       :color="percentage => (percentage === 100 ? '#67c23a' : '#409eff')"
     />
 
- 
+
   </message-bubble>
 </template>
 
@@ -38,7 +38,8 @@ export default {
   computed: {
     ...mapGetters(['imgUrlList']),
     imageUrl() {
-      const url = this.payload.imageInfoArray[0].url
+      console.log("this.payload",this.payload)
+      const url = this.payload.sourcePicture.url
       if (typeof url !== 'string') {
         return ''
       }
@@ -57,7 +58,7 @@ export default {
     },
     handlePreview() {
       this.$bus.$emit('image-preview', {
-        url: this.payload.imageInfoArray[0].url
+        url: this.payload.sourcePicture.url
       })
     }
   }

+ 1 - 1
src/components/message/message-elements/merger-element.vue

@@ -19,7 +19,7 @@
     props: {
       payload: {
         type: Object,
-        required: true
+        default: () => ({}),
       },
       message: {
         type: Object,

+ 119 - 74
src/components/message/message-elements/sound-element.vue

@@ -1,63 +1,95 @@
 <template>
-<message-bubble :isMine=isMine :message=message>
-  <div class="sound-element-wrapper" title="单击播放" @click="play">
-    <i class="iconfont icon-voice"></i>
-    {{ second + '"' }}
-  </div>
-</message-bubble>
+  <message-bubble :isMine="isMine" :message="message">
+    <div class="sound-element-wrapper" :title="playStatus === 'playing' ? '单击暂停' : '单击播放'" @click="handleClick">
+      <i class="iconfont icon-voice"></i>
+      {{ second + '"' }}
+    </div>
+  </message-bubble>
 </template>
 
 <script>
-import MessageBubble from '../message-bubble'
-export default {
-  name: 'SoundElement',
-  props: {
-    payload: {
-      type: Object,
-      required: true
+  import MessageBubble from '@/components/message/message-bubble.vue'
+
+  export default {
+    name: 'SoundElement',
+    props: {
+      payload: {
+        type: Object,
+        required: true
+      },
+      message: {
+        type: Object,
+        required: true
+      },
+      isMine: {
+        type: Boolean
+      }
     },
-    message: {
-      type: Object,
-      required: true
+    components: {
+      MessageBubble
     },
-    isMine: {
-      type: Boolean
-    }
-  },
-  components: {
-    MessageBubble
-  },
-  data() {
-    return {
-      amr: null
-    }
-  },
-  computed: {
-    url() {
-      return this.payload.url
-    },
-    size() {
-      return this.payload.size
+    data() {
+      return {
+        amr: null,
+        audio: null,
+        isAMR: false,
+        playStatus: 'stopped' // 'playing' | 'paused' | 'stopped'
+      }
     },
-    second() {
-      return this.payload.second
-    }
-  },
-  methods: {
-    play() {
-      // 目前移动端的语音消息采用 aac 格式,以前用 amr 格式。默认先用 audio 标签播放,若无法播放则尝试 amr 格式播放。
-      const audio = document.createElement('audio')
-      audio.addEventListener('error', this.tryPlayAMR) // 播放出错,则尝试使用 AMR 播放
-      audio.src = this.url
-      const promise = audio.play()
-      if (promise) {
-        promise.catch(() => {})
+    computed: {
+      url() {
+        return this.payload.sourceUrl
+      },
+      second() {
+        return this.payload.duration
       }
     },
-    tryPlayAMR() {
-      try {
+    methods: {
+      handleClick() {
+        console.log(this.payload.sourceUrl)
+        if (this.playStatus === 'playing') {
+          this.pause()
+        } else if (this.playStatus === 'paused') {
+          this.resume()
+        } else {
+          this.play()
+        }
+      },
+      play() {
+        this.cleanup()
+
+        // 默认使用 HTML5 audio 播放
+        this.audio = new Audio(this.url)
+        console.log(this.audio)
+        this.audio.addEventListener('error', this.tryPlayAMR)
+        this.audio.addEventListener('ended', this.cleanup)
+        this.audio.play()
+          .then(() => {
+            this.playStatus = 'playing'
+          })
+          .catch(() => {
+            // 播放失败 fallback 到 tryPlayAMR
+          })
+      },
+      pause() {
+        if (this.isAMR && this.amr) {
+          this.amr.pause()
+        } else if (this.audio) {
+          this.audio.pause()
+        }
+        this.playStatus = 'paused'
+      },
+      resume() {
+        if (this.isAMR && this.amr) {
+          this.amr.play()
+        } else if (this.audio) {
+          this.audio.play()
+        }
+        this.playStatus = 'playing'
+      },
+      tryPlayAMR() {
+        this.isAMR = true
         const isIE = /MSIE|Trident|Edge/.test(window.navigator.userAgent)
-        // amr 播放组件库在 IE 不支持
         if (isIE) {
           this.$store.commit('showMessage', {
             message: '您的浏览器不支持该格式的语音消息播放,请尝试更换浏览器,建议使用:谷歌浏览器',
@@ -65,42 +97,55 @@ export default {
           })
           return
         }
-        // 动态插入 amr 播放组件库
+
         if (!window.BenzAMRRecorder) {
           const script = document.createElement('script')
           script.addEventListener('load', this.playAMR)
           script.src = '/BenzAMRRecorder.js'
-          const firstScript = document.getElementsByTagName('script')[0]
-          firstScript.parentNode.insertBefore(script, firstScript)
+          document.head.appendChild(script)
           return
         }
+
         this.playAMR()
-      } catch (error) {
-        this.$store.commit('showMessage', {
-          message: '您的浏览器不支持该格式的语音消息播放,请尝试更换浏览器,建议使用:谷歌浏览器',
-          type: 'warning'
-        })
+      },
+      playAMR() {
+        if (!this.amr && window.BenzAMRRecorder) {
+          this.amr = new window.BenzAMRRecorder()
+          this.amr.onEnded(() => {
+            this.cleanup()
+          })
+        }
+
+        if (this.amr.isInit()) {
+          this.amr.play()
+          this.playStatus = 'playing'
+        } else {
+          this.amr.initWithUrl(this.url).then(() => {
+            this.amr.play()
+            this.playStatus = 'playing'
+          })
+        }
+      },
+      cleanup() {
+        if (this.audio) {
+          this.audio.pause()
+          this.audio = null
+        }
+        if (this.amr) {
+          this.amr.stop()
+        }
+        this.playStatus = 'stopped'
       }
     },
-    playAMR() {
-      if (!this.amr && window.BenzAMRRecorder) {
-        this.amr = new window.BenzAMRRecorder()
-      }
-      if (this.amr.isInit()) {
-        this.amr.play()
-        return
-      }
-      this.amr.initWithUrl(this.url).then(() => {
-        this.amr.play()
-      })
+    beforeDestroy() {
+      this.cleanup()
     }
   }
-}
 </script>
 
 <style lang="stylus" scoped>
-.sound-element-wrapper {
-  padding: 0px 10px;
-  cursor: pointer;
-}
+  .sound-element-wrapper {
+    padding: 0px 10px;
+    cursor: pointer;
+  }
 </style>

+ 3 - 1
src/components/message/message-elements/text-element.vue

@@ -39,7 +39,9 @@ export default {
   },
   computed: {
     contentList() {
-      return decodeText(this.payload)
+      if (this.message.contentType===101){
+        return decodeText(this.payload)
+      }
     }
   }
 }

+ 6 - 4
src/components/message/message-footer.vue

@@ -20,13 +20,14 @@ export default {
     ...mapState({
       currentConversation: state => state.conversation.currentConversation,
       currentUserProfile: state => state.imuser.currentUserProfile,
-      currentMemberList: state => state.group.currentMemberList
+      currentMemberList: state => state.group.currentMemberList,
+      userID: state => state.imuser.userID,
     }),
     date() {
-      return getFullDate(new Date(this.message.time * 1000))
+      return getFullDate(new Date(this.message.sendTime))
     },
     from() {
-      const isC2C = this.currentConversation.type === this.TIM.TYPES.CONV_C2C
+      const isC2C = this.currentConversation.conversationType === 1
       // 自己发送的用昵称渲染
       if (this.isMine) {
         return this.currentUserProfile.nick || this.currentUserProfile.userID
@@ -42,7 +43,8 @@ export default {
       return this.message.nick || this.message.from
     },
     isMine() {
-      return this.message.flow === 'out'
+
+      return this.message.sendID ===  this.$store.getters.userID
     }
   }
 }

+ 3 - 3
src/components/message/message-header.vue

@@ -26,7 +26,7 @@ export default {
       return getFullDate(new Date(this.message.time * 1000))
     },
     from() {
-      const isC2C = this.currentConversation.type === this.TIM.TYPES.CONV_C2C
+      const isC2C = this.currentConversation.type === 1
       // 自己发送的用昵称渲染
       if (this.isMine) {
         return this.message.nameCard || this.currentUserProfile.nick || this.currentUserProfile.userID
@@ -37,8 +37,8 @@ export default {
           this.currentConversation.userProfile.nick ||
           this.currentConversation.userProfile.userID
         )
-      } else if (this.currentConversation.type === this.TIM.TYPES.CONV_SYSTEM) {
-        return this.message.type === this.TIM.TYPES.MSG_GRP_SYS_NOTICE
+      } else if (this.currentConversation.type === 4) {
+        return this.message.type === this.OpenIM.TYPES.MSG_GRP_SYS_NOTICE
           ? '群系统通知'
           : '系统通知'
       }

+ 88 - 66
src/components/message/message-item.vue

@@ -1,7 +1,7 @@
 <template>
   <div class="message-wrapper" :class="messagePosition">
     <div
-            v-if="currentConversationType === TIM.TYPES.CONV_C2C"
+            v-if="currentConversationType === 1"
             class="c2c-layout"
             :class="messagePosition"
     >
@@ -14,70 +14,70 @@
         <div class="content-wrapper">
           <message-status-icon v-if="isMine" :message="message" />
           <text-element
-                  v-if="message.type === TIM.TYPES.MSG_TEXT"
+                  v-if="message.contentType === 101||message.contentType===2101"
                   :isMine="isMine"
-                  :payload="message.payload"
+                  :payload="message.contentType === 101 ? message.textElem : {}"
                   :message="message"
           />
           <image-element
-                  v-else-if="message.type === TIM.TYPES.MSG_IMAGE"
+                  v-else-if="message.contentType === 102"
                   :isMine="isMine"
-                  :payload="message.payload"
+                  :payload="message.pictureElem"
                   :message="message"
           />
           <file-element
-                  v-else-if="message.type === TIM.TYPES.MSG_FILE"
+                  v-else-if="message.contentType === 105"
                   :isMine="isMine"
-                  :payload="message.payload"
+                  :payload="message.fileElem"
                   :message="message"
           />
           <sound-element
-                  v-else-if="message.type === TIM.TYPES.MSG_SOUND"
+                  v-else-if="message.contentType === 103"
                   :isMine="isMine"
-                  :payload="message.payload"
+                  :payload="message.soundElem"
                   :message="message"
           />
           <group-tip-element
-                  v-else-if="message.type===TIM.TYPES.MSG_GRP_TIP"
-                  :payload="message.payload"
+                  v-else-if="message.contentType===1519"
+                  :payload="message.textElem"
                   :message="message"
           />
           <group-system-notice-element
-                  v-else-if="message.type === TIM.TYPES.MSG_GRP_SYS_NOTICE"
-                  :payload="message.payload"
+                  v-else-if="message.contentType === 1400"
+                  :payload="message.textElem"
                   :message="message"
           />
           <custom-element
-                  v-else-if="message.type === TIM.TYPES.MSG_CUSTOM"
+                  v-else-if="message.contentType === 110"
                   :isMine="isMine"
-                  :payload="message.payload"
+                  :payload="parsedCustomPayload"
                   :message="message"
           />
           <face-element
-                  v-else-if="message.type === TIM.TYPES.MSG_FACE"
+                  v-else-if="message.contentType === 115"
                   :isMine="isMine"
-                  :payload="message.payload"
+                  :payload="message.textElem"
                   :message="message"
           />
           <video-element
-                  v-else-if="message.type === TIM.TYPES.MSG_VIDEO"
+                  v-else-if="message.contentType === 104"
                   :isMine="isMine"
-                  :payload="message.payload"
+                  :payload="message.videoElem"
                   :message="message"
           />
           <geo-element
-                  v-else-if="message.type === TIM.TYPES.MSG_GEO"
+                  v-else-if="message.contentType === 109"
                   :isMine="isMine"
-                  :payload="message.payload"
+                  :payload="message.textElem"
                   :message="message"
           />
           <merger-element
-                  v-else-if="message.type === TIM.TYPES.MSG_MERGER"
+                  v-else-if="message.contentType === 107"
                   :isMine="isMine"
-                  :payload="message.payload"
+                  :payload="message.textElem"
                   :message="message"
           />
-          <span v-else>暂未支持的消息类型:{{message.type}}</span>
+          <span v-else>暂未支持的消息类型:{{message.contentType}}</span>
         </div>
         <message-footer v-if="showMessageHeader" :message="message" />
       </div>
@@ -87,7 +87,7 @@
     </div>
 
     <div
-            v-if="currentConversationType === TIM.TYPES.CONV_GROUP"
+            v-if="currentConversationType === 3"
             class="group-layout"
             :class="messagePosition"
     >
@@ -100,67 +100,77 @@
         <message-header v-if="showMessageHeader" :message="message" />
         <div class="content-wrapper">
           <message-status-icon v-if="isMine" :message="message" />
+          <!--文本-->
           <text-element
-                  v-if="message.type === TIM.TYPES.MSG_TEXT"
+                  v-if="message.contentType ===101"
                   :isMine="isMine"
-                  :payload="message.payload"
+                  :payload="message.textElem"
                   :message="message"
           />
+          <!--图片-->
           <image-element
-                  v-else-if="message.type === TIM.TYPES.MSG_IMAGE"
+                  v-else-if="message.contentType === 102"
                   :isMine="isMine"
-                  :payload="message.payload"
+                  :payload="message.textElem"
                   :message="message"
           />
+          <!--文件-->
           <file-element
-                  v-else-if="message.type === TIM.TYPES.MSG_FILE"
+                  v-else-if="message.contentType === 105"
                   :isMine="isMine"
-                  :payload="message.payload"
+                  :payload="message.textElem"
                   :message="message"
           />
+          <!--语音-->
           <sound-element
-                  v-else-if="message.type === TIM.TYPES.MSG_SOUND"
+                  v-else-if="message.contentType === 103"
                   :isMine="isMine"
-                  :payload="message.payload"
+                  :payload="message.soundElem"
                   :message="message"
           />
+          <!--群提示-->
           <group-tip-element
-                  v-else-if="message.type===TIM.TYPES.MSG_GRP_TIP"
+                  v-else-if="message.contentType===1519"
                   :isMine="isMine"
-                  :payload="message.payload"
+                  :payload="message.textElem"
                   :message="message"
           />
+          <!--自定义-->
           <custom-element
-                  v-else-if="message.type === TIM.TYPES.MSG_CUSTOM"
+                  v-else-if="message.contentType === 110"
                   :isMine="isMine"
-                  :payload="message.payload"
+                  :payload="message.textElem"
                   :message="message"
           />
+          <!--表情-->
           <face-element
-                  v-else-if="message.type === TIM.TYPES.MSG_FACE"
+                  v-else-if="message.contentType === 115"
                   :isMine="isMine"
-                  :payload="message.payload"
+                  :payload="message.textElem"
                   :message="message"
           />
+          <!--视频-->
           <video-element
-                  v-else-if="message.type === TIM.TYPES.MSG_VIDEO"
+                  v-else-if="message.contentType === 104"
                   :isMine="isMine"
-                  :payload="message.payload"
+                  :payload="message.textElem"
                   :message="message"
           />
+          <!--位置-->
           <geo-element
-                  v-else-if="message.type === TIM.TYPES.MSG_GEO"
+                  v-else-if="message.contentType === 109"
                   :isMine="isMine"
-                  :payload="message.payload"
+                  :payload="message.textElem"
                   :message="message"
           />
+          <!--合并消息-->
           <merger-element
-                  v-else-if="message.type === TIM.TYPES.MSG_MERGER"
+                  v-else-if="message.contentType === 107"
                   :isMine="isMine"
-                  :payload="message.payload"
+                  :payload="message.mergeElem"
                   :message="message"
           />
-          <span v-else>暂未支持的消息类型:{{message.type}}</span>
+          <span v-else>暂未支持的消息类型:{{message.contentType}}</span>
         </div>
       </div>
       <div class="col-3">
@@ -168,13 +178,13 @@
       </div>
     </div>
 
-    <div class="system-layout" v-if="currentConversationType === TIM.TYPES.CONV_SYSTEM ">
+    <div class="system-layout" v-if="currentConversationType === 4 ">
       <div class="col-1">
         <avatar :src="avatar" :type="currentConversationType" />
       </div>
       <div class="col-2">
         <message-header :message="message" />
-        <group-system-notice-element :payload="message.payload" :message="message" />
+        <group-system-notice-element :payload="message.textElem" :message="message" />
       </div>
     </div>
   </div>
@@ -220,6 +230,7 @@ export default {
     VideoElement,
     GeoElement,
     MergerElement,
+
   },
   data() {
     return {
@@ -227,47 +238,59 @@ export default {
     }
   },
   computed: {
+    parsedCustomPayload() {
+      try {
+        if (this.message.customElem?.data) {
+          const rawData = JSON.parse(this.message.customElem.data);
+          return rawData;
+        }
+      } catch (e) {
+        console.error('解析消息数据失败:', e);
+      }
+      return null;
+    },
     ...mapState({
       currentConversation: state => state.conversation.currentConversation,
       currentUserProfile: state => state.imuser.currentUserProfile,
+      userID: state => state.imuser.userID,
 
     }),
     // 是否显示头像,群提示消息不显示头像
     showAvatar() {
-      if (this.currentConversation.type === 'C2C' && !this.message.isRevoked) { // C2C且没有撤回的消息
+      if (this.currentConversation.conversationType === 1 && this.message.contentType !== 2101) { // C2C且没有撤回的消息
         return true
-      } else if (this.currentConversation.type === 'GROUP' && !this.message.isRevoked) { // group且没有撤回的消息
-        return this.message.type !== this.TIM.TYPES.MSG_GRP_TIP
+      } else if (this.currentConversation.sessionType === 3 && !this.message.contentType !== 2101) { // group且没有撤回的消息
+        return this.message.type !== 1519
       }
       return false
     },
     avatar() {
-      if (this.currentConversation.type === 'C2C') {
-        return this.message.avatar
-      } else if (this.currentConversation.type === 'GROUP') {
+      if (this.currentConversation.conversationType === 1) {
+        return this.message.senderFaceUrl
+      } else if (this.currentConversation.conversationType === 3) {
         return this.isMine
-          ? this.currentUserProfile.avatar
-          : this.message.avatar
+          ? this.currentUserProfile.faceUrl
+          : this.message.faceUrl
       } else {
         return ''
       }
     },
     currentConversationType() {
-      return this.currentConversation.type
+      return this.currentConversation.conversationType
     },
     isMine() {
       // console.log(this.currentUserProfile, this.currentConversation);
-      return this.message.flow === 'out'
+      return this.message.sendID ===  this.$store.getters.userID
     },
     messagePosition() {
       if (
               ['TIMGroupTipElem', 'TIMGroupSystemNoticeElem'].includes(
-                      this.message.type
+                      this.message.contentType
               )
       ) {
         return 'position-center'
       }
-      if (this.message.isRevoked) { // 撤回消息
+      if (this.message.contentType===2101) { // 撤回消息
         return 'position-center'
       }
       if (this.isMine) {
@@ -277,14 +300,14 @@ export default {
       }
     },
     showMessageHeader() {
-      if (
+      /*if (
               ['TIMGroupTipElem', 'TIMGroupSystemNoticeElem'].includes(
-                      this.message.type
+                      this.message.contentType
               )
       ) {
         return false
-      }
-      if (this.message.isRevoked) { // 撤回消息
+      }*/
+      if (this.message.contentType===2101) { // 撤回消息
         return false
       }
       return true
@@ -292,8 +315,7 @@ export default {
   },
   methods: {
     showGroupMemberProfile(event) {
-      this.tim
-              .getGroupMemberProfile({
+      this.tim.getGroupMemberProfile({
                 groupID: this.message.to,
                 userIDList: [this.message.from]
               })

+ 427 - 146
src/components/message/message-send-box.vue

@@ -4,7 +4,10 @@
       <el-popover placement="top" width="400" trigger="click">
         <div class="emojis">
           <div v-for="item in emojiName" class="emoji" :key="item" @click="chooseEmoji(item)">
-            <img :src="emojiUrl + emojiMap[item]" style="width:30px;height:30px" />
+            <!--<img :src="emojiUrl + emojiCharMap[item]" style="width:30px;height:30px" />-->
+            <span style="width:30px;height:30px">
+              {{emojiCharMap[item]}}
+            </span>
           </div>
         </div>
         <i class="iconfont icon-smile" slot="reference" title="发表情"></i>
@@ -17,23 +20,25 @@
       <!-- <i class="iconfont icon-diaocha" title="小调查" @click="surveyDialogVisible = true"></i> -->
       <el-dropdown>
       <span class="el-dropdown-link">
-      <i class="el-icon-phone-outline" v-if="toAccount !== userID&&((imType==1&&orderType==2)||imType==2)" title="语音通话"></i>
+      <!--<i class="el-icon-phone-outline" v-if="toAccount !== userID&&((imType==1&&orderType==2)||imType==2)" title="语音通话"></i>-->
+      <i class="el-icon-phone-outline"  title="语音通话"></i>
       </span>
         <el-dropdown-menu slot="dropdown">
           <el-dropdown-item  @click.native="trtcCalling('video')">视频通话</el-dropdown-item>
           <el-dropdown-item  @click.native="trtcCalling('audio')">语音通话</el-dropdown-item>
         </el-dropdown-menu>
       </el-dropdown>
-      <div class="group-live-icon-box" v-if="currentConversationType === TIM.TYPES.CONV_GROUP && groupProfile.type !== 'AVChatRoom'" title="群直播" @click="groupLive">
+      <div class="group-live-icon-box" v-if="currentConversationType === 4&& groupProfile.type !== 'AVChatRoom'" title="群直播" @click="groupLive">
         <i class="group-live-icon"></i>
         <i class="group-live-icon-hover"></i>
       </div>
-      <i class="el-icon-s-order" v-if="imType==1" title="问诊订单" @click="handleInquiryOrder()"></i>
+
+      <i class="el-icon-s-order" title="问诊订单" @click="handleInquiryOrder()"></i>
       <i class="el-icon-document" v-if="imType==1" title="诊断报告" @click="handleInquiryReport()"></i>
       <i class="el-icon-edit-outline" v-if="imType==1" title="开处方" @click="handlePrescribe()"></i>
       <i class="el-icon-circle-close" v-if="imType==1" title="结束问诊" @click="handleFinishInquiry()"></i>
       <i class="el-icon-finished" v-if="imType==2" title="随访单" @click="handleFollow()"></i>
-      <i class="el-icon-tickets"  title="药品订单" @click="handleStoreOrder()"></i>
+      <i class="el-icon-tickets" v-if="this.$store.state.conversation.currentConversation.conversationID.includes('U')" title="药品订单" @click="handleStoreOrder()"></i>
       <i class="el-icon-edit-outline" v-if="imType==2" title="开报告" @click="handleDrugReport()"></i>
       <i class="el-icon-circle-close" v-if="imType==2" title="结束咨询" @click="handleFinishDrugReport()"></i>
       <i class="el-icon-chat-dot-square" title="常用语" @click="handleDoctorWords()"></i>
@@ -114,7 +119,7 @@
     />
     <input type="file" id="filePicker" ref="filePicker" @change="sendFile" style="display:none" />
     <input type="file" id="videoPicker" ref="videoPicker" @change="sendVideo" style="display:none" accept=".mp4"/>
-    <div class="calling-member-list" v-if="currentConversationType === TIM.TYPES.CONV_GROUP && showCallingMember">
+    <div class="calling-member-list" v-if="currentConversationType === 3 && showCallingMember">
       <calling-member-list @getList="getList" :type="listTpye"></calling-member-list>
       <div class="calling-list-btn">
         <span class="calling-btn" @click="cancelCalling">取消</span>
@@ -158,7 +163,8 @@ import {
   Tooltip,
   Rate
 } from 'element-ui'
-import { emojiMap, emojiName, emojiUrl } from '../../utils/emojiMap'
+import { getOpenIM } from '@/utils/openIM';
+import { emojiMap, emojiName, emojiUrl,emojiCharMap } from '../../utils/emojiMap'
 
 export default {
   name: 'message-send-box',
@@ -209,6 +215,7 @@ export default {
       file: '',
       emojiMap: emojiMap,
       emojiName: emojiName,
+      emojiCharMap:emojiCharMap,
       emojiUrl: emojiUrl,
       showAtGroupMember: false,
       atUserID: '',
@@ -255,6 +262,12 @@ export default {
   beforeDestroy() {
     this.$refs['text-input'].removeEventListener('paste', this.handlePaste)
   },
+  created() {
+    if (!this.OpenIM) {
+      this.OpenIM = getOpenIM()
+      console.log("OpenIM SDK 初始化完成");
+    }
+  },
   methods: {
     sendWords(msg){
       console.log(msg)
@@ -314,7 +327,11 @@ export default {
       this.show.type=2;
       this.show.open=true;
       this.show.title="药品订单"
-      var userId=this.$store.state.conversation.currentConversation.conversationID.split("-")[1];
+      console.log(this.$store.state.conversation.currentConversation.conversationID)
+      const conversationID = this.$store.state.conversation.currentConversation.conversationID;
+      const match = conversationID.match(/U(\d+)/);
+      const userId = match ? Number(match[1]) : null;
+      console.log("this.$store.state.conversation.currentConversation.conversationID.",userId)
       setTimeout(() => {
         that.$refs.storeOrderList.getData(userId);
       }, 500);
@@ -325,8 +342,11 @@ export default {
       var that=this;
       this.show.type=1;
       this.show.open=true;
-      var userId=this.$store.state.conversation.currentConversation.conversationID.split("-")[1];
-        console.log(userId)
+      const userId = this.$store.state.conversation.currentConversation.conversationID
+        .split("_")
+        .filter(id => id.includes("U"))
+        .map(id => id.replace("U", ""));
+        //console.log(userID,"yonghh")
       this.show.title="问诊订单"
       setTimeout(() => {
 
@@ -362,6 +382,7 @@ export default {
         cancelButtonText: '取消',
         type: 'warning'
       }).then(() => {
+        console.log(that.$store.state.conversation)
         var data={orderId:that.$store.state.conversation.orderId}
         finishOrder(data).then(res => {
             if(res.code==200){
@@ -410,7 +431,7 @@ export default {
       if (this.listTpye === 'calling') {
         let callingData = {
           memberList:this.callingList,
-          type:this.TIM.TYPES.CONV_GROUP
+          type:3
         }
         this.$store.commit('setCallingList',callingData)
         if (this.callingType === 'video') {
@@ -424,28 +445,90 @@ export default {
 
     },
     trtcCalling(type) {
+      console.log(`尝试发起${type === 'video' ? '视频' : '语音'}通话`)
+
+      // 1. 检查OpenIM是否初始化
+      /*if (!this.OpenIM) {
+        console.error('OpenIM未初始化')
+        this.$message.error('IM服务未就绪')
+        return
+      }*/
+
+      // 2. 设置通话类型
       this.listTpye = 'calling'
-      if (type === 'video') {
-        this.callingType = 'video'
-      }
-      if (type === 'audio') {
-        this.callingType = 'audio'
+      this.callingType = type
+
+      // 3. 处理不同类型的会话
+      if (this.currentConversationType === 1) {
+        // 单聊
+        this.startSingleCall(type)
+      } else if (this.currentConversationType === 3) {
+        // 群聊 - 显示成员选择
+        this.showCallingMember = true
+      } else {
+        console.error('不支持的会话类型')
+        this.$message.error('当前会话不支持通话')
       }
-      // 呼叫方设置
-      if(this.currentConversationType === 'C2C') {
-        let member = [this.toAccount]
-        let callingData = {
-          memberList:member,
-          type:'C2C'
+    },
+
+    // 发起单聊通话
+    async startSingleCall(type) {
+      try {
+        const member = [this.toAccount]
+        const callingData = {
+          memberList: member,
+          type: 1 // 单聊
         }
-        this.$store.commit('setCallingList',callingData)
+
+        // 1. 存储通话信息
+        this.$store.commit('setCallingList', callingData)
+        console.log("通话信息",callingData)
+        // 2. 触发通话事件
         this.$bus.$emit(`${type}-call`)
+
+        // 3. 日志记录
+        console.log(`已触发${type}-call事件`, {
+          targetUser: this.toAccount,
+          conversationType: this.currentConversationType
+        })
+      } catch (error) {
+        console.error('发起通话失败:', error)
+        this.$message.error('发起通话失败')
+      }
+    },
+
+    // 群聊确定按钮处理
+    callingHandler() {
+      if (this.callingList.length < 1) {
+        this.$message.warning('请选择成员')
         return
       }
-      if(this.currentConversationType === this.TIM.TYPES.CONV_GROUP) {
-        this.showCallingMember = true
+
+      if (this.listTpye === 'groupAt') {
+        // @成员处理...(原有逻辑)
+        return
+      }
+
+      if (this.listTpye === 'calling') {
+        const callingData = {
+          memberList: this.callingList,
+          type: 3 // 群聊
+        }
+
+        // 1. 存储通话信息
+        this.$store.commit('setCallingList', callingData)
+
+        // 2. 根据类型触发不同事件
+        if (this.callingType === 'video') {
+          console.log("发起群视频通话,成员:", this.callingList)
+          this.$bus.$emit('video-call')
+        } else {
+          console.log("发起群语音通话,成员:", this.callingList)
+          this.$bus.$emit('audio-call')
+        }
+
+        this.showCallingMember = false
       }
-      // this.$store.commit('pushCurrentMessageList', true)
     },
     handleEmojiShow () {
       this.emojiShow = true
@@ -461,7 +544,7 @@ export default {
     },
     chooseBigEmoji(item) {
       this.popoverVisible = false
-      let message = this.tim.createFaceMessage({
+      let message = this.OpenIM.createFaceMessage({
         to: this.toAccount,
         conversationType: this.currentConversationType,
         payload: {
@@ -469,9 +552,18 @@ export default {
           data: `${item}@2x`
         }
       })
+      let offlinePushInfo = {
+        title:"芳华未来",
+        desc:"表情消息",
+        iOSPushSound:"",
+        iOSBadgeCount:true,
+        operatorUserID:"",
+        ex:""
+      }
       this.$store.commit('pushCurrentMessageList', message)
+      this.updateConversationList()
       this.$bus.$emit('scroll-bottom')
-      this.tim.sendMessage(message).catch(error => {
+      this.OpenIM.sendMessage(message,offlinePushInfo).catch(error => {
         this.$store.commit('showMessage', {
           type: 'error',
           message: error.message
@@ -503,7 +595,7 @@ export default {
       this.sendTextMessage()
     },
     inputChange(value) {
-      if (this.currentConversationType === this.TIM.TYPES.CONV_GROUP && value.data === '@') {
+      if (this.currentConversationType === 3 && value.data === '@') {
         this.groupAt = true
         this.listTpye = 'groupAt'
         this.showCallingMember = true
@@ -532,7 +624,7 @@ export default {
         return
       }
       // 1. 创建消息实例,接口返回的实例可以上屏
-      let message = this.tim.createImageMessage({
+      let message = this.OpenIM.createImageMessageFromFullPath({
         to: this.toAccount,
         conversationType: this.currentConversationType,
         payload: {
@@ -543,9 +635,9 @@ export default {
         }
       })
       this.$store.commit('pushCurrentMessageList', message)
-
+      this.updateConversationList()
       // 2. 发送消息
-      let promise = this.tim.sendMessage(message)
+      let promise = this.OpenIM.sendMessage(message)
       promise.catch(error => {
         this.$store.commit('showMessage', {
           type: 'error',
@@ -558,7 +650,7 @@ export default {
       let file = e.dataTransfer.files[0]
       let message = {}
       if (file.type === 'video/mp4') {
-        message = this.tim.createVideoMessage({
+        message = this.OpenIM.createVideoMessage({
           to: this.toAccount,
           conversationType: this.currentConversationType,
           payload: {
@@ -569,7 +661,7 @@ export default {
           }
         })
       } else {
-        message = this.tim.createFileMessage({
+        message = this.OpenIM.createFileMessage({
           to: this.toAccount,
           conversationType: this.currentConversationType,
           payload: {
@@ -581,7 +673,8 @@ export default {
         })
       }
       this.$store.commit('pushCurrentMessageList', message)
-      this.tim
+      this.updateConversationList()
+      this.OpenIM
         .sendMessage(message)
         .then(() => {
           this.$refs.videoPicker.value = null
@@ -612,20 +705,22 @@ export default {
           followId:this.$store.state.conversation.followId,
           orderType:this.$store.state.conversation.orderType
       }
-      if (this.currentConversationType === this.TIM.TYPES.CONV_GROUP && this.groupAt) {
+      if (this.currentConversationType === 3 && this.groupAt) {
 
-        let message = this.tim.createTextAtMessage({
+        let message = this.OpenIM.createTextAtMessage({
           cloudCustomData:JSON.stringify(customData),
           to: this.toAccount,
-          conversationType: this.TIM.TYPES.CONV_GROUP,
+          conversationType: 3,
           payload: {
             text: this.messageContent,
             atUserList: this.callingList // 'denny' 'lucy' 都是 userID,而非昵称
           }
         })
+
         this.$store.commit('pushCurrentMessageList', message)
+        this.updateConversationList()
         this.$bus.$emit('scroll-bottom')
-        this.tim.sendMessage(message).catch(error => {
+        this.OpenIM.sendMessage(message).catch(error => {
           this.$store.commit('showMessage', {
             type: 'error',
             message: error.message
@@ -635,21 +730,68 @@ export default {
         this.groupAt = false
         return
       }
-      const message = this.tim.createTextMessage({
-        cloudCustomData:JSON.stringify(customData),
-        to: this.toAccount,
-        conversationType: this.currentConversationType,
-        payload: { text: this.messageContent }
-      })
-      this.$store.commit('pushCurrentMessageList', message)
-      this.$bus.$emit('scroll-bottom')
-      this.tim.sendMessage(message).catch(error => {
-        this.$store.commit('showMessage', {
-          type: 'error',
-          message: error.message
+      console.log("this.messageContent",this.messageContent)
+      this.OpenIM.createTextMessage(this.messageContent).then(({ data }) => {
+        console.log("创建文本消息返回参数")
+        console.log(data)
+        console.log("接受哦人id"+ this.$store.getters.toAccount)
+        // 调用成功
+        //console.log("customData",customData)
+        data.ex = JSON.stringify(customData)
+        const sendText={
+          message:data,
+          recvID:this.$store.getters.toAccount,
+          groupID:"",
+          offlinePushInfo : {
+            title:data.senderNickname,
+            desc:this.messageContent,
+            iOSPushSound:"",
+            iOSBadgeCount:true,
+            operatorUserID:"",
+            ex:""
+          }
+        }
+        console.log("发送消息参数",sendText)
+        console.log("发送消息参数",this.OpenIM)
+        console.log("发送消息参数",this.OpenIM.isLogin)
+        /*if (!this.OpenIM || !this.OpenIM.isLogin) {
+          console.warn('⚠️ OpenIM SDK 尚未登录完成,无法发起邀请');
+          return;
+        }*/
+        this.OpenIM.sendMessage(sendText).then(({ data }) => {
+          console.log("发送消息返回参数",data)
+          // 调用成功
+          console.log("customData",customData)
+          const msgList = Array.isArray(data) ? data : [data];
+          this.$store.commit('pushCurrentMessageList', msgList)
+          this.updateConversationList()
+          this.$bus.$emit('scroll-bottom')
+        }).catch(({ errCode, errMsg }) => {
+            // 调用失败
+          });
+        this.messageContent = ''
+      }).catch(({ errCode, errMsg }) => {
+          // 调用失败
+        });
+      /*{
+      cloudCustomData:JSON.stringify(customData),
+      to: this.toAccount,
+      conversationType: this.currentConversationType,
+      payload: { text: this.messageContent }
+    }*/
+
+
+    },
+    updateConversationList(){
+      this.OpenIM.getAllConversationList()
+        .then(({ data }) => {
+          // 调用成功
+          console.log(data,"147852")
+          this.$store.commit('updateConversationList', data)
+        })
+        .catch(({ errCode, errMsg }) => {
+          // 调用失败
         })
-      })
-      this.messageContent = ''
     },
     sendCustomMessage() {
       if (
@@ -670,7 +812,20 @@ export default {
           followId:this.$store.state.conversation.followId,
           orderType:this.$store.state.conversation.orderType
       }
-      const message = this.tim.createCustomMessage({
+      const customMessageData = {
+        data:this.form.data,
+        description: this.form.description,
+        extension: this.form.extension
+      }
+      console.log("customMessageData",customMessageData)
+      this.OpenIM.createCustomMessage(customMessageData)
+        .then(({ data }) => {
+          // 调用成功
+        })
+        .catch(({ errCode, errMsg }) => {
+          // 调用失败
+        });
+      /*const message = this.OpenIM.createCustomMessage({
         cloudCustomData:JSON.stringify(customData),
         to: this.toAccount,
         conversationType: this.currentConversationType,
@@ -679,9 +834,9 @@ export default {
           description: this.form.description,
           extension: this.form.extension
         }
-      })
+      })*/
       this.$store.commit('pushCurrentMessageList', message)
-      this.tim.sendMessage(message).catch(error => {
+      this.OpenIM.sendMessage(message).catch(error => {
         this.$store.commit('showMessage', {
           type: 'error',
           message: error.message
@@ -705,7 +860,8 @@ export default {
           followId:this.$store.state.conversation.followId,
           orderType:this.$store.state.conversation.orderType
       }
-      const message = this.tim.createCustomMessage({
+      console.log("创建自定义消息")
+      const message = this.OpenIM.createCustomMessage({
         cloudCustomData:JSON.stringify(customData),
         to: this.toAccount,
         conversationType: this.currentConversationType,
@@ -721,9 +877,10 @@ export default {
         description: '',
         extension: ''
       })
-      this.tim
+      this.OpenIM
         .sendMessage(message)
         .then(() => {
+          console.log("发送自定义消息")
           Object.assign(this, {
             rate: 5,
             suggestion: ''
@@ -738,7 +895,9 @@ export default {
       this.surveyDialogVisible = false
     },
     chooseEmoji(item) {
-      this.messageContent += item
+      const emojiChar = this.emojiCharMap[item] || item;
+      console.log("emojiChar",emojiChar)
+      this.messageContent += emojiChar;
     },
     handleSendImageClick() {
       this.$refs.imagePicker.click()
@@ -756,102 +915,224 @@ export default {
       })
       this.$bus.$emit('open-group-live', { channel: 1 })
     },
-    sendImage() {
-      var customData={
-          type:this.$store.state.conversation.type,
-          imType:this.$store.state.conversation.imType,
-          orderId:this.$store.state.conversation.orderId,
-          followId:this.$store.state.conversation.followId,
-          orderType:this.$store.state.conversation.orderType
-      }
-      const message = this.tim.createImageMessage({
-        cloudCustomData:JSON.stringify(customData),
-        to: this.toAccount,
-        conversationType: this.currentConversationType,
-        payload: {
-          file: document.getElementById('imagePicker') // 或者用event.target
-        },
-        onProgress: percent => {
-          this.$set(message, 'progress', percent) // 手动给message 实例加个响应式属性: progress
-        }
+    generateUUID() {
+      return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
+        var r = (Math.random() * 16) | 0,
+          v = c == 'x' ? r : (r & 0x3) | 0x8
+        return v.toString(16)
       })
-      this.$store.commit('pushCurrentMessageList', message)
-      this.tim
-        .sendMessage(message)
-        .then(() => {
-          this.$refs.imagePicker.value = null
-        })
-        .catch(imError => {
-          this.$store.commit('showMessage', {
-            message: imError.message,
-            type: 'error'
+    },
+    sendImage() {
+      const input = document.getElementById('imagePicker');
+      const imageFile = input?.files?.[0];
+      if (!imageFile) return;
+
+      const picBaseInfo = {
+        uuid: this.generateUUID(),
+        type: imageFile.type,
+        size: imageFile.size,
+        width: 0,
+        height: 0,
+        url: '',
+      };
+
+      const setImageDimensions = (file, callback) => {
+        const reader = new FileReader();
+        reader.onload = (e) => {
+          const img = new Image();
+          img.onload = () => {
+            callback({ width: img.width, height: img.height });
+          };
+          img.src = e.target.result;
+        };
+        reader.readAsDataURL(file);
+      };
+
+      setImageDimensions(imageFile, ({ width, height }) => {
+        // 创建图片对象
+        const updatedPicInfo = {
+          ...picBaseInfo,
+          width,
+          height,
+        };
+
+        const messageData = {
+          sourcePicture: { ...updatedPicInfo },
+          bigPicture: { ...updatedPicInfo },
+          snapshotPicture: { ...updatedPicInfo },
+          file: imageFile,
+          sourcePath: imageFile.name,
+          onProgress: percent => {
+            this.$set(updatedPicInfo, 'progress', percent);
+          },
+        };
+
+        this.OpenIM.createImageMessageByFile(messageData)
+          .then(({ data: message }) => {
+            const isGroup = this.currentConversationType === 3;
+            return this.OpenIM.sendMessage({
+              message,
+              recvID: isGroup ? '' : this.$store.getters.toAccount,
+              groupID: isGroup ? this.$store.getters.toAccount : '',
+              offlinePushInfo : {
+                title:message.senderNickname,
+                desc:"[图片]",
+                iOSPushSound:"",
+                iOSBadgeCount:true,
+                operatorUserID:"",
+                ex:""
+              }
+            });
           })
-        })
+          .then(({ data }) => {
+            console.log('发送图片成功', data);
+            const msgList = Array.isArray(data) ? data : [data];
+            this.$store.commit('pushCurrentMessageList', msgList);
+            this.updateConversationList()
+            this.$bus.$emit('scroll-bottom');
+            this.$refs.imagePicker.value = null;
+          })
+          .catch(({ errCode, errMsg }) => {
+            console.error('发送图片失败', errCode, errMsg);
+            this.$store.commit('showMessage', {
+              message: errMsg,
+              type: 'error',
+            });
+          });
+      });
     },
+
     sendFile() {
-      var customData={
-          type:this.$store.state.conversation.type,
-          imType:this.$store.state.conversation.imType,
-          orderId:this.$store.state.conversation.orderId,
-          followId:this.$store.state.conversation.followId,
-          orderType:this.$store.state.conversation.orderType
-      }
-      const message = this.tim.createFileMessage({
-        cloudCustomData:JSON.stringify(customData),
-        to: this.toAccount,
-        conversationType: this.currentConversationType,
-        payload: {
-          file: document.getElementById('filePicker') // 或者用event.target
-        },
+      const input = document.getElementById('filePicker');
+      const file = input.files[0];
+      if (!file) return;
+
+      const customData = {
+        type: this.$store.state.conversation.type,
+        imType: this.$store.state.conversation.imType,
+        orderId: this.$store.state.conversation.orderId,
+        followId: this.$store.state.conversation.followId,
+        orderType: this.$store.state.conversation.orderType
+      };
+
+      // 1. 创建文件消息
+      this.OpenIM.createFileMessageByFile({
+        filePath: file.name,
+        fileName: file.name,
+        uuid: this.generateUUID(),
+        sourceUrl: '',
+        fileSize: file.size,
+        fileType: file.type,
+        file,
+        cloudCustomData: JSON.stringify(customData),
         onProgress: percent => {
-          this.$set(message, 'progress', percent) // 手动给message 实例加个响应式属性: progress
+          this.$set(file, 'progress', percent);
         }
-      })
-      this.$store.commit('pushCurrentMessageList', message)
-      this.tim
-        .sendMessage(message)
-        .then(() => {
-          this.$refs.filePicker.value = null
-        })
-        .catch(imError => {
-          this.$store.commit('showMessage', {
-            message: imError.message,
-            type: 'error'
-          })
-        })
+      }).then(({ data }) => {
+        // 2. 发送文件消息
+        const sendFile = {
+          message: data,
+          recvID: this.$store.getters.toAccount,
+          groupID: this.currentConversationType === 3 ? this.toAccount : "",
+          offlinePushInfo : {
+            title:data.senderNickname,
+            desc:"[文件]",
+            iOSPushSound:"",
+            iOSBadgeCount:true,
+            operatorUserID:"",
+            ex:""
+          }
+        };
+        console.error("创建文件消息返回", data);
+        console.error("发送文件消息参数", sendFile);
+        return this.OpenIM.sendMessage(sendFile);
+      }).then(({ data }) => {
+        const msgList = Array.isArray(data) ? data : [data];
+        this.$store.commit('pushCurrentMessageList', msgList);
+        this.updateConversationList()
+        this.$bus.$emit('scroll-bottom');
+        this.$refs.filePicker.value = null;
+      }).catch(({ errCode, errMsg }) => {
+        console.error("发送文件失败", errCode, errMsg);
+        this.$store.commit('showMessage', {
+          message: errMsg,
+          type: 'error'
+        });
+      });
     },
     sendVideo() {
-      var customData={
-          type:this.$store.state.conversation.type,
-          imType:this.$store.state.conversation.imType,
-          orderId:this.$store.state.conversation.orderId,
-          followId:this.$store.state.conversation.followId,
-          orderType:this.$store.state.conversation.orderType
-      }
-      const message = this.tim.createVideoMessage({
-        cloudCustomData:JSON.stringify(customData),
-        to: this.toAccount,
-        conversationType: this.currentConversationType,
-        payload: {
-          file: document.getElementById('videoPicker') // 或者用event.target
-        },
-        onProgress: percent => {
-          this.$set(message, 'progress', percent) // 手动给message 实例加个响应式属性: progress
-        }
-      })
-      this.$store.commit('pushCurrentMessageList', message)
-      this.tim
-        .sendMessage(message)
-        .then(() => {
-          this.$refs.videoPicker.value = null
-        })
-        .catch(imError => {
-          this.$store.commit('showMessage', {
-            message: imError.message,
-            type: 'error'
-          })
-        })
+      const videoInput = document.getElementById('videoPicker');
+      const file = videoInput.files[0];
+      if (!file) return;
+
+      const snapshotFile = new File([new Blob()], 'snapshot.png', { type: 'image/png' });
+
+      const customData = {
+        type: this.$store.state.conversation.type,
+        imType: this.$store.state.conversation.imType,
+        orderId: this.$store.state.conversation.orderId,
+        followId: this.$store.state.conversation.followId,
+        orderType: this.$store.state.conversation.orderType,
+      };
+
+      const videoURL = URL.createObjectURL(file);
+      const video = document.createElement('video');
+      video.preload = 'metadata';
+      video.src = videoURL;
+
+      video.onloadedmetadata = () => {
+        URL.revokeObjectURL(videoURL); // 清理临时URL
+        const duration = Math.ceil(video.duration); // 视频时长,取整
+
+        // 创建视频消息
+        this.OpenIM.createVideoMessageByFile({
+          cloudCustomData: JSON.stringify(customData),
+          videoPath: file.name,
+          duration,
+          videoType: file.type,
+          snapshotPath: snapshotFile.name,
+          videoUUID: '',
+          videoUrl: '',
+          videoSize: file.size,
+          snapshotUUID: '',
+          snapshotSize: snapshotFile.size,
+          snapshotUrl: '',
+          snapshotWidth: 1024,
+          snapshotHeight: 1024,
+          snapShotType: snapshotFile.type,
+          videoFile: file,
+          snapshotFile,
+          onProgress: percent => {
+            this.$set(this, 'videoProgress', percent);
+          }
+        }).then(({ data }) => {
+          const sendVideo = {
+            message: data,
+            recvID: this.$store.getters.toAccount,
+            groupID: this.currentConversationType === 3 ? this.toAccount : "",
+            offlinePushInfo : {
+              title:data.senderNickname,
+              desc:"[视频]",
+              iOSPushSound:"",
+              iOSBadgeCount:true,
+              operatorUserID:"",
+              ex:""
+            }
+          };
+
+          this.OpenIM.sendMessage(sendVideo).then(({ data }) => {
+            const msgList = Array.isArray(data) ? data : [data];
+            this.$store.commit('pushCurrentMessageList', msgList);
+            this.updateConversationList()
+            this.$bus.$emit('scroll-bottom');
+            this.$refs.videoPicker.value = null;
+          }).catch(({ errCode, errMsg }) => {
+            console.error("发送视频失败", errCode, errMsg);
+          });
+        });
+      };
     }
+
   }
 }
 </script>

File diff suppressed because it is too large
+ 637 - 607
src/components/message/trtc-calling/calling-index.vue


+ 6 - 1
src/components/message/trtc-calling/group-member-list.vue

@@ -6,7 +6,7 @@
         <div class="scroll-content">
             <div class="group-member-list">
                 <el-checkbox-group v-model="callingList" @change="handleCheckedMembersChange">
-                    <el-checkbox v-if="type === 'groupAt'"  :label="JSON.stringify({userID:this.TIM.TYPES.MSG_AT_ALL,nick:'所有人'})" >
+                    <el-checkbox v-if="type === 'groupAt'"  :label="JSON.stringify({userID:this.OpenIM.TYPES.MSG_AT_ALL,nick:'所有人'})" >
                         <div class="group-member">
                             <avatar  :src="''" />
                             <div class="member-name text-ellipsis">
@@ -35,10 +35,12 @@
 
 <script>
   import { mapState } from 'vuex'
+  import { getOpenIM } from '@/utils/openIM';
   export default {
     props:['type'],
     data() {
       return {
+        OpenIM:null,
         callingList:[],
         addGroupMemberVisible: false,
         currentMemberID: '',
@@ -47,6 +49,9 @@
     },
     components: {
     },
+    created() {
+      this.OpenIM = getOpenIM();
+    },
     computed: {
       ...mapState({
         userID: state => state.imuser.userID,

+ 11 - 10
src/components/my-profile.vue

@@ -10,16 +10,16 @@
         </el-form-item>
         <el-form-item label="性别">
           <el-radio-group v-model="form.gender">
-            <el-radio :label="TIM.TYPES.GENDER_MALE">男</el-radio>
-            <el-radio :label="TIM.TYPES.GENDER_FEMALE">女</el-radio>
-            <el-radio :label="TIM.TYPES.GENDER_UNKNOWN">不显示</el-radio>
+            <el-radio :label="1">男</el-radio>
+            <el-radio :label="0">女</el-radio>
+            <el-radio :label="3">不显示</el-radio>
           </el-radio-group>
         </el-form-item>
         <el-form-item label="好友申请">
           <el-radio-group v-model="form.allowType">
-            <el-radio :label="TIM.TYPES.ALLOW_TYPE_ALLOW_ANY">允许直接加为好友</el-radio>
-            <el-radio :label="TIM.TYPES.ALLOW_TYPE_NEED_CONFIRM">需要验证</el-radio>
-            <el-radio :label="TIM.TYPES.ALLOW_TYPE_DENY_ANY">不允许任何人添加好友</el-radio>
+            <!--<el-radio :label="OpenIM.TYPES.ALLOW_TYPE_ALLOW_ANY">允许直接加为好友</el-radio>
+            <el-radio :label="OpenIM.TYPES.ALLOW_TYPE_NEED_CONFIRM">需要验证</el-radio>
+            <el-radio :label="OpenIM.TYPES.ALLOW_TYPE_DENY_ANY">不允许任何人添加好友</el-radio>-->
           </el-radio-group>
         </el-form-item>
       </el-form>
@@ -33,7 +33,7 @@
       <!-- <i class="el-icon-setting edit-my-profile" @click="handleEdit"></i> -->
       <avatar
         slot="reference"
-        :src="currentUserProfile.avatar"
+        :src="currentUserProfile.faceURL"
         class="my-avatar"
       />
     </el-popover>
@@ -57,7 +57,8 @@ export default {
   data() {
     return {
       showEditMyProfile: false,
-      form: { avatar: '', nick: '', gender: '',allowType: '' }
+      form: { avatar: '', nick: '', gender: '',allowType: '' },
+      OpenIM:null
     }
   },
   computed: {
@@ -67,9 +68,9 @@ export default {
     }),
     gender() {
       switch (this.currentUserProfile.gender) {
-        case this.TIM.TYPES.GENDER_MALE:
+        case 1:
           return '男'
-        case this.TIM.TYPES.GENDER_FEMALE:
+        case 0:
           return '女'
         default:
           return '暂无'

+ 4 - 4
src/components/profile-card.vue

@@ -1,9 +1,9 @@
 <template>
   <div class="profile-card-wrapper">
     <div class="content">
-      <avatar :src="profile.avatar" />
+      <avatar :src="profile.faceURL" />
       <div class="basic">
-        <span class="nick text-ellipsis">医生:{{ profile.nick || profile.userID }}</span>
+        <span class="nick text-ellipsis">医生:{{ profile.nickname || profile.userID }}</span>
         <!-- <span class="iconfont" :class="genderClass"></span> -->
       </div>
       <div><span class="nick text-ellipsis">{{ profile.userID }}</span>
@@ -24,9 +24,9 @@ export default {
   computed: {
     genderClass() {
       switch (this.profile.gender) {
-        case this.TIM.TYPES.GENDER_MALE:
+        case 1:
           return 'icon-male'
-        case this.TIM.TYPES.GENDER_FEMALE:
+        case 0:
           return 'icon-female'
         default:
           return '暂无'

+ 215 - 33
src/components/user/login.vue

@@ -12,46 +12,228 @@
   </div>
 </template>
 
+
 <script>
+  import logo from '../../assets/image/logo.png'
+  import { getOpenIM,getCbEvents } from '@/utils/openIM';
+  import { imConfig } from '@/utils/im' // 引入配置
+  import { accountCheck } from '@/api/doctor';
+  export default {
+    name: 'Login',
+    data() {
+      return {
+        hasBindReadyEvent : false,
+        logo: logo,
+        loading: false,
+        OpenIM: null
+      }
+    },
+    created() {
+      this.OpenIM = getOpenIM();
+      this.initListener()
+    },
+    methods: {
+      submit() {
+        this.login()
+      },
+      initListener() {
+        // 登录成功后会触发 SDK_READY 事件,该事件触发后,可正常使用 SDK 接口
+        this.OpenIM.on(getCbEvents().OnConnectSuccess, () => {
+          console.log("OnConnectSuccess 事件触发!"); // 调试日志
+          this.$store.commit('toggleIsSDKReady', true);
+        });
+        this.OpenIM.on(getCbEvents().OnConnectFailed, this.onError);
+        this.OpenIM.on(getCbEvents().OnKickedOffline, this.onKickOut);
+        this.OpenIM.on(getCbEvents().OnSelfInfoUpdated, this.onSelfInfoUpdated);
+        /*this.OpenIM.on(getCbEvents().OnRecvNewMessage, (message) => {
+          console.log("收到单条消息", message);
+          this.onReceiveMessage({data: [message]}); // 包装成数组形式
+        });*/
 
-export default {
-  name: 'Login',
-  components: {
+        this.OpenIM.on(getCbEvents().OnRecvNewMessages, (data) => {
+          console.log("收到多条消息", data);
+          const msgList = []
+          data.data.forEach(msg =>{
+            if (msg.contentType!==113){
+              msgList.push(msg)
+            }
+          })
+          if (msgList.length>0){
+            this.onReceiveMessage({data: msgList});
 
-  },
-  data() {
-    return {
-      logo: require(process.env.VUE_APP_LOG_URL),
-      loading: false
-    }
-  },
-  methods: {
-    submit() {
-      this.login()
-    },
-    login() {
-      this.loading = true
-      this.tim
-        .login({
-          userID: this.$store.getters.userID,
-          userSig: this.$store.getters.userSig
-        })
-        .then(() => {
-          this.loading = false
-          this.$store.commit('toggleIsLogin', true)
-          this.$store.commit('startComputeCurrent')
-          this.$store.commit('showMessage', { type: 'success', message: '登录成功' })
-        })
-        .catch(error => {
-          this.loading = false
+          }
+        });
+        /*this.OpenIM.on(getCbEvents().OnConversationChanged, (updatedConversations) => {
+          console.log("触发OnConversationChanged事件")
+          //console.log(updatedConversations)
+          updatedConversations.data.forEach(conv => {
+            if (conv.conversationID === this.currentConversation.conversationID) {
+              context.commit('updateCurrentConversation', conv);
+            }
+          });
+        });*/
+        // SDK NOT READT
+        /*this.OpenIM.on(this.OpenIM.EVENT.SDK_NOT_READY, this.onReadyStateUpdate, this)
+        // 被踢出
+        this.OpenIM.on(this.OpenIM.EVENT.KICKED_OUT, this.onKickOut)
+        // SDK内部出错
+        this.OpenIM.on(this.OpenIM.EVENT.ERROR, this.onError)
+        // 收到新消息
+        this.OpenIM.on(this.OpenIM.EVENT.MESSAGE_RECEIVED, this.onReceiveMessage)
+        // 会话列表更新
+        this.OpenIM.on(this.OpenIM.EVENT.CONVERSATION_LIST_UPDATED, this.onUpdateConversationList)
+        // 群组列表更新
+        this.OpenIM.on(this.OpenIM.EVENT.GROUP_LIST_UPDATED, this.onUpdateGroupList)
+        // 网络监测
+        this.OpenIM.on(this.OpenIM.EVENT.NET_STATE_CHANGE, this.onNetStateChange)
+        // 已读回执
+        this.OpenIM.on(this.OpenIM.EVENT.MESSAGE_READ_BY_PEER, this.onMessageReadByPeer)
+        // 黑名单更新
+        this.OpenIM.on(this.OpenIM.EVENT.FRIEND_LIST_UPDATED, this.onFriendListUpdated)
+
+        this.OpenIM.on(this.OpenIM.EVENT.FRIEND_APPLICATION_LIST_UPDATED, this.onFriendApplicationListUpdated)
+
+        this.OpenIM.on(this.OpenIM.EVENT.FRIEND_GROUP_LIST_UPDATED, this.onFriendGroupListUpdated)*/
+
+      },
+      login() {
+        accountCheck(this.$store.getters.userID).then(response => {
+          console.log("response",response)
+          this.userToken = response.token
+          console.log("this.userToken",this.userToken)
+          console.log(this.$store.getters.userID);
+          const config = {
+            userID: this.$store.getters.userID,
+            token: this.userToken,
+            logLevel:6,
+            platformID: 5, // 使用配置的平台ID
+            apiAddr: 'https://web.im.cdwjyyh.com/api', // API地址
+            wsAddr: 'wss://web.im.cdwjyyh.com/msg_gateway', // WebSocket地址
+            dataDir: '/imdata' // 添加数据存储目录
+          }
+          console.log("config",config)
+          console.log("userToken",this.userToken)
+          this.checkSDKReadyState();
+          this.OpenIM.login(config).then(() => {
+            this.$store.commit('toggleIsLogin', true);
+            this.$store.commit('startComputeCurrent');
+            this.$store.commit('showMessage', {
+              type: 'success',
+              message: 'IM 登录成功'
+            });
+          })
+            .catch((error) => {
+              this.loading = false;
+              console.error('登录失败:', error);
+              this.$store.commit('showMessage', {
+                message: `IM 登录失败:${error.message || error.errMsg || '未知错误'}`,
+                type: 'error',
+              });
+            });
+        });
+      },
+      // 添加SDK就绪状态检查
+      checkSDKReadyState() {
+        if (this.hasBindReadyEvent) return;
+        this.hasBindReadyEvent = true;
+
+        let isReady = false;
+
+        const timeout = setTimeout(() => {
+          if (!isReady) {
+            this.$store.commit('toggleIsSDKReady', false);
+            this.$store.commit('showMessage', {
+              message: 'SDK初始化超时',
+              type: 'error'
+            });
+          }
+        }, 10000);
+
+        this.OpenIM.on(getCbEvents().OnConnectSuccess, () => {
+          console.log("WebSocket连接成功");
+          clearTimeout(timeout);
+          isReady = true;
+          this.OpenIM.getSelfUserInfo().then(({ data }) => {
+            console.log("当前登录用户基本信息",data)
+            this.$store.commit('updateCurrentUserProfile', data)
+          })
+          this.$store.commit('toggleIsSDKReady', true);
+          this.$store.commit('showMessage', {
+            type: 'success',
+            message: 'SDK 初始化成功'
+          });
+          // 触发获取用户信息等操作
+          console.log("开始加载用户数据,获取会话列表")
+          console.log(this.OpenIM)
+          this.loadUserData();
+          console.log("结束加载用户数据,获取会话列表")
+        });
+
+        this.OpenIM.on(getCbEvents().OnConnectFailed, (error) => {
+          clearTimeout(timeout);
+          this.$store.commit('toggleIsSDKReady', false);
           this.$store.commit('showMessage', {
-            message: '登录失败:' + error.message,
+            message: `SDK 连接失败: ${error.message}`,
             type: 'error'
+          });
+        });
+      },
+      onReceiveMessage({ data: messageList }) {
+        // let totalUnreadCount = this.tim.getTotalUnreadMessageCount();
+
+        messageList.forEach(element => {
+          //过滤掉正在输入状态
+          if(element.sendID!=this.$store.getters.userID&&element.contentType!==113){
+            this.$notify({
+              title: '消息提示',
+              message: '您有一条新的消息',
+              type: 'success'
+            });
+          }
+        });
+        this.OpenIM.getAllConversationList()
+          .then(({ data }) => {
+            // 调用成功
+            this.$store.commit('updateConversationList', data)
           })
-        })
-    },
+          .catch(({ errCode, errMsg }) => {
+            // 调用失败
+          })
+        console.log(messageList)
+        //this.handleVideoMessage(messageList)
+        this.handleQuitGroupTip(messageList)
+        this.handleCloseGroupLive(messageList)
+        this.$store.commit('pushCurrentMessageList', messageList)
+        this.$store.commit('pushAvChatRoomMessageList', messageList)
+      },
+
+      // 添加加载用户数据方法
+      loadUserData() {
+        //查询会话列表
+        this.OpenIM.getAllConversationList()
+          .then(({ data }) => {
+            // 调用成功
+            console.log("获取到会话列表",data)
+            this.conversationList= data
+            this.$store.commit('updateConversationList', data)
+          })
+          .catch(({ errCode, errMsg }) => {
+            // 调用失败
+          })
+        //查询好友列表
+        this.OpenIM.getFriendListPage({ offset:0, count:100 })
+          .then(({ data }) => {
+            // 调用成功
+            console.log("获取到好友列表",data)
+            //this.conversationList= data
+            this.$store.commit('updateFriendList', data)
+          })
+          .catch(({ errCode, errMsg }) => {
+            // 调用失败
+          })
+      },
+    }
   }
-}
 </script>
 
 <style lang="stylus" scoped>

+ 10 - 14
src/main.js

@@ -9,30 +9,26 @@ import { MessageBox, Row, Col, Button, Input, Loading, Dialog, Dropdown, Dropdow
 import Avatar from './components/avatar.vue'
 
 import store from './store'
-import tim from './tim.js'
-import TIM from 'tim-js-sdk/tim-js-friendship.js'
-import TWebLive from 'tweblive'
+//import TWebLive from 'tweblive'
 import VueClipboard from 'vue-clipboard2'
 import './assets/icon/iconfont.css'
 import './assets/icon/tim.css'
 import './assets/css/animate.css'
 
-import trtcCalling from './trtc-calling'
-import TRTCCalling from 'trtc-calling-js'
+//import trtc from '@/utils/trtc'
+//Vue.prototype.$trtc = trtc
+
+
 
-window.tim = tim
-window.TIM = TIM
-window.TRTCCalling = TRTCCalling
-window.trtcCalling = trtcCalling
 window.store = store
 Vue.prototype.$bus = new Vue() // event Bus 用于无关系组件间的通信。
-Vue.prototype.tim = tim
-Vue.prototype.TIM = TIM
-Vue.prototype.TWebLive = TWebLive
+
+//Vue.prototype.TWebLive = TWebLive
 Vue.prototype.$store = store
 Vue.prototype.$confirm = MessageBox.confirm
-Vue.prototype.trtcCalling = trtcCalling
-Vue.prototype.TRTCCalling = TRTCCalling
+
+
+
 
 
 

+ 3 - 3
src/router/index.js

@@ -80,7 +80,7 @@ export const constantRoutes = [
 
     ]
   },
-   
+
   {
     path: '/order',
     component: Layout,
@@ -107,7 +107,7 @@ export const constantRoutes = [
       }
     ]
   },
-  
+
   {
     path: '/myDrugStore',
     component: Layout,
@@ -248,7 +248,7 @@ Router.prototype.push = function push (location, onResolve, onReject) {
   }
   return originalPush.call(this, location).catch(err => err)
 }
-                        
+
 export default new Router({
   mode: 'history', // 去掉url中的#
   scrollBehavior: () => ({ y: 0 }),

+ 1 - 1
src/store/modules/blacklist.js

@@ -1,4 +1,4 @@
-import tim from '../../tim'
+//import tim from '../../tim'
 const blacklistModule = {
   state: {
     blacklist: []

+ 208 - 62
src/store/modules/conversation.js

@@ -1,8 +1,10 @@
-import tim from '@/tim.js';
-import TIM from 'tim-js-sdk/tim-js-friendship'
 import store from '..'
 import { titleNotify } from '../../utils'
 import { filterCallingMessage } from '../../utils/common'
+import { getOpenIM } from '@/utils/openIM';
+import da from "element-ui/src/locale/lang/da";
+
+const OpenIM = getOpenIM();
 const conversationModules = {
   state: {
     currentConversation: {},
@@ -29,23 +31,16 @@ const conversationModules = {
   },
   getters: {
     toAccount: state => {
-      if (!state.currentConversation || !state.currentConversation.conversationID) {
-        return ''
-      }
-      switch (state.currentConversation.type) {
-        case 'C2C':
-          return state.currentConversation.conversationID.replace('C2C', '')
-        case 'GROUP':
-          return state.currentConversation.conversationID.replace('GROUP', '')
-        default:
-          return state.currentConversation.conversationID
+      if (!state.currentConversation) return '';
+      if (state.currentConversation.conversationID) {
+        return state.currentConversation.conversationID.split("_").find(part => part.includes('U'));
       }
     },
     currentConversationType: state => {
-      if (!state.currentConversation || !state.currentConversation.type) {
+      if (!state.currentConversation || !state.currentConversation.conversationType) {
         return ''
       }
-      return state.currentConversation.type
+      return state.currentConversation.conversationType
     },
     totalUnreadCount: state => {
       const result = state.conversationList.reduce((count, conversation) => {
@@ -60,9 +55,10 @@ const conversationModules = {
     },
     // 用于当前会话的图片预览
     imgUrlList: state => {
+      console.log("state.currentMessageList",state.currentMessageList)
       return state.currentMessageList
-        .filter(message => message.type === TIM.TYPES.MSG_IMAGE && !message.isRevoked) // 筛选出没有撤回并且类型是图片类型的消息
-        .map(message => message.payload.imageInfoArray[0].url)
+        .filter(message => message.contentType === 102) // 筛选出没有撤回并且类型是图片类型的消息
+        .map(message => message.pictureElem.sourcePicture.url)
     }
   },
   mutations: {
@@ -147,22 +143,63 @@ const conversationModules = {
     /**
      * 更新会话列表
      * 调用时机:触发会话列表更新事件时。C
-     * 
+     *
      * @param {Object} state
      * @param {Conversation[]} conversationList
      */
     updateConversationList(state, conversationList) {
       console.log("获取会话列表")
-      conversationList.forEach(function(item) {
+      console.log("conversationList",conversationList)
+      /*conversationList.forEach(function(item) {
           console.log(item)
-          if(item.lastMessage.cloudCustomData!=null&&item.lastMessage.cloudCustomData!=""){
+        const latestMsgObj = JSON.parse(item.latestMsg);
+          if(latestMsgObj.textElem.content!=null&&latestMsgObj.textElem.content!=""){
             // try{
             //   var json=JSON.parse(item.lastMessage.cloudCustomData);
             // }
             // catch(e){
             // }
           }
-      });
+      });*/
+      /*const userIds = conversationList
+        .map(conv => {
+          const parts = conv.conversationID?.split("_");
+          if (!parts) return null;
+          // 查找包含"U"的部分(假设用户ID格式类似"U123")
+          const userPart = parts.find(part => part.includes('U'));
+          return userPart || null;
+        })
+        .filter(Boolean);
+
+      if (userIds.length === 0) return;
+
+      // 批量获取用户信息
+      return OpenIM.getUsersInfo(userIds)
+        .then(({ data: userInfos }) => {
+          console.log("用户信息列表", userInfos);
+
+          // 创建用户信息映射表
+          const userMap = {};
+          userInfos.forEach(user => {
+            userMap[user.userID] = user;
+          });
+
+          // 更新会话列表中的用户信息
+          const updatedList = conversationList.map(conv => {
+            const parts = conv.conversationID?.split("_");
+            const userId = parts && parts.length > 2 ? parts.find(part => part.includes('U')) : null;
+            if (userId && userMap[userId]) {
+              return {
+                ...conv,
+                faceURL: userMap[userId].faceURL,
+                showName: userMap[userId].nickname
+              };
+            }
+            return conv;
+          });
+
+          state.conversationList = updatedList
+        });*/
       state.conversationList = conversationList
     },
     /**
@@ -182,17 +219,22 @@ const conversationModules = {
      */
     pushCurrentMessageList(state, data) {
       // 还没当前会话,则跳过
+      console.log("触发消息列表更新",state.currentConversation)
       if (!state.currentConversation.conversationID) {
         return
       }
+      console.log("会话详细信息",state.currentConversation)
+      console.log("消息详细信息",data)
       if (Array.isArray(data)) {
         // 筛选出当前会话的消息
-        const result = data.filter(item => item.conversationID === state.currentConversation.conversationID)
+        const result = data.filter(item => item.recvID===JSON.parse(state.currentConversation.latestMsg).recvID&& item.sendID === JSON.parse(state.currentConversation.latestMsg).sendID)
         console.log("收到消息1")
-        if(result[0].cloudCustomData!=null&&result[0].cloudCustomData!=""){
+        console.log("state.currentConversation.conversationID会话id",state.currentConversation.conversationID)
+        console.log("result[0]",result[0])
+        if(result[0].ex!=null&&result[0].ex!=""){
           try{
-            var json=JSON.parse(result[0].cloudCustomData);
-            console.log(json)
+            var json=JSON.parse(result[0].ex);
+            console.log("消息json",json)
             if(json.type!=null&&json.type!=""){
               state.type=json.type;
               state.orderId=json.orderId;
@@ -200,22 +242,20 @@ const conversationModules = {
               state.followId=json.followId;
               state.orderType=json.orderType;
             }
-           
-          
           }
           catch(e){
-
           }
-          
         }
         state.currentMessageList = [...state.currentMessageList, ...result]
         filterCallingMessage(state.currentMessageList)
-      } else if (data.conversationID === state.currentConversation.conversationID) {
+      //} else if ("si_"+data.sendID+"_"+data.recvID === state.currentConversation.conversationID) {
+      } else if (data.recvID===JSON.parse(state.currentConversation.latestMsg).recvID&& data.sendID === JSON.parse(state.currentConversation.latestMsg).sendID) {
+        console.log("会话id22222",state.currentConversation.conversationID)
         state.currentMessageList = [...state.currentMessageList, data]
         console.log("收到消息2")
         console.log(data)
-        if(data.cloudCustomData!=null&&data.cloudCustomData!=""){
-          var json=JSON.parse(data.cloudCustomData);
+        if(data.ex!=null&&data.ex!=""){
+          var json=JSON.parse(data.ex);
           console.log(json)
           try{
             if(json.type!=null&&json.type!=""){
@@ -225,13 +265,9 @@ const conversationModules = {
               state.followId=json.followId;
               state.orderType=json.orderType;
             }
-            
           }
           catch(e){
-
           }
-
-          
         }
         filterCallingMessage(state.currentMessageList)
       }
@@ -258,13 +294,14 @@ const conversationModules = {
     }
   },
   actions: {
+
     /**
      * 获取消息列表
      * 调用时机:打开某一会话时或下拉获取历史消息时
      * @param {Object} context
      * @param {String} conversationID
      */
-    getMessageList(context, conversationID) {
+    async getMessageList(context, conversationID) {
       if (context.state.isCompleted) {
         context.commit('showMessage', {
           message: '已经没有更多的历史消息了哦',
@@ -272,16 +309,48 @@ const conversationModules = {
         })
         return
       }
-      const { nextReqMessageID, currentMessageList } = context.state
-      tim.getMessageList({ conversationID, nextReqMessageID, count: 15 }).then(imReponse => {
-        // 更新messageID,续拉时要用到
-        context.state.nextReqMessageID = imReponse.data.nextReqMessageID
-        context.state.isCompleted = imReponse.data.isCompleted
-        // 更新当前消息列表,从头部插入
-        context.state.currentMessageList = [...imReponse.data.messageList, ...currentMessageList]
-        filterCallingMessage(context.state.currentMessageList)
 
-      })
+      const { currentMessageList, lastClientMsgID } = context.state
+
+      try {
+        // 调用 OpenIM 的历史消息接口
+        const res = await OpenIM.getAdvancedHistoryMessageList({
+          conversationID: conversationID,
+          count: 100,
+          startClientMsgID: lastClientMsgID || '', // 第一次为空
+          lastMinSeq: 0,
+          viewType:0
+        })
+
+        let messageList = res.data.messageList || []
+        //过滤掉双方成为好友通知
+        messageList = messageList.filter(message => message.contentType !== 1201)
+        console.log("q切换会话获取聊天记录",messageList)
+        if (messageList.length === 0) {
+          context.state.isCompleted = true
+          context.commit('showMessage', {
+            message: '已经没有更多的历史消息了哦',
+            type: 'info'
+          })
+          return
+        }
+
+        // 更新 lastClientMsgID 为本次最早的消息,用于下次分页
+        context.state.lastClientMsgID = messageList[0].clientMsgID
+        // 插入历史消息到前面
+        console.log("messageList",messageList)
+        context.state.currentMessageList = [...messageList, ...currentMessageList]
+
+        console.log(context.state.currentMessageList)
+        // 过滤通话相关消息(如有)
+        //filterCallingMessage(context.state.currentMessageList)
+      } catch (error) {
+        console.error('获取历史消息失败:', error)
+        context.commit('showMessage', {
+          message: '获取历史消息失败',
+          type: 'error'
+        })
+      }
     },
     /**
      * 切换会话
@@ -289,39 +358,116 @@ const conversationModules = {
      * @param {Object} context
      * @param {String} conversationID
      */
-    checkoutConversation(context, conversationID) {
+    checkoutConversation(context, conversation) {
+      console.log("conversation",conversation)
+
       context.commit('resetCurrentMemberList')
       context.commit('resetSelectedMessage', false)
       context.commit('resetFriendContent')
+      /*console.log("用户id"+context.state.currentConversation.userID)
+      console.log("会话类型"+context.state.currentConversation.conversationType)
+      console.log("会话id"+context.state.currentConversation.conversationID)*/
       // 1.切换会话前,将切换前的会话进行已读上报
-      if (context.state.currentConversation.conversationID) {
+      //if (context.state.currentConversation.conversationID) {
+        //console.log("标记切换前会话为已读",context.state.currentConversation)
         const prevConversationID = context.state.currentConversation.conversationID
-        tim.setMessageRead({ conversationID: prevConversationID })
-      }
+        OpenIM.markConversationMessageAsRead(prevConversationID).then(({ data }) => {
+          // 调用成功
+        })
+          .catch(({ errCode, errMsg }) => {
+            if (errCode !== 10303) {
+              console.error("标记已读失败");
+            }
+          });
+        /*OpenIM.getOneConversation({
+          sourceID: context.state.currentConversation.userID,
+          sessionType: context.state.currentConversation.conversationType,
+        }).then(({ data }) => {
+          console.log("当前会话未读数量",data.unreadCount)
+
+          /!*if (data.unreadCount>0){
+            OpenIM.markConversationMessageAsRead(prevConversationID)
+          }*!/
+        })
+          .catch(({ errCode, errMsg }) => {
+            // 调用失败
+          });*/
+      //}
+      //console.log("标记待切换会话为已读",conversation.conversationID)
       // 2.待切换的会话也进行已读上报
-      tim.setMessageRead({ conversationID })
+      OpenIM.markConversationMessageAsRead(conversation.conversationID).then(({ data }) => {
+        // 调用成功
+      })
+        .catch(({ errCode, errMsg }) => {
+          if (errCode !== 10303) {
+            console.error("标记已读失败");
+          }
+        });
+      /*console.log("context.state.currentConversation",context.state.currentConversation)
+      console.log("conversation",conversation)*/
+
+      /*OpenIM.getOneConversation({
+        sourceID: conversation.userID,
+        sessionType: conversation.conversationType,
+      }).then(({ data }) => {
+        console.log("下一个会话未读数量",data.unreadCount)
+
+        /!*if (data.unreadCount>0){
+
+          // 2.待切换的会话也进行已读上报
+          OpenIM.markConversationMessageAsRead(conversation.conversationID)
+        }*!/
+      })
+        .catch(({ errCode, errMsg }) => {
+          // 调用失败
+        });*/
+
       // 3. 获取会话信息
-      return tim.getConversationProfile(conversationID).then(({ data }) => {
-        console.log("获取会话信息");
+      return OpenIM.getOneConversation({
+        sourceID:conversation.userID,
+        sessionType:conversation.conversationType
+      }).then(({ data }) => {
+        console.log("获取会话信息",data);
         console.log(data);
-        if(data.conversation.lastMessage.cloudCustomData!=null){
+        context.state.lastClientMsgID = ''
+        context.state.currentMessageList = []
+        context.state.isCompleted = false
+        console.log("ex的值",data.ex)
+        if(data.ex){
           try{
-            context.state.imType=JSON.parse(data.conversation.lastMessage.cloudCustomData).imType;
-            context.state.orderId=JSON.parse(data.conversation.lastMessage.cloudCustomData).orderId;
-            context.state.orderType=JSON.parse(data.conversation.lastMessage.cloudCustomData).orderType;
-            context.state.followId=JSON.parse(data.conversation.lastMessage.cloudCustomData).followId;
-            context.state.type=JSON.parse(data.conversation.lastMessage.cloudCustomData).type;
+            context.state.imType=JSON.parse(data.ex).imType;
+            context.state.orderId=JSON.parse(data.ex).orderId;
+            context.state.orderType=JSON.parse(data.ex).orderType;
+            context.state.followId=JSON.parse(data.ex).followId;
+            context.state.type=JSON.parse(data.ex).type;
           }
           catch(e){
           }
+        }else{
+          console.log("m没有ex")
+          context.state.imType=''
+          context.state.orderId='';
+          context.state.orderType='';
+          context.state.followId='';
+          context.state.type='';
         }
+        OpenIM.getAllConversationList()
+          .then(({ data }) => {
+            // 调用成功
+            console.log("--------------------------------------------------------------------------------------------------------------------")
+            console.log(data)
+            context.commit('updateConversationList', data)
+          })
+          .catch(({ errCode, errMsg }) => {
+            // 调用失败
+          })
         // 3.1 更新当前会话
-        context.commit('updateCurrentConversation', data.conversation)
+        context.commit('updateCurrentConversation', data)
         // 3.2 获取消息列表
-        context.dispatch('getMessageList', conversationID)
+        context.dispatch('getMessageList', conversation.conversationID)
         // 3.3 拉取第一页群成员列表
-        if (data.conversation.type === TIM.TYPES.CONV_GROUP) {
-          return context.dispatch('getGroupMemberList', data.conversation.groupProfile.groupID)
+        if (data.conversationType === 4) {
+          return context.dispatch('getGroupMemberList', data.groupID)
         }
         return Promise.resolve()
       })

+ 7 - 16
src/store/modules/friend.js

@@ -1,4 +1,3 @@
-import TIM from 'tim-js-sdk/tim-js-friendship'
 const friendModules = {
   state: {
     friendList: [],
@@ -9,7 +8,7 @@ const friendModules = {
     currentMemberList: [],
     friendContent: {},
     applicationContent: {},
-    },
+  },
   mutations: {
     updateFriendList(state, friendList) {
       state.friendList = friendList
@@ -36,31 +35,24 @@ const friendModules = {
       state.friendContent = {}
     },
     deleteApplicationList(state, applicationInfo) {
-      const { to, applicationType } = applicationInfo
-      if (applicationType === TIM.TYPES.APPLICATION_TYPE_COMEIN) {
-        state.comeInApplicationList = state.comeInApplicationList.filter(item => item.to !== to)
-      }
-      if (applicationType === TIM.TYPES.APPLICATION_TYPE_SENDOUT) {
-        state.sendOutApplicationList = state.sendOutApplicationList.filter(item => item.to !== to)
-      }
+      const { userID } = applicationInfo
+      state.applicationList = state.applicationList.filter(item => item.userID !== userID)
     },
     deleteFriend(state, userID) {
       state.friendList = state.friendList.filter(item => item.userID !== userID)
     },
-    // 删除好友分组
     deleteFriendGroupList(state, groupNameList) {
-      state.friendGroupList = state.friendGroupList.filter((groupItem) => !groupNameList.includes(groupItem.groupName))
+      state.friendGroupList = state.friendGroupList.filter(
+        groupItem => !groupNameList.includes(groupItem.groupName)
+      )
     },
-    // 增加好友分组
     addFriendGroupList(state, friendGroup) {
       state.friendGroupList = [...state.friendGroupList, ...friendGroup]
     },
-    // 更新分组信息
     updateFriendGroupInfo(state, groupInfo) {
-      state.friendGroupList = state.friendGroupList.map( groupItem=> {
+      state.friendGroupList = state.friendGroupList.map(groupItem => {
         return groupItem.groupName === groupInfo.groupName ? groupInfo : groupItem
       })
-
     },
     reset(state) {
       Object.assign(state, {
@@ -81,7 +73,6 @@ const friendModules = {
       context.commit('resetCurrentConversation')
       context.commit('resetFriendContent')
       context.commit('updateApplicationContent', applicationContent)
-
     },
   }
 }

+ 3 - 3
src/store/modules/group.js

@@ -1,4 +1,4 @@
-import tim from '@/tim.js';
+//import tim from '@/tim.js';
 const groupModules = {
   state: {
     groupList: [],
@@ -40,14 +40,14 @@ const groupModules = {
       context.commit('updateGroupList', groupList)
     },
     getGroupMemberList(context, groupID) {
-      return tim.getGroupMemberList({
+      /*return tim.getGroupMemberList({
         groupID: groupID,
         offset: context.state.currentMemberList.length,
         count: 30
       }).then((imResponse) => {
         context.commit('updateCurrentMemberList', imResponse.data.memberList)
         return imResponse
-      })
+      })*/
     }
   }
 }

+ 7 - 5
src/store/modules/imuser.js

@@ -1,4 +1,5 @@
- import tim from '../../tim'
+import { getOpenIM } from '@/utils/openIM';
+const OpenIM = getOpenIM();
 const user = {
   state: {
     currentUserProfile: {},
@@ -9,7 +10,7 @@ const user = {
     sdkAppID: 0,
   },
   mutations: {
-    
+
     updateCurrentUserProfile(state, userProfile) {
       state.currentUserProfile = userProfile
     },
@@ -56,13 +57,14 @@ const user = {
     //       }
     //     })
     // },
-    
+
     imlogout(context) {
+      console.log("退出登录")
       // 若有当前会话,在退出登录时已读上报
       if (context.rootState.conversation.currentConversation.conversationID) {
-        tim.setMessageRead({ conversationID: context.rootState.conversation.currentConversation.conversationID })
+        OpenIM.markConversationMessageAsRead(context.rootState.conversation.currentConversation.conversationID)
       }
-      tim.logout().then(() => {
+      OpenIM.logout().then(() => {
         console.log("imLogout")
         context.commit('toggleIsLogin')
         context.commit('stopComputeCurrent')

+ 3 - 3
src/store/modules/user.js

@@ -49,7 +49,7 @@ const user = {
           // 设置请求头
           axios.defaults.headers.common['APPToken'] = res.token;
           commit('SET_DOCTOR',res.doctor)
-          commit('setUserId', "D-"+res.doctor.doctorId)
+          commit('setUserId', "SCRMD"+res.doctor.doctorId)
           resolve(res)
         }).catch(error => {
           reject(error)
@@ -69,7 +69,7 @@ const user = {
           commit('SET_NAME', doctor.doctorName)
           commit('SET_AVATAR', avatar)
           commit('SET_DOCTOR', res.doctor)
-          commit('setUserId', "D-"+res.doctor.doctorId)
+          commit('setUserId', "scrmD"+res.doctor.doctorId)
           resolve(res)
         }).catch(error => {
           reject(error)
@@ -86,7 +86,7 @@ const user = {
       })
     },
 
-    
+
   }
 }
 

+ 13 - 13
src/tim.js

@@ -1,17 +1,17 @@
-import TIM from 'tim-js-sdk/tim-js-friendship.js'
-import TIMUploadPlugin from 'tim-upload-plugin'
-import { imConfig } from '@/utils/im'
-// 初始化 SDK 实例
+// import TIM from 'tim-js-sdk/tim-js-friendship.js'
+// import TIMUploadPlugin from 'tim-upload-plugin'
+// import { imConfig } from '@/utils/im'
+// // 初始化 SDK 实例
 
-const tim = TIM.create({
-  SDKAppID: imConfig.SDKAPPID
-})
+// const tim = TIM.create({
+//   SDKAppID: imConfig.SDKAPPID
+// })
 
-window.setLogLevel = tim.setLogLevel
+// window.setLogLevel = tim.setLogLevel
 
-// 无日志级别
-tim.setLogLevel(4)
+// // 无日志级别
+// tim.setLogLevel(4)
 
-// 注册 cos
-tim.registerPlugin({ 'tim-upload-plugin':TIMUploadPlugin })
-export default tim
+// // 注册 cos
+// tim.registerPlugin({ 'tim-upload-plugin':TIMUploadPlugin })
+// export default tim

+ 11 - 11
src/trtc-calling.js

@@ -1,14 +1,14 @@
-import  tim from './tim'
-import TRTCCalling from 'trtc-calling-js'
-import { imConfig } from '@/utils/im'
-let options = {
-  SDKAppID: imConfig.SDKAPPID,  // 接入时需要将0替换为您的云通信应用的 SDKAppID
-  tim: tim,
-}
+// import  tim from './tim'
+// import TRTCCalling from 'trtc-calling-js'
+// import { imConfig } from '@/utils/im'
+// let options = {
+//   SDKAppID: imConfig.SDKAPPID,  // 接入时需要将0替换为您的云通信应用的 SDKAppID
+//   tim: tim,
+// }
 
-const trtcCalling = new TRTCCalling(options)
+// const trtcCalling = new TRTCCalling(options)
 
-// 4 无日志级别
-trtcCalling.setLogLevel(0)
+// // 4 无日志级别
+// trtcCalling.setLogLevel(0)
 
-export default trtcCalling
+// export default trtcCalling

+ 55 - 55
src/utils/common.js

@@ -2,7 +2,7 @@
  * 通用js方法封装处理
  * Copyright (c) 2019 ruoyi
  */
-import TIM from 'tim-js-sdk/tim-js-friendship'
+//import TIM from 'tim-js-sdk/tim-js-friendship'
 
 
 export function translateGroupSystemNotice(message) {
@@ -38,7 +38,7 @@ export function translateGroupSystemNotice(message) {
 		return '自定义群系统通知: ' + message.payload.userDefinedField
 	}
   }
-  
+
   export const errorMap = {
 	500: '服务器错误',
 	602: '用户名或密码不合法',
@@ -47,57 +47,57 @@ export function translateGroupSystemNotice(message) {
 	620: '用户不存在',
 	621: '密码错误'
   }
-  export function filterCallingMessage(currentMessageList) {
-	currentMessageList.forEach((item) => {
-	  if (item.callType) {   // 对于自己伪造的消息不需要解析
-		return
-	  }
-	  if (item.type === TIM.TYPES.MSG_MERGER && item.payload.downloadKey !== '') {
-		let promise = window.tim.downloadMergerMessage(item)
-		promise.then(function(imResponse) {
-		  // 下载成功后,SDK会更新 message.payload.messageList 等信息
-		  item = imResponse
-		}).catch(function(imError) {
-		  // 下载失败
-		  console.warn('downloadMergerMessage error:', imError)
-		})
-	  }
-	  if(item.type === TIM.TYPES.MSG_CUSTOM) {
-		let payloadData = {}
-		try {
-		  payloadData = JSON.parse(item.payload.data)
-		}catch (e) {
-		  payloadData = {}
-		}
-		if(payloadData.businessID === 1) {
-		  if(item.conversationType === TIM.TYPES.CONV_GROUP) {
-			if(payloadData.actionType === 5) {
-			  item.nick = payloadData.inviteeList ? payloadData.inviteeList.join(','):item.from
-			}
-			let _text = window.trtcCalling.extractCallingInfoFromMessage(item)
-			let group_text = `${_text}`
-			item.type = TIM.TYPES.MSG_GRP_TIP
-			let customData = {
-			  operationType: 256,
-			  text: group_text,
-			  userIDList: []
-			}
-			item.payload = customData//JSON.stringify(customData)
-		  }
-		  if(item.conversationType === TIM.TYPES.CONV_C2C) {
-			let c2c_text = window.trtcCalling.extractCallingInfoFromMessage(item)
-			let customData = {
-			  text: c2c_text
-			}
-			item.payload = customData//JSON.stringify(customData)
-		  }
-		}
-	  }
-  
-	})
-  }
-  
-  
+export function filterCallingMessage(currentMessageList) {
+  currentMessageList.forEach((item) => {
+    console.log("item",item)
+    if (item.callType) {   // 对于自己伪造的消息不需要解析
+      return;
+    }
+    if (item.type === 'MSG_MERGER' && item.payload.downloadKey !== '') {
+      let promise = im.downloadMergerMessage(item);
+      promise.then(function(imResponse) {
+        // 下载成功后,SDK会更新 message.payload.messageList 等信息
+        item = imResponse;
+      }).catch(function(imError) {
+        // 下载失败
+        console.warn('downloadMergerMessage error:', imError);
+      });
+    }
+    if (item.type === 'MSG_CUSTOM') {
+      let payloadData = {};
+      try {
+        payloadData = JSON.parse(item.payload.data);
+      } catch (e) {
+        payloadData = {};
+      }
+      if (payloadData.businessID === 1) {
+        if (item.conversationType === 'GROUP') {
+          if (payloadData.actionType === 5) {
+            item.nick = payloadData.inviteeList ? payloadData.inviteeList.join(',') : item.from;
+          }
+          let _text = im.extractCallingInfoFromMessage(item);
+          let group_text = `${_text}`;
+          item.type = 'MSG_GRP_TIP';
+          let customData = {
+            operationType: 256,
+            text: group_text,
+            userIDList: []
+          };
+          item.payload = customData; // 通过 OpenIM SDK 传递自定义数据
+        }
+        if (item.conversationType === 'C2C') {
+          let c2c_text = im.extractCallingInfoFromMessage(item);
+          let customData = {
+            text: c2c_text
+          };
+          item.payload = customData; // 通过 OpenIM SDK 传递自定义数据
+        }
+      }
+    }
+  });
+}
+
+
 
 
 const baseURL = process.env.VUE_APP_BASE_API
@@ -147,7 +147,7 @@ export function cloneObject(obj) {
 	if (typeof obj != "object") return;
 	return JSON.parse(JSON.stringify(obj));
 }
- 
+
 // 表单重置
 export function resetForm(refName) {
 	if (this.$refs[refName]) {
@@ -199,7 +199,7 @@ export function selectDictLabels(datas, value, separator) {
 
 // 通用下载方法
 export function download(fileName) {
-	window.location.href = baseURL + "/common/download?fileName=" + encodeURI(fileName) + "&delete=" + true;
+	window.location.href = baseURL + "/app/common/download?fileName=" + encodeURI(fileName) + "&delete=" + true;
 }
 
 // 字符串格式化(%s )

+ 1 - 1
src/utils/decodeText.js

@@ -10,7 +10,7 @@ import { emojiMap, emojiUrl } from './emojiMap'
 export function decodeText (payload) {
   let renderDom = []
   // 文本消息
-    let temp = payload.text
+    let temp = payload.content
     let left = -1
     let right = -1
     while (temp !== '') {

+ 215 - 1
src/utils/emojiMap.js

@@ -143,7 +143,221 @@ export const emojiMap = {
   '[鼓掌]': 'emoji_140@2x.png',
   '[龇牙]': 'emoji_141@2x.png'
 }
+export const emojiCharMap = {
+  '[微笑]': '😀',
+  '[撇嘴]': '😒',
+  '[色]': '😍',
+  '[发呆]': '😳',
+  '[得意]': '😏',
+  '[流泪]': '😭',
+  '[害羞]': '😊',
+  '[闭嘴]': '🤐',
+  '[睡]': '😴',
+  '[大哭]': '😢',
+  '[尴尬]': '😅',
+  '[发怒]': '😡',
+  '[调皮]': '😜',
+  '[呲牙]': '😁',
+  '[惊讶]': '😲',
+  '[难过]': '😞',
+  '[酷]': '😎',
+  '[冷汗]': '😰',
+  '[抓狂]': '🤯',
+  '[吐]': '🤮',
+  '[偷笑]': '😏',
+  '[愉快]': '😄',
+  '[白眼]': '🙄',
+  '[傲慢]': '😤',
+  '[饥饿]': '😫',
+  '[困]': '😪',
+  '[惊恐]': '😱',
+  '[流汗]': '😓',
+  '[憨笑]': '😄',
+  '[大兵]': '💂‍♂️',
+  '[奋斗]': '💪',
+  '[咒骂]': '🖕',
+  '[疑问]': '❓',
+  '[嘘]': '🤫',
+  '[晕]': '😵',
+  '[折磨]': '😖',
+  '[衰]': '😞',
+  '[骷髅]': '💀',
+  '[敲打]': '👊',
+  '[再见]': '👋',
+  '[擦汗]': '😅',
+  '[抠鼻]': '🤭',
+  '[鼓掌]': '👏',
+  '[糗大了]': '😳',
+  '[坏笑]': '😈',
+  '[左哼哼]': '😤',
+  '[右哼哼]': '😤',
+  '[哈欠]': '🥱',
+  '[鄙视]': '😒',
+  '[委屈]': '😞',
+  '[快哭了]': '😢',
+  '[阴险]': '😏',
+  '[亲亲]': '😘',
+  '[吓]': '😱',
+  '[可怜]': '🥺',
+  '[菜刀]': '🔪',
+  '[西瓜]': '🍉',
+  '[啤酒]': '🍺',
+  '[篮球]': '🏀',
+  '[乒乓]': '🏓',
+  '[咖啡]': '☕',
+  '[饭]': '🍚',
+  '[猪头]': '🐷',
+  '[玫瑰]': '🌹',
+  '[凋谢]': '🥀',
+  '[示爱]': '💌',
+  '[爱心]': '❤️',
+  '[心碎]': '💔',
+  '[蛋糕]': '🎂',
+  '[闪电]': '⚡',
+  '[炸弹]': '💣',
+  '[刀]': '🔪',
+  '[足球]': '⚽',
+  '[瓢虫]': '🐞',
+  '[便便]': '💩',
+  '[月亮]': '🌙',
+  '[太阳]': '☀️',
+  '[礼物]': '🎁',
+  '[拥抱]': '🤗',
+  '[强]': '💪',
+  '[弱]': '🙌',
+  '[握手]': '🤝',
+  '[胜利]': '✌️',
+  '[抱拳]': '🙏',
+  '[勾引]': '😉',
+  '[拳头]': '👊',
+  '[差劲]': '👎',
+  '[爱你]': '❤️',
+  '[NO]': '🚫',
+  '[OK]': '👌',
+  '[爱情]': '💕',
+  '[飞吻]': '😘',
+  '[跳跳]': '🤸',
+  '[发抖]': '🤒',
+  '[怄火]': '😡',
+  '[转圈]': '🔄',
+  '[磕头]': '🙏',
+  '[回头]': '↩️',
+  '[跳绳]': '🤾',
+  '[投降]': '🏳️‍🌈',
+  '[激动]': '🤩',
+  '[乱舞]': '💃',
+  '[献吻]': '😘',
+  '[左太极]': '☯️',
+  '[右太极]': '☯️'
+};
 export const emojiName = [
+  '[微笑]',
+  '[撇嘴]',
+  '[色]',
+  '[发呆]',
+  '[得意]',
+  '[流泪]',
+  '[害羞]',
+  '[闭嘴]',
+  '[睡]',
+  '[大哭]',
+  '[尴尬]',
+  '[发怒]',
+  '[调皮]',
+  '[呲牙]',
+  '[惊讶]',
+  '[难过]',
+  '[酷]',
+  '[冷汗]',
+  '[抓狂]',
+  '[吐]',
+  '[偷笑]',
+  '[愉快]',
+  '[白眼]',
+  '[傲慢]',
+  '[饥饿]',
+  '[困]',
+  '[惊恐]',
+  '[流汗]',
+  '[憨笑]',
+  '[大兵]',
+  '[奋斗]',
+  '[咒骂]',
+  '[疑问]',
+  '[嘘]',
+  '[晕]',
+  '[折磨]',
+  '[衰]',
+  '[骷髅]',
+  '[敲打]',
+  '[再见]',
+  '[擦汗]',
+  '[抠鼻]',
+  '[鼓掌]',
+  '[糗大了]',
+  '[坏笑]',
+  '[左哼哼]',
+  '[右哼哼]',
+  '[哈欠]',
+  '[鄙视]',
+  '[委屈]',
+  '[快哭了]',
+  '[阴险]',
+  '[亲亲]',
+  '[吓]',
+  '[可怜]',
+  '[菜刀]',
+  '[西瓜]',
+  '[啤酒]',
+  '[篮球]',
+  '[乒乓]',
+  '[咖啡]',
+  '[饭]',
+  '[猪头]',
+  '[玫瑰]',
+  '[凋谢]',
+  '[示爱]',
+  '[爱心]',
+  '[心碎]',
+  '[蛋糕]',
+  '[闪电]',
+  '[炸弹]',
+  '[刀]',
+  '[足球]',
+  '[瓢虫]',
+  '[便便]',
+  '[月亮]',
+  '[太阳]',
+  '[礼物]',
+  '[拥抱]',
+  '[强]',
+  '[弱]',
+  '[握手]',
+  '[胜利]',
+  '[抱拳]',
+  '[勾引]',
+  '[拳头]',
+  '[差劲]',
+  '[爱你]',
+  '[NO]',
+  '[OK]',
+  '[爱情]',
+  '[飞吻]',
+  '[跳跳]',
+  '[发抖]',
+  '[怄火]',
+  '[转圈]',
+  '[磕头]',
+  '[回头]',
+  '[跳绳]',
+  '[投降]',
+  '[激动]',
+  '[乱舞]',
+  '[献吻]',
+  '[左太极]',
+  '[右太极]'
+]
+/*export const emojiName = [
   '[龇牙]',
   '[调皮]',
   '[流汗]',
@@ -282,4 +496,4 @@ export const emojiName = [
   '[纸巾]',
   '[手枪]',
   '[青蛙]'
-]
+]*/

+ 36 - 4
src/utils/im.js

@@ -1,5 +1,37 @@
-  export const imConfig = {
-	  // SDKAPPID: process.env.VUE_APP_IM_CONFIG
-	  // SDKAPPID: 1600089873
-    SDKAPPID: parseInt(process.env.VUE_APP_IM_CONFIG, 10)
+// @/utils/im.js - OpenIM 配置文件
+
+const config = {
+  // 基础配置
+  SDKAPPID: 0,
+  SECRET: 'openIM123',
+
+  // 服务器地址配置
+  API_ADDRESS: 'https://web.im.cdwjyyh.com/api', // OpenIM API地址
+  WS_ADDRESS: 'wss://web.im.cdwjyyh.com/msg_gateway', // WebSocket地址
+
+  // 平台配置
+  PLATFORM_ID: 5, // 平台ID (5=Web)
+
+  // 其他配置
+  DATA_DIR: '/imdata', // 数据存储目录
+  LOG_LEVEL: 'debug', // 日志级别
+
+  // 获取完整登录配置
+  getLoginConfig(userID, token) {
+    return {
+      userID,
+      token,
+      platformID: this.PLATFORM_ID,
+      apiAddr: this.API_ADDRESS,
+      wsAddr: this.WS_ADDRESS,
+      dataDir: this.DATA_DIR
+    }
+  },
+
+  // 生成随机用户ID (测试用)
+  genTestUserID() {
+    return `test_${Math.random().toString(36).substr(2, 8)}`
   }
+}
+
+export default config

+ 1 - 0
src/utils/request.js

@@ -24,6 +24,7 @@ service.interceptors.request.use(config => {
   if (getToken() && !isToken) {
     config.headers['APPToken'] =  getToken() // 让每个请求携带自定义token 请根据实际情况自行修改
     config.headers['X-Frontend-Type'] = 'doctor'
+    config.headers['Device-Type'] = 'web'
   }
   // get请求映射params参数
   if (config.method === 'get' && config.params) {

+ 23 - 23
src/utils/rtc-client.js

@@ -1,5 +1,5 @@
 /* eslint-disable */
-import TRTC from 'trtc-js-sdk'
+//import TRTC from 'trtc-js-sdk'
 
 class RtcClient {
   constructor(options) {
@@ -15,11 +15,11 @@ class RtcClient {
     this.ready = false
 
     // check if browser is compatible with TRTC
-    TRTC.checkSystemRequirements().then(result => {
+    /*TRTC.checkSystemRequirements().then(result => {
       if (!result) {
         alert('Your browser is not compatible with TRTC! Please download Chrome M72+');
       }
-    });
+    });*/
   }
 
   async join() {
@@ -29,12 +29,12 @@ class RtcClient {
     }
 
     // create a client for RtcClient
-    this.client_ = TRTC.createClient({
-      mode: 'videoCall', // 实时通话模式
-      sdkAppId: this.sdkAppId_,
-      userId: this.userId_,
-      userSig: this.userSig_
-    });
+    // this.client_ = TRTC.createClient({
+    //   mode: 'videoCall', // 实时通话模式
+    //   sdkAppId: this.sdkAppId_,
+    //   userId: this.userId_,
+    //   userSig: this.userSig_
+    // });
 
     // 处理 client 事件
     this.handleEvents();
@@ -152,19 +152,19 @@ class RtcClient {
     this.localStream_.unmuteVideo();
   }
 
-  async createLocalStream(options) {
-    this.localStream_ = TRTC.createStream({
-      audio: options.audio, // 采集麦克风
-      video: options.video, // 采集摄像头
-      userId: this.userId_
-      // cameraId: getCameraId(),
-      // microphoneId: getMicrophoneId()
-    });
-    // 设置视频分辨率帧率和码率
-    this.localStream_.setVideoProfile('480p');
-
-    await this.localStream_.initialize();
-  }
+  // async createLocalStream(options) {
+  //   this.localStream_ = TRTC.createStream({
+  //     audio: options.audio, // 采集麦克风
+  //     video: options.video, // 采集摄像头
+  //     userId: this.userId_
+  //     // cameraId: getCameraId(),
+  //     // microphoneId: getMicrophoneId()
+  //   });
+  //   // 设置视频分辨率帧率和码率
+  //   this.localStream_.setVideoProfile('480p');
+  //
+  //   await this.localStream_.initialize();
+  // }
 
   handleEvents() {
     // 处理 client 错误事件,错误均为不可恢复错误,建议提示用户后刷新页面
@@ -262,4 +262,4 @@ class RtcClient {
   }
 }
 
-export default RtcClient
+export default RtcClient

+ 13 - 0
src/views/components/drugReport/addDrugReport.vue

@@ -74,6 +74,19 @@
               remark:this.form.remark
             }
             addReport(data).then(response => {
+              /*const exMassage = {
+                conversationID: `si_D${this.item.doctorId}_U${this.item.userId}`,
+                ex: JSON.stringify({
+                  type: "drugReport",
+                  orderId: this.item.orderId,
+                  followId:this.followId,
+                  imType: 2
+                })
+              };
+
+              // 4. 调用 SDK 更新会话
+              await this.OpenIM.setConversation(exMassage);
+              console.log("会话更新请求已发送");*/
               this.msgSuccess("提交成功");
             });
           }

+ 1 - 2
src/views/components/drugReport/drugReportDetails.vue

@@ -49,7 +49,6 @@
       return {
         statusOptions: [],
         item:null,
-        
       }
     },
     created() {
@@ -90,4 +89,4 @@
     max-width: 500px;
     min-width: 100px;
   }
-</style>
+</style>

+ 140 - 140
src/views/components/msg/followMsgDetails.vue

@@ -3,33 +3,33 @@
     <div class="chat-records">
       <el-card v-for="(lt, index) in msg" :key="index" class="chat-record" :class="{ 'received': lt.msgType == '1', 'sent': lt.msgType == '2' }">
         <div   :class="{ 'right': lt.msgType == '2'}" style="margin-bottom: 20px;">
-        <div class="timestamp" style="margin-bottom: 10px;">
-          <span v-if="lt.msgType=='1'"> {{patientName}}</span>
-          <span v-if="lt.msgType=='2'"> {{doctorName}}</span>
-        {{ lt.createTime }}
-        </div>
-        <div class="message">
-          <div v-if="lt.msgContentType == '1'" :class="{ 'right': lt.msgType == '2'}">{{lt.content}}</div>
-          <div v-if="lt.msgContentType == '2'" :class="{ 'right': lt.msgType == '2'}">
-            <audio ref="audioPlayer" controls>
-              <source :src="lt.content" type="audio/mp3" />
-            </audio>
-          </div>
-          <div v-if="lt.msgContentType == '4'" :class="{ 'right': lt.msgType == '2'}">
-            <video  :src="lt.content" controls style="max-width: 400px; max-height: 400px;"></video>
+          <div class="timestamp" style="margin-bottom: 10px;">
+            <span v-if="lt.msgType=='1'"> {{patientName}}</span>
+            <span v-if="lt.msgType=='2'"> {{doctorName}}</span>
+            {{ lt.createTime }}
           </div>
-          <span v-if="lt.msgContentType == '5'" :class="{ 'right': lt.msgType == '2'}"><el-link type="primary" :underline="false" @click="getPrescribe(JSON.parse(lt.content).prescribeId)">处方单</el-link></span>
-          <span v-if="lt.msgContentType == '6'" :class="{ 'right': lt.msgType == '2'}"><el-link type="primary" :underline="false" @click="report(lt.content)">问诊报告</el-link></span>
-          <span v-if="lt.msgContentType == '7'" :class="{ 'right': lt.msgType == '2'}"><el-link type="primary" :underline="false" @click="follow(lt.content)">随访</el-link></span>
-          <span v-if="lt.msgContentType == '8'" :class="{ 'right': lt.msgType == '2'}"><el-link type="primary" :underline="false" @click="drugReport(lt.content)">用药报告</el-link></span>
-          <span v-else-if="lt.msgContentType == '3'" :class="{ 'right': lt.msgType == '2'}">
+          <div class="message">
+            <div v-if="lt.msgContentType == '1'" :class="{ 'right': lt.msgType == '2'}">{{lt.content}}</div>
+            <div v-if="lt.msgContentType == '2'" :class="{ 'right': lt.msgType == '2'}">
+              <audio ref="audioPlayer" controls>
+                <source :src="lt.content" type="audio/mp3" />
+              </audio>
+            </div>
+            <div v-if="lt.msgContentType == '4'" :class="{ 'right': lt.msgType == '2'}">
+              <video  :src="lt.content" controls style="max-width: 400px; max-height: 400px;"></video>
+            </div>
+            <span v-if="lt.msgContentType == '5'" :class="{ 'right': lt.msgType == '2'}"><el-link type="primary" :underline="false" @click="getPrescribe(JSON.parse(lt.content).prescribeId)">处方单</el-link></span>
+            <span v-if="lt.msgContentType == '6'" :class="{ 'right': lt.msgType == '2'}"><el-link type="primary" :underline="false" @click="report(lt.content)">问诊报告</el-link></span>
+            <span v-if="lt.msgContentType == '7'" :class="{ 'right': lt.msgType == '2'}"><el-link type="primary" :underline="false" @click="follow(lt.content)">随访</el-link></span>
+            <span v-if="lt.msgContentType == '8'" :class="{ 'right': lt.msgType == '2'}"><el-link type="primary" :underline="false" @click="drugReport(lt.content)">用药报告</el-link></span>
+            <span v-else-if="lt.msgContentType == '3'" :class="{ 'right': lt.msgType == '2'}">
             <el-image
               style="width: 100px"
               :src="lt.content"
               :preview-src-list="[lt.content]">
             </el-image>
           </span>
-        </div>
+          </div>
         </div>
       </el-card>
     </div>
@@ -45,34 +45,34 @@
       :visible.sync="followDialogVisible"
       width="80%"
       :before-close="handleCloseSF" append-to-body >
-              <div  style="margin-left: 40px;" v-if="followList!=null">
-               <div    :class="'questionnaire_'+index"   v-for="(ite, index) in followList"   :key="index" >
-                    <div class="flex-1">
-                      <span :class="ite.require ? 'require' : 'noRequire'">{{index+1}}.{{ite.question}}</span>
-                    <div>
-                        <div v-if="'1' == ite.type">
-                           <el-row v-for="(answerItem,i) in ite.options"  :key="i">
-                              <el-col :span="23" :offset="1"> <el-radio disabled v-model="ite.answers" :label="ite.options[i]"></el-radio></el-col>
-                           </el-row>
-                        </div>
-                        <div v-if="'2' == ite.type">
-                            <el-row v-for="(answerItem,i) in ite.options"  :key="i">
-                               <el-col :span="23" :offset="1">
-                                <el-checkbox-group v-model="ite.answers">
-                                   <el-checkbox :label="ite.options[i]" disabled></el-checkbox>
-                                </el-checkbox-group>
-                              </el-col>
-                            </el-row>
-                        </div>
-                        <div v-if="'3' == ite.type">
-                            <el-row>
-                              <el-col :span="23" :offset="1"><el-input v-model="ite.answers" :disabled="true" type="textarea"></el-input></el-col>
-                            </el-row>
-                        </div>
-                      </div>
-                    </div>
-                </div>
+      <div  style="margin-left: 40px;" v-if="followList!=null">
+        <div    :class="'questionnaire_'+index"   v-for="(ite, index) in followList"   :key="index" >
+          <div class="flex-1">
+            <span :class="ite.require ? 'require' : 'noRequire'">{{index+1}}.{{ite.question}}</span>
+            <div>
+              <div v-if="'1' == ite.type">
+                <el-row v-for="(answerItem,i) in ite.options"  :key="i">
+                  <el-col :span="23" :offset="1"> <el-radio disabled v-model="ite.answers" :label="ite.options[i]"></el-radio></el-col>
+                </el-row>
               </div>
+              <div v-if="'2' == ite.type">
+                <el-row v-for="(answerItem,i) in ite.options"  :key="i">
+                  <el-col :span="23" :offset="1">
+                    <el-checkbox-group v-model="ite.answers">
+                      <el-checkbox :label="ite.options[i]" disabled></el-checkbox>
+                    </el-checkbox-group>
+                  </el-col>
+                </el-row>
+              </div>
+              <div v-if="'3' == ite.type">
+                <el-row>
+                  <el-col :span="23" :offset="1"><el-input v-model="ite.answers" :disabled="true" type="textarea"></el-input></el-col>
+                </el-row>
+              </div>
+            </div>
+          </div>
+        </div>
+      </div>
 
       <span slot="footer" class="dialog-footer">
         <el-button @click="followDialogVisible = false">取 消</el-button>
@@ -176,7 +176,7 @@
         患者信息
       </div>
       <el-descriptions :column="3" border  >
-       <el-descriptions-item label="患者姓名" ><span v-if="reportItem.patientJson!=null">{{JSON.parse(reportItem.patientJson).patientName}}</span></el-descriptions-item>
+        <el-descriptions-item label="患者姓名" ><span v-if="reportItem.patientJson!=null">{{JSON.parse(reportItem.patientJson).patientName}}</span></el-descriptions-item>
         <el-descriptions-item label="患者年龄" ><span v-if="reportItem.patientJson!=null">{{JSON.parse(reportItem.patientJson).age}}</span></el-descriptions-item>
         <el-descriptions-item label="患者性别" ><span v-if="reportItem.patientJson!=null">{{JSON.parse(reportItem.patientJson).sex==1?'男':'女'}}</span></el-descriptions-item>
         <el-descriptions-item label="身份证号" ><span v-if="reportItem.patientJson!=null">{{JSON.parse(reportItem.patientJson).idCard}}</span></el-descriptions-item>
@@ -187,38 +187,38 @@
         <el-descriptions-item label="用药情况" ><span v-if="reportItem.patientJson!=null">{{JSON.parse(reportItem.patientJson).medication}}</span></el-descriptions-item>
         <el-descriptions-item label="主诉" span="3"><span v-if="reportItem.patientJson!=null">{{JSON.parse(reportItem.patientJson).title}}</span></el-descriptions-item>
         <el-descriptions-item label="面部照片" span="3" v-if="reportItem.patientJson!=null">
-         <div v-if="(JSON.parse(reportItem.patientJson)).faceImages">
-          <el-image v-if="JSON.parse(reportItem.patientJson).faceImages!=null&&JSON.parse(reportItem.patientJson).faceImages!=''" v-for="img in (JSON.parse(reportItem.patientJson).faceImages).split(',')" :key="img.id"
-              style="width: 100px"
-              :src="img"
-              :preview-src-list="[img]">
-          </el-image>
-         </div>
+          <div v-if="(JSON.parse(reportItem.patientJson)).faceImages">
+            <el-image v-if="JSON.parse(reportItem.patientJson).faceImages!=null&&JSON.parse(reportItem.patientJson).faceImages!=''" v-for="img in (JSON.parse(reportItem.patientJson).faceImages).split(',')" :key="img.id"
+                      style="width: 100px"
+                      :src="img"
+                      :preview-src-list="[img]">
+            </el-image>
+          </div>
         </el-descriptions-item>
         <el-descriptions-item label="舌苔照片" span="3" v-if="reportItem.patientJson!=null">
           <div v-if="(JSON.parse(reportItem.patientJson)).tongueImages">
             <el-image v-if="JSON.parse(reportItem.patientJson).tongueImages!=null&&JSON.parse(reportItem.patientJson).tongueImages!=''"  v-for="img in (JSON.parse(reportItem.patientJson).tongueImages).split(',')" :key="img.id"
-                style="width: 100px"
-                :src="img"
-                :preview-src-list="[img]">
+                      style="width: 100px"
+                      :src="img"
+                      :preview-src-list="[img]">
             </el-image>
-           </div>
+          </div>
         </el-descriptions-item>
         <el-descriptions-item label="检测报告或患病证书" span="3" v-if="reportItem.patientJson!=null">
           <div v-if="(JSON.parse(reportItem.patientJson)).tongueImages">
             <el-image v-if="JSON.parse(reportItem.patientJson).reportImages!=null && JSON.parse(reportItem.patientJson).reportImages!=''"  v-for="img in (JSON.parse(reportItem.patientJson).reportImages).split(',')" :key="img.id"
-                style="width: 100px"
-                :src="img"
-                :preview-src-list="[img]">
+                      style="width: 100px"
+                      :src="img"
+                      :preview-src-list="[img]">
             </el-image>
           </div>
         </el-descriptions-item>
       </el-descriptions>
       <div  v-if="reportItem.conditioningPlanJson!=null">
-            <div class="desct"> 调理方案</div>
-            <el-descriptions title="" :column="1" border >
-                <el-descriptions-item :label="form.name" v-for=" form in JSON.parse(reportItem.conditioningPlanJson)" ><div style="white-space: pre-wrap;">{{form.value}}</div></el-descriptions-item>
-            </el-descriptions>
+        <div class="desct"> 调理方案</div>
+        <el-descriptions title="" :column="1" border >
+          <el-descriptions-item :label="form.name" v-for=" form in JSON.parse(reportItem.conditioningPlanJson)" ><div style="white-space: pre-wrap;">{{form.value}}</div></el-descriptions-item>
+        </el-descriptions>
       </div>
       <span slot="footer" class="dialog-footer">
         <el-button @click="reportDialogVisible = false">取 消</el-button>
@@ -252,11 +252,11 @@
 </template>
 
 <script>
-import { getDrugReportById} from "@/api/drugReport";
-import { getInquiryOrderReport} from "@/api/inquiryOrder";
-import {getInquiryOrderMsgList} from "@/api/inquiryOrder";
-import {getPrescribe} from "@/api/prescribe";
-import {getFollowById} from "@/api/follow";
+  import { getDrugReportById} from "@/api/drugReport";
+  import { getInquiryOrderReport} from "@/api/inquiryOrder";
+  import {getInquiryOrderMsgList} from "@/api/inquiryOrder";
+  import {getPrescribe} from "@/api/prescribe";
+  import {getFollowById} from "@/api/follow";
   export default {
     name: "FollowMsgList",
     data() {
@@ -290,12 +290,12 @@ import {getFollowById} from "@/api/follow";
         orOptions:[],
         form: {
 
-          }
+        }
       }
     },
     created() {
       this.getDicts("sys_company_or").then(response => {
-          this.orOptions = response.data;
+        this.orOptions = response.data;
       });
       this.getDicts("sys_inquiry_sub_type").then(response => {
         this.inquirySubTypeOptions = response.data;
@@ -309,14 +309,14 @@ import {getFollowById} from "@/api/follow";
     },
     methods: {
       getPrescribe(orderId){
-      if(orderId==null){
-         return this.$message("未读取到处方单")
-       }
+        if(orderId==null){
+          return this.$message("未读取到处方单")
+        }
         this.prescribeDialog.open=true;
         getPrescribe(orderId).then(response => {
-            this.prescribeItem = response.data.prescribe;
-            this.usageJson=JSON.parse(this.prescribeItem.usageJson)
-            this.prod = response.data.drugs;
+          this.prescribeItem = response.data.prescribe;
+          this.usageJson=JSON.parse(this.prescribeItem.usageJson)
+          this.prod = response.data.drugs;
         });
       },
       getDetails(userId,followDoctorId,doctorName,patientName) {
@@ -329,8 +329,8 @@ import {getFollowById} from "@/api/follow";
       msgList(){
         this.msg=[];
         getInquiryOrderMsgList(this.msgForm).then(response => {
-        this.msg= response.data.list;
-        this.total = response.data.total;
+          this.msg= response.data.list;
+          this.total = response.data.total;
         });
       },
       handleClose(){
@@ -350,12 +350,12 @@ import {getFollowById} from "@/api/follow";
           return this.$message("未读取到随访")
         }
         getFollowById(row).then(response => {
-              if(response.follow.formJson!=null&&response.follow.formJson!=''&&response.follow.writeStatus==1){
-                        this.followList=JSON.parse(response.follow.formJson );
-                        this.followDialogVisible=true;
-              }else{
-               return this.$message("随访单未填写")
-              }
+          if(response.follow.formJson!=null&&response.follow.formJson!=''&&response.follow.writeStatus==1){
+            this.followList=JSON.parse(response.follow.formJson );
+            this.followDialogVisible=true;
+          }else{
+            return this.$message("随访单未填写")
+          }
         });
 
       },
@@ -367,11 +367,11 @@ import {getFollowById} from "@/api/follow";
           return this.$message("未读取到报告")
         }
         getInquiryOrderReport(row).then(response => {
-              if(response.data!=null){
-                  this.reportItem = response.data;
-              }
+          if(response.data!=null){
+            this.reportItem = response.data;
+          }
         });
-         this.reportDialogVisible=true;
+        this.reportDialogVisible=true;
       },
       drugReport(row){
         if(row==null){
@@ -379,9 +379,9 @@ import {getFollowById} from "@/api/follow";
         }
         var o= {reportId:row}
         getDrugReportById(o).then(response => {
-             this.drugReportItem = response.data;
+          this.drugReportItem = response.data;
         });
-         this.drugReportDialogVisible=true;
+        this.drugReportDialogVisible=true;
       },
     }
   }
@@ -389,12 +389,12 @@ import {getFollowById} from "@/api/follow";
 <style>
 
   .contentx{
-      height: 100%;
-      background-color: #fff;
-      padding: 0px 20px 20px;
+    height: 100%;
+    background-color: #fff;
+    padding: 0px 20px 20px;
 
 
-      margin: 20px;
+    margin: 20px;
   }
   .el-descriptions-item__label.is-bordered-label{
     font-weight: normal;
@@ -404,58 +404,58 @@ import {getFollowById} from "@/api/follow";
     min-width: 100px;
   }
   .desct{
-      padding-top: 20px;
-      padding-bottom: 20px;
-      color: #524b4a;
-      font-weight: bold;
-    }
+    padding-top: 20px;
+    padding-bottom: 20px;
+    color: #524b4a;
+    font-weight: bold;
+  }
 </style>
 <style scoped>
-.chat-records {
+  .chat-records {
 
-  overflow-y: auto;
-}
-.timestamp {
-  font-size: 12px;
-  color: #A9A9A9;
-}
-.chat-record {
-  margin: 10px;
-  flex-direction: column;
-  align-items: flex-start;
-}
-.sent {
-  background-color: #fbfdff;
-  color: #000839;
-}
-.right{
-  float: right;
-}
-.received {
-  background-color: #fbfdff;
-  color: #000000;
-}
+    overflow-y: auto;
+  }
+  .timestamp {
+    font-size: 12px;
+    color: #A9A9A9;
+  }
+  .chat-record {
+    margin: 10px;
+    flex-direction: column;
+    align-items: flex-start;
+  }
+  .sent {
+    background-color: #fbfdff;
+    color: #000839;
+  }
+  .right{
+    float: right;
+  }
+  .received {
+    background-color: #fbfdff;
+    color: #000000;
+  }
 
-.el-descriptions-item__content {
+  .el-descriptions-item__content {
     max-width: 150px;
     min-width: 100px;
-}
+  }
 </style>
 <style scoped>
-.order-content{
-  margin: 10px;
+  .order-content{
+    margin: 10px;
 
-}
+  }
 
-.operate-container {
-  background: #F2F6FC;
-  height: 60px;
-  margin: -20px -20px 0;
-  line-height: 60px;
-}
+  .operate-container {
+    background: #F2F6FC;
+    height: 60px;
+    margin: -20px -20px 0;
+    line-height: 60px;
+  }
 
-.operate-button-container {
-  float: right;
-  margin-right: 20px
-}
+  .operate-button-container {
+    float: right;
+    margin-right: 20px
+  }
 </style>

+ 141 - 141
src/views/components/msg/msgDetails.vue

@@ -3,33 +3,33 @@
     <div class="chat-records">
       <el-card v-for="(lt, index) in msg" :key="index" class="chat-record" :class="{ 'received': lt.msgType == '1', 'sent': lt.msgType == '2' }">
         <div   :class="{ 'right': lt.msgType == '2'}" style="margin-bottom: 20px;">
-        <div class="timestamp" style="margin-bottom: 10px;">
-          <span v-if="lt.msgType=='1'"> {{patientName}}</span>
-          <span v-if="lt.msgType=='2'"> {{doctorName}}</span>
-        {{ lt.createTime }}
-        </div>
-        <div class="message">
-          <div v-if="lt.msgContentType == '1'" :class="{ 'right': lt.msgType == '2'}">{{lt.content}}</div>
-          <div v-if="lt.msgContentType == '2'" :class="{ 'right': lt.msgType == '2'}">
-            <audio ref="audioPlayer" controls>
-              <source :src="lt.content" type="audio/mp3" />
-            </audio>
-          </div>
-          <div v-if="lt.msgContentType == '4'" :class="{ 'right': lt.msgType == '2'}">
-            <video  :src="lt.content" controls style="max-width: 400px; max-height: 400px;"></video>
+          <div class="timestamp" style="margin-bottom: 10px;">
+            <span v-if="lt.msgType=='1'"> {{patientName}}</span>
+            <span v-if="lt.msgType=='2'"> {{doctorName}}</span>
+            {{ lt.createTime }}
           </div>
-          <span v-if="lt.msgContentType == '5'" :class="{ 'right': lt.msgType == '2'}"><el-link type="primary" :underline="false" @click="getPrescribe(JSON.parse(lt.content).prescribeId)">处方单</el-link></span>
-          <span v-if="lt.msgContentType == '6'" :class="{ 'right': lt.msgType == '2'}"><el-link type="primary" :underline="false" @click="report(lt.content)">问诊报告</el-link></span>
-          <span v-if="lt.msgContentType == '7'" :class="{ 'right': lt.msgType == '2'}"><el-link type="primary" :underline="false" @click="follow(lt.content)">随访</el-link></span>
-          <span v-if="lt.msgContentType == '8'" :class="{ 'right': lt.msgType == '2'}"><el-link type="primary" :underline="false" @click="drugReport(lt.content)">用药报告</el-link></span>
-          <span v-else-if="lt.msgContentType == '3'" :class="{ 'right': lt.msgType == '2'}">
+          <div class="message">
+            <div v-if="lt.msgContentType == '1'" :class="{ 'right': lt.msgType == '2'}">{{lt.content}}</div>
+            <div v-if="lt.msgContentType == '2'" :class="{ 'right': lt.msgType == '2'}">
+              <audio ref="audioPlayer" controls>
+                <source :src="lt.content" type="audio/mp3" />
+              </audio>
+            </div>
+            <div v-if="lt.msgContentType == '4'" :class="{ 'right': lt.msgType == '2'}">
+              <video  :src="lt.content" controls style="max-width: 400px; max-height: 400px;"></video>
+            </div>
+            <span v-if="lt.msgContentType == '5'" :class="{ 'right': lt.msgType == '2'}"><el-link type="primary" :underline="false" @click="getPrescribe(JSON.parse(lt.content).prescribeId)">处方单</el-link></span>
+            <span v-if="lt.msgContentType == '6'" :class="{ 'right': lt.msgType == '2'}"><el-link type="primary" :underline="false" @click="report(lt.content)">问诊报告</el-link></span>
+            <span v-if="lt.msgContentType == '7'" :class="{ 'right': lt.msgType == '2'}"><el-link type="primary" :underline="false" @click="follow(lt.content)">随访</el-link></span>
+            <span v-if="lt.msgContentType == '8'" :class="{ 'right': lt.msgType == '2'}"><el-link type="primary" :underline="false" @click="drugReport(lt.content)">用药报告</el-link></span>
+            <span v-else-if="lt.msgContentType == '3'" :class="{ 'right': lt.msgType == '2'}">
             <el-image
               style="width: 100px"
               :src="lt.content"
               :preview-src-list="[lt.content]">
             </el-image>
           </span>
-        </div>
+          </div>
         </div>
       </el-card>
     </div>
@@ -45,34 +45,34 @@
       :visible.sync="followDialogVisible"
       width="80%"
       :before-close="handleCloseSF" append-to-body >
-              <div  style="margin-left: 40px;" v-if="followList!=null">
-               <div    :class="'questionnaire_'+index"   v-for="(ite, index) in followList"   :key="index" >
-                    <div class="flex-1">
-                      <span :class="ite.require ? 'require' : 'noRequire'">{{index+1}}.{{ite.question}}</span>
-                    <div>
-                        <div v-if="'1' == ite.type">
-                           <el-row v-for="(answerItem,i) in ite.options"  :key="i">
-                              <el-col :span="23" :offset="1"> <el-radio disabled v-model="ite.answers" :label="ite.options[i]"></el-radio></el-col>
-                           </el-row>
-                        </div>
-                        <div v-if="'2' == ite.type">
-                            <el-row v-for="(answerItem,i) in ite.options"  :key="i">
-                               <el-col :span="23" :offset="1">
-                                <el-checkbox-group v-model="ite.answers">
-                                   <el-checkbox :label="ite.options[i]" disabled></el-checkbox>
-                                </el-checkbox-group>
-                              </el-col>
-                            </el-row>
-                        </div>
-                        <div v-if="'3' == ite.type">
-                            <el-row>
-                              <el-col :span="23" :offset="1"><el-input v-model="ite.answers" :disabled="true" type="textarea"></el-input></el-col>
-                            </el-row>
-                        </div>
-                      </div>
-                    </div>
-                </div>
+      <div  style="margin-left: 40px;" v-if="followList!=null">
+        <div    :class="'questionnaire_'+index"   v-for="(ite, index) in followList"   :key="index" >
+          <div class="flex-1">
+            <span :class="ite.require ? 'require' : 'noRequire'">{{index+1}}.{{ite.question}}</span>
+            <div>
+              <div v-if="'1' == ite.type">
+                <el-row v-for="(answerItem,i) in ite.options"  :key="i">
+                  <el-col :span="23" :offset="1"> <el-radio disabled v-model="ite.answers" :label="ite.options[i]"></el-radio></el-col>
+                </el-row>
               </div>
+              <div v-if="'2' == ite.type">
+                <el-row v-for="(answerItem,i) in ite.options"  :key="i">
+                  <el-col :span="23" :offset="1">
+                    <el-checkbox-group v-model="ite.answers">
+                      <el-checkbox :label="ite.options[i]" disabled></el-checkbox>
+                    </el-checkbox-group>
+                  </el-col>
+                </el-row>
+              </div>
+              <div v-if="'3' == ite.type">
+                <el-row>
+                  <el-col :span="23" :offset="1"><el-input v-model="ite.answers" :disabled="true" type="textarea"></el-input></el-col>
+                </el-row>
+              </div>
+            </div>
+          </div>
+        </div>
+      </div>
 
       <span slot="footer" class="dialog-footer">
         <el-button @click="followDialogVisible = false">取 消</el-button>
@@ -176,7 +176,7 @@
         患者信息
       </div>
       <el-descriptions :column="3" border  >
-       <el-descriptions-item label="患者姓名" ><span v-if="reportItem.patientJson!=null">{{JSON.parse(reportItem.patientJson).patientName}}</span></el-descriptions-item>
+        <el-descriptions-item label="患者姓名" ><span v-if="reportItem.patientJson!=null">{{JSON.parse(reportItem.patientJson).patientName}}</span></el-descriptions-item>
         <el-descriptions-item label="患者年龄" ><span v-if="reportItem.patientJson!=null">{{JSON.parse(reportItem.patientJson).age}}</span></el-descriptions-item>
         <el-descriptions-item label="患者性别" ><span v-if="reportItem.patientJson!=null">{{JSON.parse(reportItem.patientJson).sex==1?'男':'女'}}</span></el-descriptions-item>
         <el-descriptions-item label="身份证号" ><span v-if="reportItem.patientJson!=null">{{JSON.parse(reportItem.patientJson).idCard}}</span></el-descriptions-item>
@@ -187,38 +187,38 @@
         <el-descriptions-item label="用药情况" ><span v-if="reportItem.patientJson!=null">{{JSON.parse(reportItem.patientJson).medication}}</span></el-descriptions-item>
         <el-descriptions-item label="主诉" span="3"><span v-if="reportItem.patientJson!=null">{{JSON.parse(reportItem.patientJson).title}}</span></el-descriptions-item>
         <el-descriptions-item label="面部照片" span="3" v-if="reportItem.patientJson!=null">
-         <div v-if="(JSON.parse(reportItem.patientJson)).faceImages">
-          <el-image v-if="JSON.parse(reportItem.patientJson).faceImages!=null&&JSON.parse(reportItem.patientJson).faceImages!=''" v-for="img in (JSON.parse(reportItem.patientJson).faceImages).split(',')" :key="img.id"
-              style="width: 100px"
-              :src="img"
-              :preview-src-list="[img]">
-          </el-image>
-         </div>
+          <div v-if="(JSON.parse(reportItem.patientJson)).faceImages">
+            <el-image v-if="JSON.parse(reportItem.patientJson).faceImages!=null&&JSON.parse(reportItem.patientJson).faceImages!=''" v-for="img in (JSON.parse(reportItem.patientJson).faceImages).split(',')" :key="img.id"
+                      style="width: 100px"
+                      :src="img"
+                      :preview-src-list="[img]">
+            </el-image>
+          </div>
         </el-descriptions-item>
         <el-descriptions-item label="舌苔照片" span="3" v-if="reportItem.patientJson!=null">
           <div v-if="(JSON.parse(reportItem.patientJson)).tongueImages">
             <el-image v-if="JSON.parse(reportItem.patientJson).tongueImages!=null&&JSON.parse(reportItem.patientJson).tongueImages!=''"  v-for="img in (JSON.parse(reportItem.patientJson).tongueImages).split(',')" :key="img.id"
-                style="width: 100px"
-                :src="img"
-                :preview-src-list="[img]">
+                      style="width: 100px"
+                      :src="img"
+                      :preview-src-list="[img]">
             </el-image>
-           </div>
+          </div>
         </el-descriptions-item>
         <el-descriptions-item label="检测报告或患病证书" span="3" v-if="reportItem.patientJson!=null">
           <div v-if="(JSON.parse(reportItem.patientJson)).tongueImages">
             <el-image v-if="JSON.parse(reportItem.patientJson).reportImages!=null && JSON.parse(reportItem.patientJson).reportImages!=''"  v-for="img in (JSON.parse(reportItem.patientJson).reportImages).split(',')" :key="img.id"
-                style="width: 100px"
-                :src="img"
-                :preview-src-list="[img]">
+                      style="width: 100px"
+                      :src="img"
+                      :preview-src-list="[img]">
             </el-image>
           </div>
         </el-descriptions-item>
       </el-descriptions>
       <div  v-if="reportItem.conditioningPlanJson!=null">
-            <div class="desct"> 调理方案</div>
-            <el-descriptions title="" :column="1" border >
-                <el-descriptions-item :label="form.name" v-for=" form in JSON.parse(reportItem.conditioningPlanJson)" ><div style="white-space: pre-wrap;">{{form.value}}</div></el-descriptions-item>
-            </el-descriptions>
+        <div class="desct"> 调理方案</div>
+        <el-descriptions title="" :column="1" border >
+          <el-descriptions-item :label="form.name" v-for=" form in JSON.parse(reportItem.conditioningPlanJson)" ><div style="white-space: pre-wrap;">{{form.value}}</div></el-descriptions-item>
+        </el-descriptions>
       </div>
       <span slot="footer" class="dialog-footer">
         <el-button @click="reportDialogVisible = false">取 消</el-button>
@@ -252,11 +252,11 @@
 </template>
 
 <script>
-import {getInquiryOrderMsgList} from "@/api/inquiryOrder";
-import { getDrugReportById} from "@/api/drugReport";
-import { getInquiryOrderReport} from "@/api/inquiryOrder";
-import {getFollowById} from "@/api/follow";
-import {getPrescribe} from "@/api/prescribe";
+  import {getInquiryOrderMsgList} from "@/api/inquiryOrder";
+  import { getDrugReportById} from "@/api/drugReport";
+  import { getInquiryOrderReport} from "@/api/inquiryOrder";
+  import {getFollowById} from "@/api/follow";
+  import {getPrescribe} from "@/api/prescribe";
   export default {
     components:{prescribeDetails},
     name: "MsgList",
@@ -290,12 +290,12 @@ import {getPrescribe} from "@/api/prescribe";
         orOptions:[],
         form: {
 
-          }
+        }
       }
     },
     created() {
       this.getDicts("sys_company_or").then(response => {
-          this.orOptions = response.data;
+        this.orOptions = response.data;
       });
       this.getDicts("sys_inquiry_sub_type").then(response => {
         this.inquirySubTypeOptions = response.data;
@@ -312,14 +312,14 @@ import {getPrescribe} from "@/api/prescribe";
         if(orderId==null){
           return this.$message("未读取到随访")
         }
-         this.prescribeDialog.open=true;
-         getPrescribe(orderId).then(response => {
-             this.prescribeItem = response.data.prescribe;
-             this.usageJson=JSON.parse(this.prescribeItem.usageJson)
-             this.prod = response.data.drugs;
-         });
+        this.prescribeDialog.open=true;
+        getPrescribe(orderId).then(response => {
+          this.prescribeItem = response.data.prescribe;
+          this.usageJson=JSON.parse(this.prescribeItem.usageJson)
+          this.prod = response.data.drugs;
+        });
 
-       },
+      },
       getDetails(orderId,doctorName,patientName) {
         this.msgForm.orderId=orderId;
         this.doctorName = doctorName;
@@ -329,8 +329,8 @@ import {getPrescribe} from "@/api/prescribe";
       msgList(){
         this.msg=[];
         getInquiryOrderMsgList(this.msgForm).then(response => {
-        this.msg= response.data.list;
-        this.total = response.data.total;
+          this.msg= response.data.list;
+          this.total = response.data.total;
         });
       },
       handleClose(){
@@ -350,12 +350,12 @@ import {getPrescribe} from "@/api/prescribe";
           return this.$message("未读取到随访")
         }
         getFollowById(row).then(response => {
-              if(response.data.formJson!=null&&response.data.formJson!=''&&response.data.writeStatus==1){
-                        this.followList=JSON.parse(response.data.formJson );
-                        this.followDialogVisible=true;
-              }else{
-               return this.$message("随访单未填写")
-              }
+          if(response.data.formJson!=null&&response.data.formJson!=''&&response.data.writeStatus==1){
+            this.followList=JSON.parse(response.data.formJson );
+            this.followDialogVisible=true;
+          }else{
+            return this.$message("随访单未填写")
+          }
         });
 
       },
@@ -367,20 +367,20 @@ import {getPrescribe} from "@/api/prescribe";
           row=this.msgForm.orderId
         }
         getInquiryOrderReport(row).then(response => {
-              if(response.data!=null){
-                  this.reportItem = response.data;
-              }
+          if(response.data!=null){
+            this.reportItem = response.data;
+          }
         });
-         this.reportDialogVisible=true;
+        this.reportDialogVisible=true;
       },
       drugReport(row){
         if(row==null){
           return this.$message("未读取到报告")
         }
         getDrugReportById(row).then(response => {
-             this.drugReportItem = response.data;
+          this.drugReportItem = response.data;
         });
-         this.drugReportDialogVisible=true;
+        this.drugReportDialogVisible=true;
       },
     }
   }
@@ -388,12 +388,12 @@ import {getPrescribe} from "@/api/prescribe";
 <style>
 
   .contentx{
-      height: 100%;
-      background-color: #fff;
-      padding: 0px 20px 20px;
+    height: 100%;
+    background-color: #fff;
+    padding: 0px 20px 20px;
 
 
-      margin: 20px;
+    margin: 20px;
   }
   .el-descriptions-item__label.is-bordered-label{
     font-weight: normal;
@@ -403,58 +403,58 @@ import {getPrescribe} from "@/api/prescribe";
     min-width: 100px;
   }
   .desct{
-      padding-top: 20px;
-      padding-bottom: 20px;
-      color: #524b4a;
-      font-weight: bold;
-    }
+    padding-top: 20px;
+    padding-bottom: 20px;
+    color: #524b4a;
+    font-weight: bold;
+  }
 </style>
 <style scoped>
-.chat-records {
+  .chat-records {
 
-  overflow-y: auto;
-}
-.timestamp {
-  font-size: 12px;
-  color: #A9A9A9;
-}
-.chat-record {
-  margin: 10px;
-  flex-direction: column;
-  align-items: flex-start;
-}
-.sent {
-  background-color: #fbfdff;
-  color: #000839;
-}
-.right{
-  float: right;
-}
-.received {
-  background-color: #fbfdff;
-  color: #000000;
-}
+    overflow-y: auto;
+  }
+  .timestamp {
+    font-size: 12px;
+    color: #A9A9A9;
+  }
+  .chat-record {
+    margin: 10px;
+    flex-direction: column;
+    align-items: flex-start;
+  }
+  .sent {
+    background-color: #fbfdff;
+    color: #000839;
+  }
+  .right{
+    float: right;
+  }
+  .received {
+    background-color: #fbfdff;
+    color: #000000;
+  }
 
-.el-descriptions-item__content {
+  .el-descriptions-item__content {
     max-width: 150px;
     min-width: 100px;
-}
+  }
 </style>
 <style scoped>
-.order-content{
-  margin: 10px;
+  .order-content{
+    margin: 10px;
 
-}
+  }
 
-.operate-container {
-  background: #F2F6FC;
-  height: 60px;
-  margin: -20px -20px 0;
-  line-height: 60px;
-}
+  .operate-container {
+    background: #F2F6FC;
+    height: 60px;
+    margin: -20px -20px 0;
+    line-height: 60px;
+  }
 
-.operate-button-container {
-  float: right;
-  margin-right: 20px
-}
+  .operate-button-container {
+    float: right;
+    margin-right: 20px
+  }
 </style>

+ 37 - 9
src/views/components/order/inquiryOrderDetails.vue

@@ -322,18 +322,46 @@ import way from '@/utils/way.js';
        });
 
       },
-      handleFinishOrder(){
-        var data={orderId:this.item.orderId}
-        this.$confirm('确认结束订单吗?', "提示", {
+      async handleFinishOrder() {
+        try {
+          // 1. 确认弹窗
+          await this.$confirm('确认结束订单吗?', "提示", {
             confirmButtonText: "确定",
             cancelButtonText: "取消",
             type: "warning"
-          }).then(() => {
-            return finishOrder(data);
-          }).then(() => {
-            this.getDetails(this.item.orderId);
-            this.msgSuccess("操作成功");
-          }).catch(() => {});
+          });
+
+          // 2. 调用结束订单接口
+          const data = { orderId: this.item.orderId };
+          await finishOrder(data);
+
+          // 3. 更新 OpenIM 会话的扩展字段
+          const exMassage = {
+            conversationID: `si_D${this.item.doctorId}_U${this.item.userId}`,
+            ex: JSON.stringify({
+              type: "finishInquiry",
+              orderId: this.item.orderId,
+              orderType: 2,
+              imType: 0
+            })
+          };
+
+          // 4. 调用 SDK 更新会话
+          //await this.OpenIM.setConversation(exMassage);
+          console.log("会话更新请求已发送");
+
+          // 5. 刷新详情并提示成功
+          await this.getDetails(this.item.orderId);
+          this.msgSuccess("操作成功");
+
+        } catch (error) {
+          console.error("结束订单失败:", error);
+
+          // 区分用户取消和真实错误
+          if (error !== "cancel") {
+            this.msgError(error.message || "结束订单失败");
+          }
+        }
       },
       handledetails(row){
         var id = this.report.orderId

+ 50 - 3
src/views/components/order/inquiryOrderList.vue

@@ -78,6 +78,13 @@
                 icon="el-icon-share"
             >详情
           </el-button>
+          <el-button
+            size="mini"
+            type="text"
+            @click="handleWenZhendetails(scope.row)"
+            icon="el-icon-share"
+          >问诊报告
+          </el-button>
         </template>
       </el-table-column>
     </el-table>
@@ -93,21 +100,32 @@
     <el-drawer :with-header="false" size="75%" :title="show.title" :visible.sync="show.open" append-to-body >
      <inquiryOrderDetails  ref="Details" />
    </el-drawer>
+    <el-drawer
+      :with-header="false"
+      :append-to-body="true"
+      size="75%"
+      :title="show.wenZhenTitle" :visible.sync="show.wenZhenOpen">
+      <inquiryOrderReportDetails  ref="Details" />
+    </el-drawer>
   </div>
 </template>
 
 <script>
 import { getOrderUserPhone,getCompanyList,getInquiryOrderList,receiveOrder,refuseOrder } from "@/api/inquiryOrder";
 import inquiryOrderDetails from '@/views/components/order/inquiryOrderDetails.vue';
+import inquiryOrderReportDetails from '../../components/order/inquiryOrderReportDetails.vue';
+import {mapGetters, mapState} from "vuex";
 export default {
   name: "inquiryOrder",
-  components: { inquiryOrderDetails },
+  components: { inquiryOrderDetails,inquiryOrderReportDetails },
   data() {
     return {
 
       show:{
         title:"问诊详情",
+        wenZhenTitle:'问诊报告',
         open:false,
+        wenZhenOpen:false,
           },
       companyList:[],
       startTime:null,
@@ -182,7 +200,19 @@ export default {
       orOptions:[],
     };
   },
-
+  computed: {
+    ...mapGetters(['toAccount', 'currentConversationType']),
+    ...mapState({
+      orderId:state => state.conversation.orderId,
+      followId:state => state.conversation.followId,
+      orderType:state => state.conversation.orderType,
+      imType: state => state.conversation.imType,
+      memberList: state => state.group.currentMemberList,
+      userID: state => state.imuser.userID,
+      currentConversation :state=>state.conversation.currentConversation,
+      groupProfile: state => state.conversation.currentConversation.groupProfile
+    })
+  },
   created() {
       this.getDicts("sys_inquiry_type").then(response => {
           this.inquiryTypeOptions = response.data;
@@ -252,7 +282,18 @@ export default {
           this.msgSuccess("拒单成功");
         }).catch(() => {});
     },
-
+    handleWenZhendetails(row){
+      console.log(row)
+      var id = row.orderId
+      if(id!=null){
+        this.show.wenZhenOpen=true;
+        setTimeout(() => {
+          this.$refs.Details.getDetails(id);
+        }, 1);
+      }else{
+        this.$message('问诊订单没有报告');
+      }
+    },
     handledetails(row){
 
         this.show.open=true;
@@ -264,6 +305,12 @@ export default {
     getList() {
       this.loading = true;
       this.queryParams.isReceive = 1;
+      //this.queryParams.userId = this.$store.state.conversation.currentConversation.conversationID.split("-")[1];
+      this.queryParams.userId = this.$store.state.conversation.currentConversation.conversationID
+        .split("_")
+        .filter(id => id.includes("U"))
+        .map(id => id.replace("U", "")).toString();
+      console.log("用户id",this.queryParams.userId )
       getInquiryOrderList(this.queryParams).then(response => {
         this.inquiryOrderList = response.data.list;
         this.total = response.data.total;

+ 3 - 0
src/views/components/order/inquiryOrderReportDetails.vue

@@ -106,6 +106,9 @@ export default {
       this.conditioningPlanJson=null;
       this.item = null;
       getInquiryOrderReport(orderId).then(response => {
+        if (!response.data){
+          this.$message('问诊订单没有报告');
+        }
           this.item = response.data;
           this.patientJson=JSON.parse(this.item.patientJson);
           this.formJson=JSON.parse(this.item.formJson);

+ 230 - 65
src/views/im/index.vue

@@ -20,7 +20,7 @@
               <current-conversation />
             </el-col>
           </el-row>
-          
+
         </div>
         <calling  ref="callLayer" class="chat-wrapper"/>
         <image-previewer />
@@ -29,7 +29,7 @@
       <div class="bg"></div>
     </div>
   </div>
-  
+
 </template>
 
 <script>
@@ -46,12 +46,15 @@ import { translateGroupSystemNotice } from '@/utils/common'
 import GroupLive from '@/components/group-live/index'
 import Calling from '@/components/message/trtc-calling/calling-index'
 import { ACTION } from '@/utils/trtcCustomMessageMap'
-
+import { getOpenIM,getCbEvents } from '@/utils/openIM';
+import { accountCheck } from '@/api/doctor';
 export default {
   title: 'TIMSDK DEMO',
   data () {
     return {
-      loginType: 2 // github 登录只使用默认账号登录
+      loginType: 2, // github 登录只使用默认账号登录
+      OpenIM: null,
+      userToken:""
     }
   },
   components: {
@@ -74,6 +77,7 @@ export default {
       isSDKReady: state => state.imuser.isSDKReady,
       isBusy: state => state.video.isBusy,
       userID: state => state.imuser.userID,
+      token: state => state.imuser.token,
       userSig: state => state.imuser.userSig,
       sdkAppID: state => state.imuser.sdkAppID
     }),
@@ -83,70 +87,221 @@ export default {
     }
   },
   created() {
+    this.OpenIM = getOpenIM();
+    this.initListener()
     this.getTlsSig();
   },
   mounted() {
-    // 初始化监听器
-    this.getTlsSig()
-    this.initListener()
-
+    //this.getTlsSig()
   },
 
   watch: {
   },
 
   methods: {
+    // 修改 getTlsSig 方法
     getTlsSig() {
-      console.log(this.$store.getters.userID);
-      var data={userId:this.$store.getters.userID}
-      getTlsSig(data).then(res => {
-        var sign = res.data;
-        this.$store.commit('setUserSig', sign)
-        this.tim
-        .login({
+      accountCheck(this.$store.getters.userID).then(response => {
+        this.userToken = response.token
+        const config = {
           userID: this.$store.getters.userID,
-          userSig: sign
+          token: this.userToken,
+          logLevel:6,
+          platformID: 5, // 使用配置的平台ID
+          apiAddr: 'https://web.im.cdwjyyh.com/api', // API地址
+          wsAddr: 'wss://web.im.cdwjyyh.com/msg_gateway', // WebSocket地址
+          dataDir: '/imdata' // 添加数据存储目录
+        }
+
+        this.OpenIM.login(config).then(() => {
+          this.$nextTick(() => {
+            this.checkSDKReadyState();
+          });
+          this.$store.commit('toggleIsLogin', true);
+          this.$store.commit('startComputeCurrent');
+          this.$store.commit('showMessage', {
+            type: 'success',
+            message: 'IM 登录成功'
+          });
+        })
+          .catch((error) => {
+            this.loading = false;
+            console.error('登录失败:', error);
+            this.$store.commit('showMessage', {
+              message: `IM 登录失败:${error.message || error.errMsg || '未知错误'}`,
+              type: 'error',
+            });
+          });
+
+      });
+    },
+    // 添加SDK就绪状态检查
+    checkSDKReadyState() {
+      if (this.hasBindReadyEvent) return;
+      this.hasBindReadyEvent = true;
+
+      let isReady = false;
+
+      const timeout = setTimeout(() => {
+        if (!isReady) {
+          this.$store.commit('toggleIsSDKReady', false);
+          this.$store.commit('showMessage', {
+            message: 'SDK初始化超时',
+            type: 'error'
+          });
+        }
+      }, 10000);
+
+      this.OpenIM.on(getCbEvents().OnConnectSuccess, () => {
+        clearTimeout(timeout);
+        isReady = true;
+        console.log("this.OpenIM",this.OpenIM)
+        this.OpenIM.getSelfUserInfo().then(({ data }) => {
+          this.$store.commit('updateCurrentUserProfile', data)
+        })
+        this.$store.commit('toggleIsSDKReady', true);
+        this.$store.commit('showMessage', {
+          type: 'success',
+          message: 'SDK 初始化成功'
+        });
+        this.loadUserData();
+      });
+
+      this.OpenIM.on(getCbEvents().OnConnectFailed, (error) => {
+        clearTimeout(timeout);
+        this.$store.commit('toggleIsSDKReady', false);
+        this.$store.commit('showMessage', {
+          message: `SDK 连接失败: ${error.message}`,
+          type: 'error'
+        });
+      });
+    },
+    // 添加加载用户数据方法
+    loadUserData() {
+      //查询会话列表
+      this.OpenIM.getAllConversationList()
+        .then(({ data }) => {
+          // 调用成功
+          console.log("获取到会话列表",data)
+          this.conversationList= data
+          this.$store.commit('updateConversationList', data)
+        })
+        .catch(({ errCode, errMsg }) => {
+          // 调用失败
         })
-        .then(() => {
-          this.$store.commit('toggleIsLogin', true)
-          this.$store.commit('startComputeCurrent')
-          this.$store.commit('setSdkAppId', imConfig.SDKAPPID)
-          this.$store.commit('showMessage', { type: 'success', message: 'IM登录成功' })
+      //查询好友列表
+      this.OpenIM.getFriendListPage({ offset:0, count:100 })
+        .then(({ data }) => {
+          // 调用成功
+          console.log("获取到好友列表",data)
+          //this.conversationList= data
+          this.$store.commit('updateFriendList', data)
         })
-        .catch(error => {
-          this.loading = false
-          // this.$store.commit('showMessage', {
-          //   message: '登录失败:' + error.message,
-          //   type: 'error'
-          // })
+        .catch(({ errCode, errMsg }) => {
+          // 调用失败
         })
+    },
+
+    selfUpdateHandler({ data }) {
+      this.updateMessageNicknameAndFaceUrl({
+        sendID: data.userID,
+        senderNickname: data.nickname,
+        senderFaceUrl: data.faceURL,
       });
-    },  
+      this.updateSelfInfo(data);
+    },
+    // 更新昵称和头像
+    updateMessageNicknameAndFaceUrl({ sendID, senderNickname, senderFaceUrl }) {
+      // 更新消息昵称和头像的逻辑
+      console.log(sendID, senderNickname, senderFaceUrl);
+    },
+
+    // 更新个人信息
+    updateSelfInfo(data) {
+      // 更新个人信息的逻辑
+      console.log(data);
+    },
     initListener() {
       // 登录成功后会触发 SDK_READY 事件,该事件触发后,可正常使用 SDK 接口
-      this.tim.on(this.TIM.EVENT.SDK_READY, this.onReadyStateUpdate, this)
+      this.OpenIM.on(getCbEvents().OnConnectSuccess, () => {
+        console.log("OnConnectSuccess 事件触发!"); // 调试日志
+        this.$store.commit('toggleIsSDKReady', true);
+      });
+      this.OpenIM.on(getCbEvents().OnConnectFailed, this.onError);
+      this.OpenIM.on(getCbEvents().OnKickedOffline, this.onKickOut);
+      this.OpenIM.on(getCbEvents().OnSelfInfoUpdated, this.onSelfInfoUpdated);
+      this.OpenIM.on(getCbEvents().OnFriendAdded,(data)=>{
+        console.log("新增好友事件触发",data)
+        this.onFriendListUpdated(data);
+      });
+      /*this.OpenIM.on(getCbEvents().OnRecvNewMessage, (message) => {
+        console.log("收到单条消息", message);
+        this.onReceiveMessage({data: [message]}); // 包装成数组形式
+      });*/
+
+      this.OpenIM.on(getCbEvents().OnRecvNewMessages, (data) => {
+        console.log("收到多条消息", data);
+        const msgList = []
+        data.data.forEach(msg =>{
+          if (msg.contentType!==113){
+            msgList.push(msg)
+          }
+        })
+        if (msgList.length>0){
+          this.onReceiveMessage({data: msgList});
+
+        }
+      });
+      /*this.OpenIM.on(getCbEvents().OnConversationChanged, (eventData) => {
+        console.log("触发OnConversationChanged事件", eventData);
+
+        try {
+          // 1. 确保数据结构正确
+          if (!eventData || !eventData.data) {
+            console.warn("无效的会话更新数据", eventData);
+            return;
+          }
+
+          // 2. 提取更新后的会话列表
+          const updatedConversations = eventData.data;
+
+          // 3. 打印调试信息
+          console.log("更新的会话列表:", updatedConversations);
+
+          // 4. 更新到Vuex store
+          this.$store.commit('updateConversationList', updatedConversations);
+
+          // 5. 可选:检查特定会话的更新
+          updatedConversations.forEach(conv => {
+            console.log(`会话ID: ${conv.conversationID} 已更新`, conv);
+          });
+
+        } catch (error) {
+          console.error("处理会话更新时出错:", error);
+        }
+      });*/
       // SDK NOT READT
-      this.tim.on(this.TIM.EVENT.SDK_NOT_READY, this.onReadyStateUpdate, this)
+      /*this.OpenIM.on(this.OpenIM.EVENT.SDK_NOT_READY, this.onReadyStateUpdate, this)
       // 被踢出
-      this.tim.on(this.TIM.EVENT.KICKED_OUT, this.onKickOut)
+      this.OpenIM.on(this.OpenIM.EVENT.KICKED_OUT, this.onKickOut)
       // SDK内部出错
-      this.tim.on(this.TIM.EVENT.ERROR, this.onError)
+      this.OpenIM.on(this.OpenIM.EVENT.ERROR, this.onError)
       // 收到新消息
-      this.tim.on(this.TIM.EVENT.MESSAGE_RECEIVED, this.onReceiveMessage)
+      this.OpenIM.on(this.OpenIM.EVENT.MESSAGE_RECEIVED, this.onReceiveMessage)
       // 会话列表更新
-      this.tim.on(this.TIM.EVENT.CONVERSATION_LIST_UPDATED, this.onUpdateConversationList)
+      this.OpenIM.on(this.OpenIM.EVENT.CONVERSATION_LIST_UPDATED, this.onUpdateConversationList)
       // 群组列表更新
-      this.tim.on(this.TIM.EVENT.GROUP_LIST_UPDATED, this.onUpdateGroupList)
+      this.OpenIM.on(this.OpenIM.EVENT.GROUP_LIST_UPDATED, this.onUpdateGroupList)
       // 网络监测
-      this.tim.on(this.TIM.EVENT.NET_STATE_CHANGE, this.onNetStateChange)
+      this.OpenIM.on(this.OpenIM.EVENT.NET_STATE_CHANGE, this.onNetStateChange)
       // 已读回执
-      this.tim.on(this.TIM.EVENT.MESSAGE_READ_BY_PEER, this.onMessageReadByPeer)
+      this.OpenIM.on(this.OpenIM.EVENT.MESSAGE_READ_BY_PEER, this.onMessageReadByPeer)
       // 黑名单更新
-      this.tim.on(this.TIM.EVENT.FRIEND_LIST_UPDATED, this.onFriendListUpdated)
+      this.OpenIM.on(this.OpenIM.EVENT.FRIEND_LIST_UPDATED, this.onFriendListUpdated)
 
-      this.tim.on(this.TIM.EVENT.FRIEND_APPLICATION_LIST_UPDATED, this.onFriendApplicationListUpdated)
+      this.OpenIM.on(this.OpenIM.EVENT.FRIEND_APPLICATION_LIST_UPDATED, this.onFriendApplicationListUpdated)
 
-      this.tim.on(this.TIM.EVENT.FRIEND_GROUP_LIST_UPDATED, this.onFriendGroupListUpdated)
+      this.OpenIM.on(this.OpenIM.EVENT.FRIEND_GROUP_LIST_UPDATED, this.onFriendGroupListUpdated)*/
 
     },
     onFriendApplicationListUpdated(data) {
@@ -162,18 +317,28 @@ export default {
 
     onReceiveMessage({ data: messageList }) {
       // let totalUnreadCount = this.tim.getTotalUnreadMessageCount();
-      console.log("收到消息数")
+
       messageList.forEach(element => {
-        if(element.from!=this.$store.getters.userID){
+        //过滤掉正在输入状态
+        if(element.sendID!=this.$store.getters.userID&&element.contentType!==113){
           this.$notify({
             title: '消息提示',
             message: '您有一条新的消息',
             type: 'success'
           });
         }
+
       });
+      this.OpenIM.getAllConversationList()
+        .then(({ data }) => {
+          // 调用成功
+          this.$store.commit('updateConversationList', data)
+        })
+        .catch(({ errCode, errMsg }) => {
+          // 调用失败
+        })
       console.log(messageList)
-      this.handleVideoMessage(messageList)
+      //this.handleVideoMessage(messageList)
       this.handleQuitGroupTip(messageList)
       this.handleCloseGroupLive(messageList)
       this.$store.commit('pushCurrentMessageList', messageList)
@@ -192,7 +357,8 @@ export default {
 
     },
     onReadyStateUpdate({ name }) {
-      const isSDKReady = name === this.TIM.EVENT.SDK_READY ? true : false
+      console.log("当前登录用户基本信息")
+      const isSDKReady = name === getCbEvents().OnConnectSuccess ? true : false
       this.$store.commit('toggleIsSDKReady', isSDKReady)
 
 
@@ -200,9 +366,8 @@ export default {
       // console.log("收到消息数"+totalUnreadCount)
 
       if (isSDKReady) {
-        this.tim
-          .getMyProfile()
-          .then(({ data }) => {
+        this.OpenIM.getSelfUserInfo().then(({ data }) => {
+            console.log("当前登录用户基本信息",data)
             this.$store.commit('updateCurrentUserProfile', data)
           })
           .catch(error => {
@@ -211,39 +376,39 @@ export default {
               message: error.message
             })
           })
-        this.$store.dispatch('getBlacklist')
+        /*this.$store.dispatch('getBlacklist')
         // 登录trtc calling
         console.log(this.sdkAppID)
         this.trtcCalling.login({
           sdkAppID: this.sdkAppID,
           userID: this.userID,
           userSig:this.userSig
-        })
+        })*/
       }
     },
     kickedOutReason(type) {
-      switch (type) {
-        case this.TIM.TYPES.KICKED_OUT_MULT_ACCOUNT:
+      /*switch (type) {
+        case this.OpenIM.TYPES.KICKED_OUT_MULT_ACCOUNT:
           return '由于多实例登录'
-        case this.TIM.TYPES.KICKED_OUT_MULT_DEVICE:
+        case this.OpenIM.TYPES.KICKED_OUT_MULT_DEVICE:
           return '由于多设备登录'
-        case this.TIM.TYPES.KICKED_OUT_USERSIG_EXPIRED:
+        case this.OpenIM.TYPES.KICKED_OUT_USERSIG_EXPIRED:
           return '由于 userSig 过期'
         default:
           return ''
-      }
+      }*/
     },
     checkoutNetState(state) {
-      switch (state) {
-        case this.TIM.TYPES.NET_STATE_CONNECTED:
+      /*switch (state) {
+        case this.OpenIM.TYPES.NET_STATE_CONNECTED:
           return { message: '已接入网络', type: 'success' }
-        case this.TIM.TYPES.NET_STATE_CONNECTING:
+        case this.OpenIM.TYPES.NET_STATE_CONNECTING:
           return { message: '当前网络不稳定', type: 'warning' }
-        case this.TIM.TYPES.NET_STATE_DISCONNECTED:
+        case this.OpenIM.TYPES.NET_STATE_DISCONNECTED:
           return { message: '当前网络不可用', type: 'error' }
         default:
           return ''
-      }
+      }*/
     },
     onNetStateChange(event) {
       this.$store.commit('showMessage', this.checkoutNetState(event.data.state))
@@ -300,7 +465,7 @@ export default {
     },
     handleVideoMessage(messageList) {
       const videoMessageList = messageList.filter(
-        message => message.type === this.TIM.TYPES.MSG_CUSTOM && this.isJsonStr(message.payload.data)
+        message => message.contentType === 110 && this.isJsonStr(message.payload.data)
       )
       if (videoMessageList.length === 0) return
       const videoPayload = JSON.parse(videoMessageList[0].payload.data)
@@ -375,9 +540,9 @@ export default {
       // 筛选出当前会话的退群/被踢群的 groupTip
       const groupTips = messageList.filter(message => {
         return this.currentConversation.conversationID === message.conversationID &&
-          message.type === this.TIM.TYPES.MSG_GRP_TIP &&
-          (message.payload.operationType === this.TIM.TYPES.GRP_TIP_MBR_QUIT ||
-          message.payload.operationType === this.TIM.TYPES.GRP_TIP_MBR_KICKED_OUT)
+          message.contentType === 1501 &&
+          (message.payload.operationType === 1504 ||
+          message.payload.operationType === 1508)
       })
       // 清理当前会话的群成员列表
       if (groupTips.length > 0) {
@@ -394,7 +559,7 @@ export default {
      */
     handleCloseGroupLive(messageList) {
       messageList.forEach(message => {
-        if (this.currentConversation.conversationID === message.conversationID && message.type === this.TIM.TYPES.MSG_CUSTOM) {
+        if (this.currentConversation.conversationID === message.conversationID && message.contentType === 110) {
           let data = {}
           try {
             data = JSON.parse(message.payload.data)
@@ -447,7 +612,7 @@ body {
   margin-top: 100px;
 }
 
- 
+
 .container
   position relative
   // height 100vh

+ 38 - 30
vue.config.js

@@ -1,13 +1,13 @@
 'use strict'
 const path = require('path')
-
+const WorkerPlugin = require('worker-plugin')
 function resolve(dir) {
   return path.join(__dirname, dir)
 }
 
 const name = process.env.VUE_APP_TITLE || '互联网医院医生端' // 网页标题
 
-const port = process.env.port || process.env.npm_config_port || 80 // 端口
+const port = process.env.port || process.env.npm_config_port || 86 // 端口
 
 // vue.config.js 配置说明
 //官方vue.config.js 参考文档 https://cli.vuejs.org/zh/config/#css-loaderoptions
@@ -42,7 +42,7 @@ module.exports = {
 
       // detail: https://cli.vuejs.org/config/#devserver-proxy
       [process.env.VUE_APP_BASE_API]: {
-        target: `http://localhost:8088`,
+        target: `http://localhost:8088 `,
         changeOrigin: true,
         pathRewrite: {
           ['^' + process.env.VUE_APP_BASE_API]: ''
@@ -60,10 +60,18 @@ module.exports = {
     }
   },
   chainWebpack(config) {
+    // 1. 删除预加载插件
     config.plugins.delete('preload') // TODO: need test
     config.plugins.delete('prefetch') // TODO: need test
 
-    // set svg-sprite-loader
+    // 2. 添加WorkerPlugin
+    config.plugin('worker-plugin')
+      .use(WorkerPlugin, [{
+        globalObject: 'self', // 解决webpack5兼容性问题
+        plugins: ['VueLoaderPlugin'] // 确保Vue loader正常工作
+      }])
+
+    // 3. SVG图标处理配置
     config.module
       .rule('svg')
       .exclude.add(resolve('src/assets/icons'))
@@ -80,6 +88,7 @@ module.exports = {
       })
       .end()
 
+    // 4. 生产环境优化配置
     config
       .when(process.env.NODE_ENV !== 'development',
         config => {
@@ -87,39 +96,38 @@ module.exports = {
             .plugin('ScriptExtHtmlWebpackPlugin')
             .after('html')
             .use('script-ext-html-webpack-plugin', [{
-            // `runtime` must same as runtimeChunk name. default is `runtime`
               inline: /runtime\..*\.js$/
             }])
             .end()
           config
             .optimization.splitChunks({
-              chunks: 'all',
-              cacheGroups: {
-                libs: {
-                  name: 'chunk-libs',
-                  test: /[\\/]node_modules[\\/]/,
-                  priority: 10,
-                  chunks: 'initial' // only package third parties that are initially dependent
-                },
-                elementUI: {
-                  name: 'chunk-elementUI', // split elementUI into a single package
-                  priority: 20, // the weight needs to be larger than libs and app or it will be packaged into libs or app
-                  test: /[\\/]node_modules[\\/]_?element-ui(.*)/ // in order to adapt to cnpm
-                },
-                commons: {
-                  name: 'chunk-commons',
-                  test: resolve('src/components'), // can customize your rules
-                  minChunks: 3, //  minimum common number
-                  priority: 5,
-                  reuseExistingChunk: true
-                }
+            chunks: 'all',
+            cacheGroups: {
+              libs: {
+                name: 'chunk-libs',
+                test: /[\\/]node_modules[\\/]/,
+                priority: 10,
+                chunks: 'initial'
+              },
+              elementUI: {
+                name: 'chunk-elementUI',
+                priority: 20,
+                test: /[\\/]node_modules[\\/]_?element-ui(.*)/
+              },
+              commons: {
+                name: 'chunk-commons',
+                test: resolve('src/components'),
+                minChunks: 3,
+                priority: 5,
+                reuseExistingChunk: true
               }
-            })
+            }
+          })
           config.optimization.runtimeChunk('single'),
-          {
-             from: path.resolve(__dirname, './public/robots.txt'), //防爬虫文件
-             to: './' //到根目录下
-          }
+            {
+              from: path.resolve(__dirname, './public/robots.txt'),
+              to: './'
+            }
         }
       )
   },

Some files were not shown because too many files changed in this diff