zj-plugin-intelligent 1.2.8-beta.10 → 1.2.8-beta.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -837,7 +837,7 @@ eval("\n\nObject.defineProperty(exports, \"__esModule\", {\n value: true\n});\n
837
837
  /***/ (function(module, exports, __webpack_require__) {
838
838
 
839
839
  "use strict";
840
- eval("\n\nvar _interopRequireDefault = __webpack_require__(/*! ./node_modules/@babel/runtime/helpers/interopRequireDefault */ \"./node_modules/@babel/runtime/helpers/interopRequireDefault.js\").default;\n\nObject.defineProperty(exports, \"__esModule\", {\n value: true\n});\nexports.default = void 0;\n\nvar _toConsumableArray2 = _interopRequireDefault(__webpack_require__(/*! ./node_modules/@babel/runtime/helpers/toConsumableArray */ \"./node_modules/@babel/runtime/helpers/toConsumableArray.js\"));\n\nvar _objectSpread2 = _interopRequireDefault(__webpack_require__(/*! ./node_modules/@babel/runtime/helpers/objectSpread2 */ \"./node_modules/@babel/runtime/helpers/objectSpread2.js\"));\n\nvar _createForOfIteratorHelper2 = _interopRequireDefault(__webpack_require__(/*! ./node_modules/@babel/runtime/helpers/createForOfIteratorHelper */ \"./node_modules/@babel/runtime/helpers/createForOfIteratorHelper.js\"));\n\nvar _asyncToGenerator2 = _interopRequireDefault(__webpack_require__(/*! ./node_modules/@babel/runtime/helpers/asyncToGenerator */ \"./node_modules/@babel/runtime/helpers/asyncToGenerator.js\"));\n\nvar _markdownIt = _interopRequireDefault(__webpack_require__(/*! markdown-it */ \"./node_modules/markdown-it/index.mjs\"));\n\n__webpack_require__(/*! @jboltai/tokui/dist/tokui.css */ \"./node_modules/@jboltai/tokui/dist/tokui.css\");\n\nvar _apichat = __webpack_require__(/*! @lib/api/apichat */ \"./src/lib/api/apichat.js\");\n\nvar _index = __webpack_require__(/*! @lib/socket/fileManager/obs/index */ \"./src/lib/socket/fileManager/obs/index.js\");\n\nvar _index2 = _interopRequireDefault(__webpack_require__(/*! @lib/socket/utils/index */ \"./src/lib/socket/utils/index.js\"));\n\nvar _cookie = __webpack_require__(/*! @lib/utils/cookie.js */ \"./src/lib/utils/cookie.js\");\n\nvar _apiObs = _interopRequireDefault(__webpack_require__(/*! @lib/api/apiObs */ \"./src/lib/api/apiObs.js\"));\n\nvar _html2canvas = _interopRequireDefault(__webpack_require__(/*! html2canvas */ \"./node_modules/html2canvas/dist/html2canvas.esm.js\"));\n\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\nvar resolveTokUIConstructor = function resolveTokUIConstructor() {\n if (typeof window !== 'undefined') {\n var _window$globalThis;\n\n var runtime = window.TokUI || ((_window$globalThis = window.globalThis) === null || _window$globalThis === void 0 ? void 0 : _window$globalThis.TokUI);\n\n if (runtime) {\n var _runtime$default;\n\n return runtime.TokUI || ((_runtime$default = runtime.default) === null || _runtime$default === void 0 ? void 0 : _runtime$default.TokUI) || runtime.default || runtime;\n }\n }\n\n try {\n if (true) {\n var _runtime = __webpack_require__(/*! @jboltai/tokui/dist/tokui.umd.js */ \"./node_modules/@jboltai/tokui/dist/tokui.umd.js\");\n\n if (_runtime) {\n var _runtime$default2;\n\n return _runtime.TokUI || ((_runtime$default2 = _runtime.default) === null || _runtime$default2 === void 0 ? void 0 : _runtime$default2.TokUI) || _runtime.default || _runtime;\n }\n }\n } catch (e) {// ignore and continue to package entry fallback\n }\n\n try {\n if (true) {\n var _runtime2 = __webpack_require__(/*! @jboltai/tokui */ \"./node_modules/@jboltai/tokui/dist/tokui.mjs\");\n\n if (_runtime2) {\n var _runtime2$default;\n\n return _runtime2.TokUI || ((_runtime2$default = _runtime2.default) === null || _runtime2$default === void 0 ? void 0 : _runtime2$default.TokUI) || _runtime2.default || _runtime2;\n }\n }\n } catch (e) {// ignore and leave unresolved\n }\n\n return null;\n};\n\nvar md = new _markdownIt.default({\n breaks: true,\n html: false,\n linkify: true,\n typographer: true\n});\nmd.enable('table');\nvar _default2 = {\n name: 'ChatDetail',\n props: {\n isMobile: {\n type: Boolean,\n default: false\n },\n activeSessionId: {\n type: String,\n default: ''\n },\n currentAgent: {\n type: String,\n default: ''\n },\n agentInfo: {\n type: Object,\n default: function _default() {\n return {};\n }\n },\n currentAgentDesc: {\n type: String,\n default: ''\n },\n showSidebar: {\n type: Boolean,\n default: false\n },\n showH5List: {\n type: Boolean,\n default: false\n },\n showAgentSelect: {\n type: Boolean,\n default: false\n },\n agentList: {\n type: Array,\n default: function _default() {\n return [];\n }\n }\n },\n data: function data() {\n return {\n messages: [],\n inputText: '',\n sending: false,\n waitTimer: null,\n waitSeconds: 0,\n canceling: false,\n msgPage: 1,\n msgMaxPage: 1,\n msgTotal: 0,\n eventSource: null,\n showToolInfo: false,\n showDownBtn: false,\n lastScrollTop: 0,\n scrollTimer: null,\n contentCache: {},\n loadingSessionMsg: false,\n greeting: '',\n _scrollTimer: null,\n _userScrolledUp: false,\n voiceMode: false,\n isRecording: false,\n recordDuration: 0,\n recordingTimer: null,\n audioContext: null,\n audioStream: null,\n audioProcessor: null,\n audioChunks: [],\n audioSampleRate: 16000,\n isCancelSwipe: false,\n recordStartY: 0,\n _pendingSendText: null\n };\n },\n computed: {\n waitClass: function waitClass() {\n if (this.waitSeconds > 15) return 'wait-15';\n if (this.waitSeconds > 10) return 'wait-10';\n if (this.waitSeconds > 5) return 'wait-5';\n return '';\n },\n currentAgentName: function currentAgentName() {\n var _this = this;\n\n if (!this.currentAgent) return '';\n var a = this.agentList.find(function (x) {\n return x.agentCode === _this.currentAgent;\n });\n return a ? a.agentName || a.agentCode : this.currentAgent;\n }\n },\n watch: {\n contentCache: {\n handler: function handler(val) {// 保持响应性\n },\n immediate: true\n },\n activeSessionId: function activeSessionId(val) {\n var _this2 = this;\n\n if (val && this._pendingSendText) {\n var text = this._pendingSendText;\n this._pendingSendText = null;\n this.$nextTick(function () {\n return _this2._sendMessage(text);\n });\n }\n },\n messages: {\n handler: function handler() {\n var _this3 = this;\n\n this.$nextTick(function () {\n return _this3._renderTokuiMessages();\n });\n },\n deep: true\n }\n },\n mounted: function mounted() {\n var _this4 = this;\n\n if (window.visualViewport) {\n window.visualViewport.addEventListener('resize', this.onViewportResize, {\n passive: true\n });\n }\n\n this.$nextTick(function () {\n _this4._renderTokuiMessages();\n });\n },\n beforeDestroy: function beforeDestroy() {\n if (window.visualViewport) {\n window.visualViewport.removeEventListener('resize', this.onViewportResize);\n }\n\n this.releaseAudio();\n this.contentCache = {};\n clearTimeout(this._scrollTimer);\n\n if (this.eventSource) {\n this.eventSource.onerror = null;\n this.eventSource.close();\n this.eventSource = null;\n }\n\n if (this.waitTimer) {\n clearInterval(this.waitTimer);\n this.waitTimer = null;\n }\n\n if (this._typeTimer) {\n clearInterval(this._typeTimer);\n this._typeTimer = null;\n }\n },\n methods: {\n getInitial: function getInitial(name) {\n if (!name) return '?';\n return name.charAt(0);\n },\n formatTime: function formatTime(t) {\n if (!t) return '';\n var d = new Date(t.replace(' ', 'T'));\n var now = new Date();\n var diff = (now - d) / 1000;\n if (diff < 60) return '刚刚';\n if (diff < 3600) return Math.floor(diff / 60) + '分钟前';\n if (diff < 86400) return Math.floor(diff / 3600) + '小时前';\n return d.getMonth() + 1 + '/' + d.getDate();\n },\n escapeHtml: function escapeHtml(text) {\n if (!text) return '';\n return text.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;');\n },\n renderMarkdown: function renderMarkdown(text) {\n if (!text) return '';\n\n try {\n return md.render(text);\n } catch (err) {\n return this.escapeHtml(text);\n }\n },\n renderStreaming: function renderStreaming(text, msgKey) {\n if (!text) return '';\n var cache = this.contentCache[msgKey];\n var lines = text.split('\\n');\n var lastLineIdx = lines.length - 1;\n\n if (!cache) {\n try {\n var html = md.render(text);\n this.$set(this.contentCache, msgKey, {\n renderedLines: lastLineIdx,\n html: html,\n fullText: text\n });\n return html;\n } catch (_unused) {\n return this.escapeHtml(text);\n }\n }\n\n if (text === cache.fullText) return cache.html;\n cache.fullText = text; // 行数没变,仅末尾追加字符,直接拼接尾行\n\n if (lastLineIdx === cache.renderedLines) {\n return cache.html + this.escapeHtml(lines[lastLineIdx]);\n } // 场景1:行数变少/文本回退截断,全量重渲染\n\n\n if (lastLineIdx < cache.renderedLines) {\n try {\n var fullLines = lines.slice(0, lastLineIdx);\n var newBaseHtml = '';\n\n if (fullLines.length > 0) {\n newBaseHtml = md.render(fullLines.join('\\n'));\n }\n\n cache.html = newBaseHtml;\n cache.renderedLines = lastLineIdx;\n\n var _lastLine = this.escapeHtml(lines[lastLineIdx]);\n\n return cache.html + (_lastLine || '');\n } catch (_unused2) {\n return this.escapeHtml(text);\n }\n } // 场景2:新增完整行\n\n\n if (cache.renderedLines < lastLineIdx) {\n var allFullLines = lines.slice(0, lastLineIdx);\n var _newBaseHtml = '';\n\n if (allFullLines.length > 0) {\n _newBaseHtml = md.render(allFullLines.join('\\n'));\n }\n\n cache.html = _newBaseHtml;\n cache.renderedLines = lastLineIdx;\n }\n\n var lastLine = this.escapeHtml(lines[lastLineIdx]);\n cache.renderedLines = lastLineIdx;\n return cache.html + (lastLine || '');\n },\n getChatAvatarStyle: function getChatAvatarStyle(agent, avatar) {\n if (avatar) {\n return {\n backgroundImage: \"url(\".concat(avatar, \")\"),\n backgroundSize: 'cover',\n backgroundPosition: 'center',\n backgroundRepeat: 'no-repeat'\n };\n }\n\n var _agent = this.agentList.find(function (x) {\n return x.agentCode === agent;\n });\n\n if (_agent && _agent.avatar) {\n return {\n backgroundImage: \"url(\".concat(_agent.avatar, \")\"),\n backgroundSize: 'cover',\n backgroundPosition: 'center',\n backgroundRepeat: 'no-repeat'\n };\n } // 没有网络图片时,根据智能体在 agentList 中的索引位置决定颜色\n\n\n var index = this.agentList.findIndex(function (item) {\n return item.agentCode === agent;\n });\n\n if (index !== -1) {\n var colorIndex = index % 4 + 1;\n return {\n background: this.getGradientByColorIndex(colorIndex)\n };\n }\n\n return {\n background: 'linear-gradient(135deg, #1677ff, #4096ff)'\n };\n },\n getGradientByColorIndex: function getGradientByColorIndex(index) {\n var gradients = {\n 1: 'linear-gradient(135deg, #1677ff, #4096ff)',\n 2: 'linear-gradient(135deg, #52c41a, #73d13d)',\n 3: 'linear-gradient(135deg, #fa8c16, #ffa940)',\n 4: 'linear-gradient(135deg, #722ed1, #b37feb)'\n };\n return gradients[index] || gradients[1];\n },\n sendQuickMsg: function sendQuickMsg(message) {\n if (message) {\n this.inputText = message;\n this.sendMessage();\n }\n },\n formatMixText: function formatMixText(str) {\n if (!str) return '';\n var res = str.replace(/([a-zA-Z0-9])([\\u4e00-\\u9fff])/g, '$1 $2').replace(/([\\u4e00-\\u9fff])([a-zA-Z0-9])/g, '$1 $2');\n res = res.replace(/([a-z])([A-Z])/g, '$1 $2');\n return res;\n },\n // 检测是否滚动到底部,控制向下箭头显示隐藏\n checkScrollBottom: function checkScrollBottom() {\n var forceShowWhenNotBottom = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false;\n var el = this.$refs.messagesRef;\n\n if (!el) {\n this.showDownBtn = false;\n return;\n }\n\n var scrollHeight = el.scrollHeight,\n scrollTop = el.scrollTop,\n clientHeight = el.clientHeight;\n var remain = scrollHeight - scrollTop - clientHeight;\n var atBottom = remain <= 80; // 检测用户是否主动向上滚动(远离底部)\n\n if (remain > 80 && scrollTop < this.lastScrollTop) {\n this._userScrolledUp = true;\n }\n\n if (atBottom) {\n this._userScrolledUp = false;\n this.showDownBtn = false;\n } else if (this._userScrolledUp) {\n // 用户已主动上滚,保持显示\"到底部\"按钮,不自动回滚\n this.showDownBtn = true;\n } else if (this.sending && scrollTop >= this.lastScrollTop && !forceShowWhenNotBottom) {\n this.showDownBtn = false;\n } else {\n this.showDownBtn = true;\n }\n\n this.lastScrollTop = scrollTop;\n this.$emit('scroll-bottom-check', {\n showDownBtn: this.showDownBtn,\n lastScrollTop: this.lastScrollTop\n });\n },\n // H5 输入框获取焦点 - 滚动到底部让键盘不遮挡\n onInputFocus: function onInputFocus() {\n if (!this.isMobile) return;\n setTimeout(function () {\n window.scrollTo(0, document.body.scrollHeight);\n }, 300);\n },\n // visualViewport 变化时(如键盘弹出)调整滚动位置\n onViewportResize: function onViewportResize() {\n if (!this.isMobile) return;\n var activeEl = document.activeElement;\n\n if (activeEl && (activeEl.tagName === 'TEXTAREA' || activeEl.tagName === 'INPUT')) {\n window.scrollTo(0, document.body.scrollHeight);\n }\n },\n autoResizeTextarea: function autoResizeTextarea() {\n var _this5 = this;\n\n var ta = this.$refs.taRef;\n if (!ta) return;\n var isMobile = this.isMobile;\n var baseH = isMobile ? 36 : 100;\n var maxH = isMobile ? 100 : 180;\n ta.style.height = \"\".concat(baseH, \"px\");\n var realH = ta.scrollHeight;\n\n if (realH > baseH) {\n ta.style.height = \"\".concat(Math.min(realH, maxH), \"px\");\n }\n\n this.$nextTick(function () {\n _this5.checkScrollBottom(true);\n });\n },\n // Ctrl+Enter换行\n newLine: function newLine(e) {\n var _this6 = this;\n\n e.preventDefault();\n var ta = this.$refs.taRef;\n var start = ta.selectionStart;\n var end = ta.selectionEnd;\n this.inputText = this.inputText.slice(0, start) + '\\n' + this.inputText.slice(end);\n this.$nextTick(function () {\n ta.selectionStart = ta.selectionEnd = start + 1;\n\n _this6.autoResizeTextarea();\n });\n },\n toggleVoiceMode: function toggleVoiceMode() {\n var _this7 = this;\n\n if (this.voiceMode) {\n this.voiceMode = false;\n this.releaseAudio();\n return;\n } // 进入语音模式前提前请求麦克风权限,避免触摸时异步弹窗导致 touchend 丢失\n\n\n this.ensureAudioReady().then(function (ready) {\n if (ready) {\n _this7.voiceMode = true;\n } else {\n _this7.voiceMode = false;\n }\n });\n },\n // 确保音频设备已就绪\n ensureAudioReady: function ensureAudioReady() {\n var _this8 = this;\n\n return (0, _asyncToGenerator2.default)( /*#__PURE__*/regeneratorRuntime.mark(function _callee() {\n var stream, audioContext, source, processor;\n return regeneratorRuntime.wrap(function _callee$(_context) {\n while (1) {\n switch (_context.prev = _context.next) {\n case 0:\n if (!(_this8.audioContext && _this8.audioStream)) {\n _context.next = 2;\n break;\n }\n\n return _context.abrupt(\"return\", true);\n\n case 2:\n if (!(!navigator.mediaDevices || !navigator.mediaDevices.getUserMedia)) {\n _context.next = 5;\n break;\n }\n\n alert('当前环境不支持麦克风访问');\n return _context.abrupt(\"return\", false);\n\n case 5:\n _context.prev = 5;\n _context.next = 8;\n return navigator.mediaDevices.getUserMedia({\n audio: true\n });\n\n case 8:\n stream = _context.sent;\n _this8.audioStream = stream;\n audioContext = new (window.AudioContext || window.webkitAudioContext)(); // iOS 上 AudioContext 默认 suspended,需要手动 resume\n\n if (!(audioContext.state === 'suspended')) {\n _context.next = 14;\n break;\n }\n\n _context.next = 14;\n return audioContext.resume();\n\n case 14:\n _this8.audioContext = audioContext; // 采集实际采样率(iOS 会忽略 sampleRate 参数,使用硬件采样率)\n\n _this8.audioSampleRate = audioContext.sampleRate || 16000;\n source = audioContext.createMediaStreamSource(stream); // 保存 source 引用到实例,防止 iOS Safari 垃圾回收导致音频处理中断\n\n _this8.audioSource = source;\n processor = audioContext.createScriptProcessor(4096, 1, 1);\n _this8.audioProcessor = processor; // iOS 上 onaudioprocess 可能先于 isRecording=true 触发\n // 因此不依赖 isRecording 过滤,由外部控制 audioChunks 的清零时机\n\n processor.onaudioprocess = function (e) {\n var inputData = e.inputBuffer.getChannelData(0);\n\n _this8.audioChunks.push(new Float32Array(inputData));\n };\n\n source.connect(processor);\n processor.connect(audioContext.destination);\n return _context.abrupt(\"return\", true);\n\n case 26:\n _context.prev = 26;\n _context.t0 = _context[\"catch\"](5);\n console.error('麦克风访问失败:', _context.t0);\n alert('麦克风权限被拒绝');\n return _context.abrupt(\"return\", false);\n\n case 31:\n case \"end\":\n return _context.stop();\n }\n }\n }, _callee, null, [[5, 26]]);\n }))();\n },\n // H5语音录制 - 触摸开始\n onRecordTouchStart: function onRecordTouchStart(e) {\n var _this9 = this;\n\n return (0, _asyncToGenerator2.default)( /*#__PURE__*/regeneratorRuntime.mark(function _callee2() {\n var ready;\n return regeneratorRuntime.wrap(function _callee2$(_context2) {\n while (1) {\n switch (_context2.prev = _context2.next) {\n case 0:\n if (!_this9.sending) {\n _context2.next = 2;\n break;\n }\n\n return _context2.abrupt(\"return\");\n\n case 2:\n _context2.next = 4;\n return _this9.ensureAudioReady();\n\n case 4:\n ready = _context2.sent;\n\n if (ready) {\n _context2.next = 7;\n break;\n }\n\n return _context2.abrupt(\"return\");\n\n case 7:\n _this9.isCancelSwipe = false;\n _this9.recordStartY = e.touches[0].clientY;\n _this9.recordDuration = 0;\n _this9.audioChunks = [];\n _this9.isRecording = true;\n _this9.recordingTimer = setInterval(function () {\n _this9.recordDuration++;\n\n if (_this9.recordDuration >= 60) {\n _this9.onRecordTouchEnd();\n }\n }, 1000);\n\n case 13:\n case \"end\":\n return _context2.stop();\n }\n }\n }, _callee2);\n }))();\n },\n // H5语音录制 - 触摸移动\n onRecordTouchMove: function onRecordTouchMove(e) {\n if (!this.isRecording) return;\n var touch = e.touches[0];\n var moveY = touch.clientY;\n var cancelThreshold = 60;\n this.isCancelSwipe = this.recordStartY - moveY > cancelThreshold;\n },\n // H5语音录制 - 触摸结束\n onRecordTouchEnd: function onRecordTouchEnd() {\n if (!this.isRecording) return;\n this.isRecording = false;\n\n if (this.recordingTimer) {\n clearInterval(this.recordingTimer);\n this.recordingTimer = null;\n }\n\n this.stopAudioCapture(!this.isCancelSwipe);\n },\n // 停止音频采集并输出 WAV\n stopAudioCapture: function stopAudioCapture(shouldSend) {\n this.isRecording = false;\n\n if (shouldSend && this.audioChunks.length > 0) {\n var wavBlob = this.encodePCMToWav(this.audioChunks, this.audioSampleRate || 16000);\n this.sendAudioBlob(wavBlob);\n }\n\n this.audioChunks = [];\n },\n // 取消录音\n cancelRecording: function cancelRecording() {\n this.isRecording = false;\n\n if (this.recordingTimer) {\n clearInterval(this.recordingTimer);\n this.recordingTimer = null;\n }\n\n this.recordDuration = 0;\n this.isCancelSwipe = false;\n this.audioChunks = [];\n },\n // 释放音频资源\n releaseAudio: function releaseAudio() {\n this.cancelRecording();\n\n if (this.audioProcessor) {\n this.audioProcessor.disconnect();\n this.audioProcessor = null;\n }\n\n if (this.audioSource) {\n this.audioSource.disconnect();\n this.audioSource = null;\n }\n\n if (this.audioContext) {\n this.audioContext.close().catch(function () {});\n this.audioContext = null;\n }\n\n if (this.audioStream) {\n this.audioStream.getTracks().forEach(function (t) {\n return t.stop();\n });\n this.audioStream = null;\n }\n },\n // 将 Float32 PCM 数据编码为 WAV Blob\n encodePCMToWav: function encodePCMToWav(chunks, sampleRate) {\n var totalLength = 0;\n\n var _iterator = (0, _createForOfIteratorHelper2.default)(chunks),\n _step;\n\n try {\n for (_iterator.s(); !(_step = _iterator.n()).done;) {\n var chunk = _step.value;\n totalLength += chunk.length;\n }\n } catch (err) {\n _iterator.e(err);\n } finally {\n _iterator.f();\n }\n\n var pcmData = new Int16Array(totalLength);\n var offset = 0;\n\n var _iterator2 = (0, _createForOfIteratorHelper2.default)(chunks),\n _step2;\n\n try {\n for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {\n var _chunk = _step2.value;\n\n for (var i = 0; i < _chunk.length; i++) {\n var s = Math.max(-1, Math.min(1, _chunk[i]));\n pcmData[offset++] = s < 0 ? s * 0x8000 : s * 0x7FFF;\n }\n }\n } catch (err) {\n _iterator2.e(err);\n } finally {\n _iterator2.f();\n }\n\n var numChannels = 1;\n var bitsPerSample = 16;\n var byteRate = sampleRate * numChannels * bitsPerSample / 8;\n var blockAlign = numChannels * bitsPerSample / 8;\n var dataSize = pcmData.length * (bitsPerSample / 8);\n var headerSize = 44;\n var totalSize = headerSize + dataSize;\n var buffer = new ArrayBuffer(totalSize);\n var view = new DataView(buffer);\n\n this._wavWriteString(view, 0, 'RIFF');\n\n view.setUint32(4, totalSize - 8, true);\n\n this._wavWriteString(view, 8, 'WAVE');\n\n this._wavWriteString(view, 12, 'fmt ');\n\n view.setUint32(16, 16, true);\n view.setUint16(20, 1, true);\n view.setUint16(22, numChannels, true);\n view.setUint32(24, sampleRate, true);\n view.setUint32(28, byteRate, true);\n view.setUint16(32, blockAlign, true);\n view.setUint16(34, bitsPerSample, true);\n\n this._wavWriteString(view, 36, 'data');\n\n view.setUint32(40, dataSize, true);\n var pcmView = new Int16Array(buffer, headerSize, pcmData.length);\n pcmView.set(pcmData);\n return new Blob([buffer], {\n type: 'audio/wav'\n });\n },\n _wavWriteString: function _wavWriteString(view, offset, str) {\n for (var i = 0; i < str.length; i++) {\n view.setUint8(offset + i, str.charCodeAt(i));\n }\n },\n // 发送音频\n sendAudioBlob: function sendAudioBlob(blob) {\n var appSeqId = _index2.default.getAppSeqId();\n\n var name = appSeqId + '.wav';\n var file = new File([blob], name, {\n type: 'audio/wav'\n });\n this.sendAudioMessage(file);\n },\n sendAudioMessage: function sendAudioMessage(file) {\n var _this10 = this;\n\n var sttKey = 'stt_' + Date.now();\n var sttMsg = {\n role: 'user',\n content: '转化中...',\n _sttStatus: 'pending',\n _sttKey: sttKey,\n createTime: new Date().toISOString(),\n _key: sttKey\n };\n this.messages.push(sttMsg);\n this.scrollToBottom(true);\n (0, _index.fileUploadToObs)({\n _file: file,\n appSeqId: file.name\n }).then(function (resp) {\n if (resp.CommonMsg.Status === 200) {\n return _apiObs.default.aliAudioToText({\n url: resp.obs_upload_data.obsUrl\n }).then(function (result) {\n if (result.code === '200' && result.data) {\n var idx = _this10.messages.findIndex(function (m) {\n return m._sttKey === sttKey;\n });\n\n if (idx !== -1) {\n _this10.messages.splice(idx, 1);\n }\n\n _this10.sendQuickMsg(result.data);\n } else {\n throw new Error(result.msg || '语音转文字失败');\n }\n });\n } else {\n throw new Error(resp.CommonMsg.Message || '文件上传失败');\n }\n }).catch(function (err) {\n console.error('语音转文字失败:', err);\n\n var idx = _this10.messages.findIndex(function (m) {\n return m._sttKey === sttKey;\n });\n\n if (idx !== -1) {\n _this10.$set(_this10.messages, idx, (0, _objectSpread2.default)((0, _objectSpread2.default)({}, _this10.messages[idx]), {}, {\n _sttStatus: 'error',\n content: '语音转文字失败'\n }));\n }\n\n _this10.$message.error('语音转文字失败');\n });\n this.$message.success(\"\\u5F55\\u97F3\\u5B8C\\u6210 (\".concat(this.recordDuration, \"s)\"));\n },\n clearWaitTimer: function clearWaitTimer() {\n if (this.waitTimer) {\n clearInterval(this.waitTimer);\n this.waitTimer = null;\n }\n },\n loadMoreMessages: function loadMoreMessages() {\n var _this11 = this;\n\n var nextPage = this.msgPage + 1;\n var maxPage = Math.ceil(this.msgTotal / 10);\n\n if (nextPage > maxPage) {\n this.loadingMore = false;\n return;\n }\n\n (0, _apichat.getSessionMessages)(this.activeSessionId, nextPage, 10).then(function (res) {\n var list = Array.isArray(res) ? res : res.list || [];\n _this11.msgPage = nextPage;\n var asAsc = (list || []).slice().reverse();\n var prepend = asAsc.map(function (m) {\n return {\n role: m.role,\n content: m.content || '',\n thinking: m.thinking || '',\n toolCalls: [],\n agentName: '',\n createTime: m.createTime || null,\n _key: m.createTime ? 'msg_' + m.createTime : 'msg_' + Date.now() + '_' + Math.random(),\n // 历史消息中如果包含 ```tokui 标记或以 TokUI 标签开头,自动启用 TokUI 渲染\n _hasTokui: m.role === 'assistant' && m.content && (/```tokui/.test(m.content) || /^\\s*\\[(card|row|list|table|callout|desc|dv|ft)\\b/.test(m.content.trim()))\n };\n });\n var container = _this11.$refs.messagesRef;\n var oldScrollHeight = container ? container.scrollHeight : 0;\n var oldScrollTop = container ? container.scrollTop : 0;\n _this11.messages = [].concat((0, _toConsumableArray2.default)(prepend), (0, _toConsumableArray2.default)(_this11.messages));\n\n _this11.$nextTick(function () {\n if (container) {\n container.scrollTop = oldScrollTop + (container.scrollHeight - oldScrollHeight);\n }\n\n _this11.loadingMore = false;\n });\n }).catch(function () {\n _this11.loadingMore = false;\n });\n },\n onScrollMessages: function onScrollMessages() {\n var container = this.$refs.messagesRef;\n if (!container || this.loadingMore) return;\n var isAtBottom = container.scrollTop + container.clientHeight >= container.scrollHeight - 100;\n this.checkScrollBottom();\n if (isAtBottom) return;\n\n if (container.scrollTop < 50 && this.msgPage < Math.ceil(this.msgTotal / 10)) {\n this.loadingMore = true;\n this.loadMoreMessages();\n }\n },\n // 检测内容是否为纯 TokUI DSL(无 ```tokui 围栏,直接以 TokUI 标签开头)\n // TokUI 标签名由字母开头,可包含字母、数字、连字符(如 hover-card、think-chain)\n _isPureTokuiDsl: function _isPureTokuiDsl(text) {\n if (!text) return false;\n return /^\\s*\\[[a-zA-Z][a-zA-Z0-9-]*(?=[\\s\\]])/.test(text.trim());\n },\n // 提取 ```tokui 代码块中的 DSL,返回混合内容片段数组\n // 每项: { type: 'md' | 'dsl', content: string }\n _extractTokuiDsl: function _extractTokuiDsl(text) {\n if (!text) return [{\n type: 'md',\n content: ''\n }]; // 纯 TokUI DSL(无 ```tokui 围栏):整个内容作为 DSL 处理\n\n if (this._isPureTokuiDsl(text)) {\n return [{\n type: 'dsl',\n content: text.trim()\n }];\n }\n\n var parts = [];\n var re = /```tokui\\s*([\\s\\S]*?)```/g;\n var lastIndex = 0;\n var match;\n\n while ((match = re.exec(text)) !== null) {\n if (match.index > lastIndex) {\n parts.push({\n type: 'md',\n content: text.substring(lastIndex, match.index)\n });\n }\n\n var dsl = match[1].trim();\n if (dsl) parts.push({\n type: 'dsl',\n content: dsl\n });\n lastIndex = match.index + match[0].length;\n }\n\n if (lastIndex < text.length) {\n parts.push({\n type: 'md',\n content: text.substring(lastIndex)\n });\n }\n\n return parts;\n },\n // 全文本增量流式 feed TokUI(参考项目方式)\n _streamTokui: function _streamTokui(msg, fullText) {\n if (!msg._tokuiStream) return; // 动态判断当前内容是否为纯 TokUI DSL\n\n var isPureDsl = this._isPureTokuiDsl(fullText); // 如果内容模式发生了变化,重置增量追踪\n\n\n if (msg._tokuiPureDsl !== isPureDsl) {\n msg._tokuiPureDsl = isPureDsl;\n msg._prevMdLen = 0;\n msg._prevDslLen = 0;\n msg._dslBuffer = '';\n }\n\n var dsl = '';\n var md = '';\n\n if (isPureDsl) {\n // 纯 DSL:整个内容为 DSL\n dsl = fullText;\n } else {\n // 混合内容:从 ```tokui 围栏中提取 DSL\n var dslParts = []; // 函数内定义,每次执行全新正则,杜绝lastIndex污染\n\n var re = /```tokui\\s*([\\s\\S]*?)```/g;\n var match;\n\n while ((match = re.exec(fullText)) !== null) {\n var inner = match[1].trim();\n if (inner) dslParts.push(inner);\n } // 处理末尾未闭合的 ```tokui(流式场景)\n\n\n var lastIdx = re.lastIndex;\n var remaining = fullText.substring(lastIdx);\n var openIdx = remaining.lastIndexOf('```tokui');\n\n if (openIdx >= 0) {\n var dslPart = remaining.substring(openIdx + 8);\n if (dslPart.charCodeAt(0) === 10) dslPart = dslPart.substring(1); // ✅ 关键防护:如果片段里面存在闭合标记 ```,说明是完整块,不要再追加!\n\n if (dslPart && !dslPart.includes('```')) {\n dslParts.push(dslPart);\n }\n }\n\n dsl = dslParts.join('\\n'); // 移除所有代码围栏得到纯 Markdown\n\n md = fullText.replace(/```[\\s\\S]*?(```|$)/g, '');\n } // Feed Markdown 增量\n\n\n if (md) {\n var prevMdLen = msg._prevMdLen || 0;\n\n if (md.length > prevMdLen) {\n var newMd = md.substring(prevMdLen);\n msg._prevMdLen = md.length;\n\n if (!msg._mdTagOpen) {\n msg._tokuiStream.feed('[md]\\n');\n\n msg._mdTagOpen = true;\n }\n\n msg._tokuiStream.feed(newMd);\n }\n } // Feed DSL 增量\n\n\n if (dsl) {\n var prevDslLen = msg._prevDslLen || 0;\n\n if (dsl.length > prevDslLen) {\n var newDsl = dsl.substring(prevDslLen);\n msg._prevDslLen = dsl.length;\n\n if (msg._mdTagOpen) {\n msg._tokuiStream.feed('[/md]\\n');\n\n msg._mdTagOpen = false;\n } // 逐行 feed DSL,缓冲未完成行\n\n\n msg._dslBuffer = (msg._dslBuffer || '') + newDsl;\n\n var lines = msg._dslBuffer.split('\\n');\n\n for (var i = 0; i < lines.length - 1; i++) {\n msg._tokuiStream.feed(lines[i] + '\\n');\n }\n\n msg._dslBuffer = lines[lines.length - 1];\n }\n }\n },\n // 渲染历史消息中的 TokUI 内容(仅在 TokUI 可用时执行)\n _renderTokuiMessages: function _renderTokuiMessages() {\n var _this12 = this;\n\n var TokUIConstructor = resolveTokUIConstructor();\n if (!TokUIConstructor) return;\n var container = this.$refs.messagesRef;\n if (!container) return;\n var allRows = container.querySelectorAll('.msg-row');\n allRows.forEach(function (row, idx) {\n var msg = _this12.messages[idx];\n if (!msg || !msg._hasTokui) return; // 已通过流式渲染完成的消息,跳过(防止 endStream 后 watcher 触发重复渲染)\n\n if (msg._tokuiRendered) return;\n if (msg.loading || !msg.content || msg._tokuiStream) return;\n var tokuiDiv = row.querySelector('.tokui-stream');\n if (!tokuiDiv) return; // 清除旧内容和状态(DOM 复用 + 流式残留)\n\n tokuiDiv.innerHTML = '';\n tokuiDiv.classList.remove('tokui-streaming');\n tokuiDiv.style.display = 'block';\n\n try {\n var ui = new TokUIConstructor({\n container: tokuiDiv\n }); // ── 与 _streamTokui 完全一致的提取逻辑(含未闭合围栏处理) ──\n\n var text = msg.content;\n\n var isPureDsl = _this12._isPureTokuiDsl(text);\n\n var dsl = '';\n var md = '';\n\n if (isPureDsl) {\n dsl = text;\n } else {\n var dslParts = []; // 每次执行新建正则!!不要提取到外层复用\n\n var re = /```tokui\\s*([\\s\\S]*?)```/g;\n var match;\n\n while ((match = re.exec(text)) !== null) {\n var inner = match[1].trim();\n if (inner) dslParts.push(inner);\n } // 处理未闭合的 ```tokui(流式逻辑)\n\n\n var lastIdx = re.lastIndex;\n var remaining = text.substring(lastIdx);\n var openIdx = remaining.lastIndexOf('```tokui');\n\n if (openIdx >= 0) {\n var dslPart = remaining.substring(openIdx + 8);\n if (dslPart.charCodeAt(0) === 10) dslPart = dslPart.substring(1); // 增强防护:如果这段dslPart包含闭合标记```,说明它其实是完整块,不要追加!\n\n if (dslPart && !dslPart.includes('```')) {\n dslParts.push(dslPart);\n }\n }\n\n dsl = dslParts.join('\\n');\n md = text.replace(/```[\\s\\S]*?(```|$)/g, '');\n } // ── 与流式完全一致的 feed 顺序和方式 ──\n\n\n ui.startStream(); // Feed Markdown\n\n if (md && md.trim()) {\n ui.feed('[md]\\n');\n ui.feed(md);\n ui.feed('[/md]\\n');\n } // Feed DSL 逐行(与流式 _streamTokui 完全一致)\n\n\n if (dsl) {\n var dslLines = dsl.split('\\n');\n\n for (var i = 0; i < dslLines.length; i++) {\n ui.feed(dslLines[i] + '\\n');\n }\n }\n\n ui.endStream();\n tokuiDiv._tokuiRendered = true;\n\n _this12.$set(msg, '_tokuiRendered', true);\n } catch (e) {\n console.error('[TokUI] render error:', e);\n tokuiDiv.textContent = msg.content;\n }\n });\n },\n sendMessage: function sendMessage() {\n var _this13 = this;\n\n return (0, _asyncToGenerator2.default)( /*#__PURE__*/regeneratorRuntime.mark(function _callee3() {\n var text;\n return regeneratorRuntime.wrap(function _callee3$(_context3) {\n while (1) {\n switch (_context3.prev = _context3.next) {\n case 0:\n text = _this13.inputText.trim();\n\n if (!(!text || _this13.sending)) {\n _context3.next = 3;\n break;\n }\n\n return _context3.abrupt(\"return\");\n\n case 3:\n if (!(text.length > 300)) {\n _context3.next = 6;\n break;\n }\n\n _this13.$message({\n message: '消息内容不能超过300字',\n type: 'warning',\n duration: 2000\n });\n\n return _context3.abrupt(\"return\");\n\n case 6:\n if (_this13.activeSessionId) {\n _context3.next = 10;\n break;\n }\n\n _this13.$emit('start-session');\n\n _this13._pendingSendText = text;\n return _context3.abrupt(\"return\");\n\n case 10:\n _this13._sendMessage(text);\n\n case 11:\n case \"end\":\n return _context3.stop();\n }\n }\n }, _callee3);\n }))();\n },\n _sendMessage: function _sendMessage(text) {\n var _this14 = this;\n\n return (0, _asyncToGenerator2.default)( /*#__PURE__*/regeneratorRuntime.mark(function _callee4() {\n var ta, isMobile, baseH, agentName, msgIdx, thinkingBuffer, finalContent, answerBuffer, thinkDisplayed, typeTimer, streamDone, url, es;\n return regeneratorRuntime.wrap(function _callee4$(_context4) {\n while (1) {\n switch (_context4.prev = _context4.next) {\n case 0:\n _this14.inputText = '';\n ta = _this14.$refs.taRef;\n isMobile = _this14.isMobile;\n baseH = isMobile ? 36 : 100;\n\n if (ta) {\n ta.style.height = baseH + 'px';\n }\n\n _this14.showDownBtn = false;\n\n _this14.messages.push({\n role: 'user',\n content: text,\n createTime: new Date().toISOString(),\n _key: 'user_' + Date.now() + '_' + Math.random()\n });\n\n agentName = _this14.currentAgentName;\n msgIdx = _this14.messages.push({\n role: \"assistant\",\n content: \"\",\n thinking: \"\",\n loading: true,\n toolCalls: [],\n agentName: agentName,\n createTime: new Date().toISOString(),\n _key: 'asst_' + Date.now() + '_' + Math.random()\n }) - 1;\n\n _this14.scrollToBottom(true);\n\n _this14.sending = true;\n _this14.waitSeconds = 0;\n if (_this14.waitTimer) clearInterval(_this14.waitTimer);\n _this14.waitTimer = setInterval(function () {\n _this14.waitSeconds++;\n }, 1000);\n thinkingBuffer = '';\n finalContent = '';\n answerBuffer = '';\n thinkDisplayed = 0;\n typeTimer = null;\n streamDone = false;\n typeTimer = setInterval(function () {\n if (!_this14.messages[msgIdx]) return; // Phase 1: 逐字展示思考内容\n\n if (thinkDisplayed < thinkingBuffer.length) {\n thinkDisplayed += 50;\n if (thinkDisplayed > thinkingBuffer.length) thinkDisplayed = thinkingBuffer.length;\n _this14.messages[msgIdx].thinking = thinkingBuffer.substring(0, thinkDisplayed);\n\n _this14.scrollToBottom();\n } // Phase 2: 渲染答案内容\n\n\n var msg = _this14.messages[msgIdx]; // TokUI 活跃期间始终用 answerBuffer(避免 finalContent 带 ```tokui 围栏导致内容跳变)\n\n var target = msg._tokuiStream ? answerBuffer : finalContent || answerBuffer;\n var prevLen = msg._tokuiPrevLen || 0;\n\n if (target.length > prevLen) {\n msg._tokuiPrevLen = target.length; // 检测内容是否包含 TokUI 标记(```tokui 围栏 或 纯 DSL 标签开头)\n\n var hasTokuiMarker = msg._tokuiStream || _this14._isPureTokuiDsl(target) || target.indexOf('```tokui') !== -1;\n\n if (hasTokuiMarker && !msg._hasTokuiFailed) {\n // ── TokUI 路径 ──\n if (!msg._tokuiStream) {\n var container = _this14.$refs.messagesRef;\n\n if (container) {\n var rows = container.querySelectorAll('.msg-row.assistant');\n var lastRow = rows[rows.length - 1];\n var tokuiDiv = lastRow === null || lastRow === void 0 ? void 0 : lastRow.querySelector('.tokui-stream');\n var TokUIConstructor = resolveTokUIConstructor();\n\n if (tokuiDiv && TokUIConstructor) {\n try {\n msg._tokuiDiv = tokuiDiv;\n msg._tokuiStream = new TokUIConstructor({\n container: tokuiDiv\n });\n\n msg._tokuiStream.startStream();\n\n tokuiDiv.classList.add('tokui-streaming');\n msg._tokuiPureDsl = _this14._isPureTokuiDsl(target);\n msg._mdTagOpen = false;\n msg._prevMdLen = 0;\n msg._prevDslLen = 0;\n msg._dslBuffer = '';\n\n _this14.$set(msg, '_hasTokui', true);\n } catch (e) {\n console.error('[TokUI] init error:', e);\n msg._hasTokuiFailed = true;\n msg._tokuiStream = null;\n }\n } else {\n msg._hasTokuiFailed = true;\n }\n }\n }\n\n if (msg._tokuiStream) {\n _this14._streamTokui(msg, target);\n } else if (msg._hasTokuiFailed) {\n // TokUI 初始化失败,回退到普通渲染\n msg.content = target;\n }\n } else {\n // ── 普通渲染路径(保持原有逻辑不变)──\n msg.content = target;\n }\n\n _this14.scrollToBottom();\n\n return;\n } // Phase 3: 流结束 → 收尾\n\n\n if (streamDone) {\n clearInterval(typeTimer);\n typeTimer = null;\n var key = _this14.messages[msgIdx]._key;\n\n if (key) {\n _this14.$delete(_this14.contentCache, key);\n\n _this14.$delete(_this14.contentCache, key + '_t');\n }\n\n if (msg._tokuiStream) {\n // TokUI 路径:关闭 [md] 标签、刷新 DSL 缓冲区、结束流\n try {\n if (msg._mdTagOpen) {\n msg._tokuiStream.feed('[/md]\\n');\n\n msg._mdTagOpen = false;\n }\n\n if (msg._dslBuffer) {\n msg._tokuiStream.feed(msg._dslBuffer + '\\n');\n\n msg._dslBuffer = '';\n }\n\n msg._tokuiStream.endStream();\n } catch (e) {\n console.error('[TokUI] endStream error:', e);\n } // 标记已渲染,防止 _renderTokuiMessages 重复创建实例\n\n\n if (msg._tokuiDiv) {\n msg._tokuiDiv._tokuiRendered = true;\n }\n\n msg._tokuiStream = null; // 使用 $set 确保响应式\n\n _this14.$set(_this14.messages[msgIdx], '_tokuiRendered', true);\n }\n\n _this14.messages[msgIdx].content = finalContent;\n _this14.messages[msgIdx].thinking = thinkingBuffer;\n _this14.messages[msgIdx].loading = false;\n _this14.sending = false;\n\n _this14.clearWaitTimer();\n\n _this14.scrollToBottom();\n\n _this14.$emit('session-refresh');\n\n _this14.$emit('message-sent');\n }\n }, 30);\n url = (0, _apichat.createStreamUrl)(_this14.activeSessionId, text);\n\n if (_this14.eventSource) {\n _this14.eventSource.close();\n }\n\n _this14.eventSource = new EventSource(url);\n es = _this14.eventSource;\n es.addEventListener('reasoning', function (e) {\n if (e.data) {\n var chunk = e.data;\n var cleanChunk = chunk.replace(/([a-z])([A-Z])/g, '$1 $2').replace(/([A-Z]+)([A-Z][a-z])/g, '$1 $2').replace(/([a-zA-Z])([\\u4e00-\\u9fff])/g, '$1 $2').replace(/([\\u4e00-\\u9fff])([a-zA-Z])/g, '$1 $2').replace(/([a-zA-Z])(\\d)/g, '$1 $2').replace(/(\\d)([a-zA-Z])/g, '$1 $2').replace(/\\s+([:,.!?])/g, '$1').replace(/([:,.!?])\\s+/g, '$1 ');\n cleanChunk = cleanChunk.replace(/\\s+/g, ' ');\n var lastChar = thinkingBuffer.slice(-1);\n var firstChar = cleanChunk.slice(0, 1);\n\n var isLetter = function isLetter(c) {\n return /[a-zA-Z]/.test(c);\n };\n\n if (isLetter(lastChar) && isLetter(firstChar)) {\n thinkingBuffer += ' ' + cleanChunk;\n } else {\n thinkingBuffer += cleanChunk;\n }\n }\n });\n es.addEventListener('reasoning_result', function (e) {\n if (e.data) {\n thinkingBuffer = e.data;\n }\n });\n es.addEventListener('answer', function (e) {\n if (e.data) {\n answerBuffer += e.data.replace(/([a-zA-Z]+)([\\u4e00-\\u9fff])/g, '$1 $2').replace(/([\\u4e00-\\u9fff])([a-zA-Z]+)/g, '$1 $2').replace(/([a-z])([A-Z])/g, '$1 $2').replace(/([A-Z]+)([A-Z][a-z])/g, '$1 $2').replace(/([a-zA-Z])(\\d)/g, '$1 $2').replace(/(\\d)([a-zA-Z])/g, '$1 $2');\n }\n });\n es.addEventListener('tool_result', function (e) {\n if (e.data && _this14.messages[msgIdx]) {\n if (!_this14.messages[msgIdx].toolCalls) _this14.messages[msgIdx].toolCalls = [];\n\n _this14.messages[msgIdx].toolCalls.push(e.data);\n\n _this14.scrollToBottom();\n }\n });\n es.addEventListener('agent_result', function (e) {\n finalContent = e.data || '';\n streamDone = true;\n es.close();\n _this14.eventSource = null;\n });\n\n es.onerror = function (err) {\n console.log('[SSE] onerror', err);\n if (thinkingBuffer.length > 0 && !streamDone) finalContent = thinkingBuffer;\n if (!streamDone) finalContent = '❌ 连接中断';\n streamDone = true;\n es.close();\n _this14.eventSource = null;\n };\n\n case 31:\n case \"end\":\n return _context4.stop();\n }\n }\n }, _callee4);\n }))();\n },\n stopAgent: function stopAgent() {\n if (this.eventSource) {\n this.eventSource.close();\n this.eventSource = null;\n }\n\n if (this.activeSessionId) {\n (0, _apichat.stopStream)(this.activeSessionId).catch(function () {});\n }\n\n if (this.messages.length > 0) {\n var last = this.messages[this.messages.length - 1];\n\n if (last && last.loading) {\n last.content = last.content || last.thinking || '⏹ 已停止';\n last.loading = false;\n this.$delete(this.contentCache, last._key);\n }\n }\n\n this.sending = false;\n this.clearWaitTimer();\n },\n scrollToTop: function scrollToTop() {\n var el = this.$refs.messagesRef;\n if (el) el.scrollTop = 0;\n },\n scrollToBottom: function scrollToBottom() {\n var _this15 = this;\n\n var force = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false;\n if (this.showDownBtn && !force) return;\n this.$nextTick(function () {\n var el = _this15.$refs.messagesRef;\n\n if (el) {\n el.scrollTop = el.scrollHeight;\n _this15.lastScrollTop = el.scrollTop;\n _this15.showDownBtn = false;\n _this15._userScrolledUp = false;\n }\n });\n },\n scrollToBottomOnce: function scrollToBottomOnce() {\n var _this16 = this;\n\n clearTimeout(this._scrollTimer);\n this.$nextTick(function () {\n var tryScroll = function tryScroll() {\n var el = _this16.$refs.messagesRef;\n\n if (!el) {\n _this16._scrollTimer = setTimeout(tryScroll, 50);\n return;\n }\n\n var originalScrollBehavior = el.style.scrollBehavior;\n el.style.scrollBehavior = 'auto';\n el.scrollTop = el.scrollHeight - el.clientHeight;\n el.style.scrollBehavior = originalScrollBehavior;\n _this16.showDownBtn = false;\n _this16._userScrolledUp = false;\n };\n\n tryScroll();\n });\n },\n copyText: function copyText(content) {\n var _this17 = this;\n\n if (!content) return;\n var text = content.replace(/<[^>]+>/g, ''); // 优先使用 Clipboard API(HTTPS 环境)\n\n if (navigator.clipboard && navigator.clipboard.writeText) {\n navigator.clipboard.writeText(text).then(function () {\n _this17.$message({\n message: '已复制到剪贴板',\n type: 'success',\n duration: 1500\n });\n }).catch(function () {\n _this17._fallbackCopyText(text);\n });\n } else {\n this._fallbackCopyText(text);\n }\n },\n _fallbackCopyText: function _fallbackCopyText(text) {\n try {\n var ta = document.createElement('textarea');\n ta.value = text;\n ta.style.cssText = 'position:fixed;left:-9999px;top:0;opacity:0';\n document.body.appendChild(ta);\n ta.focus();\n ta.select();\n document.execCommand('copy');\n document.body.removeChild(ta);\n this.$message({\n message: '已复制到剪贴板',\n type: 'success',\n duration: 1500\n });\n } catch (_unused3) {\n this.$message({\n message: '复制失败',\n type: 'error',\n duration: 2000\n });\n }\n },\n copyAsImage: function copyAsImage(content) {\n var _this18 = this;\n\n if (!content) return;\n var div = document.createElement('div');\n div.className = 'copy-image-render';\n div.style.cssText = 'position:fixed;left:-9999px;top:0;width:600px;padding:20px;background:#fff;font-size:14px;line-height:1.6;color:#333;border-radius:8px;font-family:-apple-system,BlinkMacSystemFont,sans-serif;'; // 内联表格样式(因 Vue 作用域样式不覆盖复制用的脱离文档流 div)\n\n div.innerHTML = this.renderMarkdown(content) + '<style>table{border-collapse:collapse;width:100%;margin:6px 0;font-size:14px}' + 'th,td{border:1px solid #e8e8e8;padding:5px 8px;text-align:left}' + 'th{background:#fafafa;font-weight:600}</style>';\n document.body.appendChild(div);\n this.$message({\n message: '正在生成图片...',\n type: 'info',\n duration: 2000\n });\n (0, _html2canvas.default)(div, {\n scale: 2,\n useCORS: true,\n backgroundColor: '#ffffff'\n }).then(function (canvas) {\n var base64 = canvas.toDataURL('image/png'); // 移动端:调用原生方法保存到本地相册\n\n if (_this18.isMobile) {\n if (_this18.$hybrid && typeof _this18.$hybrid.savePic2Library === 'function') {\n _this18.$hybrid.savePic2Library(base64, function () {\n _this18.$message({\n message: '图片已保存到本地相册',\n type: 'success',\n duration: 1500\n });\n });\n } else {\n // fallback:展示图片让用户长按保存\n _this18.previewImage = base64;\n\n _this18.$message({\n message: '长按图片可保存到本地',\n type: 'info',\n duration: 3000\n });\n }\n\n return;\n } // PC端:复制到剪贴板\n\n\n var canCopyImage = typeof ClipboardItem !== 'undefined' && navigator.clipboard && typeof navigator.clipboard.write === 'function';\n\n if (!canCopyImage) {\n _this18.$message({\n message: '当前浏览器不支持复制图片',\n type: 'warning',\n duration: 3000\n });\n\n return;\n }\n\n canvas.toBlob(function (blob) {\n if (!blob) {\n _this18.$message({\n message: '生成图片失败',\n type: 'error',\n duration: 2000\n });\n\n return;\n }\n\n navigator.clipboard.write([new ClipboardItem({\n 'image/png': blob\n })]).then(function () {\n _this18.$message({\n message: '图片已复制到剪贴板',\n type: 'success',\n duration: 1500\n });\n }).catch(function () {\n _this18.$message({\n message: '复制失败,请重试',\n type: 'error',\n duration: 2000\n });\n });\n }, 'image/png');\n }).catch(function () {\n _this18.$message({\n message: '生成图片失败',\n type: 'error',\n duration: 2000\n });\n }).finally(function () {\n document.body.removeChild(div);\n });\n }\n }\n};\nexports.default = _default2;\n\n//# sourceURL=webpack://ZjPluginIntelligent/./src/lib/components/chatMain/ChatDetail.vue?./node_modules/cache-loader/dist/cjs.js??ref--12-0!./node_modules/babel-loader/lib!./node_modules/cache-loader/dist/cjs.js??ref--0-0!./node_modules/vue-loader/lib??vue-loader-options");
840
+ eval("\n\nvar _interopRequireDefault = __webpack_require__(/*! ./node_modules/@babel/runtime/helpers/interopRequireDefault */ \"./node_modules/@babel/runtime/helpers/interopRequireDefault.js\").default;\n\nObject.defineProperty(exports, \"__esModule\", {\n value: true\n});\nexports.default = void 0;\n\nvar _toConsumableArray2 = _interopRequireDefault(__webpack_require__(/*! ./node_modules/@babel/runtime/helpers/toConsumableArray */ \"./node_modules/@babel/runtime/helpers/toConsumableArray.js\"));\n\nvar _objectSpread2 = _interopRequireDefault(__webpack_require__(/*! ./node_modules/@babel/runtime/helpers/objectSpread2 */ \"./node_modules/@babel/runtime/helpers/objectSpread2.js\"));\n\nvar _createForOfIteratorHelper2 = _interopRequireDefault(__webpack_require__(/*! ./node_modules/@babel/runtime/helpers/createForOfIteratorHelper */ \"./node_modules/@babel/runtime/helpers/createForOfIteratorHelper.js\"));\n\nvar _asyncToGenerator2 = _interopRequireDefault(__webpack_require__(/*! ./node_modules/@babel/runtime/helpers/asyncToGenerator */ \"./node_modules/@babel/runtime/helpers/asyncToGenerator.js\"));\n\nvar _markdownIt = _interopRequireDefault(__webpack_require__(/*! markdown-it */ \"./node_modules/markdown-it/index.mjs\"));\n\n__webpack_require__(/*! @jboltai/tokui/dist/tokui.css */ \"./node_modules/@jboltai/tokui/dist/tokui.css\");\n\nvar _apichat = __webpack_require__(/*! @lib/api/apichat */ \"./src/lib/api/apichat.js\");\n\nvar _index = __webpack_require__(/*! @lib/socket/fileManager/obs/index */ \"./src/lib/socket/fileManager/obs/index.js\");\n\nvar _index2 = _interopRequireDefault(__webpack_require__(/*! @lib/socket/utils/index */ \"./src/lib/socket/utils/index.js\"));\n\nvar _cookie = __webpack_require__(/*! @lib/utils/cookie.js */ \"./src/lib/utils/cookie.js\");\n\nvar _apiObs = _interopRequireDefault(__webpack_require__(/*! @lib/api/apiObs */ \"./src/lib/api/apiObs.js\"));\n\nvar _html2canvas = _interopRequireDefault(__webpack_require__(/*! html2canvas */ \"./node_modules/html2canvas/dist/html2canvas.esm.js\"));\n\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\nvar resolveTokUIConstructor = function resolveTokUIConstructor() {\n if (typeof window !== 'undefined') {\n var _window$globalThis;\n\n var runtime = window.TokUI || ((_window$globalThis = window.globalThis) === null || _window$globalThis === void 0 ? void 0 : _window$globalThis.TokUI);\n\n if (runtime) {\n var _runtime$default;\n\n return runtime.TokUI || ((_runtime$default = runtime.default) === null || _runtime$default === void 0 ? void 0 : _runtime$default.TokUI) || runtime.default || runtime;\n }\n }\n\n try {\n if (true) {\n var _runtime = __webpack_require__(/*! @jboltai/tokui/dist/tokui.umd.js */ \"./node_modules/@jboltai/tokui/dist/tokui.umd.js\");\n\n if (_runtime) {\n var _runtime$default2;\n\n return _runtime.TokUI || ((_runtime$default2 = _runtime.default) === null || _runtime$default2 === void 0 ? void 0 : _runtime$default2.TokUI) || _runtime.default || _runtime;\n }\n }\n } catch (e) {// ignore and continue to package entry fallback\n }\n\n try {\n if (true) {\n var _runtime2 = __webpack_require__(/*! @jboltai/tokui */ \"./node_modules/@jboltai/tokui/dist/tokui.mjs\");\n\n if (_runtime2) {\n var _runtime2$default;\n\n return _runtime2.TokUI || ((_runtime2$default = _runtime2.default) === null || _runtime2$default === void 0 ? void 0 : _runtime2$default.TokUI) || _runtime2.default || _runtime2;\n }\n }\n } catch (e) {// ignore and leave unresolved\n }\n\n return null;\n};\n\nvar md = new _markdownIt.default({\n breaks: true,\n html: false,\n linkify: true,\n typographer: true\n});\nmd.enable('table');\nvar _default2 = {\n name: 'ChatDetail',\n props: {\n isMobile: {\n type: Boolean,\n default: false\n },\n activeSessionId: {\n type: String,\n default: ''\n },\n currentAgent: {\n type: String,\n default: ''\n },\n agentInfo: {\n type: Object,\n default: function _default() {\n return {};\n }\n },\n currentAgentDesc: {\n type: String,\n default: ''\n },\n showSidebar: {\n type: Boolean,\n default: false\n },\n showH5List: {\n type: Boolean,\n default: false\n },\n showAgentSelect: {\n type: Boolean,\n default: false\n },\n agentList: {\n type: Array,\n default: function _default() {\n return [];\n }\n }\n },\n data: function data() {\n return {\n messages: [],\n inputText: '',\n sending: false,\n waitTimer: null,\n waitSeconds: 0,\n canceling: false,\n msgPage: 1,\n msgMaxPage: 1,\n msgTotal: 0,\n eventSource: null,\n showToolInfo: false,\n showDownBtn: false,\n lastScrollTop: 0,\n scrollTimer: null,\n contentCache: {},\n loadingSessionMsg: false,\n greeting: '',\n _scrollTimer: null,\n _userScrolledUp: false,\n voiceMode: false,\n isRecording: false,\n recordDuration: 0,\n recordingTimer: null,\n audioContext: null,\n audioStream: null,\n audioProcessor: null,\n audioChunks: [],\n audioSampleRate: 16000,\n isCancelSwipe: false,\n recordStartY: 0,\n isAndroid: false,\n _pendingSendText: null\n };\n },\n computed: {\n waitClass: function waitClass() {\n if (this.waitSeconds > 15) return 'wait-15';\n if (this.waitSeconds > 10) return 'wait-10';\n if (this.waitSeconds > 5) return 'wait-5';\n return '';\n },\n currentAgentName: function currentAgentName() {\n var _this = this;\n\n if (!this.currentAgent) return '';\n var a = this.agentList.find(function (x) {\n return x.agentCode === _this.currentAgent;\n });\n return a ? a.agentName || a.agentCode : this.currentAgent;\n }\n },\n watch: {\n contentCache: {\n handler: function handler(val) {// 保持响应性\n },\n immediate: true\n },\n activeSessionId: function activeSessionId(val) {\n var _this2 = this;\n\n if (val && this._pendingSendText) {\n var text = this._pendingSendText;\n this._pendingSendText = null;\n this.$nextTick(function () {\n return _this2._sendMessage(text);\n });\n }\n },\n messages: {\n handler: function handler() {\n var _this3 = this;\n\n this.$nextTick(function () {\n return _this3._renderTokuiMessages();\n });\n },\n deep: true\n }\n },\n mounted: function mounted() {\n var _this4 = this;\n\n if (window.visualViewport) {\n window.visualViewport.addEventListener('resize', this.onViewportResize, {\n passive: true\n });\n }\n\n if (typeof navigator !== 'undefined') {\n this.isAndroid = /android/i.test(navigator.userAgent);\n }\n\n this.$nextTick(function () {\n _this4._renderTokuiMessages();\n });\n },\n beforeDestroy: function beforeDestroy() {\n if (window.visualViewport) {\n window.visualViewport.removeEventListener('resize', this.onViewportResize);\n }\n\n this.releaseAudio();\n this.contentCache = {};\n clearTimeout(this._scrollTimer);\n\n if (this.eventSource) {\n this.eventSource.onerror = null;\n this.eventSource.close();\n this.eventSource = null;\n }\n\n if (this.waitTimer) {\n clearInterval(this.waitTimer);\n this.waitTimer = null;\n }\n\n if (this._typeTimer) {\n clearInterval(this._typeTimer);\n this._typeTimer = null;\n }\n },\n methods: {\n getInitial: function getInitial(name) {\n if (!name) return '?';\n return name.charAt(0);\n },\n formatTime: function formatTime(t) {\n if (!t) return '';\n var d = new Date(t.replace(' ', 'T'));\n var now = new Date();\n var diff = (now - d) / 1000;\n if (diff < 60) return '刚刚';\n if (diff < 3600) return Math.floor(diff / 60) + '分钟前';\n if (diff < 86400) return Math.floor(diff / 3600) + '小时前';\n return d.getMonth() + 1 + '/' + d.getDate();\n },\n escapeHtml: function escapeHtml(text) {\n if (!text) return '';\n return text.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;');\n },\n renderMarkdown: function renderMarkdown(text) {\n if (!text) return '';\n\n try {\n return md.render(text);\n } catch (err) {\n return this.escapeHtml(text);\n }\n },\n renderStreaming: function renderStreaming(text, msgKey) {\n if (!text) return '';\n var cache = this.contentCache[msgKey];\n var lines = text.split('\\n');\n var lastLineIdx = lines.length - 1;\n\n if (!cache) {\n try {\n var html = md.render(text);\n this.$set(this.contentCache, msgKey, {\n renderedLines: lastLineIdx,\n html: html,\n fullText: text\n });\n return html;\n } catch (_unused) {\n return this.escapeHtml(text);\n }\n }\n\n if (text === cache.fullText) return cache.html;\n cache.fullText = text; // 行数没变,仅末尾追加字符,直接拼接尾行\n\n if (lastLineIdx === cache.renderedLines) {\n return cache.html + this.escapeHtml(lines[lastLineIdx]);\n } // 场景1:行数变少/文本回退截断,全量重渲染\n\n\n if (lastLineIdx < cache.renderedLines) {\n try {\n var fullLines = lines.slice(0, lastLineIdx);\n var newBaseHtml = '';\n\n if (fullLines.length > 0) {\n newBaseHtml = md.render(fullLines.join('\\n'));\n }\n\n cache.html = newBaseHtml;\n cache.renderedLines = lastLineIdx;\n\n var _lastLine = this.escapeHtml(lines[lastLineIdx]);\n\n return cache.html + (_lastLine || '');\n } catch (_unused2) {\n return this.escapeHtml(text);\n }\n } // 场景2:新增完整行\n\n\n if (cache.renderedLines < lastLineIdx) {\n var allFullLines = lines.slice(0, lastLineIdx);\n var _newBaseHtml = '';\n\n if (allFullLines.length > 0) {\n _newBaseHtml = md.render(allFullLines.join('\\n'));\n }\n\n cache.html = _newBaseHtml;\n cache.renderedLines = lastLineIdx;\n }\n\n var lastLine = this.escapeHtml(lines[lastLineIdx]);\n cache.renderedLines = lastLineIdx;\n return cache.html + (lastLine || '');\n },\n getChatAvatarStyle: function getChatAvatarStyle(agent, avatar) {\n if (avatar) {\n return {\n backgroundImage: \"url(\".concat(avatar, \")\"),\n backgroundSize: 'cover',\n backgroundPosition: 'center',\n backgroundRepeat: 'no-repeat'\n };\n }\n\n var _agent = this.agentList.find(function (x) {\n return x.agentCode === agent;\n });\n\n if (_agent && _agent.avatar) {\n return {\n backgroundImage: \"url(\".concat(_agent.avatar, \")\"),\n backgroundSize: 'cover',\n backgroundPosition: 'center',\n backgroundRepeat: 'no-repeat'\n };\n } // 没有网络图片时,根据智能体在 agentList 中的索引位置决定颜色\n\n\n var index = this.agentList.findIndex(function (item) {\n return item.agentCode === agent;\n });\n\n if (index !== -1) {\n var colorIndex = index % 4 + 1;\n return {\n background: this.getGradientByColorIndex(colorIndex)\n };\n }\n\n return {\n background: 'linear-gradient(135deg, #1677ff, #4096ff)'\n };\n },\n getGradientByColorIndex: function getGradientByColorIndex(index) {\n var gradients = {\n 1: 'linear-gradient(135deg, #1677ff, #4096ff)',\n 2: 'linear-gradient(135deg, #52c41a, #73d13d)',\n 3: 'linear-gradient(135deg, #fa8c16, #ffa940)',\n 4: 'linear-gradient(135deg, #722ed1, #b37feb)'\n };\n return gradients[index] || gradients[1];\n },\n sendQuickMsg: function sendQuickMsg(message) {\n if (message) {\n this.inputText = message;\n this.sendMessage();\n }\n },\n formatMixText: function formatMixText(str) {\n if (!str) return '';\n var res = str.replace(/([a-zA-Z0-9])([\\u4e00-\\u9fff])/g, '$1 $2').replace(/([\\u4e00-\\u9fff])([a-zA-Z0-9])/g, '$1 $2');\n res = res.replace(/([a-z])([A-Z])/g, '$1 $2');\n return res;\n },\n // 检测是否滚动到底部,控制向下箭头显示隐藏\n checkScrollBottom: function checkScrollBottom() {\n var forceShowWhenNotBottom = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false;\n var el = this.$refs.messagesRef;\n\n if (!el) {\n this.showDownBtn = false;\n return;\n }\n\n var scrollHeight = el.scrollHeight,\n scrollTop = el.scrollTop,\n clientHeight = el.clientHeight;\n var remain = scrollHeight - scrollTop - clientHeight;\n var atBottom = remain <= 80; // 检测用户是否主动向上滚动(远离底部)\n\n if (remain > 80 && scrollTop < this.lastScrollTop) {\n this._userScrolledUp = true;\n }\n\n if (atBottom) {\n this._userScrolledUp = false;\n this.showDownBtn = false;\n } else if (this._userScrolledUp) {\n // 用户已主动上滚,保持显示\"到底部\"按钮,不自动回滚\n this.showDownBtn = true;\n } else if (this.sending && scrollTop >= this.lastScrollTop && !forceShowWhenNotBottom) {\n this.showDownBtn = false;\n } else {\n this.showDownBtn = true;\n }\n\n this.lastScrollTop = scrollTop;\n this.$emit('scroll-bottom-check', {\n showDownBtn: this.showDownBtn,\n lastScrollTop: this.lastScrollTop\n });\n },\n // H5 输入框获取焦点 - 滚动到底部让键盘不遮挡\n onInputFocus: function onInputFocus() {\n if (!this.isMobile) return;\n setTimeout(function () {\n window.scrollTo(0, document.body.scrollHeight);\n }, 300);\n },\n // visualViewport 变化时(如键盘弹出)调整滚动位置\n onViewportResize: function onViewportResize() {\n if (!this.isMobile) return;\n var activeEl = document.activeElement;\n\n if (activeEl && (activeEl.tagName === 'TEXTAREA' || activeEl.tagName === 'INPUT')) {\n window.scrollTo(0, document.body.scrollHeight);\n }\n },\n autoResizeTextarea: function autoResizeTextarea() {\n var _this5 = this;\n\n var ta = this.$refs.taRef;\n if (!ta) return;\n var isMobile = this.isMobile;\n var baseH = isMobile ? 36 : 100;\n var maxH = isMobile ? 100 : 180;\n ta.style.height = \"\".concat(baseH, \"px\");\n var realH = ta.scrollHeight;\n\n if (realH > baseH) {\n ta.style.height = \"\".concat(Math.min(realH, maxH), \"px\");\n }\n\n this.$nextTick(function () {\n _this5.checkScrollBottom(true);\n });\n },\n // Ctrl+Enter换行\n newLine: function newLine(e) {\n var _this6 = this;\n\n e.preventDefault();\n var ta = this.$refs.taRef;\n var start = ta.selectionStart;\n var end = ta.selectionEnd;\n this.inputText = this.inputText.slice(0, start) + '\\n' + this.inputText.slice(end);\n this.$nextTick(function () {\n ta.selectionStart = ta.selectionEnd = start + 1;\n\n _this6.autoResizeTextarea();\n });\n },\n toggleVoiceMode: function toggleVoiceMode() {\n var _this7 = this;\n\n if (this.voiceMode) {\n this.voiceMode = false;\n this.releaseAudio();\n return;\n } // 进入语音模式前提前请求麦克风权限,避免触摸时异步弹窗导致 touchend 丢失\n\n\n this.ensureAudioReady().then(function (ready) {\n if (ready) {\n _this7.voiceMode = true;\n } else {\n _this7.voiceMode = false;\n }\n });\n },\n // 确保音频设备已就绪\n ensureAudioReady: function ensureAudioReady() {\n var _this8 = this;\n\n return (0, _asyncToGenerator2.default)( /*#__PURE__*/regeneratorRuntime.mark(function _callee() {\n var stream, audioContext, source, processor;\n return regeneratorRuntime.wrap(function _callee$(_context) {\n while (1) {\n switch (_context.prev = _context.next) {\n case 0:\n if (!(_this8.audioContext && _this8.audioStream)) {\n _context.next = 2;\n break;\n }\n\n return _context.abrupt(\"return\", true);\n\n case 2:\n if (!(!navigator.mediaDevices || !navigator.mediaDevices.getUserMedia)) {\n _context.next = 5;\n break;\n }\n\n alert('当前环境不支持麦克风访问');\n return _context.abrupt(\"return\", false);\n\n case 5:\n _context.prev = 5;\n _context.next = 8;\n return navigator.mediaDevices.getUserMedia({\n audio: true\n });\n\n case 8:\n stream = _context.sent;\n _this8.audioStream = stream;\n audioContext = new (window.AudioContext || window.webkitAudioContext)(); // iOS 上 AudioContext 默认 suspended,需要手动 resume\n\n if (!(audioContext.state === 'suspended')) {\n _context.next = 14;\n break;\n }\n\n _context.next = 14;\n return audioContext.resume();\n\n case 14:\n _this8.audioContext = audioContext; // 采集实际采样率(iOS 会忽略 sampleRate 参数,使用硬件采样率)\n\n _this8.audioSampleRate = audioContext.sampleRate || 16000;\n source = audioContext.createMediaStreamSource(stream); // 保存 source 引用到实例,防止 iOS Safari 垃圾回收导致音频处理中断\n\n _this8.audioSource = source;\n processor = audioContext.createScriptProcessor(4096, 1, 1);\n _this8.audioProcessor = processor; // iOS 上 onaudioprocess 可能先于 isRecording=true 触发\n // 因此不依赖 isRecording 过滤,由外部控制 audioChunks 的清零时机\n\n processor.onaudioprocess = function (e) {\n var inputData = e.inputBuffer.getChannelData(0);\n\n _this8.audioChunks.push(new Float32Array(inputData));\n };\n\n source.connect(processor);\n processor.connect(audioContext.destination);\n return _context.abrupt(\"return\", true);\n\n case 26:\n _context.prev = 26;\n _context.t0 = _context[\"catch\"](5);\n console.error('麦克风访问失败:', _context.t0);\n alert('麦克风权限被拒绝');\n return _context.abrupt(\"return\", false);\n\n case 31:\n case \"end\":\n return _context.stop();\n }\n }\n }, _callee, null, [[5, 26]]);\n }))();\n },\n // H5语音录制 - 触摸开始\n onRecordTouchStart: function onRecordTouchStart(e) {\n var _this9 = this;\n\n return (0, _asyncToGenerator2.default)( /*#__PURE__*/regeneratorRuntime.mark(function _callee2() {\n var ready;\n return regeneratorRuntime.wrap(function _callee2$(_context2) {\n while (1) {\n switch (_context2.prev = _context2.next) {\n case 0:\n if (!_this9.sending) {\n _context2.next = 2;\n break;\n }\n\n return _context2.abrupt(\"return\");\n\n case 2:\n _context2.next = 4;\n return _this9.ensureAudioReady();\n\n case 4:\n ready = _context2.sent;\n\n if (ready) {\n _context2.next = 7;\n break;\n }\n\n return _context2.abrupt(\"return\");\n\n case 7:\n _this9.isCancelSwipe = false;\n _this9.recordStartY = e.touches[0].clientY;\n _this9.recordDuration = 0;\n _this9.audioChunks = [];\n _this9.isRecording = true;\n _this9.recordingTimer = setInterval(function () {\n _this9.recordDuration++;\n\n if (_this9.recordDuration >= 60) {\n _this9.onRecordTouchEnd();\n }\n }, 1000);\n\n case 13:\n case \"end\":\n return _context2.stop();\n }\n }\n }, _callee2);\n }))();\n },\n // H5语音录制 - 触摸移动\n onRecordTouchMove: function onRecordTouchMove(e) {\n if (!this.isRecording) return;\n var touch = e.touches[0];\n var moveY = touch.clientY;\n var cancelThreshold = 60;\n this.isCancelSwipe = this.recordStartY - moveY > cancelThreshold;\n },\n // H5语音录制 - 触摸结束\n onRecordTouchEnd: function onRecordTouchEnd() {\n if (!this.isRecording) return;\n this.isRecording = false;\n\n if (this.recordingTimer) {\n clearInterval(this.recordingTimer);\n this.recordingTimer = null;\n }\n\n this.stopAudioCapture(!this.isCancelSwipe);\n },\n // 停止音频采集并输出 WAV\n stopAudioCapture: function stopAudioCapture(shouldSend) {\n this.isRecording = false;\n\n if (shouldSend && this.audioChunks.length > 0) {\n var wavBlob = this.encodePCMToWav(this.audioChunks, this.audioSampleRate || 16000);\n this.sendAudioBlob(wavBlob);\n }\n\n this.audioChunks = [];\n },\n // 取消录音\n cancelRecording: function cancelRecording() {\n this.isRecording = false;\n\n if (this.recordingTimer) {\n clearInterval(this.recordingTimer);\n this.recordingTimer = null;\n }\n\n this.recordDuration = 0;\n this.isCancelSwipe = false;\n this.audioChunks = [];\n },\n // 释放音频资源\n releaseAudio: function releaseAudio() {\n this.cancelRecording();\n\n if (this.audioProcessor) {\n this.audioProcessor.disconnect();\n this.audioProcessor = null;\n }\n\n if (this.audioSource) {\n this.audioSource.disconnect();\n this.audioSource = null;\n }\n\n if (this.audioContext) {\n this.audioContext.close().catch(function () {});\n this.audioContext = null;\n }\n\n if (this.audioStream) {\n this.audioStream.getTracks().forEach(function (t) {\n return t.stop();\n });\n this.audioStream = null;\n }\n },\n // 将 Float32 PCM 数据编码为 WAV Blob\n encodePCMToWav: function encodePCMToWav(chunks, sampleRate) {\n var totalLength = 0;\n\n var _iterator = (0, _createForOfIteratorHelper2.default)(chunks),\n _step;\n\n try {\n for (_iterator.s(); !(_step = _iterator.n()).done;) {\n var chunk = _step.value;\n totalLength += chunk.length;\n }\n } catch (err) {\n _iterator.e(err);\n } finally {\n _iterator.f();\n }\n\n var pcmData = new Int16Array(totalLength);\n var offset = 0;\n\n var _iterator2 = (0, _createForOfIteratorHelper2.default)(chunks),\n _step2;\n\n try {\n for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {\n var _chunk = _step2.value;\n\n for (var i = 0; i < _chunk.length; i++) {\n var s = Math.max(-1, Math.min(1, _chunk[i]));\n pcmData[offset++] = s < 0 ? s * 0x8000 : s * 0x7FFF;\n }\n }\n } catch (err) {\n _iterator2.e(err);\n } finally {\n _iterator2.f();\n }\n\n var numChannels = 1;\n var bitsPerSample = 16;\n var byteRate = sampleRate * numChannels * bitsPerSample / 8;\n var blockAlign = numChannels * bitsPerSample / 8;\n var dataSize = pcmData.length * (bitsPerSample / 8);\n var headerSize = 44;\n var totalSize = headerSize + dataSize;\n var buffer = new ArrayBuffer(totalSize);\n var view = new DataView(buffer);\n\n this._wavWriteString(view, 0, 'RIFF');\n\n view.setUint32(4, totalSize - 8, true);\n\n this._wavWriteString(view, 8, 'WAVE');\n\n this._wavWriteString(view, 12, 'fmt ');\n\n view.setUint32(16, 16, true);\n view.setUint16(20, 1, true);\n view.setUint16(22, numChannels, true);\n view.setUint32(24, sampleRate, true);\n view.setUint32(28, byteRate, true);\n view.setUint16(32, blockAlign, true);\n view.setUint16(34, bitsPerSample, true);\n\n this._wavWriteString(view, 36, 'data');\n\n view.setUint32(40, dataSize, true);\n var pcmView = new Int16Array(buffer, headerSize, pcmData.length);\n pcmView.set(pcmData);\n return new Blob([buffer], {\n type: 'audio/wav'\n });\n },\n _wavWriteString: function _wavWriteString(view, offset, str) {\n for (var i = 0; i < str.length; i++) {\n view.setUint8(offset + i, str.charCodeAt(i));\n }\n },\n // 发送音频\n sendAudioBlob: function sendAudioBlob(blob) {\n var appSeqId = _index2.default.getAppSeqId();\n\n var name = appSeqId + '.wav';\n var file = new File([blob], name, {\n type: 'audio/wav'\n });\n this.sendAudioMessage(file);\n },\n sendAudioMessage: function sendAudioMessage(file) {\n var _this10 = this;\n\n var sttKey = 'stt_' + Date.now();\n var sttMsg = {\n role: 'user',\n content: '转化中...',\n _sttStatus: 'pending',\n _sttKey: sttKey,\n createTime: new Date().toISOString(),\n _key: sttKey\n };\n this.messages.push(sttMsg);\n this.scrollToBottom(true);\n (0, _index.fileUploadToObs)({\n _file: file,\n appSeqId: file.name\n }).then(function (resp) {\n if (resp.CommonMsg.Status === 200) {\n return _apiObs.default.aliAudioToText({\n url: resp.obs_upload_data.obsUrl\n }).then(function (result) {\n if (result.code === '200' && result.data) {\n var idx = _this10.messages.findIndex(function (m) {\n return m._sttKey === sttKey;\n });\n\n if (idx !== -1) {\n _this10.messages.splice(idx, 1);\n }\n\n _this10.sendQuickMsg(result.data);\n } else {\n throw new Error(result.msg || '语音转文字失败');\n }\n });\n } else {\n throw new Error(resp.CommonMsg.Message || '文件上传失败');\n }\n }).catch(function (err) {\n console.error('语音转文字失败:', err);\n\n var idx = _this10.messages.findIndex(function (m) {\n return m._sttKey === sttKey;\n });\n\n if (idx !== -1) {\n _this10.$set(_this10.messages, idx, (0, _objectSpread2.default)((0, _objectSpread2.default)({}, _this10.messages[idx]), {}, {\n _sttStatus: 'error',\n content: '语音转文字失败'\n }));\n }\n\n _this10.$message.error('语音转文字失败');\n });\n this.$message.success(\"\\u5F55\\u97F3\\u5B8C\\u6210 (\".concat(this.recordDuration, \"s)\"));\n },\n clearWaitTimer: function clearWaitTimer() {\n if (this.waitTimer) {\n clearInterval(this.waitTimer);\n this.waitTimer = null;\n }\n },\n loadMoreMessages: function loadMoreMessages() {\n var _this11 = this;\n\n var nextPage = this.msgPage + 1;\n var maxPage = Math.ceil(this.msgTotal / 10);\n\n if (nextPage > maxPage) {\n this.loadingMore = false;\n return;\n }\n\n (0, _apichat.getSessionMessages)(this.activeSessionId, nextPage, 10).then(function (res) {\n var list = Array.isArray(res) ? res : res.list || [];\n _this11.msgPage = nextPage;\n var asAsc = (list || []).slice().reverse();\n var prepend = asAsc.map(function (m) {\n return {\n role: m.role,\n content: m.content || '',\n thinking: m.thinking || '',\n toolCalls: [],\n agentName: '',\n createTime: m.createTime || null,\n _key: m.createTime ? 'msg_' + m.createTime : 'msg_' + Date.now() + '_' + Math.random(),\n // 历史消息中如果包含 ```tokui 标记或以 TokUI 标签开头,自动启用 TokUI 渲染\n _hasTokui: m.role === 'assistant' && m.content && (/```tokui/.test(m.content) || /^\\s*\\[(card|row|list|table|callout|desc|dv|ft)\\b/.test(m.content.trim()))\n };\n });\n var container = _this11.$refs.messagesRef;\n var oldScrollHeight = container ? container.scrollHeight : 0;\n var oldScrollTop = container ? container.scrollTop : 0;\n _this11.messages = [].concat((0, _toConsumableArray2.default)(prepend), (0, _toConsumableArray2.default)(_this11.messages));\n\n _this11.$nextTick(function () {\n if (container) {\n container.scrollTop = oldScrollTop + (container.scrollHeight - oldScrollHeight);\n }\n\n _this11.loadingMore = false;\n });\n }).catch(function () {\n _this11.loadingMore = false;\n });\n },\n onScrollMessages: function onScrollMessages() {\n var container = this.$refs.messagesRef;\n if (!container || this.loadingMore) return;\n var isAtBottom = container.scrollTop + container.clientHeight >= container.scrollHeight - 100;\n this.checkScrollBottom();\n if (isAtBottom) return;\n\n if (container.scrollTop < 50 && this.msgPage < Math.ceil(this.msgTotal / 10)) {\n this.loadingMore = true;\n this.loadMoreMessages();\n }\n },\n // 检测内容是否为纯 TokUI DSL(无 ```tokui 围栏,直接以 TokUI 标签开头)\n // TokUI 标签名由字母开头,可包含字母、数字、连字符(如 hover-card、think-chain)\n _isPureTokuiDsl: function _isPureTokuiDsl(text) {\n if (!text) return false;\n return /^\\s*\\[[a-zA-Z][a-zA-Z0-9-]*(?=[\\s\\]])/.test(text.trim());\n },\n // 提取 ```tokui 代码块中的 DSL,返回混合内容片段数组\n // 每项: { type: 'md' | 'dsl', content: string }\n _extractTokuiDsl: function _extractTokuiDsl(text) {\n if (!text) return [{\n type: 'md',\n content: ''\n }]; // 纯 TokUI DSL(无 ```tokui 围栏):整个内容作为 DSL 处理\n\n if (this._isPureTokuiDsl(text)) {\n return [{\n type: 'dsl',\n content: text.trim()\n }];\n }\n\n var parts = [];\n var re = /```tokui\\s*([\\s\\S]*?)```/g;\n var lastIndex = 0;\n var match;\n\n while ((match = re.exec(text)) !== null) {\n if (match.index > lastIndex) {\n parts.push({\n type: 'md',\n content: text.substring(lastIndex, match.index)\n });\n }\n\n var dsl = match[1].trim();\n if (dsl) parts.push({\n type: 'dsl',\n content: dsl\n });\n lastIndex = match.index + match[0].length;\n }\n\n if (lastIndex < text.length) {\n parts.push({\n type: 'md',\n content: text.substring(lastIndex)\n });\n }\n\n return parts;\n },\n // 全文本增量流式 feed TokUI(参考项目方式)\n _streamTokui: function _streamTokui(msg, fullText) {\n if (!msg._tokuiStream) return; // 动态判断当前内容是否为纯 TokUI DSL\n\n var isPureDsl = this._isPureTokuiDsl(fullText); // 如果内容模式发生了变化,重置增量追踪\n\n\n if (msg._tokuiPureDsl !== isPureDsl) {\n msg._tokuiPureDsl = isPureDsl;\n msg._prevMdLen = 0;\n msg._prevDslLen = 0;\n msg._dslBuffer = '';\n }\n\n var dsl = '';\n var md = '';\n\n if (isPureDsl) {\n // 纯 DSL:整个内容为 DSL\n dsl = fullText;\n } else {\n // 混合内容:从 ```tokui 围栏中提取 DSL\n var dslParts = []; // 函数内定义,每次执行全新正则,杜绝lastIndex污染\n\n var re = /```tokui\\s*([\\s\\S]*?)```/g;\n var match;\n\n while ((match = re.exec(fullText)) !== null) {\n var inner = match[1].trim();\n if (inner) dslParts.push(inner);\n } // 处理末尾未闭合的 ```tokui(流式场景)\n\n\n var lastIdx = re.lastIndex;\n var remaining = fullText.substring(lastIdx);\n var openIdx = remaining.lastIndexOf('```tokui');\n\n if (openIdx >= 0) {\n var dslPart = remaining.substring(openIdx + 8);\n if (dslPart.charCodeAt(0) === 10) dslPart = dslPart.substring(1); // ✅ 关键防护:如果片段里面存在闭合标记 ```,说明是完整块,不要再追加!\n\n if (dslPart && !dslPart.includes('```')) {\n dslParts.push(dslPart);\n }\n }\n\n dsl = dslParts.join('\\n'); // 移除所有代码围栏得到纯 Markdown\n\n md = fullText.replace(/```[\\s\\S]*?(```|$)/g, '');\n } // Feed Markdown 增量\n\n\n if (md) {\n var prevMdLen = msg._prevMdLen || 0;\n\n if (md.length > prevMdLen) {\n var newMd = md.substring(prevMdLen);\n msg._prevMdLen = md.length;\n\n if (!msg._mdTagOpen) {\n msg._tokuiStream.feed('[md]\\n');\n\n msg._mdTagOpen = true;\n }\n\n msg._tokuiStream.feed(newMd);\n }\n } // Feed DSL 增量\n\n\n if (dsl) {\n var prevDslLen = msg._prevDslLen || 0;\n\n if (dsl.length > prevDslLen) {\n var newDsl = dsl.substring(prevDslLen);\n msg._prevDslLen = dsl.length;\n\n if (msg._mdTagOpen) {\n msg._tokuiStream.feed('[/md]\\n');\n\n msg._mdTagOpen = false;\n } // 逐行 feed DSL,缓冲未完成行\n\n\n msg._dslBuffer = (msg._dslBuffer || '') + newDsl;\n\n var lines = msg._dslBuffer.split('\\n');\n\n for (var i = 0; i < lines.length - 1; i++) {\n msg._tokuiStream.feed(lines[i] + '\\n');\n }\n\n msg._dslBuffer = lines[lines.length - 1];\n }\n }\n },\n // 渲染历史消息中的 TokUI 内容(仅在 TokUI 可用时执行)\n _renderTokuiMessages: function _renderTokuiMessages() {\n var _this12 = this;\n\n var TokUIConstructor = resolveTokUIConstructor();\n if (!TokUIConstructor) return;\n var container = this.$refs.messagesRef;\n if (!container) return;\n var allRows = container.querySelectorAll('.msg-row');\n allRows.forEach(function (row, idx) {\n var msg = _this12.messages[idx];\n if (!msg || !msg._hasTokui) return; // 已通过流式渲染完成的消息,跳过(防止 endStream 后 watcher 触发重复渲染)\n\n if (msg._tokuiRendered) return;\n if (msg.loading || !msg.content || msg._tokuiStream) return;\n var tokuiDiv = row.querySelector('.tokui-stream');\n if (!tokuiDiv) return; // 清除旧内容和状态(DOM 复用 + 流式残留)\n\n tokuiDiv.innerHTML = '';\n tokuiDiv.classList.remove('tokui-streaming');\n tokuiDiv.style.display = 'block';\n\n try {\n var ui = new TokUIConstructor({\n container: tokuiDiv\n }); // ── 与 _streamTokui 完全一致的提取逻辑(含未闭合围栏处理) ──\n\n var text = msg.content;\n\n var isPureDsl = _this12._isPureTokuiDsl(text);\n\n var dsl = '';\n var md = '';\n\n if (isPureDsl) {\n dsl = text;\n } else {\n var dslParts = []; // 每次执行新建正则!!不要提取到外层复用\n\n var re = /```tokui\\s*([\\s\\S]*?)```/g;\n var match;\n\n while ((match = re.exec(text)) !== null) {\n var inner = match[1].trim();\n if (inner) dslParts.push(inner);\n } // 处理未闭合的 ```tokui(流式逻辑)\n\n\n var lastIdx = re.lastIndex;\n var remaining = text.substring(lastIdx);\n var openIdx = remaining.lastIndexOf('```tokui');\n\n if (openIdx >= 0) {\n var dslPart = remaining.substring(openIdx + 8);\n if (dslPart.charCodeAt(0) === 10) dslPart = dslPart.substring(1); // 增强防护:如果这段dslPart包含闭合标记```,说明它其实是完整块,不要追加!\n\n if (dslPart && !dslPart.includes('```')) {\n dslParts.push(dslPart);\n }\n }\n\n dsl = dslParts.join('\\n');\n md = text.replace(/```[\\s\\S]*?(```|$)/g, '');\n } // ── 与流式完全一致的 feed 顺序和方式 ──\n\n\n ui.startStream(); // Feed Markdown\n\n if (md && md.trim()) {\n ui.feed('[md]\\n');\n ui.feed(md);\n ui.feed('[/md]\\n');\n } // Feed DSL 逐行(与流式 _streamTokui 完全一致)\n\n\n if (dsl) {\n var dslLines = dsl.split('\\n');\n\n for (var i = 0; i < dslLines.length; i++) {\n ui.feed(dslLines[i] + '\\n');\n }\n }\n\n ui.endStream();\n tokuiDiv._tokuiRendered = true;\n\n _this12.$set(msg, '_tokuiRendered', true);\n } catch (e) {\n console.error('[TokUI] render error:', e);\n tokuiDiv.textContent = msg.content;\n }\n });\n },\n sendMessage: function sendMessage() {\n var _this13 = this;\n\n return (0, _asyncToGenerator2.default)( /*#__PURE__*/regeneratorRuntime.mark(function _callee3() {\n var text;\n return regeneratorRuntime.wrap(function _callee3$(_context3) {\n while (1) {\n switch (_context3.prev = _context3.next) {\n case 0:\n text = _this13.inputText.trim();\n\n if (!(!text || _this13.sending)) {\n _context3.next = 3;\n break;\n }\n\n return _context3.abrupt(\"return\");\n\n case 3:\n if (!(text.length > 300)) {\n _context3.next = 6;\n break;\n }\n\n _this13.$message({\n message: '消息内容不能超过300字',\n type: 'warning',\n duration: 2000\n });\n\n return _context3.abrupt(\"return\");\n\n case 6:\n if (_this13.activeSessionId) {\n _context3.next = 10;\n break;\n }\n\n _this13.$emit('start-session');\n\n _this13._pendingSendText = text;\n return _context3.abrupt(\"return\");\n\n case 10:\n _this13._sendMessage(text);\n\n case 11:\n case \"end\":\n return _context3.stop();\n }\n }\n }, _callee3);\n }))();\n },\n _sendMessage: function _sendMessage(text) {\n var _this14 = this;\n\n return (0, _asyncToGenerator2.default)( /*#__PURE__*/regeneratorRuntime.mark(function _callee4() {\n var ta, isMobile, baseH, agentName, msgIdx, thinkingBuffer, finalContent, answerBuffer, thinkDisplayed, typeTimer, streamDone, url, es;\n return regeneratorRuntime.wrap(function _callee4$(_context4) {\n while (1) {\n switch (_context4.prev = _context4.next) {\n case 0:\n _this14.inputText = '';\n ta = _this14.$refs.taRef;\n isMobile = _this14.isMobile;\n baseH = isMobile ? 36 : 100;\n\n if (ta) {\n ta.style.height = baseH + 'px';\n }\n\n _this14.showDownBtn = false;\n\n _this14.messages.push({\n role: 'user',\n content: text,\n createTime: new Date().toISOString(),\n _key: 'user_' + Date.now() + '_' + Math.random()\n });\n\n agentName = _this14.currentAgentName;\n msgIdx = _this14.messages.push({\n role: \"assistant\",\n content: \"\",\n thinking: \"\",\n loading: true,\n toolCalls: [],\n agentName: agentName,\n createTime: new Date().toISOString(),\n _key: 'asst_' + Date.now() + '_' + Math.random()\n }) - 1;\n\n _this14.scrollToBottom(true);\n\n _this14.sending = true;\n _this14.waitSeconds = 0;\n if (_this14.waitTimer) clearInterval(_this14.waitTimer);\n _this14.waitTimer = setInterval(function () {\n _this14.waitSeconds++;\n }, 1000);\n thinkingBuffer = '';\n finalContent = '';\n answerBuffer = '';\n thinkDisplayed = 0;\n typeTimer = null;\n streamDone = false;\n typeTimer = setInterval(function () {\n if (!_this14.messages[msgIdx]) return; // Phase 1: 逐字展示思考内容\n\n if (thinkDisplayed < thinkingBuffer.length) {\n thinkDisplayed += 50;\n if (thinkDisplayed > thinkingBuffer.length) thinkDisplayed = thinkingBuffer.length;\n _this14.messages[msgIdx].thinking = thinkingBuffer.substring(0, thinkDisplayed);\n\n _this14.scrollToBottom();\n } // Phase 2: 渲染答案内容\n\n\n var msg = _this14.messages[msgIdx]; // TokUI 活跃期间始终用 answerBuffer(避免 finalContent 带 ```tokui 围栏导致内容跳变)\n\n var target = msg._tokuiStream ? answerBuffer : finalContent || answerBuffer;\n var prevLen = msg._tokuiPrevLen || 0;\n\n if (target.length > prevLen) {\n msg._tokuiPrevLen = target.length; // 检测内容是否包含 TokUI 标记(```tokui 围栏 或 纯 DSL 标签开头)\n\n var hasTokuiMarker = msg._tokuiStream || _this14._isPureTokuiDsl(target) || target.indexOf('```tokui') !== -1;\n\n if (hasTokuiMarker && !msg._hasTokuiFailed) {\n // ── TokUI 路径 ──\n if (!msg._tokuiStream) {\n var container = _this14.$refs.messagesRef;\n\n if (container) {\n var rows = container.querySelectorAll('.msg-row.assistant');\n var lastRow = rows[rows.length - 1];\n var tokuiDiv = lastRow === null || lastRow === void 0 ? void 0 : lastRow.querySelector('.tokui-stream');\n var TokUIConstructor = resolveTokUIConstructor();\n\n if (tokuiDiv && TokUIConstructor) {\n try {\n msg._tokuiDiv = tokuiDiv;\n msg._tokuiStream = new TokUIConstructor({\n container: tokuiDiv\n });\n\n msg._tokuiStream.startStream();\n\n tokuiDiv.classList.add('tokui-streaming');\n msg._tokuiPureDsl = _this14._isPureTokuiDsl(target);\n msg._mdTagOpen = false;\n msg._prevMdLen = 0;\n msg._prevDslLen = 0;\n msg._dslBuffer = '';\n\n _this14.$set(msg, '_hasTokui', true);\n } catch (e) {\n console.error('[TokUI] init error:', e);\n msg._hasTokuiFailed = true;\n msg._tokuiStream = null;\n }\n } else {\n msg._hasTokuiFailed = true;\n }\n }\n }\n\n if (msg._tokuiStream) {\n _this14._streamTokui(msg, target);\n } else if (msg._hasTokuiFailed) {\n // TokUI 初始化失败,回退到普通渲染\n msg.content = target;\n }\n } else {\n // ── 普通渲染路径(保持原有逻辑不变)──\n msg.content = target;\n }\n\n _this14.scrollToBottom();\n\n return;\n } // Phase 3: 流结束 → 收尾\n\n\n if (streamDone) {\n clearInterval(typeTimer);\n typeTimer = null;\n var key = _this14.messages[msgIdx]._key;\n\n if (key) {\n _this14.$delete(_this14.contentCache, key);\n\n _this14.$delete(_this14.contentCache, key + '_t');\n }\n\n if (msg._tokuiStream) {\n // TokUI 路径:关闭 [md] 标签、刷新 DSL 缓冲区、结束流\n try {\n if (msg._mdTagOpen) {\n msg._tokuiStream.feed('[/md]\\n');\n\n msg._mdTagOpen = false;\n }\n\n if (msg._dslBuffer) {\n msg._tokuiStream.feed(msg._dslBuffer + '\\n');\n\n msg._dslBuffer = '';\n }\n\n msg._tokuiStream.endStream();\n } catch (e) {\n console.error('[TokUI] endStream error:', e);\n } // 标记已渲染,防止 _renderTokuiMessages 重复创建实例\n\n\n if (msg._tokuiDiv) {\n msg._tokuiDiv._tokuiRendered = true;\n }\n\n msg._tokuiStream = null; // 使用 $set 确保响应式\n\n _this14.$set(_this14.messages[msgIdx], '_tokuiRendered', true);\n }\n\n _this14.messages[msgIdx].content = finalContent;\n _this14.messages[msgIdx].thinking = thinkingBuffer;\n _this14.messages[msgIdx].loading = false;\n _this14.sending = false;\n\n _this14.clearWaitTimer();\n\n _this14.scrollToBottom();\n\n _this14.$emit('session-refresh');\n\n _this14.$emit('message-sent');\n }\n }, 30);\n url = (0, _apichat.createStreamUrl)(_this14.activeSessionId, text);\n\n if (_this14.eventSource) {\n _this14.eventSource.close();\n }\n\n _this14.eventSource = new EventSource(url);\n es = _this14.eventSource;\n es.addEventListener('reasoning', function (e) {\n if (e.data) {\n var chunk = e.data;\n var cleanChunk = chunk.replace(/([a-z])([A-Z])/g, '$1 $2').replace(/([A-Z]+)([A-Z][a-z])/g, '$1 $2').replace(/([a-zA-Z])([\\u4e00-\\u9fff])/g, '$1 $2').replace(/([\\u4e00-\\u9fff])([a-zA-Z])/g, '$1 $2').replace(/([a-zA-Z])(\\d)/g, '$1 $2').replace(/(\\d)([a-zA-Z])/g, '$1 $2').replace(/\\s+([:,.!?])/g, '$1').replace(/([:,.!?])\\s+/g, '$1 ');\n cleanChunk = cleanChunk.replace(/\\s+/g, ' ');\n var lastChar = thinkingBuffer.slice(-1);\n var firstChar = cleanChunk.slice(0, 1);\n\n var isLetter = function isLetter(c) {\n return /[a-zA-Z]/.test(c);\n };\n\n if (isLetter(lastChar) && isLetter(firstChar)) {\n thinkingBuffer += ' ' + cleanChunk;\n } else {\n thinkingBuffer += cleanChunk;\n }\n }\n });\n es.addEventListener('reasoning_result', function (e) {\n if (e.data) {\n thinkingBuffer = e.data;\n }\n });\n es.addEventListener('answer', function (e) {\n if (e.data) {\n answerBuffer += e.data.replace(/([a-zA-Z]+)([\\u4e00-\\u9fff])/g, '$1 $2').replace(/([\\u4e00-\\u9fff])([a-zA-Z]+)/g, '$1 $2').replace(/([a-z])([A-Z])/g, '$1 $2').replace(/([A-Z]+)([A-Z][a-z])/g, '$1 $2').replace(/([a-zA-Z])(\\d)/g, '$1 $2').replace(/(\\d)([a-zA-Z])/g, '$1 $2');\n }\n });\n es.addEventListener('tool_result', function (e) {\n if (e.data && _this14.messages[msgIdx]) {\n if (!_this14.messages[msgIdx].toolCalls) _this14.messages[msgIdx].toolCalls = [];\n\n _this14.messages[msgIdx].toolCalls.push(e.data);\n\n _this14.scrollToBottom();\n }\n });\n es.addEventListener('agent_result', function (e) {\n finalContent = e.data || '';\n streamDone = true;\n es.close();\n _this14.eventSource = null;\n });\n\n es.onerror = function (err) {\n console.log('[SSE] onerror', err);\n if (thinkingBuffer.length > 0 && !streamDone) finalContent = thinkingBuffer;\n if (!streamDone) finalContent = '❌ 连接中断';\n streamDone = true;\n es.close();\n _this14.eventSource = null;\n };\n\n case 31:\n case \"end\":\n return _context4.stop();\n }\n }\n }, _callee4);\n }))();\n },\n stopAgent: function stopAgent() {\n if (this.eventSource) {\n this.eventSource.close();\n this.eventSource = null;\n }\n\n if (this.activeSessionId) {\n (0, _apichat.stopStream)(this.activeSessionId).catch(function () {});\n }\n\n if (this.messages.length > 0) {\n var last = this.messages[this.messages.length - 1];\n\n if (last && last.loading) {\n last.content = last.content || last.thinking || '⏹ 已停止';\n last.loading = false;\n this.$delete(this.contentCache, last._key);\n }\n }\n\n this.sending = false;\n this.clearWaitTimer();\n },\n scrollToTop: function scrollToTop() {\n var el = this.$refs.messagesRef;\n if (el) el.scrollTop = 0;\n },\n scrollToBottom: function scrollToBottom() {\n var _this15 = this;\n\n var force = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false;\n if (this.showDownBtn && !force) return;\n this.$nextTick(function () {\n var el = _this15.$refs.messagesRef;\n\n if (el) {\n el.scrollTop = el.scrollHeight;\n _this15.lastScrollTop = el.scrollTop;\n _this15.showDownBtn = false;\n _this15._userScrolledUp = false;\n }\n });\n },\n scrollToBottomOnce: function scrollToBottomOnce() {\n var _this16 = this;\n\n clearTimeout(this._scrollTimer);\n this.$nextTick(function () {\n var tryScroll = function tryScroll() {\n var el = _this16.$refs.messagesRef;\n\n if (!el) {\n _this16._scrollTimer = setTimeout(tryScroll, 50);\n return;\n }\n\n var originalScrollBehavior = el.style.scrollBehavior;\n el.style.scrollBehavior = 'auto';\n el.scrollTop = el.scrollHeight - el.clientHeight;\n el.style.scrollBehavior = originalScrollBehavior;\n _this16.showDownBtn = false;\n _this16._userScrolledUp = false;\n };\n\n tryScroll();\n });\n },\n copyText: function copyText(content) {\n var _this17 = this;\n\n if (!content) return;\n var text = content.replace(/<[^>]+>/g, ''); // 优先使用 Clipboard API(HTTPS 环境)\n\n if (navigator.clipboard && navigator.clipboard.writeText) {\n navigator.clipboard.writeText(text).then(function () {\n _this17.$message({\n message: '已复制到剪贴板',\n type: 'success',\n duration: 1500\n });\n }).catch(function () {\n _this17._fallbackCopyText(text);\n });\n } else {\n this._fallbackCopyText(text);\n }\n },\n _fallbackCopyText: function _fallbackCopyText(text) {\n try {\n var ta = document.createElement('textarea');\n ta.value = text;\n ta.style.cssText = 'position:fixed;left:-9999px;top:0;opacity:0';\n document.body.appendChild(ta);\n ta.focus();\n ta.select();\n document.execCommand('copy');\n document.body.removeChild(ta);\n this.$message({\n message: '已复制到剪贴板',\n type: 'success',\n duration: 1500\n });\n } catch (_unused3) {\n this.$message({\n message: '复制失败',\n type: 'error',\n duration: 2000\n });\n }\n },\n copyAsImage: function copyAsImage(content) {\n var _this18 = this;\n\n if (!content) return;\n var div = document.createElement('div');\n div.className = 'copy-image-render';\n div.style.cssText = 'position:fixed;left:-9999px;top:0;width:600px;padding:20px;background:#fff;font-size:14px;line-height:1.6;color:#333;border-radius:8px;font-family:-apple-system,BlinkMacSystemFont,sans-serif;'; // 内联表格样式(因 Vue 作用域样式不覆盖复制用的脱离文档流 div)\n\n div.innerHTML = this.renderMarkdown(content) + '<style>table{border-collapse:collapse;width:100%;margin:6px 0;font-size:14px}' + 'th,td{border:1px solid #e8e8e8;padding:5px 8px;text-align:left}' + 'th{background:#fafafa;font-weight:600}</style>';\n document.body.appendChild(div);\n this.$message({\n message: '正在生成图片...',\n type: 'info',\n duration: 2000\n });\n (0, _html2canvas.default)(div, {\n scale: 2,\n useCORS: true,\n backgroundColor: '#ffffff'\n }).then(function (canvas) {\n var base64 = canvas.toDataURL('image/png'); // 移动端:调用原生方法保存到本地相册\n\n if (_this18.isMobile) {\n if (_this18.$hybrid && typeof _this18.$hybrid.savePic2Library === 'function') {\n _this18.$hybrid.savePic2Library(base64, function () {\n _this18.$message({\n message: '图片已保存到本地相册',\n type: 'success',\n duration: 1500\n });\n });\n } else {\n // fallback:展示图片让用户长按保存\n _this18.previewImage = base64;\n\n _this18.$message({\n message: '长按图片可保存到本地',\n type: 'info',\n duration: 3000\n });\n }\n\n return;\n } // PC端:复制到剪贴板\n\n\n var canCopyImage = typeof ClipboardItem !== 'undefined' && navigator.clipboard && typeof navigator.clipboard.write === 'function';\n\n if (!canCopyImage) {\n _this18.$message({\n message: '当前浏览器不支持复制图片',\n type: 'warning',\n duration: 3000\n });\n\n return;\n }\n\n canvas.toBlob(function (blob) {\n if (!blob) {\n _this18.$message({\n message: '生成图片失败',\n type: 'error',\n duration: 2000\n });\n\n return;\n }\n\n navigator.clipboard.write([new ClipboardItem({\n 'image/png': blob\n })]).then(function () {\n _this18.$message({\n message: '图片已复制到剪贴板',\n type: 'success',\n duration: 1500\n });\n }).catch(function () {\n _this18.$message({\n message: '复制失败,请重试',\n type: 'error',\n duration: 2000\n });\n });\n }, 'image/png');\n }).catch(function () {\n _this18.$message({\n message: '生成图片失败',\n type: 'error',\n duration: 2000\n });\n }).finally(function () {\n document.body.removeChild(div);\n });\n }\n }\n};\nexports.default = _default2;\n\n//# sourceURL=webpack://ZjPluginIntelligent/./src/lib/components/chatMain/ChatDetail.vue?./node_modules/cache-loader/dist/cjs.js??ref--12-0!./node_modules/babel-loader/lib!./node_modules/cache-loader/dist/cjs.js??ref--0-0!./node_modules/vue-loader/lib??vue-loader-options");
841
841
 
842
842
  /***/ }),
843
843
 
@@ -933,7 +933,7 @@ eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export (binding) *
933
933
  /***/ (function(module, __webpack_exports__, __webpack_require__) {
934
934
 
935
935
  "use strict";
936
- eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"render\", function() { return render; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"staticRenderFns\", function() { return staticRenderFns; });\nvar render = function() {\n var _vm = this\n var _h = _vm.$createElement\n var _c = _vm._self._c || _h\n return _c(\"div\", { staticClass: \"chat-main\" }, [\n _c(\"div\", { staticClass: \"chat-header\" }, [\n _c(\"div\", { staticClass: \"header-left\" }, [\n _vm.isMobile && _vm.activeSessionId\n ? _c(\n \"button\",\n {\n staticClass: \"mobile-back-btn\",\n attrs: { type: \"button\" },\n on: {\n click: function($event) {\n return _vm.$emit(\"go-back-to-list\")\n }\n }\n },\n [\n _c(\n \"svg\",\n {\n attrs: {\n width: \"20\",\n height: \"20\",\n viewBox: \"0 0 24 24\",\n fill: \"none\"\n }\n },\n [\n _c(\"path\", {\n attrs: {\n d: \"M15 18l-6-6 6-6\",\n stroke: \"currentColor\",\n \"stroke-width\": \"2\",\n \"stroke-linecap\": \"round\",\n \"stroke-linejoin\": \"round\"\n }\n })\n ]\n )\n ]\n )\n : _vm.isMobile\n ? _c(\n \"button\",\n {\n staticClass: \"mobile-menu-btn\",\n attrs: { type: \"button\" },\n on: {\n click: function($event) {\n return _vm.$emit(\"toggle-sidebar\")\n }\n }\n },\n [\n _c(\n \"svg\",\n {\n attrs: {\n width: \"20\",\n height: \"20\",\n viewBox: \"0 0 24 24\",\n fill: \"none\"\n }\n },\n [\n _c(\"path\", {\n attrs: {\n d: \"M3 6h18M3 12h18M3 18h18\",\n stroke: \"currentColor\",\n \"stroke-width\": \"2\",\n \"stroke-linecap\": \"round\"\n }\n })\n ]\n )\n ]\n )\n : _vm._e(),\n _vm.currentAgent && (_vm.activeSessionId || _vm.messages.length > 0)\n ? _c(\"div\", { staticClass: \"agent-info\" }, [\n _c(\"div\", { staticClass: \"chat-agent-avatar-wrapper\" }, [\n _c(\n \"div\",\n {\n staticClass: \"agent-list-avatar session-avatar\",\n class: { \"has-agent-img\": _vm.agentInfo.avatar },\n style: {\n background:\n _vm.agentInfo.color ||\n \"linear-gradient(135deg, #1677ff, #4096ff)\"\n }\n },\n [\n _vm.agentInfo.avatar\n ? _c(\"img\", {\n staticClass: \"avatar-pic\",\n attrs: { src: _vm.agentInfo.avatar, alt: \"\" }\n })\n : [\n _vm._v(\n _vm._s(\n _vm.getInitial(\n _vm.agentInfo.agentName ||\n _vm.agentInfo.agentCode\n )\n )\n )\n ]\n ],\n 2\n )\n ]),\n _c(\"div\", { staticClass: \"agent-text\" }, [\n _c(\"div\", { staticClass: \"agent-name\" }, [\n _vm._v(_vm._s(_vm.currentAgentName))\n ]),\n _c(\"div\", { staticClass: \"agent-desc\" }, [\n _vm._v(_vm._s(_vm.currentAgentDesc))\n ])\n ])\n ])\n : _c(\"div\", { staticClass: \"agent-info\" }, [_vm._m(0)])\n ]),\n _vm.isMobile && !_vm.activeSessionId\n ? _c(\"div\", { staticClass: \"header-actions\" }, [\n _c(\n \"button\",\n {\n staticClass: \"mobile-header-btn\",\n attrs: { type: \"button\" },\n on: {\n click: function($event) {\n return _vm.$emit(\"agent-jump-click\")\n }\n }\n },\n [\n _c(\n \"svg\",\n {\n attrs: {\n width: \"20\",\n height: \"20\",\n viewBox: \"0 0 24 24\",\n fill: \"currentColor\"\n }\n },\n [\n _c(\"path\", {\n attrs: {\n d:\n \"M12 3C6.5 3 2 6.58 2 11c0 2.03.95 3.88 2.5 5.3L3 21l4.6-1.7c1.36.45 2.86.7 4.4.7 5.5 0 10-3.58 10-8s-4.5-8-10-8z\"\n }\n }),\n _c(\"circle\", {\n attrs: { cx: \"8\", cy: \"11\", r: \"1.3\", fill: \"#fff\" }\n }),\n _c(\"circle\", {\n attrs: { cx: \"12\", cy: \"11\", r: \"1.3\", fill: \"#fff\" }\n }),\n _c(\"circle\", {\n attrs: { cx: \"16\", cy: \"11\", r: \"1.3\", fill: \"#fff\" }\n })\n ]\n )\n ]\n )\n ])\n : _vm._e()\n ]),\n _c(\n \"div\",\n {\n ref: \"messagesRef\",\n staticClass: \"chat-body\",\n on: { scroll: _vm.onScrollMessages }\n },\n [\n !_vm.activeSessionId\n ? _c(\"div\", { staticClass: \"welcome welcome-default\" }, [\n _c(\"div\", { staticClass: \"welcome-icon\" }, [\n _c(\n \"svg\",\n {\n attrs: { viewBox: \"0 0 48 48\", width: \"64\", height: \"64\" }\n },\n [\n _c(\"path\", {\n attrs: {\n fill: \"#e6f4ff\",\n d:\n \"M40 22c-2.21 0-4 1.79-4 4v10H12c-2.21 0-4-1.79-4-4V14c0-2.21 1.79-4 4-4h24c2.21 0 4 1.79 4 4v8z\"\n }\n }),\n _c(\"path\", {\n attrs: {\n fill: \"#1677ff\",\n d:\n \"M36 8c-2.21 0-4 1.79-4 4v18H8c-2.21 0-4-1.79-4-4V12c0-2.21 1.79-4 4-4h28z\"\n }\n }),\n _c(\"circle\", {\n attrs: { cx: \"20\", cy: \"28\", r: \"3\", fill: \"#fff\" }\n }),\n _c(\"circle\", {\n attrs: { cx: \"28\", cy: \"28\", r: \"3\", fill: \"#fff\" }\n })\n ]\n )\n ]),\n _c(\"div\", { staticClass: \"welcome-title\" }, [\n _vm._v(\"欢迎使用 AI 助手\")\n ]),\n _c(\"div\", { staticClass: \"welcome-text\" }, [\n _vm._v(\"从左侧选择一个会话,或搜索助手开始新的对话\")\n ])\n ])\n : _vm.messages.length === 0 && !_vm.loadingSessionMsg\n ? _c(\"div\", { staticClass: \"chat-empty-welcome\" }, [\n _vm.agentInfo.hasOwnProperty(\"agentCode\")\n ? _c(\"div\", { staticClass: \"welcome-card\" }, [\n _c(\"div\", { staticClass: \"welcome-avatar-box\" }, [\n _c(\n \"div\",\n {\n staticClass: \"welcome-avatar\",\n class: { \"has-chat-agent-img\": _vm.agentInfo.avatar },\n style: _vm.getChatAvatarStyle(\n _vm.currentAgent,\n _vm.agentInfo.avatar\n )\n },\n [\n !_vm.agentInfo.avatar\n ? [\n _vm._v(\n _vm._s(_vm.getInitial(_vm.currentAgentName))\n )\n ]\n : _vm._e()\n ],\n 2\n )\n ]),\n _c(\"div\", { staticClass: \"welcome-text-group\" }, [\n _c(\"div\", { staticClass: \"text-sm\" }, [\n _vm._v(\"您好,我是\" + _vm._s(_vm.currentAgentName))\n ]),\n _c(\"div\", { staticClass: \"text-lg\" }, [\n _vm._v(_vm._s(_vm.greeting))\n ])\n ])\n ])\n : _vm._e(),\n _c(\"div\", { staticClass: \"guess-box\" }, [\n _c(\"div\", { staticClass: \"guess-title\" }, [\n _c(\n \"svg\",\n {\n attrs: {\n width: \"16\",\n height: \"16\",\n viewBox: \"0 0 24 24\",\n fill: \"#1677ff\"\n }\n },\n [\n _c(\"path\", {\n attrs: {\n d:\n \"M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm0 18c-4.41 0-8-3.59-8-8s3.59-8 8-8 8 3.59 8 8-3.59 8-8 8zm-1-13h2v6h-2zm0 8h2v2h-2z\"\n }\n })\n ]\n ),\n _c(\"span\", [_vm._v(\"猜您想问\")])\n ]),\n _c(\n \"div\",\n { staticClass: \"tag-wrap\" },\n _vm._l(_vm.agentInfo.suggestedQuestions, function(tag) {\n return _c(\n \"div\",\n {\n key: tag,\n staticClass: \"quick-tag\",\n on: {\n click: function($event) {\n return _vm.sendQuickMsg(tag)\n }\n }\n },\n [_vm._v(\" \" + _vm._s(tag) + \" \")]\n )\n }),\n 0\n )\n ])\n ])\n : _vm._e(),\n _vm._l(_vm.messages, function(m) {\n return _c(\n \"div\",\n { key: m.id, staticClass: \"msg-row\", class: m.role },\n [\n _c(\"div\", { staticClass: \"msg-main\" }, [\n _c(\"div\", { staticClass: \"msg-content\" }, [\n _c(\"div\", { staticClass: \"bubble\", class: m.role }, [\n m.role === \"user\" && m._sttStatus\n ? _c(\"div\", { staticClass: \"stt-bubble-wrap\" }, [\n m._sttStatus === \"pending\"\n ? _c(\"span\", {\n staticClass: \"stt-spinner stt-outside-icon\"\n })\n : m._sttStatus === \"error\"\n ? _c(\n \"span\",\n {\n staticClass: \"stt-error-icon stt-outside-icon\"\n },\n [_vm._v(\"!\")]\n )\n : _vm._e(),\n _c(\"span\", { staticClass: \"stt-bubble-text\" }, [\n _vm._v(\n _vm._s(\n m._sttStatus === \"pending\"\n ? \"转化中...\"\n : \"语音转文字失败\"\n )\n )\n ])\n ])\n : _vm._e(),\n !m._sttStatus && m.thinking\n ? _c(\n \"details\",\n {\n staticClass: \"thinking-details\",\n attrs: { open: \"\" }\n },\n [\n _c(\"summary\", { staticClass: \"thinking-summary\" }, [\n _vm._v(\"💭 思考过程\")\n ]),\n _c(\"div\", {\n staticClass: \"thinking-body\",\n domProps: {\n innerHTML: _vm._s(_vm.escapeHtml(m.thinking))\n }\n })\n ]\n )\n : _vm._e(),\n m.role === \"assistant\" &&\n !m._sttStatus &&\n m.content &&\n !m._hasTokui &&\n m.loading\n ? _c(\"div\", {\n staticClass: \"final-content\",\n domProps: {\n innerHTML: _vm._s(\n _vm.renderStreaming(m.content, m._key)\n )\n }\n })\n : _vm._e(),\n m.role === \"assistant\" &&\n !m._sttStatus &&\n m.content &&\n !m._hasTokui &&\n !m.loading\n ? _c(\"div\", {\n staticClass: \"final-content\",\n domProps: {\n innerHTML: _vm._s(_vm.renderMarkdown(m.content))\n }\n })\n : _vm._e(),\n _c(\n \"div\",\n {\n directives: [\n {\n name: \"show\",\n rawName: \"v-show\",\n value:\n m.role === \"assistant\" &&\n !m._sttStatus &&\n m._hasTokui,\n expression:\n \"m.role === 'assistant' && !m._sttStatus && m._hasTokui\"\n }\n ],\n staticClass: \"final-content tokui-shell\"\n },\n [_c(\"div\", { staticClass: \"tokui-stream\" })]\n ),\n m.role === \"user\" && !m._sttStatus && m.content && m.loading\n ? _c(\"div\", {\n staticClass: \"final-content\",\n domProps: {\n innerHTML: _vm._s(\n _vm.renderStreaming(m.content, m._key)\n )\n }\n })\n : _vm._e(),\n m.role === \"user\" &&\n !m._sttStatus &&\n m.content &&\n !m.loading\n ? _c(\"div\", {\n staticClass: \"final-content\",\n domProps: {\n innerHTML: _vm._s(_vm.renderMarkdown(m.content))\n }\n })\n : _vm._e(),\n _c(\n \"div\",\n {\n directives: [\n {\n name: \"show\",\n rawName: \"v-show\",\n value:\n !m._sttStatus &&\n _vm.showToolInfo &&\n m.toolCalls &&\n m.toolCalls.length,\n expression:\n \"!m._sttStatus && showToolInfo && m.toolCalls && m.toolCalls.length\"\n }\n ],\n staticClass: \"tool-calls\"\n },\n _vm._l(m.toolCalls, function(tc, ti) {\n return _c(\n \"div\",\n { key: ti, staticClass: \"tool-item\" },\n [\n _c(\"span\", { staticClass: \"tool-badge\" }, [\n _vm._v(\"工具返回\")\n ]),\n _c(\"pre\", [\n _vm._v(\n _vm._s(tc.substring(0, 300)) +\n _vm._s(tc.length > 300 ? \"...\" : \"\")\n )\n ])\n ]\n )\n }),\n 0\n ),\n m.loading\n ? _c(\n \"div\",\n { staticClass: \"typing\", class: _vm.waitClass },\n [\n _c(\"span\", { staticClass: \"phrase\" }, [\n _vm._v(\"思考中\")\n ]),\n _vm._m(1, true)\n ]\n )\n : _vm._e()\n ]),\n m.role === \"assistant\" && m.content && !m.loading\n ? _c(\"div\", { staticClass: \"msg-actions\" }, [\n _c(\n \"span\",\n {\n staticClass: \"action-btn\",\n attrs: { title: \"复制\" },\n on: {\n click: function($event) {\n return _vm.copyText(m.content)\n }\n }\n },\n [_vm._v(\"📋 复制\")]\n ),\n _c(\n \"span\",\n {\n staticClass: \"action-btn\",\n attrs: { title: \"复制为图片\" },\n on: {\n click: function($event) {\n return _vm.copyAsImage(m.content)\n }\n }\n },\n [_vm._v(\"🖼 复制为图片\")]\n ),\n _c(\"span\", { staticClass: \"ai-badge\" }, [\n _vm._v(\"AI 生成(仅供参考)\")\n ])\n ])\n : _vm._e()\n ])\n ])\n ]\n )\n })\n ],\n 2\n ),\n _c(\"div\", { staticClass: \"chat-footer\" }, [\n _c(\n \"div\",\n { staticClass: \"input-area\" },\n [\n !_vm.voiceMode || !_vm.isMobile\n ? [\n _c(\"textarea\", {\n directives: [\n {\n name: \"model\",\n rawName: \"v-model\",\n value: _vm.inputText,\n expression: \"inputText\"\n }\n ],\n ref: \"taRef\",\n staticClass: \"chat-textarea\",\n attrs: {\n placeholder: \"请输入消息\",\n maxlength: \"300\",\n disabled: _vm.sending\n },\n domProps: { value: _vm.inputText },\n on: {\n input: [\n function($event) {\n if ($event.target.composing) {\n return\n }\n _vm.inputText = $event.target.value\n },\n _vm.autoResizeTextarea\n ],\n focus: _vm.onInputFocus,\n keydown: [\n function($event) {\n if (\n !$event.type.indexOf(\"key\") &&\n _vm._k(\n $event.keyCode,\n \"enter\",\n 13,\n $event.key,\n \"Enter\"\n )\n ) {\n return null\n }\n if (\n $event.ctrlKey ||\n $event.shiftKey ||\n $event.altKey ||\n $event.metaKey\n ) {\n return null\n }\n $event.preventDefault()\n _vm.isMobile ? _vm.newLine($event) : _vm.sendMessage()\n },\n function($event) {\n if (\n !$event.type.indexOf(\"key\") &&\n _vm._k(\n $event.keyCode,\n \"enter\",\n 13,\n $event.key,\n \"Enter\"\n )\n ) {\n return null\n }\n if (!$event.ctrlKey) {\n return null\n }\n return _vm.newLine.apply(null, arguments)\n }\n ]\n }\n }),\n !_vm.sending\n ? _c(\n \"button\",\n {\n staticClass: \"send-btn\",\n class: { active: _vm.inputText.trim() },\n attrs: {\n disabled: _vm.sending || !_vm.inputText.trim()\n },\n on: { click: _vm.sendMessage }\n },\n [\n _c(\n \"svg\",\n {\n attrs: {\n viewBox: \"0 0 24 24\",\n width: \"20\",\n height: \"20\",\n fill: \"currentColor\"\n }\n },\n [\n _c(\"path\", {\n attrs: {\n d: \"M2.01 21L23 12 2.01 3 2 10l15 2-15 2z\"\n }\n })\n ]\n )\n ]\n )\n : _vm._e(),\n _vm.sending\n ? _c(\n \"button\",\n { staticClass: \"stop-btn\", on: { click: _vm.stopAgent } },\n [\n _c(\n \"svg\",\n {\n attrs: {\n viewBox: \"0 0 24 24\",\n width: \"18\",\n height: \"18\",\n fill: \"currentColor\"\n }\n },\n [\n _c(\"rect\", {\n attrs: {\n x: \"6\",\n y: \"6\",\n width: \"12\",\n height: \"12\",\n rx: \"2\"\n }\n })\n ]\n )\n ]\n )\n : _vm._e()\n ]\n : [\n _c(\n \"div\",\n {\n staticClass: \"hold-talk-btn\",\n class: { recording: _vm.isRecording },\n on: {\n touchstart: function($event) {\n $event.preventDefault()\n return _vm.onRecordTouchStart($event)\n },\n touchmove: function($event) {\n $event.preventDefault()\n return _vm.onRecordTouchMove($event)\n },\n touchend: function($event) {\n $event.preventDefault()\n return _vm.onRecordTouchEnd.apply(null, arguments)\n }\n }\n },\n [\n !_vm.isRecording\n ? _c(\n \"svg\",\n {\n staticClass: \"hold-talk-icon\",\n attrs: {\n viewBox: \"0 0 24 24\",\n width: \"18\",\n height: \"18\",\n fill: \"currentColor\"\n }\n },\n [\n _c(\"path\", {\n attrs: {\n d:\n \"M12 14a3 3 0 003-3V5a3 3 0 00-6 0v6a3 3 0 003 3z\"\n }\n }),\n _c(\"path\", {\n attrs: {\n d: \"M17 11a5 5 0 01-10 0H5a7 7 0 0014 0h-2z\"\n }\n }),\n _c(\"rect\", {\n attrs: {\n x: \"11\",\n y: \"17\",\n width: \"2\",\n height: \"4\",\n rx: \"1\"\n }\n })\n ]\n )\n : _vm._e(),\n _c(\"span\", [\n _vm._v(\n _vm._s(\n _vm.isRecording\n ? _vm.isCancelSwipe\n ? \"松开取消\"\n : \"松手发送\"\n : \"按住说话\"\n )\n )\n ])\n ]\n ),\n _vm.sending\n ? _c(\n \"button\",\n { staticClass: \"stop-btn\", on: { click: _vm.stopAgent } },\n [\n _c(\n \"svg\",\n {\n attrs: {\n viewBox: \"0 0 24 24\",\n width: \"18\",\n height: \"18\",\n fill: \"currentColor\"\n }\n },\n [\n _c(\"rect\", {\n attrs: {\n x: \"6\",\n y: \"6\",\n width: \"12\",\n height: \"12\",\n rx: \"2\"\n }\n })\n ]\n )\n ]\n )\n : _vm._e()\n ],\n _vm.showDownBtn && _vm.messages.length !== 0\n ? _c(\"div\", { staticClass: \"scroll-bottom-wrap\" }, [\n _c(\n \"div\",\n {\n staticClass: \"scroll-bottom-btn\",\n on: {\n click: function($event) {\n return _vm.scrollToBottom(true)\n }\n }\n },\n [\n _vm.sending\n ? _c(\"div\", { staticClass: \"loading-circle\" })\n : _vm._e(),\n _c(\n \"svg\",\n {\n attrs: {\n width: \"14\",\n height: \"14\",\n viewBox: \"0 0 24 24\",\n fill: \"none\"\n }\n },\n [\n _c(\"path\", {\n attrs: {\n d: \"M6 9l6 6 6-6\",\n stroke: \"currentColor\",\n \"stroke-width\": \"2\",\n \"stroke-linecap\": \"round\",\n \"stroke-linejoin\": \"round\"\n }\n })\n ]\n )\n ]\n )\n ])\n : _vm._e()\n ],\n 2\n )\n ]),\n _vm.isRecording\n ? _c(\"div\", { staticClass: \"voice-recording-overlay\" }, [\n _c(\"div\", { staticClass: \"voice-recording-card\" }, [\n _vm._m(2),\n _c(\"div\", { staticClass: \"voice-recording-duration\" }, [\n _vm._v(_vm._s(_vm.recordDuration)),\n _c(\"span\", { staticClass: \"unit\" }, [_vm._v(\"s\")])\n ]),\n _c(\n \"div\",\n {\n staticClass: \"voice-recording-hint\",\n class: { cancel: _vm.isCancelSwipe }\n },\n [\n _vm.isCancelSwipe\n ? _c(\n \"svg\",\n {\n attrs: {\n viewBox: \"0 0 24 24\",\n width: \"16\",\n height: \"16\",\n fill: \"#ff4d4f\"\n }\n },\n [\n _c(\"path\", {\n attrs: {\n d:\n \"M12 2C6.47 2 2 6.47 2 12s4.47 10 10 10 10-4.47 10-10S17.53 2 12 2zm5 13.59L15.59 17 12 13.41 8.41 17 7 15.59 10.59 12 7 8.41 8.41 7 12 10.59 15.59 7 17 8.41 13.41 12 17 15.59z\"\n }\n })\n ]\n )\n : _c(\n \"svg\",\n {\n attrs: {\n viewBox: \"0 0 24 24\",\n width: \"16\",\n height: \"16\",\n fill: \"#999\"\n }\n },\n [\n _c(\"path\", {\n attrs: {\n d:\n \"M12 4l-1.41 1.41L16.17 11H4v2h12.17l-5.58 5.59L12 20l8-8z\"\n }\n })\n ]\n ),\n _vm._v(\n \" \" +\n _vm._s(\n _vm.isCancelSwipe ? \"松开取消发送\" : \"手指上滑 取消发送\"\n ) +\n \" \"\n )\n ]\n )\n ])\n ])\n : _vm._e()\n ])\n}\nvar staticRenderFns = [\n function() {\n var _vm = this\n var _h = _vm.$createElement\n var _c = _vm._self._c || _h\n return _c(\"div\", { staticClass: \"agent-text\" }, [\n _c(\"div\", { staticClass: \"agent-name\", staticStyle: { color: \"#bbb\" } }, [\n _vm._v(\"请选择助手\")\n ])\n ])\n },\n function() {\n var _vm = this\n var _h = _vm.$createElement\n var _c = _vm._self._c || _h\n return _c(\"span\", { staticClass: \"dots\" }, [\n _c(\"span\"),\n _c(\"span\"),\n _c(\"span\")\n ])\n },\n function() {\n var _vm = this\n var _h = _vm.$createElement\n var _c = _vm._self._c || _h\n return _c(\"div\", { staticClass: \"voice-recording-wave\" }, [\n _c(\"span\"),\n _c(\"span\"),\n _c(\"span\"),\n _c(\"span\"),\n _c(\"span\")\n ])\n }\n]\nrender._withStripped = true\n\n\n\n//# sourceURL=webpack://ZjPluginIntelligent/./src/lib/components/chatMain/ChatDetail.vue?./node_modules/cache-loader/dist/cjs.js?%7B%22cacheDirectory%22:%22node_modules/.cache/vue-loader%22,%22cacheIdentifier%22:%2268609640-vue-loader-template%22%7D!./node_modules/vue-loader/lib/loaders/templateLoader.js??vue-loader-options!./node_modules/cache-loader/dist/cjs.js??ref--0-0!./node_modules/vue-loader/lib??vue-loader-options");
936
+ eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"render\", function() { return render; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"staticRenderFns\", function() { return staticRenderFns; });\nvar render = function() {\n var _vm = this\n var _h = _vm.$createElement\n var _c = _vm._self._c || _h\n return _c(\"div\", { staticClass: \"chat-main\" }, [\n _c(\"div\", { staticClass: \"chat-header\" }, [\n _c(\"div\", { staticClass: \"header-left\" }, [\n _vm.isMobile && _vm.activeSessionId\n ? _c(\n \"button\",\n {\n staticClass: \"mobile-back-btn\",\n attrs: { type: \"button\" },\n on: {\n click: function($event) {\n return _vm.$emit(\"go-back-to-list\")\n }\n }\n },\n [\n _c(\n \"svg\",\n {\n attrs: {\n width: \"20\",\n height: \"20\",\n viewBox: \"0 0 24 24\",\n fill: \"none\"\n }\n },\n [\n _c(\"path\", {\n attrs: {\n d: \"M15 18l-6-6 6-6\",\n stroke: \"currentColor\",\n \"stroke-width\": \"2\",\n \"stroke-linecap\": \"round\",\n \"stroke-linejoin\": \"round\"\n }\n })\n ]\n )\n ]\n )\n : _vm.isMobile\n ? _c(\n \"button\",\n {\n staticClass: \"mobile-menu-btn\",\n attrs: { type: \"button\" },\n on: {\n click: function($event) {\n return _vm.$emit(\"toggle-sidebar\")\n }\n }\n },\n [\n _c(\n \"svg\",\n {\n attrs: {\n width: \"20\",\n height: \"20\",\n viewBox: \"0 0 24 24\",\n fill: \"none\"\n }\n },\n [\n _c(\"path\", {\n attrs: {\n d: \"M3 6h18M3 12h18M3 18h18\",\n stroke: \"currentColor\",\n \"stroke-width\": \"2\",\n \"stroke-linecap\": \"round\"\n }\n })\n ]\n )\n ]\n )\n : _vm._e(),\n _vm.currentAgent && (_vm.activeSessionId || _vm.messages.length > 0)\n ? _c(\"div\", { staticClass: \"agent-info\" }, [\n _c(\"div\", { staticClass: \"chat-agent-avatar-wrapper\" }, [\n _c(\n \"div\",\n {\n staticClass: \"agent-list-avatar session-avatar\",\n class: { \"has-agent-img\": _vm.agentInfo.avatar },\n style: {\n background:\n _vm.agentInfo.color ||\n \"linear-gradient(135deg, #1677ff, #4096ff)\"\n }\n },\n [\n _vm.agentInfo.avatar\n ? _c(\"img\", {\n staticClass: \"avatar-pic\",\n attrs: { src: _vm.agentInfo.avatar, alt: \"\" }\n })\n : [\n _vm._v(\n _vm._s(\n _vm.getInitial(\n _vm.agentInfo.agentName ||\n _vm.agentInfo.agentCode\n )\n )\n )\n ]\n ],\n 2\n )\n ]),\n _c(\"div\", { staticClass: \"agent-text\" }, [\n _c(\"div\", { staticClass: \"agent-name\" }, [\n _vm._v(_vm._s(_vm.currentAgentName))\n ]),\n _c(\"div\", { staticClass: \"agent-desc\" }, [\n _vm._v(_vm._s(_vm.currentAgentDesc))\n ])\n ])\n ])\n : _c(\"div\", { staticClass: \"agent-info\" }, [_vm._m(0)])\n ]),\n _vm.isMobile && !_vm.activeSessionId\n ? _c(\"div\", { staticClass: \"header-actions\" }, [\n _c(\n \"button\",\n {\n staticClass: \"mobile-header-btn\",\n attrs: { type: \"button\" },\n on: {\n click: function($event) {\n return _vm.$emit(\"agent-jump-click\")\n }\n }\n },\n [\n _c(\n \"svg\",\n {\n attrs: {\n width: \"20\",\n height: \"20\",\n viewBox: \"0 0 24 24\",\n fill: \"currentColor\"\n }\n },\n [\n _c(\"path\", {\n attrs: {\n d:\n \"M12 3C6.5 3 2 6.58 2 11c0 2.03.95 3.88 2.5 5.3L3 21l4.6-1.7c1.36.45 2.86.7 4.4.7 5.5 0 10-3.58 10-8s-4.5-8-10-8z\"\n }\n }),\n _c(\"circle\", {\n attrs: { cx: \"8\", cy: \"11\", r: \"1.3\", fill: \"#fff\" }\n }),\n _c(\"circle\", {\n attrs: { cx: \"12\", cy: \"11\", r: \"1.3\", fill: \"#fff\" }\n }),\n _c(\"circle\", {\n attrs: { cx: \"16\", cy: \"11\", r: \"1.3\", fill: \"#fff\" }\n })\n ]\n )\n ]\n )\n ])\n : _vm._e()\n ]),\n _c(\n \"div\",\n {\n ref: \"messagesRef\",\n staticClass: \"chat-body\",\n on: { scroll: _vm.onScrollMessages }\n },\n [\n !_vm.activeSessionId\n ? _c(\"div\", { staticClass: \"welcome welcome-default\" }, [\n _c(\"div\", { staticClass: \"welcome-icon\" }, [\n _c(\n \"svg\",\n {\n attrs: { viewBox: \"0 0 48 48\", width: \"64\", height: \"64\" }\n },\n [\n _c(\"path\", {\n attrs: {\n fill: \"#e6f4ff\",\n d:\n \"M40 22c-2.21 0-4 1.79-4 4v10H12c-2.21 0-4-1.79-4-4V14c0-2.21 1.79-4 4-4h24c2.21 0 4 1.79 4 4v8z\"\n }\n }),\n _c(\"path\", {\n attrs: {\n fill: \"#1677ff\",\n d:\n \"M36 8c-2.21 0-4 1.79-4 4v18H8c-2.21 0-4-1.79-4-4V12c0-2.21 1.79-4 4-4h28z\"\n }\n }),\n _c(\"circle\", {\n attrs: { cx: \"20\", cy: \"28\", r: \"3\", fill: \"#fff\" }\n }),\n _c(\"circle\", {\n attrs: { cx: \"28\", cy: \"28\", r: \"3\", fill: \"#fff\" }\n })\n ]\n )\n ]),\n _c(\"div\", { staticClass: \"welcome-title\" }, [\n _vm._v(\"欢迎使用 AI 助手\")\n ]),\n _c(\"div\", { staticClass: \"welcome-text\" }, [\n _vm._v(\"从左侧选择一个会话,或搜索助手开始新的对话\")\n ])\n ])\n : _vm.messages.length === 0 && !_vm.loadingSessionMsg\n ? _c(\"div\", { staticClass: \"chat-empty-welcome\" }, [\n _vm.agentInfo.hasOwnProperty(\"agentCode\")\n ? _c(\"div\", { staticClass: \"welcome-card\" }, [\n _c(\"div\", { staticClass: \"welcome-avatar-box\" }, [\n _c(\n \"div\",\n {\n staticClass: \"welcome-avatar\",\n class: { \"has-chat-agent-img\": _vm.agentInfo.avatar },\n style: _vm.getChatAvatarStyle(\n _vm.currentAgent,\n _vm.agentInfo.avatar\n )\n },\n [\n !_vm.agentInfo.avatar\n ? [\n _vm._v(\n _vm._s(_vm.getInitial(_vm.currentAgentName))\n )\n ]\n : _vm._e()\n ],\n 2\n )\n ]),\n _c(\"div\", { staticClass: \"welcome-text-group\" }, [\n _c(\"div\", { staticClass: \"text-sm\" }, [\n _vm._v(\"您好,我是\" + _vm._s(_vm.currentAgentName))\n ]),\n _c(\"div\", { staticClass: \"text-lg\" }, [\n _vm._v(_vm._s(_vm.greeting))\n ])\n ])\n ])\n : _vm._e(),\n _c(\"div\", { staticClass: \"guess-box\" }, [\n _c(\"div\", { staticClass: \"guess-title\" }, [\n _c(\n \"svg\",\n {\n attrs: {\n width: \"16\",\n height: \"16\",\n viewBox: \"0 0 24 24\",\n fill: \"#1677ff\"\n }\n },\n [\n _c(\"path\", {\n attrs: {\n d:\n \"M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm0 18c-4.41 0-8-3.59-8-8s3.59-8 8-8 8 3.59 8 8-3.59 8-8 8zm-1-13h2v6h-2zm0 8h2v2h-2z\"\n }\n })\n ]\n ),\n _c(\"span\", [_vm._v(\"猜您想问\")])\n ]),\n _c(\n \"div\",\n { staticClass: \"tag-wrap\" },\n _vm._l(_vm.agentInfo.suggestedQuestions, function(tag) {\n return _c(\n \"div\",\n {\n key: tag,\n staticClass: \"quick-tag\",\n on: {\n click: function($event) {\n return _vm.sendQuickMsg(tag)\n }\n }\n },\n [_vm._v(\" \" + _vm._s(tag) + \" \")]\n )\n }),\n 0\n )\n ])\n ])\n : _vm._e(),\n _vm._l(_vm.messages, function(m) {\n return _c(\n \"div\",\n { key: m.id, staticClass: \"msg-row\", class: m.role },\n [\n _c(\"div\", { staticClass: \"msg-main\" }, [\n _c(\"div\", { staticClass: \"msg-content\" }, [\n _c(\"div\", { staticClass: \"bubble\", class: m.role }, [\n m.role === \"user\" && m._sttStatus\n ? _c(\"div\", { staticClass: \"stt-bubble-wrap\" }, [\n m._sttStatus === \"pending\"\n ? _c(\"span\", {\n staticClass: \"stt-spinner stt-outside-icon\"\n })\n : m._sttStatus === \"error\"\n ? _c(\n \"span\",\n {\n staticClass: \"stt-error-icon stt-outside-icon\"\n },\n [_vm._v(\"!\")]\n )\n : _vm._e(),\n _c(\"span\", { staticClass: \"stt-bubble-text\" }, [\n _vm._v(\n _vm._s(\n m._sttStatus === \"pending\"\n ? \"转化中...\"\n : \"语音转文字失败\"\n )\n )\n ])\n ])\n : _vm._e(),\n !m._sttStatus && m.thinking\n ? _c(\n \"details\",\n {\n staticClass: \"thinking-details\",\n attrs: { open: \"\" }\n },\n [\n _c(\"summary\", { staticClass: \"thinking-summary\" }, [\n _vm._v(\"💭 思考过程\")\n ]),\n _c(\"div\", {\n staticClass: \"thinking-body\",\n domProps: {\n innerHTML: _vm._s(_vm.escapeHtml(m.thinking))\n }\n })\n ]\n )\n : _vm._e(),\n m.role === \"assistant\" &&\n !m._sttStatus &&\n m.content &&\n !m._hasTokui &&\n m.loading\n ? _c(\"div\", {\n staticClass: \"final-content\",\n domProps: {\n innerHTML: _vm._s(\n _vm.renderStreaming(m.content, m._key)\n )\n }\n })\n : _vm._e(),\n m.role === \"assistant\" &&\n !m._sttStatus &&\n m.content &&\n !m._hasTokui &&\n !m.loading\n ? _c(\"div\", {\n staticClass: \"final-content\",\n domProps: {\n innerHTML: _vm._s(_vm.renderMarkdown(m.content))\n }\n })\n : _vm._e(),\n _c(\n \"div\",\n {\n directives: [\n {\n name: \"show\",\n rawName: \"v-show\",\n value:\n m.role === \"assistant\" &&\n !m._sttStatus &&\n m._hasTokui,\n expression:\n \"m.role === 'assistant' && !m._sttStatus && m._hasTokui\"\n }\n ],\n staticClass: \"final-content tokui-shell\",\n class: { android: _vm.isAndroid }\n },\n [_c(\"div\", { staticClass: \"tokui-stream\" })]\n ),\n m.role === \"user\" && !m._sttStatus && m.content && m.loading\n ? _c(\"div\", {\n staticClass: \"final-content\",\n domProps: {\n innerHTML: _vm._s(\n _vm.renderStreaming(m.content, m._key)\n )\n }\n })\n : _vm._e(),\n m.role === \"user\" &&\n !m._sttStatus &&\n m.content &&\n !m.loading\n ? _c(\"div\", {\n staticClass: \"final-content\",\n domProps: {\n innerHTML: _vm._s(_vm.renderMarkdown(m.content))\n }\n })\n : _vm._e(),\n _c(\n \"div\",\n {\n directives: [\n {\n name: \"show\",\n rawName: \"v-show\",\n value:\n !m._sttStatus &&\n _vm.showToolInfo &&\n m.toolCalls &&\n m.toolCalls.length,\n expression:\n \"!m._sttStatus && showToolInfo && m.toolCalls && m.toolCalls.length\"\n }\n ],\n staticClass: \"tool-calls\"\n },\n _vm._l(m.toolCalls, function(tc, ti) {\n return _c(\n \"div\",\n { key: ti, staticClass: \"tool-item\" },\n [\n _c(\"span\", { staticClass: \"tool-badge\" }, [\n _vm._v(\"工具返回\")\n ]),\n _c(\"pre\", [\n _vm._v(\n _vm._s(tc.substring(0, 300)) +\n _vm._s(tc.length > 300 ? \"...\" : \"\")\n )\n ])\n ]\n )\n }),\n 0\n ),\n m.loading\n ? _c(\n \"div\",\n { staticClass: \"typing\", class: _vm.waitClass },\n [\n _c(\"span\", { staticClass: \"phrase\" }, [\n _vm._v(\"思考中\")\n ]),\n _vm._m(1, true)\n ]\n )\n : _vm._e()\n ]),\n m.role === \"assistant\" && m.content && !m.loading\n ? _c(\"div\", { staticClass: \"msg-actions\" }, [\n _c(\n \"span\",\n {\n staticClass: \"action-btn\",\n attrs: { title: \"复制\" },\n on: {\n click: function($event) {\n return _vm.copyText(m.content)\n }\n }\n },\n [_vm._v(\"📋 复制\")]\n ),\n _c(\n \"span\",\n {\n staticClass: \"action-btn\",\n attrs: { title: \"复制为图片\" },\n on: {\n click: function($event) {\n return _vm.copyAsImage(m.content)\n }\n }\n },\n [_vm._v(\"🖼 复制为图片\")]\n ),\n _c(\"span\", { staticClass: \"ai-badge\" }, [\n _vm._v(\"AI 生成(仅供参考)\")\n ])\n ])\n : _vm._e()\n ])\n ])\n ]\n )\n })\n ],\n 2\n ),\n _c(\"div\", { staticClass: \"chat-footer\" }, [\n _c(\n \"div\",\n { staticClass: \"input-area\" },\n [\n !_vm.voiceMode || !_vm.isMobile\n ? [\n _c(\"textarea\", {\n directives: [\n {\n name: \"model\",\n rawName: \"v-model\",\n value: _vm.inputText,\n expression: \"inputText\"\n }\n ],\n ref: \"taRef\",\n staticClass: \"chat-textarea\",\n attrs: {\n placeholder: \"请输入消息\",\n maxlength: \"300\",\n disabled: _vm.sending\n },\n domProps: { value: _vm.inputText },\n on: {\n input: [\n function($event) {\n if ($event.target.composing) {\n return\n }\n _vm.inputText = $event.target.value\n },\n _vm.autoResizeTextarea\n ],\n focus: _vm.onInputFocus,\n keydown: [\n function($event) {\n if (\n !$event.type.indexOf(\"key\") &&\n _vm._k(\n $event.keyCode,\n \"enter\",\n 13,\n $event.key,\n \"Enter\"\n )\n ) {\n return null\n }\n if (\n $event.ctrlKey ||\n $event.shiftKey ||\n $event.altKey ||\n $event.metaKey\n ) {\n return null\n }\n $event.preventDefault()\n _vm.isMobile ? _vm.newLine($event) : _vm.sendMessage()\n },\n function($event) {\n if (\n !$event.type.indexOf(\"key\") &&\n _vm._k(\n $event.keyCode,\n \"enter\",\n 13,\n $event.key,\n \"Enter\"\n )\n ) {\n return null\n }\n if (!$event.ctrlKey) {\n return null\n }\n return _vm.newLine.apply(null, arguments)\n }\n ]\n }\n }),\n !_vm.sending\n ? _c(\n \"button\",\n {\n staticClass: \"send-btn\",\n class: { active: _vm.inputText.trim() },\n attrs: {\n disabled: _vm.sending || !_vm.inputText.trim()\n },\n on: { click: _vm.sendMessage }\n },\n [\n _c(\n \"svg\",\n {\n attrs: {\n viewBox: \"0 0 24 24\",\n width: \"20\",\n height: \"20\",\n fill: \"currentColor\"\n }\n },\n [\n _c(\"path\", {\n attrs: {\n d: \"M2.01 21L23 12 2.01 3 2 10l15 2-15 2z\"\n }\n })\n ]\n )\n ]\n )\n : _vm._e(),\n _vm.sending\n ? _c(\n \"button\",\n { staticClass: \"stop-btn\", on: { click: _vm.stopAgent } },\n [\n _c(\n \"svg\",\n {\n attrs: {\n viewBox: \"0 0 24 24\",\n width: \"18\",\n height: \"18\",\n fill: \"currentColor\"\n }\n },\n [\n _c(\"rect\", {\n attrs: {\n x: \"6\",\n y: \"6\",\n width: \"12\",\n height: \"12\",\n rx: \"2\"\n }\n })\n ]\n )\n ]\n )\n : _vm._e()\n ]\n : [\n _c(\n \"div\",\n {\n staticClass: \"hold-talk-btn\",\n class: { recording: _vm.isRecording },\n on: {\n touchstart: function($event) {\n $event.preventDefault()\n return _vm.onRecordTouchStart($event)\n },\n touchmove: function($event) {\n $event.preventDefault()\n return _vm.onRecordTouchMove($event)\n },\n touchend: function($event) {\n $event.preventDefault()\n return _vm.onRecordTouchEnd.apply(null, arguments)\n }\n }\n },\n [\n !_vm.isRecording\n ? _c(\n \"svg\",\n {\n staticClass: \"hold-talk-icon\",\n attrs: {\n viewBox: \"0 0 24 24\",\n width: \"18\",\n height: \"18\",\n fill: \"currentColor\"\n }\n },\n [\n _c(\"path\", {\n attrs: {\n d:\n \"M12 14a3 3 0 003-3V5a3 3 0 00-6 0v6a3 3 0 003 3z\"\n }\n }),\n _c(\"path\", {\n attrs: {\n d: \"M17 11a5 5 0 01-10 0H5a7 7 0 0014 0h-2z\"\n }\n }),\n _c(\"rect\", {\n attrs: {\n x: \"11\",\n y: \"17\",\n width: \"2\",\n height: \"4\",\n rx: \"1\"\n }\n })\n ]\n )\n : _vm._e(),\n _c(\"span\", [\n _vm._v(\n _vm._s(\n _vm.isRecording\n ? _vm.isCancelSwipe\n ? \"松开取消\"\n : \"松手发送\"\n : \"按住说话\"\n )\n )\n ])\n ]\n ),\n _vm.sending\n ? _c(\n \"button\",\n { staticClass: \"stop-btn\", on: { click: _vm.stopAgent } },\n [\n _c(\n \"svg\",\n {\n attrs: {\n viewBox: \"0 0 24 24\",\n width: \"18\",\n height: \"18\",\n fill: \"currentColor\"\n }\n },\n [\n _c(\"rect\", {\n attrs: {\n x: \"6\",\n y: \"6\",\n width: \"12\",\n height: \"12\",\n rx: \"2\"\n }\n })\n ]\n )\n ]\n )\n : _vm._e()\n ],\n _vm.showDownBtn && _vm.messages.length !== 0\n ? _c(\"div\", { staticClass: \"scroll-bottom-wrap\" }, [\n _c(\n \"div\",\n {\n staticClass: \"scroll-bottom-btn\",\n on: {\n click: function($event) {\n return _vm.scrollToBottom(true)\n }\n }\n },\n [\n _vm.sending\n ? _c(\"div\", { staticClass: \"loading-circle\" })\n : _vm._e(),\n _c(\n \"svg\",\n {\n attrs: {\n width: \"14\",\n height: \"14\",\n viewBox: \"0 0 24 24\",\n fill: \"none\"\n }\n },\n [\n _c(\"path\", {\n attrs: {\n d: \"M6 9l6 6 6-6\",\n stroke: \"currentColor\",\n \"stroke-width\": \"2\",\n \"stroke-linecap\": \"round\",\n \"stroke-linejoin\": \"round\"\n }\n })\n ]\n )\n ]\n )\n ])\n : _vm._e()\n ],\n 2\n )\n ]),\n _vm.isRecording\n ? _c(\"div\", { staticClass: \"voice-recording-overlay\" }, [\n _c(\"div\", { staticClass: \"voice-recording-card\" }, [\n _vm._m(2),\n _c(\"div\", { staticClass: \"voice-recording-duration\" }, [\n _vm._v(_vm._s(_vm.recordDuration)),\n _c(\"span\", { staticClass: \"unit\" }, [_vm._v(\"s\")])\n ]),\n _c(\n \"div\",\n {\n staticClass: \"voice-recording-hint\",\n class: { cancel: _vm.isCancelSwipe }\n },\n [\n _vm.isCancelSwipe\n ? _c(\n \"svg\",\n {\n attrs: {\n viewBox: \"0 0 24 24\",\n width: \"16\",\n height: \"16\",\n fill: \"#ff4d4f\"\n }\n },\n [\n _c(\"path\", {\n attrs: {\n d:\n \"M12 2C6.47 2 2 6.47 2 12s4.47 10 10 10 10-4.47 10-10S17.53 2 12 2zm5 13.59L15.59 17 12 13.41 8.41 17 7 15.59 10.59 12 7 8.41 8.41 7 12 10.59 15.59 7 17 8.41 13.41 12 17 15.59z\"\n }\n })\n ]\n )\n : _c(\n \"svg\",\n {\n attrs: {\n viewBox: \"0 0 24 24\",\n width: \"16\",\n height: \"16\",\n fill: \"#999\"\n }\n },\n [\n _c(\"path\", {\n attrs: {\n d:\n \"M12 4l-1.41 1.41L16.17 11H4v2h12.17l-5.58 5.59L12 20l8-8z\"\n }\n })\n ]\n ),\n _vm._v(\n \" \" +\n _vm._s(\n _vm.isCancelSwipe ? \"松开取消发送\" : \"手指上滑 取消发送\"\n ) +\n \" \"\n )\n ]\n )\n ])\n ])\n : _vm._e()\n ])\n}\nvar staticRenderFns = [\n function() {\n var _vm = this\n var _h = _vm.$createElement\n var _c = _vm._self._c || _h\n return _c(\"div\", { staticClass: \"agent-text\" }, [\n _c(\"div\", { staticClass: \"agent-name\", staticStyle: { color: \"#bbb\" } }, [\n _vm._v(\"请选择助手\")\n ])\n ])\n },\n function() {\n var _vm = this\n var _h = _vm.$createElement\n var _c = _vm._self._c || _h\n return _c(\"span\", { staticClass: \"dots\" }, [\n _c(\"span\"),\n _c(\"span\"),\n _c(\"span\")\n ])\n },\n function() {\n var _vm = this\n var _h = _vm.$createElement\n var _c = _vm._self._c || _h\n return _c(\"div\", { staticClass: \"voice-recording-wave\" }, [\n _c(\"span\"),\n _c(\"span\"),\n _c(\"span\"),\n _c(\"span\"),\n _c(\"span\")\n ])\n }\n]\nrender._withStripped = true\n\n\n\n//# sourceURL=webpack://ZjPluginIntelligent/./src/lib/components/chatMain/ChatDetail.vue?./node_modules/cache-loader/dist/cjs.js?%7B%22cacheDirectory%22:%22node_modules/.cache/vue-loader%22,%22cacheIdentifier%22:%2268609640-vue-loader-template%22%7D!./node_modules/vue-loader/lib/loaders/templateLoader.js??vue-loader-options!./node_modules/cache-loader/dist/cjs.js??ref--0-0!./node_modules/vue-loader/lib??vue-loader-options");
937
937
 
938
938
  /***/ }),
939
939
 
@@ -1432,7 +1432,7 @@ eval("// Imports\nvar ___CSS_LOADER_API_IMPORT___ = __webpack_require__(/*! ../.
1432
1432
  /*! no static exports found */
1433
1433
  /***/ (function(module, exports, __webpack_require__) {
1434
1434
 
1435
- eval("// Imports\nvar ___CSS_LOADER_API_IMPORT___ = __webpack_require__(/*! ../../../../node_modules/css-loader/dist/runtime/api.js */ \"./node_modules/css-loader/dist/runtime/api.js\");\nexports = ___CSS_LOADER_API_IMPORT___(false);\n// Module\nexports.push([module.i, \"\\n.chat-main[data-v-9693c11e] {\\r\\n flex: 1;\\r\\n display: flex;\\r\\n flex-direction: column;\\r\\n min-width: 0;\\r\\n min-height: 0;\\n}\\r\\n\\r\\n/* ── Header ── */\\n.chat-header[data-v-9693c11e] {\\r\\n display: flex;\\r\\n align-items: center;\\r\\n justify-content: space-between;\\r\\n padding: 10px 20px;\\r\\n background: #fff;\\r\\n border-bottom: 1px solid #e8e8e8;\\r\\n flex-shrink: 0;\\r\\n z-index: 10;\\n}\\n.header-left[data-v-9693c11e] {\\r\\n display: flex;\\r\\n align-items: center;\\r\\n gap: 10px;\\r\\n min-width: 0;\\r\\n flex: 1;\\n}\\n.header-actions[data-v-9693c11e] {\\r\\n display: flex;\\r\\n align-items: center;\\r\\n flex-shrink: 0;\\n}\\n.agent-info[data-v-9693c11e] {\\r\\n display: flex;\\r\\n align-items: center;\\r\\n gap: 10px;\\n}\\n.agent-icon[data-v-9693c11e] {\\r\\n width: 36px;\\r\\n height: 36px;\\r\\n border-radius: 8px;\\r\\n background: linear-gradient(135deg, #1677ff, #4096ff);\\r\\n color: #fff;\\r\\n display: flex;\\r\\n align-items: center;\\r\\n justify-content: center;\\r\\n font-size: 16px;\\r\\n font-weight: 600;\\r\\n flex-shrink: 0;\\n}\\n.agent-info:nth-child(4n + 2) .agent-icon-avatar[data-v-9693c11e] {\\r\\n background: linear-gradient(135deg, #52c41a, #73d13d);\\n}\\n.agent-info:nth-child(4n + 3) .agent-icon-avatar[data-v-9693c11e] {\\r\\n background: linear-gradient(135deg, #fa8c16, #ffa940);\\n}\\n.agent-info:nth-child(4n + 4) .agent-icon-avatar[data-v-9693c11e] {\\r\\n background: linear-gradient(135deg, #722ed1, #b37feb);\\n}\\n.agent-text[data-v-9693c11e] {\\r\\n min-width: 0;\\n}\\n.agent-name[data-v-9693c11e] {\\r\\n font-size: 15px;\\r\\n font-weight: 600;\\r\\n color: #333;\\r\\n line-height: 1.3;\\n}\\n.agent-desc[data-v-9693c11e] {\\r\\n font-size: 12px;\\r\\n color: #999;\\r\\n overflow: hidden;\\r\\n text-overflow: ellipsis;\\r\\n white-space: nowrap;\\r\\n max-width: min(300px, 45vw);\\n}\\n.header-right[data-v-9693c11e] {\\r\\n flex-shrink: 0;\\n}\\n.manage-link[data-v-9693c11e] {\\r\\n font-size: 13px;\\r\\n color: #1677ff;\\r\\n text-decoration: none;\\n}\\n.manage-link[data-v-9693c11e]:hover {\\r\\n color: #4096ff;\\n}\\r\\n\\r\\n/* ── Chat Body ── */\\n.chat-body[data-v-9693c11e] {\\r\\n flex: 1;\\r\\n overflow-y: auto;\\r\\n padding: 16px clamp(12px, 3vw, 40px);\\r\\n scroll-behavior: auto;\\r\\n position: relative;\\r\\n -webkit-overflow-scrolling: touch;\\r\\n background: url(https://qiguanbang.obs.cn-east-3.myhuaweicloud.com/production/image/AlAgent/agentbackground.png) 100% no-repeat;\\r\\n background-size: 100% 100%;\\r\\n background-position: center;\\r\\n background-size: cover;\\r\\n min-height: 0;\\n}\\n.welcome[data-v-9693c11e] {\\r\\n display: flex;\\r\\n flex-direction: column;\\r\\n align-items: center;\\r\\n justify-content: center;\\r\\n height: 100%;\\r\\n color: #bbb;\\r\\n margin: 0 -20px;\\n}\\n.welcome-icon[data-v-9693c11e] {\\r\\n margin-bottom: 12px;\\r\\n opacity: 0.7;\\n}\\n.welcome-text[data-v-9693c11e] {\\r\\n font-size: 15px;\\n}\\n.welcome-default .welcome-icon[data-v-9693c11e] {\\r\\n margin-bottom: 16px;\\n}\\n.welcome-title[data-v-9693c11e] {\\r\\n font-size: 20px;\\r\\n font-weight: 600;\\r\\n color: #333;\\r\\n margin-bottom: 8px;\\n}\\r\\n\\r\\n/* ── Message Row ── */\\n.msg-row[data-v-9693c11e] {\\r\\n width: 100%;\\r\\n display: flex;\\r\\n justify-content: center;\\r\\n padding: 20px 16px;\\r\\n box-sizing: border-box;\\r\\n align-items: center;\\n}\\n.msg-main[data-v-9693c11e] {\\r\\n display: flex;\\r\\n align-items: flex-start;\\r\\n gap: 10px;\\r\\n max-width: 85%;\\r\\n width: min(100%, 860px) !important;\\r\\n max-width: 860px;\\n}\\n.msg-row.user .msg-main[data-v-9693c11e] {\\r\\n flex-direction: row-reverse;\\n}\\n.msg-row.assistant[data-v-9693c11e] {\\r\\n justify-content: center;\\n}\\n.load-more[data-v-9693c11e] {\\r\\n text-align: center;\\r\\n font-size: 12px;\\r\\n color: #999;\\r\\n padding: 4px 0;\\n}\\n.msg-time[data-v-9693c11e] {\\r\\n font-size: 11px;\\r\\n color: #bbb;\\r\\n margin-top: 2px;\\r\\n padding-left: 4px;\\n}\\n.msg-row.user .msg-time[data-v-9693c11e] {\\r\\n text-align: right;\\r\\n padding-right: 4px;\\n}\\n.msg-actions[data-v-9693c11e] {\\r\\n display: flex;\\r\\n gap: 4px;\\r\\n margin-top: 4px;\\r\\n padding-left: 4px;\\r\\n align-items: center;\\r\\n justify-content: space-between;\\n}\\n.ai-badge[data-v-9693c11e] {\\r\\n font-size: 11px;\\r\\n color: #999;\\r\\n /* background: #f5f5f5; */\\r\\n padding: 1px 6px;\\r\\n border-radius: 3px;\\r\\n white-space: nowrap;\\r\\n -webkit-user-select: none;\\r\\n -moz-user-select: none;\\r\\n -ms-user-select: none;\\r\\n user-select: none;\\r\\n margin-left: auto;\\n}\\n.action-btn[data-v-9693c11e] {\\r\\n font-size: 12px;\\r\\n color: #999;\\r\\n cursor: pointer;\\r\\n padding: 2px 6px 2px 0;\\r\\n border-radius: 4px;\\r\\n transition: all 0.2s;\\r\\n -webkit-user-select: none;\\r\\n -moz-user-select: none;\\r\\n -ms-user-select: none;\\r\\n user-select: none;\\n}\\n.action-btn[data-v-9693c11e]:hover {\\r\\n color: #1677ff;\\r\\n background: #f0f5ff;\\n}\\r\\n\\r\\n/* ── STT 语音转文字状态 ── */\\n.stt-status-block[data-v-9693c11e] {\\r\\n display: flex;\\r\\n align-items: center;\\r\\n gap: 8px;\\r\\n font-size: 14px;\\r\\n line-height: 1.5;\\n}\\n.stt-bubble-wrap[data-v-9693c11e] {\\r\\n position: relative;\\r\\n display: flex;\\r\\n align-items: center;\\r\\n font-size: 15px;\\r\\n line-height: 1.4;\\n}\\n.stt-outside-icon[data-v-9693c11e] {\\r\\n position: absolute;\\r\\n right: 100%;\\r\\n top: 50%;\\r\\n margin-top: -9px;\\r\\n margin-right: 20px;\\n}\\n.stt-spinner[data-v-9693c11e] {\\r\\n display: inline-block;\\r\\n width: 18px;\\r\\n height: 18px;\\r\\n border: 2.5px solid #d9d9d9;\\r\\n border-top-color: #1677ff;\\r\\n border-right-color: #4096ff;\\r\\n border-radius: 50%;\\r\\n -webkit-animation: stt-spin-data-v-9693c11e 0.6s linear infinite;\\r\\n animation: stt-spin-data-v-9693c11e 0.6s linear infinite;\\r\\n flex-shrink: 0;\\r\\n box-sizing: border-box;\\n}\\n@-webkit-keyframes stt-spin-data-v-9693c11e {\\nto { transform: rotate(360deg);\\n}\\n}\\n@keyframes stt-spin-data-v-9693c11e {\\nto { transform: rotate(360deg);\\n}\\n}\\n.stt-error-icon[data-v-9693c11e] {\\r\\n display: inline-flex;\\r\\n align-items: center;\\r\\n justify-content: center;\\r\\n width: 18px;\\r\\n height: 18px;\\r\\n background: #ff4d4f;\\r\\n color: #fff;\\r\\n font-size: 12px;\\r\\n font-weight: 700;\\r\\n border-radius: 50%;\\r\\n line-height: 1;\\r\\n flex-shrink: 0;\\n}\\n.stt-bubble-text[data-v-9693c11e] {\\r\\n font-size: 15px;\\r\\n line-height: 1.4;\\r\\n color: #fff;\\r\\n white-space: nowrap;\\r\\n margin: 6px 0;\\n}\\n.msg-avatar[data-v-9693c11e] {\\r\\n width: 36px;\\r\\n height: 36px;\\r\\n border-radius: 50%;\\r\\n display: flex;\\r\\n align-items: center;\\r\\n justify-content: center;\\r\\n font-size: 13px;\\r\\n font-weight: 700;\\r\\n flex-shrink: 0;\\r\\n color: #fff;\\n}\\n.msg-avatar.user[data-v-9693c11e] {\\r\\n background: linear-gradient(135deg, #1677ff, #4096ff);\\r\\n color: #fff;\\n}\\n.msg-avatar.assistant[data-v-9693c11e] {\\r\\n background: linear-gradient(135deg, #52c41a, #73d13d);\\r\\n color: #fff;\\n}\\n.msg-agent-label[data-v-9693c11e] {\\r\\n font-size: 12px;\\r\\n color: #999;\\r\\n margin-bottom: 2px;\\n}\\n.msg-content[data-v-9693c11e] {\\r\\n width: 100% !important;\\r\\n max-width: 100%;\\r\\n box-sizing: border-box;\\r\\n overflow: hidden;\\n}\\r\\n\\r\\n/* ── Bubble ── */\\n.bubble[data-v-9693c11e] {\\r\\n max-width: 100%;\\r\\n min-width: 30px;\\r\\n width: -webkit-fit-content;\\r\\n width: -moz-fit-content;\\r\\n width: fit-content;\\r\\n padding: 8px 14px;\\r\\n border-radius: 12px;\\r\\n line-height: 1.4;\\r\\n font-size: 15px;\\r\\n word-break: break-word;\\r\\n white-space: normal;\\r\\n text-align: left;\\r\\n overflow-wrap: anywhere;\\n}\\n.bubble[data-v-9693c11e]:has(.typing) {\\r\\n padding: 16px 20px;\\n}\\n.bubble.user[data-v-9693c11e] {\\r\\n background: #1677ff;\\r\\n color: #fff;\\r\\n border-bottom-right-radius: 4px;\\r\\n box-shadow: 0 2px 8px rgba(22, 119, 255, 0.15);\\r\\n float: none;\\r\\n margin-left: auto;\\r\\n max-width: min(100%, 520px);\\n}\\n.bubble.assistant[data-v-9693c11e] {\\r\\n background: #fff;\\r\\n color: #333;\\r\\n border-bottom-left-radius: 4px;\\r\\n box-shadow: 0 1px 4px rgba(0, 0, 0, 0.06);\\r\\n text-align: left;\\r\\n width: 100%;\\r\\n box-sizing: border-box;\\n}\\n.bubble[data-v-9693c11e] table {\\r\\n border-collapse: collapse;\\r\\n width: 100%;\\r\\n margin: 6px 0;\\r\\n font-size: 14px;\\n}\\n.bubble[data-v-9693c11e] th,\\r\\n.bubble[data-v-9693c11e] td {\\r\\n border: 1px solid #e8e8e8;\\r\\n padding: 5px 8px;\\r\\n text-align: left;\\n}\\n.bubble[data-v-9693c11e] th {\\r\\n background: #fafafa;\\r\\n font-weight: 600;\\n}\\n.bubble[data-v-9693c11e] code {\\r\\n padding: 1px 5px;\\r\\n border-radius: 3px;\\r\\n font-size: 14px;\\n}\\n.bubble[data-v-9693c11e] pre {\\r\\n background: #f6f8fa;\\r\\n color: #333;\\r\\n padding: 12px;\\r\\n border-radius: 6px;\\r\\n overflow-x: auto;\\r\\n font-size: 13px;\\r\\n border: 1px solid #e8e8e8;\\r\\n margin: 8px 0;\\r\\n line-height: 1.5;\\r\\n white-space: pre;\\n}\\n.bubble[data-v-9693c11e] ul,\\r\\n.bubble[data-v-9693c11e] ol {\\r\\n padding-left: 20px;\\r\\n margin: 4px 0;\\n}\\n.bubble[data-v-9693c11e] li {\\r\\n margin: 2px 0;\\n}\\n.bubble[data-v-9693c11e] p {\\r\\n margin: 6px 0;\\n}\\r\\n\\r\\n/* ── Thinking ── */\\n.thinking-details[data-v-9693c11e] {\\r\\n margin-bottom: 10px;\\r\\n border: 1px solid #e8e8e8;\\r\\n border-radius: 8px;\\r\\n overflow: hidden;\\r\\n background: #fafafa;\\n}\\n.thinking-summary[data-v-9693c11e] {\\r\\n font-size: 12px;\\r\\n color: #888;\\r\\n cursor: pointer;\\r\\n padding: 6px 10px;\\r\\n -webkit-user-select: none;\\r\\n -moz-user-select: none;\\r\\n -ms-user-select: none;\\r\\n user-select: none;\\n}\\n.thinking-summary[data-v-9693c11e]:hover {\\r\\n color: #1677ff;\\n}\\n.thinking-body[data-v-9693c11e] {\\r\\n font-size: 14px;\\r\\n color: #666;\\r\\n padding: 8px 12px;\\r\\n line-height: 1.6;\\r\\n border-top: 1px solid #f0f0f0;\\r\\n text-align: left;\\r\\n white-space: pre-wrap;\\r\\n word-break: break-word;\\r\\n overflow-wrap: break-word;\\r\\n overflow-wrap: anywhere;\\n}\\n.final-content[data-v-9693c11e] {\\r\\n word-break: break-word;\\r\\n overflow-wrap: break-word;\\r\\n overflow-wrap: anywhere;\\n}\\n.tokui-shell[data-v-9693c11e] {\\r\\n font-size: 14px;\\r\\n line-height: 1.6;\\r\\n color: inherit;\\r\\n font-family: \\\"Segoe UI\\\", \\\"PingFang SC\\\", \\\"Microsoft YaHei\\\", Arial, sans-serif;\\r\\n font-weight: normal;\\r\\n letter-spacing: normal;\\r\\n text-transform: none;\\n}\\n.tokui-shell .tokui-stream[data-v-9693c11e] {\\r\\n font-size: 14px !important;\\r\\n line-height: 1.6 !important;\\r\\n color: inherit;\\r\\n font-family: \\\"Segoe UI\\\", \\\"PingFang SC\\\", \\\"Microsoft YaHei\\\", Arial, sans-serif !important;\\r\\n font-weight: normal !important;\\r\\n letter-spacing: normal !important;\\r\\n text-align: left;\\r\\n width: 100%;\\r\\n overflow-wrap: anywhere;\\r\\n -webkit-text-size-adjust: 100%;\\n}\\n.tokui-shell .tokui-stream > *[data-v-9693c11e] {\\r\\n font-size: 14px !important;\\r\\n line-height: 1.6 !important;\\r\\n font-family: \\\"Segoe UI\\\", \\\"PingFang SC\\\", \\\"Microsoft YaHei\\\", Arial, sans-serif !important;\\r\\n font-weight: normal !important;\\r\\n letter-spacing: normal !important;\\n}\\n.tokui-shell .tokui-stream p[data-v-9693c11e],\\r\\n.tokui-shell .tokui-stream ul[data-v-9693c11e],\\r\\n.tokui-shell .tokui-stream ol[data-v-9693c11e],\\r\\n.tokui-shell .tokui-stream li[data-v-9693c11e],\\r\\n.tokui-shell .tokui-stream table[data-v-9693c11e],\\r\\n.tokui-shell .tokui-stream code[data-v-9693c11e],\\r\\n.tokui-shell .tokui-stream pre[data-v-9693c11e],\\r\\n.tokui-shell .tokui-stream th[data-v-9693c11e],\\r\\n.tokui-shell .tokui-stream td[data-v-9693c11e] {\\r\\n font-size: 14px !important;\\r\\n line-height: 1.6 !important;\\r\\n font-family: \\\"Segoe UI\\\", \\\"PingFang SC\\\", \\\"Microsoft YaHei\\\", Arial, sans-serif !important;\\r\\n font-weight: normal !important;\\r\\n letter-spacing: normal !important;\\n}\\n.tokui-shell .tokui-stream[data-v-9693c11e] .tokui-desc__label,\\r\\n.tokui-shell .tokui-stream[data-v-9693c11e] .tokui-desc__value,\\r\\n.tokui-shell .tokui-stream[data-v-9693c11e] .tokui-dv-text,\\r\\n.tokui-shell .tokui-stream[data-v-9693c11e] .tokui-tag,\\r\\n.tokui-shell .tokui-stream[data-v-9693c11e] .tokui-h3,\\r\\n.tokui-shell .tokui-stream[data-v-9693c11e] .tokui-label {\\r\\n box-sizing: border-box;\\r\\n font-family: \\\"Segoe UI\\\", \\\"PingFang SC\\\", \\\"Microsoft YaHei\\\", Arial, sans-serif !important;\\r\\n font-weight: normal !important;\\r\\n line-height: 1.6 !important;\\r\\n letter-spacing: normal !important;\\r\\n text-transform: none !important;\\r\\n color: inherit;\\r\\n margin: 0;\\r\\n padding: 0;\\n}\\n.tokui-shell[data-v-9693c11e] .tokui-desc__label {\\r\\n font-size: 13px !important;\\r\\n color: #8c8c8c !important;\\r\\n line-height: 1.4 !important;\\r\\n margin-bottom: 2px !important;\\n}\\n.tokui-shell .tokui-stream[data-v-9693c11e] .tokui-desc__value {\\r\\n font-size: 14px !important;\\r\\n color: inherit !important;\\r\\n line-height: 1.6 !important;\\r\\n overflow-wrap: anywhere;\\n}\\n.tokui-shell .tokui-stream[data-v-9693c11e] .tokui-dv-text {\\r\\n font-size: 14px !important;\\r\\n color: inherit !important;\\r\\n line-height: 1.6 !important;\\r\\n display: inline-block;\\r\\n overflow-wrap: anywhere;\\n}\\n.tokui-shell .tokui-stream[data-v-9693c11e] .tokui-tag {\\r\\n display: inline-flex !important;\\r\\n align-items: center;\\r\\n justify-content: center;\\r\\n padding: 2px 8px !important;\\r\\n border-radius: 999px !important;\\r\\n font-size: 12px !important;\\r\\n font-weight: 600 !important;\\r\\n line-height: 1.4 !important;\\r\\n color: #1677ff !important;\\r\\n background: #e6f4ff !important;\\r\\n border: 1px solid #bae0ff !important;\\r\\n white-space: nowrap;\\n}\\n.tokui-shell[data-v-9693c11e] .tokui-card-header {\\r\\n display: flex !important;\\r\\n align-items: center !important;\\r\\n padding: 10px 12px !important;\\r\\n margin: 0 !important;\\r\\n font-size: 14px !important;\\r\\n line-height: 1.4 !important;\\r\\n color: inherit !important;\\r\\n background: transparent !important;\\r\\n border: none !important;\\n}\\n.tokui-shell[data-v-9693c11e] .tokui-card-header .tokui-h3,\\r\\n.tokui-shell[data-v-9693c11e] .tokui-card-header .tokui-h4 {\\r\\n font-size: 15px !important;\\r\\n font-weight: 600 !important;\\r\\n line-height: 1.4 !important;\\r\\n margin: 0 !important;\\r\\n color: inherit !important;\\n}\\n.tokui-shell .tokui-stream[data-v-9693c11e] .tokui-h3 {\\r\\n font-size: 16px !important;\\r\\n font-weight: 600 !important;\\r\\n line-height: 1.4 !important;\\r\\n color: inherit !important;\\r\\n margin: 10px 0 6px !important;\\n}\\n.tokui-shell .tokui-stream[data-v-9693c11e] .tokui-label {\\r\\n display: block !important;\\r\\n font-size: 13px !important;\\r\\n font-weight: 500 !important;\\r\\n line-height: 1.4 !important;\\r\\n color: #8c8c8c !important;\\r\\n margin: 0 0 4px !important;\\n}\\n.thinking-body[data-v-9693c11e] p {\\r\\n margin: 4px 0;\\n}\\r\\n\\r\\n/* ── Typing ── */\\n.typing[data-v-9693c11e] {\\r\\n display: flex;\\r\\n flex-direction: row;\\r\\n align-items: center;\\r\\n gap: 8px;\\r\\n min-height: 24px;\\r\\n justify-content: flex-start;\\r\\n padding: 4px 0;\\n}\\n.typing .phrase[data-v-9693c11e] {\\r\\n font-size: 14px;\\r\\n color: #888;\\r\\n white-space: nowrap;\\r\\n -webkit-animation: phraseFade-data-v-9693c11e 0.5s ease;\\r\\n animation: phraseFade-data-v-9693c11e 0.5s ease;\\r\\n letter-spacing: 0.5px;\\n}\\n.typing .dots[data-v-9693c11e] {\\r\\n display: flex;\\r\\n gap: 5px;\\r\\n align-items: center;\\r\\n justify-content: center;\\n}\\n.typing .dots span[data-v-9693c11e] {\\r\\n width: 8px;\\r\\n height: 8px;\\r\\n background: #bbb;\\r\\n border-radius: 50%;\\r\\n -webkit-animation: dtTyping-data-v-9693c11e 1.3s infinite ease-in-out;\\r\\n animation: dtTyping-data-v-9693c11e 1.3s infinite ease-in-out;\\n}\\n.typing .dots span[data-v-9693c11e]:nth-child(2) {\\r\\n -webkit-animation-delay: 0.16s;\\r\\n animation-delay: 0.16s;\\n}\\n.typing .dots span[data-v-9693c11e]:nth-child(3) {\\r\\n -webkit-animation-delay: 0.32s;\\r\\n animation-delay: 0.32s;\\n}\\n@-webkit-keyframes phraseFade-data-v-9693c11e {\\nfrom {\\r\\n opacity: 0.2;\\r\\n transform: translateY(4px);\\n}\\nto {\\r\\n opacity: 1;\\r\\n transform: translateY(0);\\n}\\n}\\n@keyframes phraseFade-data-v-9693c11e {\\nfrom {\\r\\n opacity: 0.2;\\r\\n transform: translateY(4px);\\n}\\nto {\\r\\n opacity: 1;\\r\\n transform: translateY(0);\\n}\\n}\\n@-webkit-keyframes dtTyping-data-v-9693c11e {\\n0%,\\r\\n 60%,\\r\\n 100% {\\r\\n transform: translateY(0);\\r\\n opacity: 0.3;\\n}\\n30% {\\r\\n transform: translateY(-5px);\\r\\n opacity: 1;\\n}\\n}\\n@keyframes dtTyping-data-v-9693c11e {\\n0%,\\r\\n 60%,\\r\\n 100% {\\r\\n transform: translateY(0);\\r\\n opacity: 0.3;\\n}\\n30% {\\r\\n transform: translateY(-5px);\\r\\n opacity: 1;\\n}\\n}\\r\\n\\r\\n/* ── Wait Timer ── */\\n.typing.wait-5 .dots span[data-v-9693c11e] {\\r\\n width: 8px;\\r\\n height: 8px;\\r\\n -webkit-animation-duration: 1s;\\r\\n animation-duration: 1s;\\n}\\n.typing.wait-5 .phrase[data-v-9693c11e] {\\r\\n color: #888;\\n}\\n.typing.wait-10 .dots span[data-v-9693c11e] {\\r\\n width: 9px;\\r\\n height: 9px;\\r\\n -webkit-animation-duration: 0.8s;\\r\\n animation-duration: 0.8s;\\r\\n background: #909399;\\n}\\n.typing.wait-10 .phrase[data-v-9693c11e] {\\r\\n color: #909399;\\n}\\n.typing.wait-10 .dots[data-v-9693c11e] {\\r\\n -webkit-animation: dtPulse-data-v-9693c11e 1s infinite ease-in-out;\\r\\n animation: dtPulse-data-v-9693c11e 1s infinite ease-in-out;\\n}\\n.typing.wait-15 .dots span[data-v-9693c11e] {\\r\\n width: 10px;\\r\\n height: 10px;\\r\\n -webkit-animation-duration: 0.6s;\\r\\n animation-duration: 0.6s;\\r\\n background: #1677ff;\\n}\\n.typing.wait-15 .phrase[data-v-9693c11e] {\\r\\n color: #1677ff;\\n}\\n.typing.wait-15 .dots[data-v-9693c11e] {\\r\\n -webkit-animation: dtPulse-data-v-9693c11e 0.6s infinite ease-in-out;\\r\\n animation: dtPulse-data-v-9693c11e 0.6s infinite ease-in-out;\\n}\\n@-webkit-keyframes dtPulse-data-v-9693c11e {\\n0%,\\r\\n 100% {\\r\\n transform: scale(1);\\n}\\n50% {\\r\\n transform: scale(1.05);\\n}\\n}\\n@keyframes dtPulse-data-v-9693c11e {\\n0%,\\r\\n 100% {\\r\\n transform: scale(1);\\n}\\n50% {\\r\\n transform: scale(1.05);\\n}\\n}\\r\\n\\r\\n/* ── Tool Calls ── */\\n.tool-calls[data-v-9693c11e] {\\r\\n margin-top: 8px;\\n}\\n.tool-item[data-v-9693c11e] {\\r\\n background: #f5f5f5;\\r\\n border-radius: 6px;\\r\\n padding: 6px 10px;\\r\\n margin-bottom: 4px;\\r\\n font-size: 12px;\\n}\\n.tool-badge[data-v-9693c11e] {\\r\\n display: inline-block;\\r\\n margin-bottom: 2px;\\r\\n font-size: 11px;\\r\\n color: #fa8c16;\\r\\n font-weight: 500;\\n}\\n.tool-item pre[data-v-9693c11e] {\\r\\n margin: 0;\\r\\n white-space: pre-wrap;\\r\\n word-break: break-all;\\r\\n font-size: 12px;\\r\\n color: #666;\\r\\n max-height: 120px;\\r\\n overflow-y: auto;\\n}\\r\\n\\r\\n/* ── Scroll Buttons ── */\\n.scroll-btns[data-v-9693c11e] {\\r\\n position: sticky;\\r\\n left: 50%;\\r\\n transform: translateX(-50%);\\r\\n bottom: 20px;\\r\\n z-index: 99;\\r\\n display: flex;\\r\\n justify-content: center;\\r\\n margin-top: 10px;\\r\\n pointer-events: none;\\n}\\n.scroll-btn[data-v-9693c11e] {\\r\\n pointer-events: auto;\\r\\n width: 38px;\\r\\n height: 38px;\\r\\n border-radius: 50%;\\r\\n background: #fff;\\r\\n box-shadow: 0 2px 10px rgba(0, 0, 0, 0.15);\\r\\n display: flex;\\r\\n align-items: center;\\r\\n justify-content: center;\\r\\n cursor: pointer;\\n}\\n.scroll-btn i[data-v-9693c11e] {\\r\\n font-size: 16px;\\r\\n color: #333;\\n}\\r\\n\\r\\n/* ── Footer ── */\\n.chat-footer[data-v-9693c11e] {\\r\\n flex-shrink: 0;\\r\\n border-top: none;\\r\\n padding: 30px 0;\\r\\n display: flex;\\r\\n align-items: center;\\r\\n justify-content: center;\\r\\n margin: 0 auto;\\r\\n width: 100%;\\n}\\n.input-area[data-v-9693c11e] {\\r\\n position: relative;\\r\\n display: flex;\\r\\n align-items: flex-end;\\r\\n gap: 6px;\\r\\n background: #fff;\\r\\n border-radius: 24px;\\r\\n margin: 0 24px;\\r\\n padding: 18px 20px;\\r\\n border: 1px solid #b3d8ff;\\r\\n transition: border-color 0.2s;\\r\\n flex-wrap: wrap;\\r\\n width: min(100%, 1000px) !important;\\r\\n box-sizing: border-box;\\n}\\n.input-area[data-v-9693c11e]:focus-within {\\r\\n border-color: #1677ff;\\r\\n background: #fff;\\r\\n box-shadow: none;\\n}\\n.input-area[data-v-9693c11e]::after {\\r\\n content: \\\"Enter 发送,Ctrl+Enter 换行\\\";\\r\\n position: absolute;\\r\\n right: 100px;\\r\\n bottom: 28px;\\r\\n font-size: 14px;\\r\\n color: #8c8c8c;\\r\\n pointer-events: none;\\n}\\n.scroll-bottom-wrap[data-v-9693c11e] {\\r\\n position: absolute;\\r\\n left: 50%;\\r\\n transform: translateX(-50%);\\r\\n bottom: calc(100% + 30px);\\r\\n z-index: 99;\\r\\n display: flex;\\r\\n justify-content: center;\\r\\n pointer-events: none;\\n}\\n.scroll-bottom-btn[data-v-9693c11e] {\\r\\n width: 36px;\\r\\n height: 36px;\\r\\n border-radius: 50%;\\r\\n background: #fff;\\r\\n border: 1px solid #e5e7eb;\\r\\n display: flex;\\r\\n align-items: center;\\r\\n justify-content: center;\\r\\n cursor: pointer;\\r\\n pointer-events: auto;\\r\\n position: relative;\\r\\n box-shadow: 0 2px 10px rgba(0, 0, 0, 0.08);\\n}\\n.scroll-bottom-btn svg[data-v-9693c11e] {\\r\\n color: #4e5969;\\n}\\n.scroll-bottom-btn[data-v-9693c11e]:hover {\\r\\n transform: scale(1.1);\\n}\\n.loading-circle[data-v-9693c11e] {\\r\\n position: absolute;\\r\\n inset: 3px;\\r\\n border-radius: 50%;\\r\\n border: 1.5px solid transparent;\\r\\n border-top: 1.5px solid #1677ff;\\r\\n -webkit-animation: circle-spin-data-v-9693c11e 1.5s linear infinite;\\r\\n animation: circle-spin-data-v-9693c11e 1.5s linear infinite;\\n}\\n@-webkit-keyframes circle-spin-data-v-9693c11e {\\nfrom {\\r\\n transform: rotate(0deg);\\n}\\nto {\\r\\n transform: rotate(360deg);\\n}\\n}\\n@keyframes circle-spin-data-v-9693c11e {\\nfrom {\\r\\n transform: rotate(0deg);\\n}\\nto {\\r\\n transform: rotate(360deg);\\n}\\n}\\n.chat-textarea[data-v-9693c11e] {\\r\\n flex: 1;\\r\\n border: none;\\r\\n outline: none;\\r\\n background: transparent;\\r\\n resize: none;\\r\\n font-size: 16px;\\r\\n line-height: 24px;\\r\\n min-height: 38px;\\r\\n height: 100px;\\r\\n max-height: 100px;\\r\\n overflow-y: auto;\\r\\n padding: 0;\\r\\n box-sizing: border-box;\\r\\n font-family: inherit;\\r\\n color: #333;\\r\\n flex: 1 1 320px;\\r\\n min-width: 0;\\n}\\n.chat-textarea[data-v-9693c11e]::-moz-placeholder {\\r\\n color: #999;\\r\\n font-size: 16px;\\n}\\n.chat-textarea[data-v-9693c11e]:-ms-input-placeholder {\\r\\n color: #999;\\r\\n font-size: 16px;\\n}\\n.chat-textarea[data-v-9693c11e]::placeholder {\\r\\n color: #999;\\r\\n font-size: 16px;\\n}\\n.send-btn[data-v-9693c11e] {\\r\\n width: auto;\\r\\n height: 40px;\\r\\n padding: 0 21px;\\r\\n border-radius: 6px;\\r\\n border: none;\\r\\n display: flex;\\r\\n align-items: center;\\r\\n justify-content: center;\\r\\n cursor: pointer;\\r\\n flex-shrink: 0;\\r\\n transition: all 0.2s;\\r\\n background: #1677ff;\\r\\n color: #fff;\\r\\n font-size: 14px;\\n}\\n.send-btn svg[data-v-9693c11e] {\\r\\n display: none;\\n}\\n.send-btn[data-v-9693c11e]::after {\\r\\n content: \\\"发送\\\";\\n}\\n.send-btn.active[data-v-9693c11e] {\\r\\n background: #1677ff;\\n}\\n.send-btn.active[data-v-9693c11e]:hover {\\r\\n background: #4096ff;\\n}\\n.send-btn[data-v-9693c11e]:disabled {\\r\\n background: #88bfff;\\r\\n cursor: not-allowed;\\n}\\n.stop-btn[data-v-9693c11e] {\\r\\n width: 35px;\\r\\n height: 35px;\\r\\n border-radius: 50%;\\r\\n border: none;\\r\\n cursor: pointer;\\r\\n display: flex;\\r\\n align-items: center;\\r\\n justify-content: center;\\r\\n background: #ff4d4f;\\r\\n color: #fff;\\r\\n flex-shrink: 0;\\r\\n transition: all 0.2s;\\n}\\n.stop-btn[data-v-9693c11e]:hover {\\r\\n background: #ff7875;\\n}\\r\\n\\r\\n/* ── Voice ── */\\n.voice-btn[data-v-9693c11e] {\\r\\n display: flex;\\r\\n align-items: center;\\r\\n justify-content: center;\\r\\n width: 36px;\\r\\n height: 36px;\\r\\n min-width: 36px;\\r\\n border: none;\\r\\n background: transparent;\\r\\n border-radius: 50%;\\r\\n color: #333;\\r\\n cursor: pointer;\\r\\n flex-shrink: 0;\\r\\n transition: background 0.2s;\\r\\n padding: 0;\\n}\\n.voice-btn[data-v-9693c11e]:active {\\r\\n background: rgba(0,0,0,0.05);\\n}\\n.voice-btn[data-v-9693c11e]:disabled {\\r\\n opacity: 0.4;\\r\\n cursor: not-allowed;\\n}\\n.hold-talk-btn[data-v-9693c11e] {\\r\\n flex: 1;\\r\\n display: flex;\\r\\n align-items: center;\\r\\n justify-content: center;\\r\\n gap: 6px;\\r\\n height: 36px;\\r\\n min-height: 36px;\\r\\n margin: 0 4px;\\r\\n border-radius: 18px;\\r\\n background: #EBEBEB;\\r\\n border: none;\\r\\n font-size: 14px;\\r\\n color: #666;\\r\\n cursor: pointer;\\r\\n -moz-user-select: none;\\r\\n -ms-user-select: none;\\r\\n user-select: none;\\r\\n -webkit-user-select: none;\\r\\n transition: background 0.15s;\\n}\\n.hold-talk-btn[data-v-9693c11e]:active {\\r\\n background: #ddd;\\n}\\n.hold-talk-btn.recording[data-v-9693c11e] {\\r\\n background: #e8f0fe;\\r\\n color: #333;\\n}\\n.hold-talk-btn .hold-talk-icon[data-v-9693c11e] {\\r\\n flex-shrink: 0;\\n}\\r\\n\\r\\n/* ── Voice Recording Overlay ── */\\n.voice-recording-overlay[data-v-9693c11e] {\\r\\n position: fixed;\\r\\n left: 0;\\r\\n right: 0;\\r\\n top: 0;\\r\\n bottom: 0;\\r\\n z-index: 1000;\\r\\n display: flex;\\r\\n align-items: center;\\r\\n justify-content: center;\\r\\n background: rgba(0,0,0,0.35);\\r\\n -webkit-animation: fadeIn-data-v-9693c11e 0.15s ease;\\r\\n animation: fadeIn-data-v-9693c11e 0.15s ease;\\n}\\n.voice-recording-card[data-v-9693c11e] {\\r\\n width: 200px;\\r\\n padding: 32px 24px 24px;\\r\\n background: #fff;\\r\\n border-radius: 20px;\\r\\n display: flex;\\r\\n flex-direction: column;\\r\\n align-items: center;\\r\\n gap: 16px;\\r\\n box-shadow: 0 8px 32px rgba(0,0,0,0.15);\\n}\\n.voice-recording-wave[data-v-9693c11e] {\\r\\n display: flex;\\r\\n align-items: center;\\r\\n gap: 4px;\\r\\n height: 40px;\\n}\\n.voice-recording-wave span[data-v-9693c11e] {\\r\\n width: 4px;\\r\\n background: #1677ff;\\r\\n border-radius: 2px;\\r\\n -webkit-animation: waveAnim-data-v-9693c11e 0.6s ease-in-out infinite alternate;\\r\\n animation: waveAnim-data-v-9693c11e 0.6s ease-in-out infinite alternate;\\n}\\n.voice-recording-wave span[data-v-9693c11e]:nth-child(1) { height: 16px; -webkit-animation-delay: 0s; animation-delay: 0s;\\n}\\n.voice-recording-wave span[data-v-9693c11e]:nth-child(2) { height: 28px; -webkit-animation-delay: 0.1s; animation-delay: 0.1s;\\n}\\n.voice-recording-wave span[data-v-9693c11e]:nth-child(3) { height: 40px; -webkit-animation-delay: 0.2s; animation-delay: 0.2s;\\n}\\n.voice-recording-wave span[data-v-9693c11e]:nth-child(4) { height: 28px; -webkit-animation-delay: 0.3s; animation-delay: 0.3s;\\n}\\n.voice-recording-wave span[data-v-9693c11e]:nth-child(5) { height: 16px; -webkit-animation-delay: 0.4s; animation-delay: 0.4s;\\n}\\n@-webkit-keyframes waveAnim-data-v-9693c11e {\\n0% { transform: scaleY(0.6);\\n}\\n100% { transform: scaleY(1);\\n}\\n}\\n@keyframes waveAnim-data-v-9693c11e {\\n0% { transform: scaleY(0.6);\\n}\\n100% { transform: scaleY(1);\\n}\\n}\\n.voice-recording-duration[data-v-9693c11e] {\\r\\n font-size: 32px;\\r\\n font-weight: 600;\\r\\n color: #333;\\r\\n line-height: 1;\\n}\\n.voice-recording-duration .unit[data-v-9693c11e] {\\r\\n font-size: 18px;\\r\\n font-weight: 400;\\r\\n color: #999;\\r\\n margin-left: 2px;\\n}\\n.voice-recording-hint[data-v-9693c11e] {\\r\\n display: flex;\\r\\n align-items: center;\\r\\n gap: 4px;\\r\\n font-size: 13px;\\r\\n color: #999;\\n}\\n.voice-recording-hint.cancel[data-v-9693c11e] {\\r\\n color: #ff4d4f;\\n}\\n@-webkit-keyframes fadeIn-data-v-9693c11e {\\nfrom { opacity: 0;\\n}\\nto { opacity: 1;\\n}\\n}\\n@keyframes fadeIn-data-v-9693c11e {\\nfrom { opacity: 0;\\n}\\nto { opacity: 1;\\n}\\n}\\r\\n\\r\\n/* ── Chat Agent Avatar ── */\\n.chat-agent-avatar-wrapper div[data-v-9693c11e] {\\r\\n width: 44px;\\r\\n height: 44px;\\n}\\r\\n\\r\\n/* ── Agent List Avatar ── */\\n.agent-list-avatar[data-v-9693c11e] {\\r\\n background-repeat: no-repeat;\\r\\n background-position: center;\\r\\n display: flex;\\r\\n align-items: center;\\r\\n justify-content: center;\\r\\n color: #fff;\\r\\n font-size: 22px;\\r\\n font-weight: 600;\\r\\n border-radius: 8px;\\n}\\n.agent-list-avatar.has-agent-img[data-v-9693c11e] {\\r\\n width: 97px;\\r\\n height: 126px;\\r\\n background-size: cover;\\n}\\n.agent-list-avatar[data-v-9693c11e]:not(.has-agent-img) {\\r\\n width: 76px;\\r\\n height: 108px;\\r\\n transform: translateX(9px);\\n}\\n.session-avatar[data-v-9693c11e] {\\r\\n width: 44px !important;\\r\\n height: 44px !important;\\r\\n border-radius: 50% !important;\\r\\n display: flex;\\r\\n align-items: center;\\r\\n justify-content: center;\\r\\n font-size: 16px !important;\\r\\n font-weight: 600;\\r\\n color: #fff;\\r\\n flex-shrink: 0;\\r\\n overflow: hidden;\\n}\\n.avatar-pic[data-v-9693c11e] {\\r\\n width: 85%;\\r\\n height: 85%;\\r\\n -o-object-fit: contain;\\r\\n object-fit: contain;\\n}\\r\\n\\r\\n/* ── Mobile Buttons ── */\\n.mobile-menu-btn[data-v-9693c11e],\\r\\n.mobile-back-btn[data-v-9693c11e],\\r\\n.mobile-header-btn[data-v-9693c11e] {\\r\\n display: inline-flex;\\r\\n align-items: center;\\r\\n justify-content: center;\\r\\n width: 36px;\\r\\n height: 36px;\\r\\n border: none;\\r\\n border-radius: 10px;\\r\\n background: #f5f7fa;\\r\\n color: #333;\\r\\n cursor: pointer;\\r\\n flex-shrink: 0;\\n}\\n.mobile-menu-btn i[data-v-9693c11e],\\r\\n.mobile-back-btn i[data-v-9693c11e],\\r\\n.mobile-header-btn i[data-v-9693c11e] {\\r\\n font-size: 18px;\\n}\\n.mobile-back-btn i[data-v-9693c11e] {\\r\\n font-size: 20px;\\r\\n font-weight: 600;\\n}\\r\\n/* ── 聊天空白欢迎页(匹配蓝湖移动端聊天首页) ── */\\n.chat-empty-welcome[data-v-9693c11e] {\\r\\n width: 100%;\\r\\n padding: 40px 20px;\\r\\n box-sizing: border-box;\\r\\n display: flex;\\r\\n flex-direction: column;\\r\\n gap: 0px;\\r\\n max-width: 600px;\\r\\n margin: 80px auto;\\n}\\r\\n\\r\\n/* 顶部渐变欢迎卡片 */\\n.welcome-card[data-v-9693c11e] {\\r\\n position: relative;\\r\\n background: linear-gradient(296deg, #D6EDFF 20%, #E8EBFF 80%);\\r\\nborder-radius: 16px 16px 0px 0px;\\r\\n padding: 24px 24px 24px 150px;\\r\\n overflow: visible;\\n}\\r\\n/* 左侧探出头像容器 */\\n.welcome-avatar-box[data-v-9693c11e] {\\r\\n position: absolute;\\r\\n left: 15px;\\r\\n bottom: 0px;\\r\\n width: 110px;\\r\\n height: 137px;\\n}\\n.welcome-avatar[data-v-9693c11e] {\\r\\n width: 100%;\\r\\n height: 100%;\\r\\n border-radius: 12px;\\r\\n background-size: cover;\\r\\n background-position: center;\\r\\n display: flex;\\r\\n align-items: center;\\r\\n justify-content: center;\\r\\n font-size: 20px;\\r\\n color: #fff;\\r\\n font-weight: 600;\\n}\\n.welcome-avatar.has-chat-agent-img[data-v-9693c11e] {\\r\\n background: transparent;\\r\\n background-repeat: no-repeat;\\r\\n background-position: center;\\n}\\n.welcome-text-group[data-v-9693c11e] {\\r\\n display: flex;\\r\\n flex-direction: column;\\r\\n gap: 6px;\\n}\\n.welcome-text-group .text-sm[data-v-9693c11e] {\\r\\nfont-weight: 400;font-size: 12px;color: #666666;\\r\\ntext-align: left;\\r\\nfont-style: normal;\\n}\\n.welcome-text-group .text-lg[data-v-9693c11e] {\\r\\n \\r\\n font-weight: 500;\\r\\nfont-size: 16px;\\r\\ncolor: #000000;\\n}\\r\\n\\r\\n/* 猜你想问容器 */\\n.guess-box[data-v-9693c11e] {\\r\\n border-top: 1px solid #fff;\\r\\n background: linear-gradient(180deg, #B8DCFF 0%, #DFF0FF 50%, #FFFFFF 100%);\\r\\n border-radius: 0 0 16px 16px;\\r\\n padding: 20px;\\n}\\n.guess-title[data-v-9693c11e] {\\r\\n display: flex;\\r\\n align-items: center;\\r\\n gap: 6px;\\r\\n font-size: 16px;\\r\\n font-weight: 500;\\r\\n color: #222;\\r\\n margin-bottom: 16px;\\n}\\n.tag-wrap[data-v-9693c11e] {\\r\\n display: flex;\\r\\n flex-wrap: wrap;\\r\\n gap: 10px;\\n}\\n.quick-tag[data-v-9693c11e] {\\r\\n padding: 8px 14px;\\r\\n background: #F2FAFF;\\r\\n border-radius: 8px;\\r\\n font-size: 14px;\\r\\n color: #333;\\r\\n cursor: pointer;\\r\\n border: 1px solid #e0eaff;\\r\\n transition: all 0.2s;\\r\\n white-space: nowrap;\\n}\\r\\n/* .quick-tag:hover {\\r\\n background: #f0f7ff;\\r\\n border-color: #1677ff;\\r\\n} */\\n.chat-agent-avatar-wrapper div[data-v-9693c11e]{\\r\\n width: 44px;\\r\\n height: 44px;\\n}\\r\\n/* ── Responsive ── */\\n@media screen and (max-width: 768px) {\\n.chat-header[data-v-9693c11e] {\\r\\n padding: 10px 12px;\\r\\n background: transparent;\\r\\n border-bottom: none;\\n}\\n.chat-header .chat-agent-avatar-wrapper[data-v-9693c11e] {\\r\\n display: none;\\n}\\n.chat-header .agent-desc[data-v-9693c11e] {\\r\\n display: none;\\n}\\n.chat-header .header-left[data-v-9693c11e] {\\r\\n flex: 1;\\r\\n justify-content: center;\\r\\n position: relative;\\n}\\n.chat-header .header-left .mobile-back-btn[data-v-9693c11e] {\\r\\n position: absolute;\\r\\n left: 12px;\\r\\n background: transparent;\\n}\\n.chat-header .header-actions .mobile-header-btn[data-v-9693c11e] {\\r\\n background: transparent;\\n}\\n.chat-body[data-v-9693c11e] {\\r\\n padding: 12px;\\r\\n background-position: center top;\\n}\\n.msg-row[data-v-9693c11e] {\\r\\n padding: 12px 0;\\n}\\n.msg-main[data-v-9693c11e] {\\r\\n width: 100% !important;\\r\\n max-width: 100%;\\n}\\n.bubble[data-v-9693c11e] {\\r\\n font-size: 14px;\\n}\\n.bubble.user[data-v-9693c11e] {\\r\\n max-width: 88%;\\n}\\n.chat-footer[data-v-9693c11e] {\\r\\n padding: 12px;\\r\\n flex-shrink: 0;\\r\\n background: #f5f5f5;\\r\\n box-sizing: border-box;\\n}\\r\\n /* 安全区域由 .chat-footer 统一处理,.chat-body 不需要重复加 padding */\\n.input-area[data-v-9693c11e] {\\r\\n width: 100% !important;\\r\\n margin: 0;\\r\\n padding: 6px 6px 6px 4px;\\r\\n border-radius: 24px;\\r\\n border: none;\\r\\n background: #f5f5f5;\\r\\n box-shadow: 0 2px 8px rgba(0,0,0,0.06);\\r\\n flex-wrap: nowrap;\\r\\n align-items: center;\\n}\\n.input-area[data-v-9693c11e]:focus-within {\\r\\n border-color: transparent;\\r\\n background: #f5f5f5;\\r\\n box-shadow: 0 2px 8px rgba(0,0,0,0.06);\\n}\\n.input-area[data-v-9693c11e]::after {\\r\\n display: none;\\n}\\n.voice-btn[data-v-9693c11e] {\\r\\n display: flex;\\r\\n align-items: center;\\r\\n justify-content: center;\\r\\n width: 36px;\\r\\n height: 36px;\\r\\n min-width: 36px;\\r\\n border: none;\\r\\n background: transparent;\\r\\n border-radius: 50%;\\r\\n color: #333;\\r\\n cursor: pointer;\\r\\n flex-shrink: 0;\\r\\n transition: background 0.2s;\\r\\n padding: 0;\\n}\\n.voice-btn[data-v-9693c11e]:active {\\r\\n background: rgba(0,0,0,0.05);\\n}\\n.voice-btn[data-v-9693c11e]:disabled {\\r\\n opacity: 0.4;\\r\\n cursor: not-allowed;\\n}\\n.chat-textarea[data-v-9693c11e] {\\r\\n flex: 1;\\r\\n flex-basis: 0;\\r\\n height: 36px;\\r\\n min-height: 36px;\\r\\n max-height: 100px;\\r\\n font-size: 15px;\\r\\n background: #EBEBEB;\\r\\n border-radius: 18px;\\r\\n padding: 0 14px;\\r\\n line-height: 36px;\\r\\n margin: 0 4px;\\r\\n color: #333;\\n}\\n.chat-textarea[data-v-9693c11e]::-moz-placeholder {\\r\\n color: #999;\\r\\n font-size: 15px;\\n}\\n.chat-textarea[data-v-9693c11e]:-ms-input-placeholder {\\r\\n color: #999;\\r\\n font-size: 15px;\\n}\\n.chat-textarea[data-v-9693c11e]::placeholder {\\r\\n color: #999;\\r\\n font-size: 15px;\\n}\\n.send-btn[data-v-9693c11e] {\\r\\n width: 36px;\\r\\n height: 36px;\\r\\n min-width: 36px;\\r\\n padding: 0;\\r\\n border-radius: 50%;\\r\\n display: flex;\\r\\n align-items: center;\\r\\n justify-content: center;\\r\\n background: #1677ff;\\r\\n color: #fff;\\r\\n border: none;\\r\\n cursor: pointer;\\r\\n flex-shrink: 0;\\n}\\n.send-btn svg[data-v-9693c11e] {\\r\\n display: block;\\n}\\n.send-btn[data-v-9693c11e]::after {\\r\\n content: none;\\n}\\n.send-btn.active[data-v-9693c11e] {\\r\\n background: #1677ff;\\n}\\n.send-btn[data-v-9693c11e]:disabled {\\r\\n background: #88bfff;\\r\\n cursor: not-allowed;\\n}\\n.send-btn[data-v-9693c11e]:active {\\r\\n transform: scale(0.92);\\n}\\n.stop-btn[data-v-9693c11e] {\\r\\n width: 36px;\\r\\n height: 36px;\\r\\n min-width: 36px;\\n}\\n.guess-box[data-v-9693c11e] {\\r\\n padding: 16px;\\n}\\r\\n\\r\\n /* H5 语音模式 */\\n.hold-talk-btn[data-v-9693c11e] {\\r\\n flex: 1;\\r\\n display: flex;\\r\\n align-items: center;\\r\\n justify-content: center;\\r\\n gap: 6px;\\r\\n height: 36px;\\r\\n min-height: 36px;\\r\\n margin: 0 4px;\\r\\n border-radius: 18px;\\r\\n background: #EBEBEB;\\r\\n border: none;\\r\\n font-size: 14px;\\r\\n color: #666;\\r\\n cursor: pointer;\\r\\n -moz-user-select: none;\\r\\n -ms-user-select: none;\\r\\n user-select: none;\\r\\n -webkit-user-select: none;\\r\\n transition: background 0.15s;\\n}\\n.hold-talk-btn[data-v-9693c11e]:active {\\r\\n background: #ddd;\\n}\\n.hold-talk-btn.recording[data-v-9693c11e] {\\r\\n background: #e8f0fe;\\r\\n color: #333;\\n}\\n.hold-talk-btn .hold-talk-icon[data-v-9693c11e] {\\r\\n flex-shrink: 0;\\n}\\r\\n\\r\\n /* 语音录制浮层 */\\n.voice-recording-overlay[data-v-9693c11e] {\\r\\n position: fixed;\\r\\n left: 0;\\r\\n right: 0;\\r\\n top: 0;\\r\\n bottom: 0;\\r\\n z-index: 1000;\\r\\n display: flex;\\r\\n align-items: center;\\r\\n justify-content: center;\\r\\n background: rgba(0,0,0,0.35);\\r\\n -webkit-animation: fadeIn-data-v-9693c11e 0.15s ease;\\r\\n animation: fadeIn-data-v-9693c11e 0.15s ease;\\n}\\n.voice-recording-card[data-v-9693c11e] {\\r\\n width: 200px;\\r\\n padding: 32px 24px 24px;\\r\\n background: #fff;\\r\\n border-radius: 20px;\\r\\n display: flex;\\r\\n flex-direction: column;\\r\\n align-items: center;\\r\\n gap: 16px;\\r\\n box-shadow: 0 8px 32px rgba(0,0,0,0.15);\\n}\\n.voice-recording-wave[data-v-9693c11e] {\\r\\n display: flex;\\r\\n align-items: center;\\r\\n gap: 4px;\\r\\n height: 40px;\\n}\\n.voice-recording-wave span[data-v-9693c11e] {\\r\\n width: 4px;\\r\\n background: #1677ff;\\r\\n border-radius: 2px;\\r\\n -webkit-animation: waveAnim-data-v-9693c11e 0.6s ease-in-out infinite alternate;\\r\\n animation: waveAnim-data-v-9693c11e 0.6s ease-in-out infinite alternate;\\n}\\n.voice-recording-wave span[data-v-9693c11e]:nth-child(1) { height: 16px; -webkit-animation-delay: 0s; animation-delay: 0s;\\n}\\n.voice-recording-wave span[data-v-9693c11e]:nth-child(2) { height: 28px; -webkit-animation-delay: 0.1s; animation-delay: 0.1s;\\n}\\n.voice-recording-wave span[data-v-9693c11e]:nth-child(3) { height: 40px; -webkit-animation-delay: 0.2s; animation-delay: 0.2s;\\n}\\n.voice-recording-wave span[data-v-9693c11e]:nth-child(4) { height: 28px; -webkit-animation-delay: 0.3s; animation-delay: 0.3s;\\n}\\n.voice-recording-wave span[data-v-9693c11e]:nth-child(5) { height: 16px; -webkit-animation-delay: 0.4s; animation-delay: 0.4s;\\n}\\n@-webkit-keyframes waveAnim-data-v-9693c11e {\\n0% { transform: scaleY(0.6);\\n}\\n100% { transform: scaleY(1);\\n}\\n}\\n@keyframes waveAnim-data-v-9693c11e {\\n0% { transform: scaleY(0.6);\\n}\\n100% { transform: scaleY(1);\\n}\\n}\\n.voice-recording-duration[data-v-9693c11e] {\\r\\n font-size: 32px;\\r\\n font-weight: 600;\\r\\n color: #333;\\r\\n line-height: 1;\\n}\\n.voice-recording-duration .unit[data-v-9693c11e] {\\r\\n font-size: 18px;\\r\\n font-weight: 400;\\r\\n color: #999;\\r\\n margin-left: 2px;\\n}\\n.voice-recording-hint[data-v-9693c11e] {\\r\\n display: flex;\\r\\n align-items: center;\\r\\n gap: 4px;\\r\\n font-size: 13px;\\r\\n color: #999;\\n}\\n.voice-recording-hint.cancel[data-v-9693c11e] {\\r\\n color: #ff4d4f;\\n}\\n@-webkit-keyframes fadeIn-data-v-9693c11e {\\nfrom { opacity: 0;\\n}\\nto { opacity: 1;\\n}\\n}\\n@keyframes fadeIn-data-v-9693c11e {\\nfrom { opacity: 0;\\n}\\nto { opacity: 1;\\n}\\n}\\n}\\n@media screen and (max-width: 480px) {\\n.agent-name[data-v-9693c11e] {\\r\\n font-size: 14px;\\n}\\n.agent-desc[data-v-9693c11e] {\\r\\n max-width: calc(100vw - 132px);\\n}\\n.mobile-menu-btn[data-v-9693c11e],\\r\\n .mobile-header-btn[data-v-9693c11e] {\\r\\n width: 32px;\\r\\n height: 32px;\\n}\\n}\\r\\n\\r\\n/* ═══════════════════════════════════════════════════════════════\\r\\n Android 兼容性修复\\r\\n ═══════════════════════════════════════════════════════════════\\r\\n 问题一:tokui-col--6 在安卓窄屏上仍按 grid-column: span 6 并排,\\r\\n 导致内部 tokui-desc__value 被挤压成竖排。\\r\\n 修复:≤640px 时重置 grid-column,与 tokui.css 的断点对齐。\\r\\n 问题二:tokui-desc 默认 3 列网格 + overflow-wrap:anywhere(ChatDetail.vue\\r\\n 第 1913/1964 行)导致窄屏下每个字符都断行→竖列展示。\\r\\n 修复:≤640px 时 desc 改为 1 列 + overflow-wrap 改用 break-word。\\r\\n 问题三:tokui-desc--horizontal 水平模式下,overflow-wrap:anywhere\\r\\n 破坏 flex:1 收缩,value 掉到 label 下方。\\r\\n 修复:显式声明 flex-direction:row 并修正 overflow-wrap。 */\\n@media screen and (max-width: 640px) {\\r\\n /* ── 修复一:tokui-col 窄屏全宽堆叠 ── */\\n.tokui-shell .tokui-stream[data-v-9693c11e] .tokui-col {\\r\\n grid-column: span 1 !important;\\r\\n width: 100% !important;\\n}\\r\\n\\r\\n /* ── 修复二:tokui-desc 窄屏改为 1 列 + 修正 overflow-wrap ──\\r\\n tokui.css 默认 3 列网格 + ChatDetail.vue 的 overflow-wrap:anywhere\\r\\n 导致窄屏下每个 item 仅 1/3 宽度,text 在任意字符断行→竖排。\\r\\n 改为 1 列让每个 item 有足够宽度,同时用 break-word 替代 anywhere。 */\\n.tokui-shell .tokui-stream[data-v-9693c11e] .tokui-desc {\\r\\n --tokui-desc-cols: 1 !important;\\r\\n grid-template-columns: 1fr !important;\\n}\\n.tokui-shell .tokui-stream[data-v-9693c11e] .tokui-desc__value {\\r\\n overflow-wrap: break-word !important;\\r\\n word-break: break-word;\\n}\\n}\\r\\n\\r\\n/* ── 修复三:tokui-desc--horizontal item 内部 label/value 强制水平并排 ──\\r\\n 原 tokui.css:.tokui-desc--horizontal .tokui-desc__item { display:flex }\\r\\n Android 上 ChatDetail.vue 的 overflow-wrap:anywhere 导致 flex:1 失效。\\r\\n 修复:显式方向 + 修正 value 的 overflow-wrap 避免破坏 flex 收缩。 */\\n.tokui-shell .tokui-stream[data-v-9693c11e] .tokui-desc--horizontal .tokui-desc__item {\\r\\n display: flex !important;\\r\\n flex-direction: row !important;\\r\\n flex-wrap: nowrap !important;\\r\\n align-items: baseline !important;\\r\\n width: 100% !important;\\n}\\n.tokui-shell .tokui-stream[data-v-9693c11e] .tokui-desc--horizontal .tokui-desc__label {\\r\\n flex: 0 0 auto !important;\\r\\n flex-shrink: 0 !important;\\r\\n min-width: var(--tokui-desc-label-w, 100px);\\r\\n white-space: nowrap !important;\\r\\n overflow: hidden;\\r\\n text-overflow: ellipsis;\\r\\n margin-bottom: 0 !important;\\r\\n padding-right: 8px;\\n}\\n.tokui-shell .tokui-stream[data-v-9693c11e] .tokui-desc--horizontal .tokui-desc__value {\\r\\n flex: 1 1 0% !important;\\r\\n min-width: 0 !important;\\r\\n width: auto !important;\\r\\n overflow-wrap: break-word !important;\\r\\n word-break: break-word;\\n}\\r\\n\", \"\"]);\n// Exports\nmodule.exports = exports;\n\n\n//# sourceURL=webpack://ZjPluginIntelligent/./src/lib/components/chatMain/ChatDetail.vue?./node_modules/css-loader/dist/cjs.js??ref--6-oneOf-1-1!./node_modules/vue-loader/lib/loaders/stylePostLoader.js!./node_modules/postcss-loader/src??ref--6-oneOf-1-2!./node_modules/cache-loader/dist/cjs.js??ref--0-0!./node_modules/vue-loader/lib??vue-loader-options");
1435
+ eval("// Imports\nvar ___CSS_LOADER_API_IMPORT___ = __webpack_require__(/*! ../../../../node_modules/css-loader/dist/runtime/api.js */ \"./node_modules/css-loader/dist/runtime/api.js\");\nexports = ___CSS_LOADER_API_IMPORT___(false);\n// Module\nexports.push([module.i, \"\\n.chat-main[data-v-9693c11e] {\\r\\n flex: 1;\\r\\n display: flex;\\r\\n flex-direction: column;\\r\\n min-width: 0;\\r\\n min-height: 0;\\n}\\r\\n\\r\\n/* ── Header ── */\\n.chat-header[data-v-9693c11e] {\\r\\n display: flex;\\r\\n align-items: center;\\r\\n justify-content: space-between;\\r\\n padding: 10px 20px;\\r\\n background: #fff;\\r\\n border-bottom: 1px solid #e8e8e8;\\r\\n flex-shrink: 0;\\r\\n z-index: 10;\\n}\\n.header-left[data-v-9693c11e] {\\r\\n display: flex;\\r\\n align-items: center;\\r\\n gap: 10px;\\r\\n min-width: 0;\\r\\n flex: 1;\\n}\\n.header-actions[data-v-9693c11e] {\\r\\n display: flex;\\r\\n align-items: center;\\r\\n flex-shrink: 0;\\n}\\n.agent-info[data-v-9693c11e] {\\r\\n display: flex;\\r\\n align-items: center;\\r\\n gap: 10px;\\n}\\n.agent-icon[data-v-9693c11e] {\\r\\n width: 36px;\\r\\n height: 36px;\\r\\n border-radius: 8px;\\r\\n background: linear-gradient(135deg, #1677ff, #4096ff);\\r\\n color: #fff;\\r\\n display: flex;\\r\\n align-items: center;\\r\\n justify-content: center;\\r\\n font-size: 16px;\\r\\n font-weight: 600;\\r\\n flex-shrink: 0;\\n}\\n.agent-info:nth-child(4n + 2) .agent-icon-avatar[data-v-9693c11e] {\\r\\n background: linear-gradient(135deg, #52c41a, #73d13d);\\n}\\n.agent-info:nth-child(4n + 3) .agent-icon-avatar[data-v-9693c11e] {\\r\\n background: linear-gradient(135deg, #fa8c16, #ffa940);\\n}\\n.agent-info:nth-child(4n + 4) .agent-icon-avatar[data-v-9693c11e] {\\r\\n background: linear-gradient(135deg, #722ed1, #b37feb);\\n}\\n.agent-text[data-v-9693c11e] {\\r\\n min-width: 0;\\n}\\n.agent-name[data-v-9693c11e] {\\r\\n font-size: 15px;\\r\\n font-weight: 600;\\r\\n color: #333;\\r\\n line-height: 1.3;\\n}\\n.agent-desc[data-v-9693c11e] {\\r\\n font-size: 12px;\\r\\n color: #999;\\r\\n overflow: hidden;\\r\\n text-overflow: ellipsis;\\r\\n white-space: nowrap;\\r\\n max-width: min(300px, 45vw);\\n}\\n.header-right[data-v-9693c11e] {\\r\\n flex-shrink: 0;\\n}\\n.manage-link[data-v-9693c11e] {\\r\\n font-size: 13px;\\r\\n color: #1677ff;\\r\\n text-decoration: none;\\n}\\n.manage-link[data-v-9693c11e]:hover {\\r\\n color: #4096ff;\\n}\\r\\n\\r\\n/* ── Chat Body ── */\\n.chat-body[data-v-9693c11e] {\\r\\n flex: 1;\\r\\n overflow-y: auto;\\r\\n padding: 16px clamp(12px, 3vw, 40px);\\r\\n scroll-behavior: auto;\\r\\n position: relative;\\r\\n -webkit-overflow-scrolling: touch;\\r\\n background: url(https://qiguanbang.obs.cn-east-3.myhuaweicloud.com/production/image/AlAgent/agentbackground.png) 100% no-repeat;\\r\\n background-size: 100% 100%;\\r\\n background-position: center;\\r\\n background-size: cover;\\r\\n min-height: 0;\\n}\\n.welcome[data-v-9693c11e] {\\r\\n display: flex;\\r\\n flex-direction: column;\\r\\n align-items: center;\\r\\n justify-content: center;\\r\\n height: 100%;\\r\\n color: #bbb;\\r\\n margin: 0 -20px;\\n}\\n.welcome-icon[data-v-9693c11e] {\\r\\n margin-bottom: 12px;\\r\\n opacity: 0.7;\\n}\\n.welcome-text[data-v-9693c11e] {\\r\\n font-size: 15px;\\n}\\n.welcome-default .welcome-icon[data-v-9693c11e] {\\r\\n margin-bottom: 16px;\\n}\\n.welcome-title[data-v-9693c11e] {\\r\\n font-size: 20px;\\r\\n font-weight: 600;\\r\\n color: #333;\\r\\n margin-bottom: 8px;\\n}\\r\\n\\r\\n/* ── Message Row ── */\\n.msg-row[data-v-9693c11e] {\\r\\n width: 100%;\\r\\n display: flex;\\r\\n justify-content: center;\\r\\n padding: 20px 16px;\\r\\n box-sizing: border-box;\\r\\n align-items: center;\\n}\\n.msg-main[data-v-9693c11e] {\\r\\n display: flex;\\r\\n align-items: flex-start;\\r\\n gap: 10px;\\r\\n max-width: 85%;\\r\\n width: min(100%, 860px) !important;\\r\\n max-width: 860px;\\n}\\n.msg-row.user .msg-main[data-v-9693c11e] {\\r\\n flex-direction: row-reverse;\\n}\\n.msg-row.assistant[data-v-9693c11e] {\\r\\n justify-content: center;\\n}\\n.load-more[data-v-9693c11e] {\\r\\n text-align: center;\\r\\n font-size: 12px;\\r\\n color: #999;\\r\\n padding: 4px 0;\\n}\\n.msg-time[data-v-9693c11e] {\\r\\n font-size: 11px;\\r\\n color: #bbb;\\r\\n margin-top: 2px;\\r\\n padding-left: 4px;\\n}\\n.msg-row.user .msg-time[data-v-9693c11e] {\\r\\n text-align: right;\\r\\n padding-right: 4px;\\n}\\n.msg-actions[data-v-9693c11e] {\\r\\n display: flex;\\r\\n gap: 4px;\\r\\n margin-top: 4px;\\r\\n padding-left: 4px;\\r\\n align-items: center;\\r\\n justify-content: space-between;\\n}\\n.ai-badge[data-v-9693c11e] {\\r\\n font-size: 11px;\\r\\n color: #999;\\r\\n /* background: #f5f5f5; */\\r\\n padding: 1px 6px;\\r\\n border-radius: 3px;\\r\\n white-space: nowrap;\\r\\n -webkit-user-select: none;\\r\\n -moz-user-select: none;\\r\\n -ms-user-select: none;\\r\\n user-select: none;\\r\\n margin-left: auto;\\n}\\n.action-btn[data-v-9693c11e] {\\r\\n font-size: 12px;\\r\\n color: #999;\\r\\n cursor: pointer;\\r\\n padding: 2px 6px 2px 0;\\r\\n border-radius: 4px;\\r\\n transition: all 0.2s;\\r\\n -webkit-user-select: none;\\r\\n -moz-user-select: none;\\r\\n -ms-user-select: none;\\r\\n user-select: none;\\n}\\n.action-btn[data-v-9693c11e]:hover {\\r\\n color: #1677ff;\\r\\n background: #f0f5ff;\\n}\\r\\n\\r\\n/* ── STT 语音转文字状态 ── */\\n.stt-status-block[data-v-9693c11e] {\\r\\n display: flex;\\r\\n align-items: center;\\r\\n gap: 8px;\\r\\n font-size: 14px;\\r\\n line-height: 1.5;\\n}\\n.stt-bubble-wrap[data-v-9693c11e] {\\r\\n position: relative;\\r\\n display: flex;\\r\\n align-items: center;\\r\\n font-size: 15px;\\r\\n line-height: 1.4;\\n}\\n.stt-outside-icon[data-v-9693c11e] {\\r\\n position: absolute;\\r\\n right: 100%;\\r\\n top: 50%;\\r\\n margin-top: -9px;\\r\\n margin-right: 20px;\\n}\\n.stt-spinner[data-v-9693c11e] {\\r\\n display: inline-block;\\r\\n width: 18px;\\r\\n height: 18px;\\r\\n border: 2.5px solid #d9d9d9;\\r\\n border-top-color: #1677ff;\\r\\n border-right-color: #4096ff;\\r\\n border-radius: 50%;\\r\\n -webkit-animation: stt-spin-data-v-9693c11e 0.6s linear infinite;\\r\\n animation: stt-spin-data-v-9693c11e 0.6s linear infinite;\\r\\n flex-shrink: 0;\\r\\n box-sizing: border-box;\\n}\\n@-webkit-keyframes stt-spin-data-v-9693c11e {\\nto { transform: rotate(360deg);\\n}\\n}\\n@keyframes stt-spin-data-v-9693c11e {\\nto { transform: rotate(360deg);\\n}\\n}\\n.stt-error-icon[data-v-9693c11e] {\\r\\n display: inline-flex;\\r\\n align-items: center;\\r\\n justify-content: center;\\r\\n width: 18px;\\r\\n height: 18px;\\r\\n background: #ff4d4f;\\r\\n color: #fff;\\r\\n font-size: 12px;\\r\\n font-weight: 700;\\r\\n border-radius: 50%;\\r\\n line-height: 1;\\r\\n flex-shrink: 0;\\n}\\n.stt-bubble-text[data-v-9693c11e] {\\r\\n font-size: 15px;\\r\\n line-height: 1.4;\\r\\n color: #fff;\\r\\n white-space: nowrap;\\r\\n margin: 6px 0;\\n}\\n.msg-avatar[data-v-9693c11e] {\\r\\n width: 36px;\\r\\n height: 36px;\\r\\n border-radius: 50%;\\r\\n display: flex;\\r\\n align-items: center;\\r\\n justify-content: center;\\r\\n font-size: 13px;\\r\\n font-weight: 700;\\r\\n flex-shrink: 0;\\r\\n color: #fff;\\n}\\n.msg-avatar.user[data-v-9693c11e] {\\r\\n background: linear-gradient(135deg, #1677ff, #4096ff);\\r\\n color: #fff;\\n}\\n.msg-avatar.assistant[data-v-9693c11e] {\\r\\n background: linear-gradient(135deg, #52c41a, #73d13d);\\r\\n color: #fff;\\n}\\n.msg-agent-label[data-v-9693c11e] {\\r\\n font-size: 12px;\\r\\n color: #999;\\r\\n margin-bottom: 2px;\\n}\\n.msg-content[data-v-9693c11e] {\\r\\n width: 100% !important;\\r\\n max-width: 100%;\\r\\n box-sizing: border-box;\\r\\n overflow: hidden;\\n}\\r\\n\\r\\n/* ── Bubble ── */\\n.bubble[data-v-9693c11e] {\\r\\n max-width: 100%;\\r\\n min-width: 30px;\\r\\n width: -webkit-fit-content;\\r\\n width: -moz-fit-content;\\r\\n width: fit-content;\\r\\n padding: 8px 14px;\\r\\n border-radius: 12px;\\r\\n line-height: 1.4;\\r\\n font-size: 15px;\\r\\n word-break: break-word;\\r\\n white-space: normal;\\r\\n text-align: left;\\r\\n overflow-wrap: anywhere;\\n}\\n.bubble[data-v-9693c11e]:has(.typing) {\\r\\n padding: 16px 20px;\\n}\\n.bubble.user[data-v-9693c11e] {\\r\\n background: #1677ff;\\r\\n color: #fff;\\r\\n border-bottom-right-radius: 4px;\\r\\n box-shadow: 0 2px 8px rgba(22, 119, 255, 0.15);\\r\\n float: none;\\r\\n margin-left: auto;\\r\\n max-width: min(100%, 520px);\\n}\\n.bubble.assistant[data-v-9693c11e] {\\r\\n background: #fff;\\r\\n color: #333;\\r\\n border-bottom-left-radius: 4px;\\r\\n box-shadow: 0 1px 4px rgba(0, 0, 0, 0.06);\\r\\n text-align: left;\\r\\n width: 100%;\\r\\n box-sizing: border-box;\\n}\\n.bubble[data-v-9693c11e] table {\\r\\n border-collapse: collapse;\\r\\n width: 100%;\\r\\n margin: 6px 0;\\r\\n font-size: 14px;\\n}\\n.bubble[data-v-9693c11e] th,\\r\\n.bubble[data-v-9693c11e] td {\\r\\n border: 1px solid #e8e8e8;\\r\\n padding: 5px 8px;\\r\\n text-align: left;\\n}\\n.bubble[data-v-9693c11e] th {\\r\\n background: #fafafa;\\r\\n font-weight: 600;\\n}\\n.bubble[data-v-9693c11e] code {\\r\\n padding: 1px 5px;\\r\\n border-radius: 3px;\\r\\n font-size: 14px;\\n}\\n.bubble[data-v-9693c11e] pre {\\r\\n background: #f6f8fa;\\r\\n color: #333;\\r\\n padding: 12px;\\r\\n border-radius: 6px;\\r\\n overflow-x: auto;\\r\\n font-size: 13px;\\r\\n border: 1px solid #e8e8e8;\\r\\n margin: 8px 0;\\r\\n line-height: 1.5;\\r\\n white-space: pre;\\n}\\n.bubble[data-v-9693c11e] ul,\\r\\n.bubble[data-v-9693c11e] ol {\\r\\n padding-left: 20px;\\r\\n margin: 4px 0;\\n}\\n.bubble[data-v-9693c11e] li {\\r\\n margin: 2px 0;\\n}\\n.bubble[data-v-9693c11e] p {\\r\\n margin: 6px 0;\\n}\\r\\n\\r\\n/* ── Thinking ── */\\n.thinking-details[data-v-9693c11e] {\\r\\n margin-bottom: 10px;\\r\\n border: 1px solid #e8e8e8;\\r\\n border-radius: 8px;\\r\\n overflow: hidden;\\r\\n background: #fafafa;\\n}\\n.thinking-summary[data-v-9693c11e] {\\r\\n font-size: 12px;\\r\\n color: #888;\\r\\n cursor: pointer;\\r\\n padding: 6px 10px;\\r\\n -webkit-user-select: none;\\r\\n -moz-user-select: none;\\r\\n -ms-user-select: none;\\r\\n user-select: none;\\n}\\n.thinking-summary[data-v-9693c11e]:hover {\\r\\n color: #1677ff;\\n}\\n.thinking-body[data-v-9693c11e] {\\r\\n font-size: 14px;\\r\\n color: #666;\\r\\n padding: 8px 12px;\\r\\n line-height: 1.6;\\r\\n border-top: 1px solid #f0f0f0;\\r\\n text-align: left;\\r\\n white-space: pre-wrap;\\r\\n word-break: break-word;\\r\\n overflow-wrap: break-word;\\r\\n overflow-wrap: anywhere;\\n}\\n.final-content[data-v-9693c11e] {\\r\\n word-break: break-word;\\r\\n overflow-wrap: break-word;\\r\\n overflow-wrap: anywhere;\\n}\\n.tokui-shell[data-v-9693c11e] {\\r\\n font-size: 14px;\\r\\n line-height: 1.6;\\r\\n color: inherit;\\r\\n font-family: \\\"Segoe UI\\\", \\\"PingFang SC\\\", \\\"Microsoft YaHei\\\", Arial, sans-serif;\\r\\n font-weight: normal;\\r\\n letter-spacing: normal;\\r\\n text-transform: none;\\n}\\n.tokui-shell .tokui-stream[data-v-9693c11e] {\\r\\n font-size: 14px !important;\\r\\n line-height: 1.6 !important;\\r\\n color: inherit;\\r\\n font-family: \\\"Segoe UI\\\", \\\"PingFang SC\\\", \\\"Microsoft YaHei\\\", Arial, sans-serif !important;\\r\\n font-weight: normal !important;\\r\\n letter-spacing: normal !important;\\r\\n text-align: left;\\r\\n width: 100%;\\r\\n overflow-wrap: anywhere;\\r\\n -webkit-text-size-adjust: 100%;\\n}\\n.tokui-shell .tokui-stream > *[data-v-9693c11e] {\\r\\n font-size: 14px !important;\\r\\n line-height: 1.6 !important;\\r\\n font-family: \\\"Segoe UI\\\", \\\"PingFang SC\\\", \\\"Microsoft YaHei\\\", Arial, sans-serif !important;\\r\\n font-weight: normal !important;\\r\\n letter-spacing: normal !important;\\n}\\n.tokui-shell .tokui-stream p[data-v-9693c11e],\\r\\n.tokui-shell .tokui-stream ul[data-v-9693c11e],\\r\\n.tokui-shell .tokui-stream ol[data-v-9693c11e],\\r\\n.tokui-shell .tokui-stream li[data-v-9693c11e],\\r\\n.tokui-shell .tokui-stream table[data-v-9693c11e],\\r\\n.tokui-shell .tokui-stream code[data-v-9693c11e],\\r\\n.tokui-shell .tokui-stream pre[data-v-9693c11e],\\r\\n.tokui-shell .tokui-stream th[data-v-9693c11e],\\r\\n.tokui-shell .tokui-stream td[data-v-9693c11e] {\\r\\n font-size: 14px !important;\\r\\n line-height: 1.6 !important;\\r\\n font-family: \\\"Segoe UI\\\", \\\"PingFang SC\\\", \\\"Microsoft YaHei\\\", Arial, sans-serif !important;\\r\\n font-weight: normal !important;\\r\\n letter-spacing: normal !important;\\n}\\n.tokui-shell .tokui-stream[data-v-9693c11e] .tokui-desc__label,\\r\\n.tokui-shell .tokui-stream[data-v-9693c11e] .tokui-desc__value,\\r\\n.tokui-shell .tokui-stream[data-v-9693c11e] .tokui-dv-text,\\r\\n.tokui-shell .tokui-stream[data-v-9693c11e] .tokui-tag,\\r\\n.tokui-shell .tokui-stream[data-v-9693c11e] .tokui-h3,\\r\\n.tokui-shell .tokui-stream[data-v-9693c11e] .tokui-label {\\r\\n box-sizing: border-box;\\r\\n font-family: \\\"Segoe UI\\\", \\\"PingFang SC\\\", \\\"Microsoft YaHei\\\", Arial, sans-serif !important;\\r\\n font-weight: normal !important;\\r\\n line-height: 1.6 !important;\\r\\n letter-spacing: normal !important;\\r\\n text-transform: none !important;\\r\\n color: inherit;\\r\\n margin: 0;\\r\\n padding: 0;\\n}\\n.tokui-shell[data-v-9693c11e] .tokui-desc__label {\\r\\n font-size: 13px !important;\\r\\n color: #8c8c8c !important;\\r\\n line-height: 1.4 !important;\\r\\n margin-bottom: 2px !important;\\n}\\n.tokui-shell .tokui-stream[data-v-9693c11e] .tokui-desc__value {\\r\\n font-size: 14px !important;\\r\\n color: inherit !important;\\r\\n line-height: 1.6 !important;\\r\\n overflow-wrap: anywhere;\\n}\\n.tokui-shell .tokui-stream[data-v-9693c11e] .tokui-dv-text {\\r\\n font-size: 14px !important;\\r\\n color: inherit !important;\\r\\n line-height: 1.6 !important;\\r\\n display: inline-block;\\r\\n overflow-wrap: anywhere;\\n}\\n.tokui-shell .tokui-stream[data-v-9693c11e] .tokui-tag {\\r\\n display: inline-flex !important;\\r\\n align-items: center;\\r\\n justify-content: center;\\r\\n padding: 2px 8px !important;\\r\\n border-radius: 999px !important;\\r\\n font-size: 12px !important;\\r\\n font-weight: 600 !important;\\r\\n line-height: 1.4 !important;\\r\\n color: #1677ff !important;\\r\\n background: #e6f4ff !important;\\r\\n border: 1px solid #bae0ff !important;\\r\\n white-space: nowrap;\\n}\\n.tokui-shell.android .tokui-stream[data-v-9693c11e] .tokui-row {\\r\\n display: flex !important;\\r\\n flex-wrap: wrap !important;\\r\\n gap: 12px !important;\\n}\\n.tokui-shell.android .tokui-stream[data-v-9693c11e] .tokui-col.tokui-col--6 {\\r\\n flex: 1 1 calc(50% - 12px) !important;\\r\\n max-width: calc(50% - 12px) !important;\\r\\n min-width: min(260px, 100%) !important;\\r\\n box-sizing: border-box !important;\\n}\\n.tokui-shell.android .tokui-stream[data-v-9693c11e] .tokui-desc__value {\\r\\n min-width: 0 !important;\\r\\n width: 100% !important;\\r\\n white-space: normal !important;\\r\\n overflow-wrap: anywhere !important;\\n}\\n.tokui-shell[data-v-9693c11e] .tokui-card-header {\\r\\n display: flex !important;\\r\\n align-items: center !important;\\r\\n padding: 10px 12px !important;\\r\\n margin: 0 !important;\\r\\n font-size: 14px !important;\\r\\n line-height: 1.4 !important;\\r\\n color: inherit !important;\\r\\n background: transparent !important;\\r\\n border: none !important;\\n}\\n.tokui-shell[data-v-9693c11e] .tokui-card-header .tokui-h3,\\r\\n.tokui-shell[data-v-9693c11e] .tokui-card-header .tokui-h4 {\\r\\n font-size: 15px !important;\\r\\n font-weight: 600 !important;\\r\\n line-height: 1.4 !important;\\r\\n margin: 0 !important;\\r\\n color: inherit !important;\\n}\\n.tokui-shell .tokui-stream[data-v-9693c11e] .tokui-h3 {\\r\\n font-size: 16px !important;\\r\\n font-weight: 600 !important;\\r\\n line-height: 1.4 !important;\\r\\n color: inherit !important;\\r\\n margin: 10px 0 6px !important;\\n}\\n.tokui-shell .tokui-stream[data-v-9693c11e] .tokui-label {\\r\\n display: block !important;\\r\\n font-size: 13px !important;\\r\\n font-weight: 500 !important;\\r\\n line-height: 1.4 !important;\\r\\n color: #8c8c8c !important;\\r\\n margin: 0 0 4px !important;\\n}\\n.thinking-body[data-v-9693c11e] p {\\r\\n margin: 4px 0;\\n}\\r\\n\\r\\n/* ── Typing ── */\\n.typing[data-v-9693c11e] {\\r\\n display: flex;\\r\\n flex-direction: row;\\r\\n align-items: center;\\r\\n gap: 8px;\\r\\n min-height: 24px;\\r\\n justify-content: flex-start;\\r\\n padding: 4px 0;\\n}\\n.typing .phrase[data-v-9693c11e] {\\r\\n font-size: 14px;\\r\\n color: #888;\\r\\n white-space: nowrap;\\r\\n -webkit-animation: phraseFade-data-v-9693c11e 0.5s ease;\\r\\n animation: phraseFade-data-v-9693c11e 0.5s ease;\\r\\n letter-spacing: 0.5px;\\n}\\n.typing .dots[data-v-9693c11e] {\\r\\n display: flex;\\r\\n gap: 5px;\\r\\n align-items: center;\\r\\n justify-content: center;\\n}\\n.typing .dots span[data-v-9693c11e] {\\r\\n width: 8px;\\r\\n height: 8px;\\r\\n background: #bbb;\\r\\n border-radius: 50%;\\r\\n -webkit-animation: dtTyping-data-v-9693c11e 1.3s infinite ease-in-out;\\r\\n animation: dtTyping-data-v-9693c11e 1.3s infinite ease-in-out;\\n}\\n.typing .dots span[data-v-9693c11e]:nth-child(2) {\\r\\n -webkit-animation-delay: 0.16s;\\r\\n animation-delay: 0.16s;\\n}\\n.typing .dots span[data-v-9693c11e]:nth-child(3) {\\r\\n -webkit-animation-delay: 0.32s;\\r\\n animation-delay: 0.32s;\\n}\\n@-webkit-keyframes phraseFade-data-v-9693c11e {\\nfrom {\\r\\n opacity: 0.2;\\r\\n transform: translateY(4px);\\n}\\nto {\\r\\n opacity: 1;\\r\\n transform: translateY(0);\\n}\\n}\\n@keyframes phraseFade-data-v-9693c11e {\\nfrom {\\r\\n opacity: 0.2;\\r\\n transform: translateY(4px);\\n}\\nto {\\r\\n opacity: 1;\\r\\n transform: translateY(0);\\n}\\n}\\n@-webkit-keyframes dtTyping-data-v-9693c11e {\\n0%,\\r\\n 60%,\\r\\n 100% {\\r\\n transform: translateY(0);\\r\\n opacity: 0.3;\\n}\\n30% {\\r\\n transform: translateY(-5px);\\r\\n opacity: 1;\\n}\\n}\\n@keyframes dtTyping-data-v-9693c11e {\\n0%,\\r\\n 60%,\\r\\n 100% {\\r\\n transform: translateY(0);\\r\\n opacity: 0.3;\\n}\\n30% {\\r\\n transform: translateY(-5px);\\r\\n opacity: 1;\\n}\\n}\\r\\n\\r\\n/* ── Wait Timer ── */\\n.typing.wait-5 .dots span[data-v-9693c11e] {\\r\\n width: 8px;\\r\\n height: 8px;\\r\\n -webkit-animation-duration: 1s;\\r\\n animation-duration: 1s;\\n}\\n.typing.wait-5 .phrase[data-v-9693c11e] {\\r\\n color: #888;\\n}\\n.typing.wait-10 .dots span[data-v-9693c11e] {\\r\\n width: 9px;\\r\\n height: 9px;\\r\\n -webkit-animation-duration: 0.8s;\\r\\n animation-duration: 0.8s;\\r\\n background: #909399;\\n}\\n.typing.wait-10 .phrase[data-v-9693c11e] {\\r\\n color: #909399;\\n}\\n.typing.wait-10 .dots[data-v-9693c11e] {\\r\\n -webkit-animation: dtPulse-data-v-9693c11e 1s infinite ease-in-out;\\r\\n animation: dtPulse-data-v-9693c11e 1s infinite ease-in-out;\\n}\\n.typing.wait-15 .dots span[data-v-9693c11e] {\\r\\n width: 10px;\\r\\n height: 10px;\\r\\n -webkit-animation-duration: 0.6s;\\r\\n animation-duration: 0.6s;\\r\\n background: #1677ff;\\n}\\n.typing.wait-15 .phrase[data-v-9693c11e] {\\r\\n color: #1677ff;\\n}\\n.typing.wait-15 .dots[data-v-9693c11e] {\\r\\n -webkit-animation: dtPulse-data-v-9693c11e 0.6s infinite ease-in-out;\\r\\n animation: dtPulse-data-v-9693c11e 0.6s infinite ease-in-out;\\n}\\n@-webkit-keyframes dtPulse-data-v-9693c11e {\\n0%,\\r\\n 100% {\\r\\n transform: scale(1);\\n}\\n50% {\\r\\n transform: scale(1.05);\\n}\\n}\\n@keyframes dtPulse-data-v-9693c11e {\\n0%,\\r\\n 100% {\\r\\n transform: scale(1);\\n}\\n50% {\\r\\n transform: scale(1.05);\\n}\\n}\\r\\n\\r\\n/* ── Tool Calls ── */\\n.tool-calls[data-v-9693c11e] {\\r\\n margin-top: 8px;\\n}\\n.tool-item[data-v-9693c11e] {\\r\\n background: #f5f5f5;\\r\\n border-radius: 6px;\\r\\n padding: 6px 10px;\\r\\n margin-bottom: 4px;\\r\\n font-size: 12px;\\n}\\n.tool-badge[data-v-9693c11e] {\\r\\n display: inline-block;\\r\\n margin-bottom: 2px;\\r\\n font-size: 11px;\\r\\n color: #fa8c16;\\r\\n font-weight: 500;\\n}\\n.tool-item pre[data-v-9693c11e] {\\r\\n margin: 0;\\r\\n white-space: pre-wrap;\\r\\n word-break: break-all;\\r\\n font-size: 12px;\\r\\n color: #666;\\r\\n max-height: 120px;\\r\\n overflow-y: auto;\\n}\\r\\n\\r\\n/* ── Scroll Buttons ── */\\n.scroll-btns[data-v-9693c11e] {\\r\\n position: sticky;\\r\\n left: 50%;\\r\\n transform: translateX(-50%);\\r\\n bottom: 20px;\\r\\n z-index: 99;\\r\\n display: flex;\\r\\n justify-content: center;\\r\\n margin-top: 10px;\\r\\n pointer-events: none;\\n}\\n.scroll-btn[data-v-9693c11e] {\\r\\n pointer-events: auto;\\r\\n width: 38px;\\r\\n height: 38px;\\r\\n border-radius: 50%;\\r\\n background: #fff;\\r\\n box-shadow: 0 2px 10px rgba(0, 0, 0, 0.15);\\r\\n display: flex;\\r\\n align-items: center;\\r\\n justify-content: center;\\r\\n cursor: pointer;\\n}\\n.scroll-btn i[data-v-9693c11e] {\\r\\n font-size: 16px;\\r\\n color: #333;\\n}\\r\\n\\r\\n/* ── Footer ── */\\n.chat-footer[data-v-9693c11e] {\\r\\n flex-shrink: 0;\\r\\n border-top: none;\\r\\n padding: 30px 0;\\r\\n display: flex;\\r\\n align-items: center;\\r\\n justify-content: center;\\r\\n margin: 0 auto;\\r\\n width: 100%;\\n}\\n.input-area[data-v-9693c11e] {\\r\\n position: relative;\\r\\n display: flex;\\r\\n align-items: flex-end;\\r\\n gap: 6px;\\r\\n background: #fff;\\r\\n border-radius: 24px;\\r\\n margin: 0 24px;\\r\\n padding: 18px 20px;\\r\\n border: 1px solid #b3d8ff;\\r\\n transition: border-color 0.2s;\\r\\n flex-wrap: wrap;\\r\\n width: min(100%, 1000px) !important;\\r\\n box-sizing: border-box;\\n}\\n.input-area[data-v-9693c11e]:focus-within {\\r\\n border-color: #1677ff;\\r\\n background: #fff;\\r\\n box-shadow: none;\\n}\\n.input-area[data-v-9693c11e]::after {\\r\\n content: \\\"Enter 发送,Ctrl+Enter 换行\\\";\\r\\n position: absolute;\\r\\n right: 100px;\\r\\n bottom: 28px;\\r\\n font-size: 14px;\\r\\n color: #8c8c8c;\\r\\n pointer-events: none;\\n}\\n.scroll-bottom-wrap[data-v-9693c11e] {\\r\\n position: absolute;\\r\\n left: 50%;\\r\\n transform: translateX(-50%);\\r\\n bottom: calc(100% + 30px);\\r\\n z-index: 99;\\r\\n display: flex;\\r\\n justify-content: center;\\r\\n pointer-events: none;\\n}\\n.scroll-bottom-btn[data-v-9693c11e] {\\r\\n width: 36px;\\r\\n height: 36px;\\r\\n border-radius: 50%;\\r\\n background: #fff;\\r\\n border: 1px solid #e5e7eb;\\r\\n display: flex;\\r\\n align-items: center;\\r\\n justify-content: center;\\r\\n cursor: pointer;\\r\\n pointer-events: auto;\\r\\n position: relative;\\r\\n box-shadow: 0 2px 10px rgba(0, 0, 0, 0.08);\\n}\\n.scroll-bottom-btn svg[data-v-9693c11e] {\\r\\n color: #4e5969;\\n}\\n.scroll-bottom-btn[data-v-9693c11e]:hover {\\r\\n transform: scale(1.1);\\n}\\n.loading-circle[data-v-9693c11e] {\\r\\n position: absolute;\\r\\n inset: 3px;\\r\\n border-radius: 50%;\\r\\n border: 1.5px solid transparent;\\r\\n border-top: 1.5px solid #1677ff;\\r\\n -webkit-animation: circle-spin-data-v-9693c11e 1.5s linear infinite;\\r\\n animation: circle-spin-data-v-9693c11e 1.5s linear infinite;\\n}\\n@-webkit-keyframes circle-spin-data-v-9693c11e {\\nfrom {\\r\\n transform: rotate(0deg);\\n}\\nto {\\r\\n transform: rotate(360deg);\\n}\\n}\\n@keyframes circle-spin-data-v-9693c11e {\\nfrom {\\r\\n transform: rotate(0deg);\\n}\\nto {\\r\\n transform: rotate(360deg);\\n}\\n}\\n.chat-textarea[data-v-9693c11e] {\\r\\n flex: 1;\\r\\n border: none;\\r\\n outline: none;\\r\\n background: transparent;\\r\\n resize: none;\\r\\n font-size: 16px;\\r\\n line-height: 24px;\\r\\n min-height: 38px;\\r\\n height: 100px;\\r\\n max-height: 100px;\\r\\n overflow-y: auto;\\r\\n padding: 0;\\r\\n box-sizing: border-box;\\r\\n font-family: inherit;\\r\\n color: #333;\\r\\n flex: 1 1 320px;\\r\\n min-width: 0;\\n}\\n.chat-textarea[data-v-9693c11e]::-moz-placeholder {\\r\\n color: #999;\\r\\n font-size: 16px;\\n}\\n.chat-textarea[data-v-9693c11e]:-ms-input-placeholder {\\r\\n color: #999;\\r\\n font-size: 16px;\\n}\\n.chat-textarea[data-v-9693c11e]::placeholder {\\r\\n color: #999;\\r\\n font-size: 16px;\\n}\\n.send-btn[data-v-9693c11e] {\\r\\n width: auto;\\r\\n height: 40px;\\r\\n padding: 0 21px;\\r\\n border-radius: 6px;\\r\\n border: none;\\r\\n display: flex;\\r\\n align-items: center;\\r\\n justify-content: center;\\r\\n cursor: pointer;\\r\\n flex-shrink: 0;\\r\\n transition: all 0.2s;\\r\\n background: #1677ff;\\r\\n color: #fff;\\r\\n font-size: 14px;\\n}\\n.send-btn svg[data-v-9693c11e] {\\r\\n display: none;\\n}\\n.send-btn[data-v-9693c11e]::after {\\r\\n content: \\\"发送\\\";\\n}\\n.send-btn.active[data-v-9693c11e] {\\r\\n background: #1677ff;\\n}\\n.send-btn.active[data-v-9693c11e]:hover {\\r\\n background: #4096ff;\\n}\\n.send-btn[data-v-9693c11e]:disabled {\\r\\n background: #88bfff;\\r\\n cursor: not-allowed;\\n}\\n.stop-btn[data-v-9693c11e] {\\r\\n width: 35px;\\r\\n height: 35px;\\r\\n border-radius: 50%;\\r\\n border: none;\\r\\n cursor: pointer;\\r\\n display: flex;\\r\\n align-items: center;\\r\\n justify-content: center;\\r\\n background: #ff4d4f;\\r\\n color: #fff;\\r\\n flex-shrink: 0;\\r\\n transition: all 0.2s;\\n}\\n.stop-btn[data-v-9693c11e]:hover {\\r\\n background: #ff7875;\\n}\\r\\n\\r\\n/* ── Voice ── */\\n.voice-btn[data-v-9693c11e] {\\r\\n display: flex;\\r\\n align-items: center;\\r\\n justify-content: center;\\r\\n width: 36px;\\r\\n height: 36px;\\r\\n min-width: 36px;\\r\\n border: none;\\r\\n background: transparent;\\r\\n border-radius: 50%;\\r\\n color: #333;\\r\\n cursor: pointer;\\r\\n flex-shrink: 0;\\r\\n transition: background 0.2s;\\r\\n padding: 0;\\n}\\n.voice-btn[data-v-9693c11e]:active {\\r\\n background: rgba(0,0,0,0.05);\\n}\\n.voice-btn[data-v-9693c11e]:disabled {\\r\\n opacity: 0.4;\\r\\n cursor: not-allowed;\\n}\\n.hold-talk-btn[data-v-9693c11e] {\\r\\n flex: 1;\\r\\n display: flex;\\r\\n align-items: center;\\r\\n justify-content: center;\\r\\n gap: 6px;\\r\\n height: 36px;\\r\\n min-height: 36px;\\r\\n margin: 0 4px;\\r\\n border-radius: 18px;\\r\\n background: #EBEBEB;\\r\\n border: none;\\r\\n font-size: 14px;\\r\\n color: #666;\\r\\n cursor: pointer;\\r\\n -moz-user-select: none;\\r\\n -ms-user-select: none;\\r\\n user-select: none;\\r\\n -webkit-user-select: none;\\r\\n transition: background 0.15s;\\n}\\n.hold-talk-btn[data-v-9693c11e]:active {\\r\\n background: #ddd;\\n}\\n.hold-talk-btn.recording[data-v-9693c11e] {\\r\\n background: #e8f0fe;\\r\\n color: #333;\\n}\\n.hold-talk-btn .hold-talk-icon[data-v-9693c11e] {\\r\\n flex-shrink: 0;\\n}\\r\\n\\r\\n/* ── Voice Recording Overlay ── */\\n.voice-recording-overlay[data-v-9693c11e] {\\r\\n position: fixed;\\r\\n left: 0;\\r\\n right: 0;\\r\\n top: 0;\\r\\n bottom: 0;\\r\\n z-index: 1000;\\r\\n display: flex;\\r\\n align-items: center;\\r\\n justify-content: center;\\r\\n background: rgba(0,0,0,0.35);\\r\\n -webkit-animation: fadeIn-data-v-9693c11e 0.15s ease;\\r\\n animation: fadeIn-data-v-9693c11e 0.15s ease;\\n}\\n.voice-recording-card[data-v-9693c11e] {\\r\\n width: 200px;\\r\\n padding: 32px 24px 24px;\\r\\n background: #fff;\\r\\n border-radius: 20px;\\r\\n display: flex;\\r\\n flex-direction: column;\\r\\n align-items: center;\\r\\n gap: 16px;\\r\\n box-shadow: 0 8px 32px rgba(0,0,0,0.15);\\n}\\n.voice-recording-wave[data-v-9693c11e] {\\r\\n display: flex;\\r\\n align-items: center;\\r\\n gap: 4px;\\r\\n height: 40px;\\n}\\n.voice-recording-wave span[data-v-9693c11e] {\\r\\n width: 4px;\\r\\n background: #1677ff;\\r\\n border-radius: 2px;\\r\\n -webkit-animation: waveAnim-data-v-9693c11e 0.6s ease-in-out infinite alternate;\\r\\n animation: waveAnim-data-v-9693c11e 0.6s ease-in-out infinite alternate;\\n}\\n.voice-recording-wave span[data-v-9693c11e]:nth-child(1) { height: 16px; -webkit-animation-delay: 0s; animation-delay: 0s;\\n}\\n.voice-recording-wave span[data-v-9693c11e]:nth-child(2) { height: 28px; -webkit-animation-delay: 0.1s; animation-delay: 0.1s;\\n}\\n.voice-recording-wave span[data-v-9693c11e]:nth-child(3) { height: 40px; -webkit-animation-delay: 0.2s; animation-delay: 0.2s;\\n}\\n.voice-recording-wave span[data-v-9693c11e]:nth-child(4) { height: 28px; -webkit-animation-delay: 0.3s; animation-delay: 0.3s;\\n}\\n.voice-recording-wave span[data-v-9693c11e]:nth-child(5) { height: 16px; -webkit-animation-delay: 0.4s; animation-delay: 0.4s;\\n}\\n@-webkit-keyframes waveAnim-data-v-9693c11e {\\n0% { transform: scaleY(0.6);\\n}\\n100% { transform: scaleY(1);\\n}\\n}\\n@keyframes waveAnim-data-v-9693c11e {\\n0% { transform: scaleY(0.6);\\n}\\n100% { transform: scaleY(1);\\n}\\n}\\n.voice-recording-duration[data-v-9693c11e] {\\r\\n font-size: 32px;\\r\\n font-weight: 600;\\r\\n color: #333;\\r\\n line-height: 1;\\n}\\n.voice-recording-duration .unit[data-v-9693c11e] {\\r\\n font-size: 18px;\\r\\n font-weight: 400;\\r\\n color: #999;\\r\\n margin-left: 2px;\\n}\\n.voice-recording-hint[data-v-9693c11e] {\\r\\n display: flex;\\r\\n align-items: center;\\r\\n gap: 4px;\\r\\n font-size: 13px;\\r\\n color: #999;\\n}\\n.voice-recording-hint.cancel[data-v-9693c11e] {\\r\\n color: #ff4d4f;\\n}\\n@-webkit-keyframes fadeIn-data-v-9693c11e {\\nfrom { opacity: 0;\\n}\\nto { opacity: 1;\\n}\\n}\\n@keyframes fadeIn-data-v-9693c11e {\\nfrom { opacity: 0;\\n}\\nto { opacity: 1;\\n}\\n}\\r\\n\\r\\n/* ── Chat Agent Avatar ── */\\n.chat-agent-avatar-wrapper div[data-v-9693c11e] {\\r\\n width: 44px;\\r\\n height: 44px;\\n}\\r\\n\\r\\n/* ── Agent List Avatar ── */\\n.agent-list-avatar[data-v-9693c11e] {\\r\\n background-repeat: no-repeat;\\r\\n background-position: center;\\r\\n display: flex;\\r\\n align-items: center;\\r\\n justify-content: center;\\r\\n color: #fff;\\r\\n font-size: 22px;\\r\\n font-weight: 600;\\r\\n border-radius: 8px;\\n}\\n.agent-list-avatar.has-agent-img[data-v-9693c11e] {\\r\\n width: 97px;\\r\\n height: 126px;\\r\\n background-size: cover;\\n}\\n.agent-list-avatar[data-v-9693c11e]:not(.has-agent-img) {\\r\\n width: 76px;\\r\\n height: 108px;\\r\\n transform: translateX(9px);\\n}\\n.session-avatar[data-v-9693c11e] {\\r\\n width: 44px !important;\\r\\n height: 44px !important;\\r\\n border-radius: 50% !important;\\r\\n display: flex;\\r\\n align-items: center;\\r\\n justify-content: center;\\r\\n font-size: 16px !important;\\r\\n font-weight: 600;\\r\\n color: #fff;\\r\\n flex-shrink: 0;\\r\\n overflow: hidden;\\n}\\n.avatar-pic[data-v-9693c11e] {\\r\\n width: 85%;\\r\\n height: 85%;\\r\\n -o-object-fit: contain;\\r\\n object-fit: contain;\\n}\\r\\n\\r\\n/* ── Mobile Buttons ── */\\n.mobile-menu-btn[data-v-9693c11e],\\r\\n.mobile-back-btn[data-v-9693c11e],\\r\\n.mobile-header-btn[data-v-9693c11e] {\\r\\n display: inline-flex;\\r\\n align-items: center;\\r\\n justify-content: center;\\r\\n width: 36px;\\r\\n height: 36px;\\r\\n border: none;\\r\\n border-radius: 10px;\\r\\n background: #f5f7fa;\\r\\n color: #333;\\r\\n cursor: pointer;\\r\\n flex-shrink: 0;\\n}\\n.mobile-menu-btn i[data-v-9693c11e],\\r\\n.mobile-back-btn i[data-v-9693c11e],\\r\\n.mobile-header-btn i[data-v-9693c11e] {\\r\\n font-size: 18px;\\n}\\n.mobile-back-btn i[data-v-9693c11e] {\\r\\n font-size: 20px;\\r\\n font-weight: 600;\\n}\\r\\n/* ── 聊天空白欢迎页(匹配蓝湖移动端聊天首页) ── */\\n.chat-empty-welcome[data-v-9693c11e] {\\r\\n width: 100%;\\r\\n padding: 40px 20px;\\r\\n box-sizing: border-box;\\r\\n display: flex;\\r\\n flex-direction: column;\\r\\n gap: 0px;\\r\\n max-width: 600px;\\r\\n margin: 80px auto;\\n}\\r\\n\\r\\n/* 顶部渐变欢迎卡片 */\\n.welcome-card[data-v-9693c11e] {\\r\\n position: relative;\\r\\n background: linear-gradient(296deg, #D6EDFF 20%, #E8EBFF 80%);\\r\\nborder-radius: 16px 16px 0px 0px;\\r\\n padding: 24px 24px 24px 150px;\\r\\n overflow: visible;\\n}\\r\\n/* 左侧探出头像容器 */\\n.welcome-avatar-box[data-v-9693c11e] {\\r\\n position: absolute;\\r\\n left: 15px;\\r\\n bottom: 0px;\\r\\n width: 110px;\\r\\n height: 137px;\\n}\\n.welcome-avatar[data-v-9693c11e] {\\r\\n width: 100%;\\r\\n height: 100%;\\r\\n border-radius: 12px;\\r\\n background-size: cover;\\r\\n background-position: center;\\r\\n display: flex;\\r\\n align-items: center;\\r\\n justify-content: center;\\r\\n font-size: 20px;\\r\\n color: #fff;\\r\\n font-weight: 600;\\n}\\n.welcome-avatar.has-chat-agent-img[data-v-9693c11e] {\\r\\n background: transparent;\\r\\n background-repeat: no-repeat;\\r\\n background-position: center;\\n}\\n.welcome-text-group[data-v-9693c11e] {\\r\\n display: flex;\\r\\n flex-direction: column;\\r\\n gap: 6px;\\n}\\n.welcome-text-group .text-sm[data-v-9693c11e] {\\r\\nfont-weight: 400;font-size: 12px;color: #666666;\\r\\ntext-align: left;\\r\\nfont-style: normal;\\n}\\n.welcome-text-group .text-lg[data-v-9693c11e] {\\r\\n \\r\\n font-weight: 500;\\r\\nfont-size: 16px;\\r\\ncolor: #000000;\\n}\\r\\n\\r\\n/* 猜你想问容器 */\\n.guess-box[data-v-9693c11e] {\\r\\n border-top: 1px solid #fff;\\r\\n background: linear-gradient(180deg, #B8DCFF 0%, #DFF0FF 50%, #FFFFFF 100%);\\r\\n border-radius: 0 0 16px 16px;\\r\\n padding: 20px;\\n}\\n.guess-title[data-v-9693c11e] {\\r\\n display: flex;\\r\\n align-items: center;\\r\\n gap: 6px;\\r\\n font-size: 16px;\\r\\n font-weight: 500;\\r\\n color: #222;\\r\\n margin-bottom: 16px;\\n}\\n.tag-wrap[data-v-9693c11e] {\\r\\n display: flex;\\r\\n flex-wrap: wrap;\\r\\n gap: 10px;\\n}\\n.quick-tag[data-v-9693c11e] {\\r\\n padding: 8px 14px;\\r\\n background: #F2FAFF;\\r\\n border-radius: 8px;\\r\\n font-size: 14px;\\r\\n color: #333;\\r\\n cursor: pointer;\\r\\n border: 1px solid #e0eaff;\\r\\n transition: all 0.2s;\\r\\n white-space: nowrap;\\n}\\r\\n/* .quick-tag:hover {\\r\\n background: #f0f7ff;\\r\\n border-color: #1677ff;\\r\\n} */\\n.chat-agent-avatar-wrapper div[data-v-9693c11e]{\\r\\n width: 44px;\\r\\n height: 44px;\\n}\\r\\n/* ── Responsive ── */\\n@media screen and (max-width: 768px) {\\n.chat-header[data-v-9693c11e] {\\r\\n padding: 10px 12px;\\r\\n background: transparent;\\r\\n border-bottom: none;\\n}\\n.chat-header .chat-agent-avatar-wrapper[data-v-9693c11e] {\\r\\n display: none;\\n}\\n.chat-header .agent-desc[data-v-9693c11e] {\\r\\n display: none;\\n}\\n.chat-header .header-left[data-v-9693c11e] {\\r\\n flex: 1;\\r\\n justify-content: center;\\r\\n position: relative;\\n}\\n.chat-header .header-left .mobile-back-btn[data-v-9693c11e] {\\r\\n position: absolute;\\r\\n left: 12px;\\r\\n background: transparent;\\n}\\n.chat-header .header-actions .mobile-header-btn[data-v-9693c11e] {\\r\\n background: transparent;\\n}\\n.chat-body[data-v-9693c11e] {\\r\\n padding: 12px;\\r\\n background-position: center top;\\n}\\n.msg-row[data-v-9693c11e] {\\r\\n padding: 12px 0;\\n}\\n.msg-main[data-v-9693c11e] {\\r\\n width: 100% !important;\\r\\n max-width: 100%;\\n}\\n.bubble[data-v-9693c11e] {\\r\\n font-size: 14px;\\n}\\n.bubble.user[data-v-9693c11e] {\\r\\n max-width: 88%;\\n}\\n.chat-footer[data-v-9693c11e] {\\r\\n padding: 12px;\\r\\n flex-shrink: 0;\\r\\n background: #f5f5f5;\\r\\n box-sizing: border-box;\\n}\\r\\n /* 安全区域由 .chat-footer 统一处理,.chat-body 不需要重复加 padding */\\n.input-area[data-v-9693c11e] {\\r\\n width: 100% !important;\\r\\n margin: 0;\\r\\n padding: 6px 6px 6px 4px;\\r\\n border-radius: 24px;\\r\\n border: none;\\r\\n background: #f5f5f5;\\r\\n box-shadow: 0 2px 8px rgba(0,0,0,0.06);\\r\\n flex-wrap: nowrap;\\r\\n align-items: center;\\n}\\n.input-area[data-v-9693c11e]:focus-within {\\r\\n border-color: transparent;\\r\\n background: #f5f5f5;\\r\\n box-shadow: 0 2px 8px rgba(0,0,0,0.06);\\n}\\n.input-area[data-v-9693c11e]::after {\\r\\n display: none;\\n}\\n.voice-btn[data-v-9693c11e] {\\r\\n display: flex;\\r\\n align-items: center;\\r\\n justify-content: center;\\r\\n width: 36px;\\r\\n height: 36px;\\r\\n min-width: 36px;\\r\\n border: none;\\r\\n background: transparent;\\r\\n border-radius: 50%;\\r\\n color: #333;\\r\\n cursor: pointer;\\r\\n flex-shrink: 0;\\r\\n transition: background 0.2s;\\r\\n padding: 0;\\n}\\n.voice-btn[data-v-9693c11e]:active {\\r\\n background: rgba(0,0,0,0.05);\\n}\\n.voice-btn[data-v-9693c11e]:disabled {\\r\\n opacity: 0.4;\\r\\n cursor: not-allowed;\\n}\\n.chat-textarea[data-v-9693c11e] {\\r\\n flex: 1;\\r\\n flex-basis: 0;\\r\\n height: 36px;\\r\\n min-height: 36px;\\r\\n max-height: 100px;\\r\\n font-size: 15px;\\r\\n background: #EBEBEB;\\r\\n border-radius: 18px;\\r\\n padding: 0 14px;\\r\\n line-height: 36px;\\r\\n margin: 0 4px;\\r\\n color: #333;\\n}\\n.chat-textarea[data-v-9693c11e]::-moz-placeholder {\\r\\n color: #999;\\r\\n font-size: 15px;\\n}\\n.chat-textarea[data-v-9693c11e]:-ms-input-placeholder {\\r\\n color: #999;\\r\\n font-size: 15px;\\n}\\n.chat-textarea[data-v-9693c11e]::placeholder {\\r\\n color: #999;\\r\\n font-size: 15px;\\n}\\n.send-btn[data-v-9693c11e] {\\r\\n width: 36px;\\r\\n height: 36px;\\r\\n min-width: 36px;\\r\\n padding: 0;\\r\\n border-radius: 50%;\\r\\n display: flex;\\r\\n align-items: center;\\r\\n justify-content: center;\\r\\n background: #1677ff;\\r\\n color: #fff;\\r\\n border: none;\\r\\n cursor: pointer;\\r\\n flex-shrink: 0;\\n}\\n.send-btn svg[data-v-9693c11e] {\\r\\n display: block;\\n}\\n.send-btn[data-v-9693c11e]::after {\\r\\n content: none;\\n}\\n.send-btn.active[data-v-9693c11e] {\\r\\n background: #1677ff;\\n}\\n.send-btn[data-v-9693c11e]:disabled {\\r\\n background: #88bfff;\\r\\n cursor: not-allowed;\\n}\\n.send-btn[data-v-9693c11e]:active {\\r\\n transform: scale(0.92);\\n}\\n.stop-btn[data-v-9693c11e] {\\r\\n width: 36px;\\r\\n height: 36px;\\r\\n min-width: 36px;\\n}\\n.guess-box[data-v-9693c11e] {\\r\\n padding: 16px;\\n}\\r\\n\\r\\n /* H5 语音模式 */\\n.hold-talk-btn[data-v-9693c11e] {\\r\\n flex: 1;\\r\\n display: flex;\\r\\n align-items: center;\\r\\n justify-content: center;\\r\\n gap: 6px;\\r\\n height: 36px;\\r\\n min-height: 36px;\\r\\n margin: 0 4px;\\r\\n border-radius: 18px;\\r\\n background: #EBEBEB;\\r\\n border: none;\\r\\n font-size: 14px;\\r\\n color: #666;\\r\\n cursor: pointer;\\r\\n -moz-user-select: none;\\r\\n -ms-user-select: none;\\r\\n user-select: none;\\r\\n -webkit-user-select: none;\\r\\n transition: background 0.15s;\\n}\\n.hold-talk-btn[data-v-9693c11e]:active {\\r\\n background: #ddd;\\n}\\n.hold-talk-btn.recording[data-v-9693c11e] {\\r\\n background: #e8f0fe;\\r\\n color: #333;\\n}\\n.hold-talk-btn .hold-talk-icon[data-v-9693c11e] {\\r\\n flex-shrink: 0;\\n}\\r\\n\\r\\n /* 语音录制浮层 */\\n.voice-recording-overlay[data-v-9693c11e] {\\r\\n position: fixed;\\r\\n left: 0;\\r\\n right: 0;\\r\\n top: 0;\\r\\n bottom: 0;\\r\\n z-index: 1000;\\r\\n display: flex;\\r\\n align-items: center;\\r\\n justify-content: center;\\r\\n background: rgba(0,0,0,0.35);\\r\\n -webkit-animation: fadeIn-data-v-9693c11e 0.15s ease;\\r\\n animation: fadeIn-data-v-9693c11e 0.15s ease;\\n}\\n.voice-recording-card[data-v-9693c11e] {\\r\\n width: 200px;\\r\\n padding: 32px 24px 24px;\\r\\n background: #fff;\\r\\n border-radius: 20px;\\r\\n display: flex;\\r\\n flex-direction: column;\\r\\n align-items: center;\\r\\n gap: 16px;\\r\\n box-shadow: 0 8px 32px rgba(0,0,0,0.15);\\n}\\n.voice-recording-wave[data-v-9693c11e] {\\r\\n display: flex;\\r\\n align-items: center;\\r\\n gap: 4px;\\r\\n height: 40px;\\n}\\n.voice-recording-wave span[data-v-9693c11e] {\\r\\n width: 4px;\\r\\n background: #1677ff;\\r\\n border-radius: 2px;\\r\\n -webkit-animation: waveAnim-data-v-9693c11e 0.6s ease-in-out infinite alternate;\\r\\n animation: waveAnim-data-v-9693c11e 0.6s ease-in-out infinite alternate;\\n}\\n.voice-recording-wave span[data-v-9693c11e]:nth-child(1) { height: 16px; -webkit-animation-delay: 0s; animation-delay: 0s;\\n}\\n.voice-recording-wave span[data-v-9693c11e]:nth-child(2) { height: 28px; -webkit-animation-delay: 0.1s; animation-delay: 0.1s;\\n}\\n.voice-recording-wave span[data-v-9693c11e]:nth-child(3) { height: 40px; -webkit-animation-delay: 0.2s; animation-delay: 0.2s;\\n}\\n.voice-recording-wave span[data-v-9693c11e]:nth-child(4) { height: 28px; -webkit-animation-delay: 0.3s; animation-delay: 0.3s;\\n}\\n.voice-recording-wave span[data-v-9693c11e]:nth-child(5) { height: 16px; -webkit-animation-delay: 0.4s; animation-delay: 0.4s;\\n}\\n@-webkit-keyframes waveAnim-data-v-9693c11e {\\n0% { transform: scaleY(0.6);\\n}\\n100% { transform: scaleY(1);\\n}\\n}\\n@keyframes waveAnim-data-v-9693c11e {\\n0% { transform: scaleY(0.6);\\n}\\n100% { transform: scaleY(1);\\n}\\n}\\n.voice-recording-duration[data-v-9693c11e] {\\r\\n font-size: 32px;\\r\\n font-weight: 600;\\r\\n color: #333;\\r\\n line-height: 1;\\n}\\n.voice-recording-duration .unit[data-v-9693c11e] {\\r\\n font-size: 18px;\\r\\n font-weight: 400;\\r\\n color: #999;\\r\\n margin-left: 2px;\\n}\\n.voice-recording-hint[data-v-9693c11e] {\\r\\n display: flex;\\r\\n align-items: center;\\r\\n gap: 4px;\\r\\n font-size: 13px;\\r\\n color: #999;\\n}\\n.voice-recording-hint.cancel[data-v-9693c11e] {\\r\\n color: #ff4d4f;\\n}\\n@-webkit-keyframes fadeIn-data-v-9693c11e {\\nfrom { opacity: 0;\\n}\\nto { opacity: 1;\\n}\\n}\\n@keyframes fadeIn-data-v-9693c11e {\\nfrom { opacity: 0;\\n}\\nto { opacity: 1;\\n}\\n}\\n}\\n@media screen and (max-width: 480px) {\\n.agent-name[data-v-9693c11e] {\\r\\n font-size: 14px;\\n}\\n.agent-desc[data-v-9693c11e] {\\r\\n max-width: calc(100vw - 132px);\\n}\\n.mobile-menu-btn[data-v-9693c11e],\\r\\n .mobile-header-btn[data-v-9693c11e] {\\r\\n width: 32px;\\r\\n height: 32px;\\n}\\n}\\r\\n\", \"\"]);\n// Exports\nmodule.exports = exports;\n\n\n//# sourceURL=webpack://ZjPluginIntelligent/./src/lib/components/chatMain/ChatDetail.vue?./node_modules/css-loader/dist/cjs.js??ref--6-oneOf-1-1!./node_modules/vue-loader/lib/loaders/stylePostLoader.js!./node_modules/postcss-loader/src??ref--6-oneOf-1-2!./node_modules/cache-loader/dist/cjs.js??ref--0-0!./node_modules/vue-loader/lib??vue-loader-options");
1436
1436
 
1437
1437
  /***/ }),
1438
1438
 
@@ -11033,7 +11033,7 @@ eval("module.exports = function(module) {\n\tif (!module.webpackPolyfill) {\n\t\
11033
11033
  /*! exports provided: name, version, main, private, scripts, dependencies, devDependencies, browserslist, directories, keywords, license, files, default */
11034
11034
  /***/ (function(module) {
11035
11035
 
11036
- eval("module.exports = JSON.parse(\"{\\\"name\\\":\\\"zj-plugin-intelligent\\\",\\\"version\\\":\\\"1.2.8-beta.10\\\",\\\"main\\\":\\\"lib/ZjPluginIntelligent.umd.min.js\\\",\\\"private\\\":false,\\\"scripts\\\":{\\\"serve\\\":\\\"set NODE_OPTIONS=--openssl-legacy-provider && vue-cli-service serve\\\",\\\"build\\\":\\\"set NODE_OPTIONS=--openssl-legacy-provider && vue-cli-service build\\\",\\\"lib\\\":\\\"set NODE_OPTIONS=--openssl-legacy-provider && vue-cli-service build --target lib --name ZjPluginIntelligent --dest lib src/lib/index.js\\\",\\\"lib:test\\\":\\\"set NODE_OPTIONS=--openssl-legacy-provider && vue-cli-service build --mode test --target lib --name ZjPluginIntelligent --dest lib src/lib/index.js\\\"},\\\"dependencies\\\":{\\\"@jboltai/tokui\\\":\\\"^0.1.6\\\",\\\"crypto-js\\\":\\\"^4.2.0\\\",\\\"html2canvas\\\":\\\"^1.4.1\\\",\\\"markdown-it\\\":\\\"^14.1.0\\\"},\\\"devDependencies\\\":{\\\"@babel/preset-env\\\":\\\"^7.14.9\\\",\\\"@vue/cli-plugin-babel\\\":\\\"~4.5.0\\\",\\\"@vue/cli-plugin-eslint\\\":\\\"^4.5.13\\\",\\\"@vue/cli-plugin-vuex\\\":\\\"~4.5.0\\\",\\\"@vue/cli-service\\\":\\\"~4.5.0\\\",\\\"axios\\\":\\\"^0.27.2\\\",\\\"babel-eslint\\\":\\\"^10.1.0\\\",\\\"babel-plugin-component\\\":\\\"^1.1.1\\\",\\\"compression-webpack-plugin\\\":\\\"^6.0.3\\\",\\\"core-js\\\":\\\"^3.6.5\\\",\\\"element-ui\\\":\\\"^2.15.4\\\",\\\"eslint\\\":\\\"^7.30.0\\\",\\\"eslint-plugin-vue\\\":\\\"^7.13.0\\\",\\\"js-cookie\\\":\\\"^2.2.1\\\",\\\"obs-upload\\\":\\\"^1.0.4\\\",\\\"pako\\\":\\\"^2.1.0\\\",\\\"reconnecting-websocket\\\":\\\"^4.4.0\\\",\\\"sass\\\":\\\"^1.71.0\\\",\\\"sass-loader\\\":\\\"^8.0.2\\\",\\\"snowflake-id\\\":\\\"^1.1.0\\\",\\\"vue\\\":\\\"^2.6.11\\\",\\\"vue-template-compiler\\\":\\\"^2.6.11\\\",\\\"vuex\\\":\\\"^3.4.0\\\",\\\"webpack-bundle-analyzer\\\":\\\"^4.4.2\\\"},\\\"browserslist\\\":[\\\"> 1%\\\",\\\"last 2 versions\\\",\\\"not dead\\\"],\\\"directories\\\":{\\\"lib\\\":\\\"lib\\\"},\\\"keywords\\\":[],\\\"license\\\":\\\"ISC\\\",\\\"files\\\":[\\\"lib\\\"]}\");\n\n//# sourceURL=webpack://ZjPluginIntelligent/./package.json?");
11036
+ eval("module.exports = JSON.parse(\"{\\\"name\\\":\\\"zj-plugin-intelligent\\\",\\\"version\\\":\\\"1.2.8-beta.11\\\",\\\"main\\\":\\\"lib/ZjPluginIntelligent.umd.min.js\\\",\\\"private\\\":false,\\\"scripts\\\":{\\\"serve\\\":\\\"set NODE_OPTIONS=--openssl-legacy-provider && vue-cli-service serve\\\",\\\"build\\\":\\\"set NODE_OPTIONS=--openssl-legacy-provider && vue-cli-service build\\\",\\\"lib\\\":\\\"set NODE_OPTIONS=--openssl-legacy-provider && vue-cli-service build --target lib --name ZjPluginIntelligent --dest lib src/lib/index.js\\\",\\\"lib:test\\\":\\\"set NODE_OPTIONS=--openssl-legacy-provider && vue-cli-service build --mode test --target lib --name ZjPluginIntelligent --dest lib src/lib/index.js\\\"},\\\"dependencies\\\":{\\\"@jboltai/tokui\\\":\\\"^0.1.6\\\",\\\"crypto-js\\\":\\\"^4.2.0\\\",\\\"html2canvas\\\":\\\"^1.4.1\\\",\\\"markdown-it\\\":\\\"^14.1.0\\\"},\\\"devDependencies\\\":{\\\"@babel/preset-env\\\":\\\"^7.14.9\\\",\\\"@vue/cli-plugin-babel\\\":\\\"~4.5.0\\\",\\\"@vue/cli-plugin-eslint\\\":\\\"^4.5.13\\\",\\\"@vue/cli-plugin-vuex\\\":\\\"~4.5.0\\\",\\\"@vue/cli-service\\\":\\\"~4.5.0\\\",\\\"axios\\\":\\\"^0.27.2\\\",\\\"babel-eslint\\\":\\\"^10.1.0\\\",\\\"babel-plugin-component\\\":\\\"^1.1.1\\\",\\\"compression-webpack-plugin\\\":\\\"^6.0.3\\\",\\\"core-js\\\":\\\"^3.6.5\\\",\\\"element-ui\\\":\\\"^2.15.4\\\",\\\"eslint\\\":\\\"^7.30.0\\\",\\\"eslint-plugin-vue\\\":\\\"^7.13.0\\\",\\\"js-cookie\\\":\\\"^2.2.1\\\",\\\"obs-upload\\\":\\\"^1.0.4\\\",\\\"pako\\\":\\\"^2.1.0\\\",\\\"reconnecting-websocket\\\":\\\"^4.4.0\\\",\\\"sass\\\":\\\"^1.71.0\\\",\\\"sass-loader\\\":\\\"^8.0.2\\\",\\\"snowflake-id\\\":\\\"^1.1.0\\\",\\\"vue\\\":\\\"^2.6.11\\\",\\\"vue-template-compiler\\\":\\\"^2.6.11\\\",\\\"vuex\\\":\\\"^3.4.0\\\",\\\"webpack-bundle-analyzer\\\":\\\"^4.4.2\\\"},\\\"browserslist\\\":[\\\"> 1%\\\",\\\"last 2 versions\\\",\\\"not dead\\\"],\\\"directories\\\":{\\\"lib\\\":\\\"lib\\\"},\\\"keywords\\\":[],\\\"license\\\":\\\"ISC\\\",\\\"files\\\":[\\\"lib\\\"]}\");\n\n//# sourceURL=webpack://ZjPluginIntelligent/./package.json?");
11037
11037
 
11038
11038
  /***/ }),
11039
11039