zj-plugin-intelligent 1.2.5-beta.4 → 1.2.5-beta.6
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.
|
@@ -939,7 +939,7 @@ eval("\n\nvar _interopRequireWildcard = __webpack_require__(/*! ./node_modules/_
|
|
|
939
939
|
/***/ (function(module, exports, __webpack_require__) {
|
|
940
940
|
|
|
941
941
|
"use strict";
|
|
942
|
-
eval("\n\nvar _interopRequireDefault = __webpack_require__(/*! ./node_modules/_@babel_runtime@7.28.4@@babel/runtime/helpers/interopRequireDefault.js */ \"./node_modules/_@babel_runtime@7.28.4@@babel/runtime/helpers/interopRequireDefault.js\").default;\nObject.defineProperty(exports, \"__esModule\", {\n value: true\n});\nexports.default = void 0;\n__webpack_require__(/*! core-js/modules/es.error.cause.js */ \"./node_modules/_core-js@3.45.1@core-js/modules/es.error.cause.js\");\n__webpack_require__(/*! core-js/modules/es.array.push.js */ \"./node_modules/_core-js@3.45.1@core-js/modules/es.array.push.js\");\n__webpack_require__(/*! core-js/modules/es.array-buffer.detached.js */ \"./node_modules/_core-js@3.45.1@core-js/modules/es.array-buffer.detached.js\");\n__webpack_require__(/*! core-js/modules/es.array-buffer.transfer.js */ \"./node_modules/_core-js@3.45.1@core-js/modules/es.array-buffer.transfer.js\");\n__webpack_require__(/*! core-js/modules/es.array-buffer.transfer-to-fixed-length.js */ \"./node_modules/_core-js@3.45.1@core-js/modules/es.array-buffer.transfer-to-fixed-length.js\");\n__webpack_require__(/*! core-js/modules/es.iterator.constructor.js */ \"./node_modules/_core-js@3.45.1@core-js/modules/es.iterator.constructor.js\");\n__webpack_require__(/*! core-js/modules/es.iterator.filter.js */ \"./node_modules/_core-js@3.45.1@core-js/modules/es.iterator.filter.js\");\n__webpack_require__(/*! core-js/modules/es.iterator.find.js */ \"./node_modules/_core-js@3.45.1@core-js/modules/es.iterator.find.js\");\n__webpack_require__(/*! core-js/modules/es.iterator.for-each.js */ \"./node_modules/_core-js@3.45.1@core-js/modules/es.iterator.for-each.js\");\n__webpack_require__(/*! core-js/modules/es.iterator.map.js */ \"./node_modules/_core-js@3.45.1@core-js/modules/es.iterator.map.js\");\n__webpack_require__(/*! core-js/modules/es.typed-array.at.js */ \"./node_modules/_core-js@3.45.1@core-js/modules/es.typed-array.at.js\");\n__webpack_require__(/*! core-js/modules/es.typed-array.find-last.js */ \"./node_modules/_core-js@3.45.1@core-js/modules/es.typed-array.find-last.js\");\n__webpack_require__(/*! core-js/modules/es.typed-array.find-last-index.js */ \"./node_modules/_core-js@3.45.1@core-js/modules/es.typed-array.find-last-index.js\");\n__webpack_require__(/*! core-js/modules/es.typed-array.set.js */ \"./node_modules/_core-js@3.45.1@core-js/modules/es.typed-array.set.js\");\n__webpack_require__(/*! core-js/modules/es.typed-array.to-reversed.js */ \"./node_modules/_core-js@3.45.1@core-js/modules/es.typed-array.to-reversed.js\");\n__webpack_require__(/*! core-js/modules/es.typed-array.to-sorted.js */ \"./node_modules/_core-js@3.45.1@core-js/modules/es.typed-array.to-sorted.js\");\n__webpack_require__(/*! core-js/modules/es.typed-array.with.js */ \"./node_modules/_core-js@3.45.1@core-js/modules/es.typed-array.with.js\");\nvar _apichat = __webpack_require__(/*! @lib/api/apichat */ \"./src/lib/api/apichat.js\");\nvar _markdownIt = _interopRequireDefault(__webpack_require__(/*! markdown-it */ \"./node_modules/_markdown-it@14.1.0@markdown-it/index.mjs\"));\nvar _html2canvas = _interopRequireDefault(__webpack_require__(/*! html2canvas */ \"./node_modules/_html2canvas@1.4.1@html2canvas/dist/html2canvas.js\"));\nvar _index = __webpack_require__(/*! @lib/socket/fileManager/obs/index */ \"./src/lib/socket/fileManager/obs/index.js\");\nvar _index2 = _interopRequireDefault(__webpack_require__(/*! @lib/socket/utils/index */ \"./src/lib/socket/utils/index.js\"));\nvar _cookie = __webpack_require__(/*! @lib/utils/cookie.js */ \"./src/lib/utils/cookie.js\");\nvar _apiObs = _interopRequireDefault(__webpack_require__(/*! @lib/api/apiObs */ \"./src/lib/api/apiObs.js\"));\nconst md = new _markdownIt.default({\n breaks: true,\n html: false,\n linkify: true,\n typographer: true\n});\nmd.enable('table');\nvar _default = exports.default = {\n name: 'ChatMain',\n props: {\n Ak: {\n type: String,\n default: ''\n },\n Sk: {\n type: String,\n default: ''\n },\n imAccount: {\n type: String,\n default: ''\n },\n companyNo: {\n type: String,\n default: ''\n },\n isIntelShow: {\n default: false,\n type: Boolean\n },\n chatImToken: {\n default: '',\n type: String\n }\n },\n data() {\n return {\n agentList: [],\n currentAgent: '',\n currentAgentDesc: '',\n sessionsLoaded: false,\n searchKeyword: '',\n agentSuggestions: [],\n showAgentSuggestions: false,\n sessionList: [],\n activeSessionId: '',\n messages: [],\n loadingMore: false,\n sending: false,\n waitTimer: null,\n waitSeconds: 0,\n canceling: false,\n msgPage: 1,\n msgMaxPage: 1,\n msgTotal: 0,\n inputText: '',\n eventSource: null,\n showToolInfo: false,\n showDownBtn: false,\n // 控制向下箭头显隐\n lastScrollTop: 0,\n scrollTimer: null,\n // 滚动防抖(新增)\n showAgentSelect: true,\n isMobile: false,\n showSidebar: false,\n showH5List: false,\n // H5列表模式(展示会话列表而非聊天详情)\n _scrollTimer: null,\n agentInfo: {},\n contentCache: {},\n // 流式分行缓存 key=msg._key\n loadingSessionMsg: false,\n // 会话消息加载中标记\n greeting: '',\n longPressTimer: null,\n longPressed: false,\n // H5 语音输入\n voiceMode: false,\n // true=语音模式,false=文字模式\n isRecording: false,\n // 是否正在录音\n recordDuration: 0,\n // 录音时长(秒)\n recordingTimer: null,\n // 时长计时器\n audioContext: null,\n // AudioContext 实例\n audioStream: null,\n // MediaStream(用于清理)\n audioProcessor: null,\n // ScriptProcessorNode\n audioChunks: [],\n // Float32Array 数据块\n isCancelSwipe: false,\n // 是否上滑取消\n recordStartY: 0 // 触摸起始Y坐标\n };\n },\n created() {\n if (this.Ak || this.Sk) {\n (0, _apichat.setApiAuth)(this.Ak, this.Sk, this.imAccount, this.companyNo, this.chatImToken);\n }\n this.loadAgents();\n this.loadSessions();\n },\n mounted() {\n this.updateViewportState();\n window.addEventListener('resize', this.updateViewportState, {\n passive: true\n });\n },\n computed: {\n 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 filteredSessions() {\n if (!this.searchKeyword) return this.sessionList;\n const kw = this.searchKeyword.toLowerCase();\n return this.sessionList.filter(s => {\n const name = (s.agentName || s.agentCode || '').toLowerCase();\n return name.includes(kw);\n });\n },\n currentAgentName() {\n if (!this.currentAgent) return '';\n const a = this.agentList.find(x => x.agentCode === this.currentAgent);\n return a ? a.agentName || a.agentCode : this.currentAgent;\n }\n },\n watch: {\n searchKeyword(val) {\n if (this.searchTimer) clearTimeout(this.searchTimer);\n if (!val.trim()) {\n this.agentSuggestions = [];\n this.showAgentSuggestions = false;\n this.closeSidebar();\n return;\n }\n this.searchTimer = setTimeout(() => {\n (0, _apichat.getChatAgents)(val.trim()).then(list => {\n this.agentSuggestions = list || [];\n this.showAgentSuggestions = this.agentSuggestions.length > 0;\n }).catch(() => {\n this.agentSuggestions = [];\n });\n }, 300);\n }\n // ak: {\n // handler(newVal) {\n // setApiAuth(newVal, this.sk)\n // },\n // immediate: true\n // },\n // sk: {\n // handler(newVal) {\n // setApiAuth(this.ak, newVal)\n // },\n // immediate: true\n // }\n },\n methods: {\n updateViewportState() {\n if (typeof window === 'undefined') return;\n const nextIsMobile = window.innerWidth <= 768;\n const wasMobile = this.isMobile;\n this.isMobile = nextIsMobile;\n if (!nextIsMobile) {\n this.showSidebar = false;\n this.showH5List = false;\n } else if (!wasMobile && nextIsMobile) {\n // 从桌面端切换到H5:如果加载了会话列表且无活跃会话,展示列表页\n if (this.sessionList.length > 0 && !this.activeSessionId) {\n this.showH5List = true;\n this.showAgentSelect = false;\n }\n }\n },\n toggleSidebar() {\n if (!this.isMobile) return;\n this.showSidebar = !this.showSidebar;\n },\n closeSidebar() {\n this.showSidebar = false;\n },\n // H5:调用原生返回上一级\n handleNativeBack() {\n if (this.$hybrid && typeof this.$hybrid.closePage === 'function') {\n this.$hybrid.closePage();\n } else if (window.history.length > 1) {\n window.history.back();\n }\n },\n // H5侧边栏返回按钮\n handleSidebarBack() {\n this.handleNativeBack();\n },\n agentjumpclick() {\n if (this.sending) {\n this.$message.warning('AI正在生成内容,暂时请不要切换对话');\n return;\n }\n this.currentAgent = '';\n this.currentAgentDesc = '';\n this.searchKeyword = '';\n this.activeSessionId = '';\n this.agentSuggestions = [];\n this.messages = [];\n this.showAgentSuggestions = false;\n this.showAgentSelect = true;\n this.showH5List = false;\n this.closeSidebar();\n },\n // H5:从详情页返回列表页\n goBackToList() {\n if (this.sending) {\n this.$message.warning('AI正在生成内容,暂时请不要切换对话');\n return;\n }\n // 关闭流连接\n if (this.eventSource) {\n this.eventSource.close();\n this.eventSource = null;\n }\n this.sending = false;\n this.clearWaitTimer();\n this.activeSessionId = '';\n this.messages = [];\n this.currentAgent = '';\n this.currentAgentDesc = '';\n this.agentInfo = {};\n this.contentCache = {};\n\n // 始终返回列表页\n this.showH5List = true;\n this.showAgentSelect = false;\n this.closeSidebar();\n },\n sendQuickMsg(message) {\n if (message) {\n this.inputText = message;\n this.sendMessage();\n }\n },\n formatMixText(str) {\n if (!str) return '';\n // 1. 中文 <=> 英文/数字 之间加空格\n let res = str.replace(/([a-zA-Z0-9])([\\u4e00-\\u9fff])/g, '$1 $2').replace(/([\\u4e00-\\u9fff])([a-zA-Z0-9])/g, '$1 $2');\n // 2. 连续英文单词分片粘连修复:字母紧跟字母中间加空格\n // 匹配 小写+大写 驼峰、连续分片拼接成一坨的英文\n res = res.replace(/([a-z])([A-Z])/g, '$1 $2');\n return res;\n },\n // 获取右侧头像样式(根据当前智能体在左侧列表中的位置决定颜色)\n getChatAvatarStyle(agent, avatar) {\n if (avatar) {\n return {\n backgroundImage: `url(${avatar})`,\n backgroundSize: 'cover',\n backgroundPosition: 'center',\n backgroundRepeat: 'no-repeat'\n };\n }\n const _agent = this.agentList.find(x => x.agentCode === agent);\n // 如果有网络图片,返回背景图样式\n if (agent.avatar) {\n return {\n backgroundImage: `url(${agent.avatar})`,\n backgroundSize: 'cover',\n backgroundPosition: 'center',\n backgroundRepeat: 'no-repeat'\n };\n }\n\n // 没有网络图片时,根据智能体在 agentList 中的索引位置决定颜色\n if (this.sessionList) {\n // 找到当前智能体在列表中的索引\n const index = this.sessionList.findIndex(item => item.agentCode === agent);\n if (index !== -1) {\n // 根据索引计算颜色类(4色循环)\n const colorIndex = index % 4 + 1;\n return {\n background: this.getGradientByColorIndex(colorIndex)\n };\n }\n }\n\n // 默认返回蓝色渐变\n return {\n background: 'linear-gradient(135deg, #1677ff, #4096ff)'\n };\n },\n // 根据颜色索引获取对应的渐变色\n getGradientByColorIndex(index) {\n const 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 selectAgent(agentItem) {\n this.showAgentSelect = false;\n this.currentAgent = agentItem.agentCode;\n this.currentAgentName = agentItem.agentName;\n // 查找历史会话\n const existSession = this.sessionList.find(s => s.agentCode === agentItem.agentCode);\n if (existSession) {\n this.activeSessionId = existSession.id;\n this.switchSession(existSession);\n } else {\n this.createNewSession(agentItem.agentCode);\n }\n },\n createNewSession(agentCode) {\n // 你原有新建会话逻辑\n },\n // 检测是否滚动到底部,控制向下箭头显示隐藏\n checkScrollBottom(forceShowWhenNotBottom = false) {\n const el = this.$refs.messagesRef;\n if (!el) {\n this.showDownBtn = false;\n return;\n }\n const {\n scrollHeight,\n scrollTop,\n clientHeight\n } = el;\n const remain = scrollHeight - scrollTop - clientHeight;\n const atBottom = remain <= 80;\n if (atBottom) {\n this.showDownBtn = false;\n } else if (this.sending && scrollTop >= this.lastScrollTop && !forceShowWhenNotBottom) {\n // 发送AI回答时,如果用户没有主动向上滚动,就不要显示下箭头闪烁\n this.showDownBtn = false;\n } else {\n this.showDownBtn = true;\n }\n this.lastScrollTop = scrollTop;\n },\n // 固定最小高度:单行不撑开,超出才增高\n autoResizeTextarea() {\n const ta = this.$refs.taRef;\n if (!ta) return;\n // 根据端适配基准高度和最大高度\n const isMobile = this.isMobile;\n const baseH = isMobile ? 36 : 100;\n const maxH = isMobile ? 100 : 180;\n ta.style.height = `${baseH}px`;\n // 内容真实高度\n const realH = ta.scrollHeight;\n // 只有内容高度>基准才撑开,否则保持初始高度\n if (realH > baseH) {\n ta.style.height = `${Math.min(realH, maxH)}px`;\n }\n this.$nextTick(() => {\n this.checkScrollBottom(true);\n });\n },\n // Shift+Enter换行\n newLine(e) {\n // 取消浏览器默认行为\n e.preventDefault();\n // 拿到光标位置\n const ta = this.$refs.taRef;\n const start = ta.selectionStart;\n const end = ta.selectionEnd;\n // 在光标处插入换行符\n this.inputText = this.inputText.slice(0, start) + '\\n' + this.inputText.slice(end);\n // 光标定位到换行后\n this.$nextTick(() => {\n ta.selectionStart = ta.selectionEnd = start + 1;\n // 自动调整输入框高度\n this.autoResizeTextarea();\n });\n },\n toggleVoiceMode() {\n this.voiceMode = !this.voiceMode;\n if (!this.voiceMode) {\n // 切回文字模式时清理录音状态\n this.cancelRecording();\n }\n },\n // H5语音录制 - 触摸开始\n async onRecordTouchStart(e) {\n if (this.sending) return;\n this.isCancelSwipe = false;\n this.recordStartY = e.touches[0].clientY;\n this.recordDuration = 0;\n this.audioChunks = [];\n this.isRecording = true;\n\n // 启动时长计时\n this.recordingTimer = setInterval(() => {\n this.recordDuration++;\n if (this.recordDuration >= 60) {\n this.onRecordTouchEnd();\n }\n }, 1000);\n\n // 使用 AudioContext 采集 PCM 数据,输出 WAV 格式\n try {\n const stream = await navigator.mediaDevices.getUserMedia({\n audio: true\n });\n this.audioStream = stream;\n const audioContext = new (window.AudioContext || window.webkitAudioContext)({\n sampleRate: 16000\n });\n this.audioContext = audioContext;\n const source = audioContext.createMediaStreamSource(stream);\n // bufferSize=4096, 1 input channel, 1 output channel\n const processor = audioContext.createScriptProcessor(4096, 1, 1);\n this.audioProcessor = processor;\n processor.onaudioprocess = e => {\n if (!this.isRecording) return;\n const inputData = e.inputBuffer.getChannelData(0);\n // 保存 float32 采样数据\n this.audioChunks.push(new Float32Array(inputData));\n };\n source.connect(processor);\n processor.connect(audioContext.destination);\n } catch (err) {\n console.error('麦克风访问失败:', err);\n this.$message.warning('麦克风权限被拒绝');\n this.cancelRecording();\n }\n },\n // H5语音录制 - 触摸移动(检测上滑取消)\n onRecordTouchMove(e) {\n if (!this.isRecording) return;\n const touch = e.touches[0];\n const moveY = touch.clientY;\n const cancelThreshold = 60; // 上滑60px进入取消区域\n this.isCancelSwipe = this.recordStartY - moveY > cancelThreshold;\n },\n // H5语音录制 - 触摸结束\n onRecordTouchEnd() {\n if (!this.isRecording) return;\n this.isRecording = false;\n if (this.recordingTimer) {\n clearInterval(this.recordingTimer);\n this.recordingTimer = null;\n }\n this.stopAudioCapture(!this.isCancelSwipe);\n },\n // 停止音频采集并输出 WAV\n stopAudioCapture(shouldSend) {\n // 断开并清理音频节点\n if (this.audioProcessor) {\n this.audioProcessor.disconnect();\n this.audioProcessor = null;\n }\n if (this.audioContext) {\n this.audioContext.close().catch(() => {});\n this.audioContext = null;\n }\n if (this.audioStream) {\n this.audioStream.getTracks().forEach(t => t.stop());\n this.audioStream = null;\n }\n if (shouldSend && this.audioChunks.length > 0) {\n const wavBlob = this.encodePCMToWav(this.audioChunks, 16000);\n this.sendAudioBlob(wavBlob);\n }\n this.audioChunks = [];\n },\n // 取消录音\n cancelRecording() {\n this.isRecording = false;\n if (this.recordingTimer) {\n clearInterval(this.recordingTimer);\n this.recordingTimer = null;\n }\n this.stopAudioCapture(false);\n this.recordDuration = 0;\n this.isCancelSwipe = false;\n },\n // 将 Float32 PCM 数据编码为 WAV Blob\n encodePCMToWav(chunks, sampleRate) {\n // 计算总采样数\n let totalLength = 0;\n for (const chunk of chunks) {\n totalLength += chunk.length;\n }\n\n // 转换为 Int16 PCM\n const pcmData = new Int16Array(totalLength);\n let offset = 0;\n for (const chunk of chunks) {\n for (let i = 0; i < chunk.length; i++) {\n const s = Math.max(-1, Math.min(1, chunk[i]));\n pcmData[offset++] = s < 0 ? s * 0x8000 : s * 0x7FFF;\n }\n }\n const numChannels = 1;\n const bitsPerSample = 16;\n const byteRate = sampleRate * numChannels * bitsPerSample / 8;\n const blockAlign = numChannels * bitsPerSample / 8;\n const dataSize = pcmData.length * (bitsPerSample / 8);\n const headerSize = 44;\n const totalSize = headerSize + dataSize;\n const buffer = new ArrayBuffer(totalSize);\n const view = new DataView(buffer);\n\n // RIFF header\n this._wavWriteString(view, 0, 'RIFF');\n view.setUint32(4, totalSize - 8, true);\n this._wavWriteString(view, 8, 'WAVE');\n\n // fmt chunk\n this._wavWriteString(view, 12, 'fmt ');\n view.setUint32(16, 16, true); // chunk size\n view.setUint16(20, 1, true); // PCM format\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 // data chunk\n this._wavWriteString(view, 36, 'data');\n view.setUint32(40, dataSize, true);\n\n // 写入 PCM 数据\n const pcmView = new Int16Array(buffer, headerSize, pcmData.length);\n pcmView.set(pcmData);\n return new Blob([buffer], {\n type: 'audio/wav'\n });\n },\n _wavWriteString(view, offset, str) {\n for (let i = 0; i < str.length; i++) {\n view.setUint8(offset + i, str.charCodeAt(i));\n }\n },\n // 发送音频\n sendAudioBlob(blob) {\n let appSeqId = _index2.default.getAppSeqId();\n let name = appSeqId + '.wav';\n const file = new File([blob], name, {\n type: 'audio/wav'\n });\n // TODO: 上传音频文件并调用 STT 接口\n this.sendAudioMessage(file);\n },\n sendAudioMessage(file) {\n // 插入本地 pending 消息\n const sttKey = 'stt_' + Date.now();\n const 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(resp => {\n if (resp.CommonMsg.Status === 200) {\n // 调用语音转文字接口\n return _apiObs.default.aliAudioToText({\n url: resp.obs_upload_data.obsUrl\n }).then(result => {\n if (result.code === '200' && result.data) {\n // 成功:删除 pending 消息,发送给后端\n const idx = this.messages.findIndex(m => m._sttKey === sttKey);\n if (idx !== -1) {\n this.messages.splice(idx, 1);\n }\n this.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(err => {\n console.error('语音转文字失败:', err);\n // 失败:更新为错误状态\n const idx = this.messages.findIndex(m => m._sttKey === sttKey);\n if (idx !== -1) {\n this.$set(this.messages, idx, {\n ...this.messages[idx],\n _sttStatus: 'error',\n content: '语音转文字失败'\n });\n }\n this.$message.error('语音转文字失败');\n });\n this.$message.success(`录音完成 (${this.recordDuration}s)`);\n },\n clearWaitTimer() {\n if (this.waitTimer) {\n clearInterval(this.waitTimer);\n this.waitTimer = null;\n }\n },\n loadAgents() {\n (0, _apichat.getChatAgents)().then(list => {\n this.agentList = list || [];\n // if (this.agentList.length > 0 && !this.currentAgent) {\n // const first = this.agentList[0]\n // this.currentAgent = first.agentCode\n // this.currentAgentDesc = first.description || ''\n // }\n }).catch(() => {});\n },\n loadSessions() {\n (0, _apichat.getSessionList)().then(list => {\n if (!this.activeSessionId) {\n this.sessionList = list || [];\n if (this.sessionList.length > 0) {\n if (this.isMobile) {\n // H5模式:不自动选中会话,展示列表页\n this.showAgentSelect = false;\n this.showH5List = true;\n this.showSidebar = false;\n } else {\n this.switchSession(this.sessionList[0]);\n }\n }\n if (this.sessionList.length === 0) {\n this.showAgentSelect = true;\n this.showH5List = false;\n }\n } else {\n this.sessionList = list || [];\n let _item = list.find(res => res.sessionId == this.activeSessionId);\n try {\n if (_item.suggestedQuestions) {\n _item.suggestedQuestions = JSON.parse(_item.suggestedQuestions);\n } else {\n _item.suggestedQuestions = [];\n }\n _item && (this.agentInfo = _item);\n } catch (err) {\n // JSON格式错误兜底空数组,防止页面报错\n this.agentInfo.questionArr = [];\n console.warn('快捷提问解析失败', err);\n }\n }\n }).catch(() => {});\n },\n onSearchClear() {\n this.agentSuggestions = [];\n this.showAgentSuggestions = false;\n },\n startChatWithAgent(agent) {\n console.log('选择了助手', agent.agentCode, this.currentAgent);\n if (agent.agentCode == this.currentAgent) {\n this.searchKeyword = '';\n this.agentSuggestions = [];\n this.showAgentSuggestions = false;\n return;\n }\n this.currentAgent = agent.agentCode;\n this.currentAgentDesc = agent.description || '';\n this.searchKeyword = '';\n this.agentInfo = {};\n this.agentSuggestions = [];\n this.messages = [];\n this.showAgentSuggestions = false;\n this.showAgentSelect = false;\n this.closeSidebar();\n if (this.isMobile) {\n this.showH5List = false; // H5:进入详情页,隐藏列表\n }\n const existing = this.sessionList.find(s => s.agentCode === agent.agentCode);\n if (existing) {\n this.switchSession(existing);\n } else {\n this.handleNewSession();\n }\n },\n handleNewSession() {\n if (!this.currentAgent) return;\n if (this.activeSessionId) this.closeOldSession();\n (0, _apichat.startSession)(this.currentAgent).then(res => {\n console.log(res, 'startChatWithAgentstartChatWithAgentstartChatWithAgent', this.agentInfo);\n this.activeSessionId = res.sessionId || '';\n this.loadSessions();\n const agent = this.agentList.find(a => a.agentCode === this.currentAgent);\n if (agent) this.addWelcomeMessage(agent);\n }).catch(() => {});\n },\n // H5长按删除 - 触摸开始\n onSessionTouchStart(s, e) {\n if (!this.isMobile) return;\n this.longPressed = false;\n this.longPressTimer = setTimeout(() => {\n this.longPressed = true;\n this.handleDeleteSession(s);\n }, 600);\n },\n // H5长按删除 - 触摸结束/移动(取消长按)\n onSessionTouchEnd() {\n if (this.longPressTimer) {\n clearTimeout(this.longPressTimer);\n this.longPressTimer = null;\n }\n },\n onSessionTouchMove() {\n if (this.longPressTimer) {\n clearTimeout(this.longPressTimer);\n this.longPressTimer = null;\n }\n },\n async switchSession(s) {\n if (this.longPressed) {\n this.longPressed = false;\n return;\n }\n if (this.sending) {\n this.$message.warning('AI正在生成内容,暂时请不要切换对话');\n return;\n }\n this.showAgentSelect = false;\n this.closeSidebar();\n if (this.isMobile) {\n this.showH5List = false; // H5:进入详情页,隐藏列表\n }\n if (this.activeSessionId === s.sessionId) return;\n this.contentCache = {};\n this.activeSessionId = s.sessionId;\n this.currentAgent = s.agentCode;\n console.log('进入');\n this.agentInfo = s;\n console.log('进入', this.agentInfo);\n try {\n if (s.suggestedQuestions) {\n this.agentInfo.suggestedQuestions = JSON.parse(s.suggestedQuestions);\n } else {\n this.agentInfo.suggestedQuestions = [];\n }\n } catch (err) {\n // JSON格式错误兜底空数组,防止页面报错\n this.agentInfo.questionArr = [];\n console.warn('快捷提问解析失败', err);\n }\n const agent = this.agentList.find(a => a.agentCode === s.agentCode);\n this.currentAgentDesc = agent ? agent.description || '' : '';\n this.msgPage = 1;\n this.msgTotal = 0;\n this.messages = []; // 先清空,但开启加载锁屏蔽空白页\n this.loadingSessionMsg = true; // 开启加载标记\n (0, _apichat.syncToken)((0, _cookie.getToken)(), s.sessionId);\n try {\n const res = await (0, _apichat.getSessionMessages)(s.sessionId, 1, 10);\n const list = Array.isArray(res) ? res : res.list || [];\n this.msgTotal = res.total || list.length;\n this.msgPage = 1;\n const asAsc = (list || []).slice().reverse();\n this.messages = asAsc.map(m => ({\n role: m.role,\n content: m.content || '',\n thinking: m.thinking || '',\n toolCalls: [],\n agentName: m.role === 'assistant' ? s.agentName || '' : '',\n createTime: m.createTime || null,\n _key: m.createTime ? 'msg_' + m.createTime : 'msg_' + Date.now() + '_' + Math.random()\n }));\n if (this.messages.length === 0 && agent) this.addWelcomeMessage(agent);\n await this.$nextTick();\n this.$nextTick(() => {\n this.scrollToBottomOnce();\n this.checkScrollBottom();\n });\n } catch (e) {\n this.messages = [];\n } finally {\n // 无论成功失败,结束后关闭加载锁\n this.loadingSessionMsg = false;\n }\n },\n loadMoreMessages() {\n const nextPage = this.msgPage + 1;\n const maxPage = Math.ceil(this.msgTotal / 10);\n if (nextPage > maxPage) {\n this.loadingMore = false;\n return;\n }\n (0, _apichat.getSessionMessages)(this.activeSessionId, nextPage, 10).then(res => {\n const list = Array.isArray(res) ? res : res.list || [];\n this.msgPage = nextPage;\n const asAsc = (list || []).slice().reverse();\n const prepend = asAsc.map(m => ({\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 }));\n const container = this.$refs.messagesRef;\n const oldScrollHeight = container ? container.scrollHeight : 0;\n const oldScrollTop = container ? container.scrollTop : 0;\n this.messages = [...prepend, ...this.messages];\n this.$nextTick(() => {\n if (container) {\n container.scrollTop = oldScrollTop + (container.scrollHeight - oldScrollHeight);\n }\n this.loadingMore = false;\n });\n }).catch(() => {\n this.loadingMore = false;\n });\n },\n onScrollMessages() {\n const container = this.$refs.messagesRef;\n if (!container || this.loadingMore) return;\n const isAtBottom = container.scrollTop + container.clientHeight >= container.scrollHeight - 100;\n this.checkScrollBottom();\n if (isAtBottom) return;\n if (container.scrollTop < 50 && this.msgPage < Math.ceil(this.msgTotal / 10)) {\n this.loadingMore = true;\n this.loadMoreMessages();\n }\n },\n handleDeleteSession(s) {\n this.$confirm(`确认删除「${s.agentName || s.agentCode}」的会话?`, '提示', {\n type: 'warning'\n }).then(() => {\n (0, _apichat.deleteSession)(s.sessionId).then(() => {\n if (this.activeSessionId === s.sessionId) {\n this.activeSessionId = '';\n this.messages = [];\n this.currentAgent = '';\n this.currentAgentDesc = '';\n if (this.isMobile) {\n this.showH5List = false;\n this.showAgentSelect = true;\n } else {\n this.showAgentSelect = true;\n }\n }\n this.loadSessions();\n });\n }).catch(() => {});\n },\n closeOldSession() {},\n onAgentChange(code) {\n const agent = this.agentList.find(a => a.agentCode === code);\n this.currentAgentDesc = agent ? agent.description || '' : '';\n this.handleNewSession();\n },\n addWelcomeMessage(agent) {\n this.greeting = '';\n // if (!agent) return\n // const name = agent.agentName || '助手';\n const _agent = this.agentList.find(x => x.agentCode === this.currentAgent);\n this.greeting = _agent.greeting || `很高兴为您服务,请问有什么可以帮到您?`;\n // this.messages.push({\n // role: 'assistant',\n // content: _content,\n // thinking: '',\n // agentName: name,\n // _key: 'welcome_' + Date.now()\n // })\n },\n async sendMessage() {\n const text = this.inputText.trim();\n if (!text || this.sending) return;\n if (!this.activeSessionId) {\n await (0, _apichat.startSession)(this.currentAgent).then(res => {\n this.activeSessionId = res.sessionId || '';\n this.loadSessions();\n });\n if (!this.activeSessionId) return;\n }\n this.inputText = '';\n const ta = this.$refs.taRef;\n const isMobile = this.isMobile;\n const baseH = isMobile ? 36 : 100;\n if (ta) {\n ta.style.height = baseH + 'px'; // 强制恢复初始高度\n }\n this.showDownBtn = false;\n this.messages.push({\n role: 'user',\n content: text,\n createTime: new Date().toISOString(),\n _key: 'user_' + Date.now() + '_' + Math.random()\n });\n const agentName = this.currentAgentName;\n const msgIdx = this.messages.push({\n role: \"assistant\",\n content: \"\",\n thinking: \"\",\n loading: true,\n toolCalls: [],\n agentName,\n createTime: new Date().toISOString(),\n _key: 'asst_' + Date.now() + '_' + Math.random()\n }) - 1;\n this.scrollToBottom(true);\n this.sending = true;\n this.waitSeconds = 0;\n if (this.waitTimer) clearInterval(this.waitTimer);\n this.waitTimer = setInterval(() => {\n this.waitSeconds++;\n }, 1000);\n let thinkingBuffer = '';\n let finalContent = '';\n let answerBuffer = '';\n let thinkDisplayed = 0;\n let typeTimer = null;\n typeTimer = setInterval(() => {\n if (!this.messages[msgIdx]) return;\n if (thinkDisplayed < thinkingBuffer.length) {\n thinkDisplayed += 50;\n if (thinkDisplayed > thinkingBuffer.length) thinkDisplayed = thinkingBuffer.length;\n this.messages[msgIdx].thinking = thinkingBuffer.substring(0, thinkDisplayed);\n this.scrollToBottom();\n } else if (finalContent && !this.messages[msgIdx].content) {\n clearInterval(typeTimer);\n const key = this.messages[msgIdx]._key;\n if (key) {\n this.$delete(this.contentCache, key);\n this.$delete(this.contentCache, key + '_t');\n }\n typeTimer = null;\n this.messages[msgIdx].content = finalContent;\n this.messages[msgIdx].thinking = thinkingBuffer;\n this.messages[msgIdx].loading = false;\n this.sending = false;\n this.clearWaitTimer();\n this.scrollToBottom();\n this.loadSessions();\n }\n }, 30);\n const url = (0, _apichat.createStreamUrl)(this.activeSessionId, text);\n if (this.eventSource) {\n this.eventSource.close();\n }\n this.eventSource = new EventSource(url);\n const es = this.eventSource;\n es.addEventListener('reasoning', e => {\n if (e.data) {\n const chunk = e.data;\n // 1. 先处理当前分片内部的中英文、数字、标点空格\n let 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\n // 2. 关键:判断前一段末尾 + 当前段开头都是英文,补空格分隔\n const lastChar = thinkingBuffer.slice(-1);\n const firstChar = cleanChunk.slice(0, 1);\n const isLetter = c => /[a-zA-Z]/.test(c);\n if (isLetter(lastChar) && isLetter(firstChar)) {\n // 两段都是英文衔接,中间加空格\n thinkingBuffer += ' ' + cleanChunk;\n } else {\n thinkingBuffer += cleanChunk;\n }\n }\n });\n es.addEventListener('reasoning_result', e => {\n if (e.data) {\n thinkingBuffer = e.data;\n }\n });\n es.addEventListener('answer', e => {\n if (e.data) {\n answerBuffer += e.data;\n if (this.messages[msgIdx]) {\n this.messages[msgIdx].content += 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 this.scrollToBottom();\n }\n }\n });\n es.addEventListener('tool_result', e => {\n if (e.data && this.messages[msgIdx]) {\n if (!this.messages[msgIdx].toolCalls) this.messages[msgIdx].toolCalls = [];\n this.messages[msgIdx].toolCalls.push(e.data);\n this.scrollToBottom();\n }\n });\n es.addEventListener('agent_result', e => {\n finalContent = e.data || '';\n es.close();\n this.eventSource = null;\n if (this.messages[msgIdx]) {\n const key = this.messages[msgIdx]._key;\n if (key) this.$delete(this.contentCache, key);\n this.messages[msgIdx].content = finalContent;\n this.messages[msgIdx].thinking = thinkingBuffer;\n this.messages[msgIdx].loading = false;\n }\n this.sending = false;\n this.clearWaitTimer();\n if (typeTimer) {\n clearInterval(typeTimer);\n typeTimer = null;\n }\n this.scrollToBottom();\n this.loadSessions();\n });\n es.onerror = err => {\n console.log('[SSE] onerror', err);\n if (thinkingBuffer.length > 0 && !finalContent) finalContent = thinkingBuffer;\n if (!finalContent) finalContent = '❌ 连接中断';\n es.close();\n this.eventSource = null;\n if (this.messages[msgIdx]) {\n const key = this.messages[msgIdx]._key;\n if (key) this.$delete(this.contentCache, key);\n this.messages[msgIdx].content = finalContent;\n this.messages[msgIdx].thinking = thinkingBuffer;\n this.messages[msgIdx].loading = false;\n }\n this.sending = false;\n this.clearWaitTimer();\n if (typeTimer) {\n clearInterval(typeTimer);\n typeTimer = null;\n }\n this.scrollToBottom();\n };\n },\n stopAgent() {\n if (this.eventSource) {\n this.eventSource.close();\n this.eventSource = null;\n }\n if (this.activeSessionId) {\n (0, _apichat.stopStream)(this.activeSessionId).catch(() => {});\n }\n if (this.messages.length > 0) {\n const last = this.messages[this.messages.length - 1];\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 this.sending = false;\n this.clearWaitTimer();\n },\n copyText(content) {\n if (!content) return;\n navigator.clipboard.writeText(content.replace(/<[^>]+>/g, '')).then(() => {\n this.$message({\n message: '已复制到剪贴板',\n type: 'success',\n duration: 1500\n });\n }).catch(() => {\n this.$message({\n message: '复制失败',\n type: 'error',\n duration: 2000\n });\n });\n },\n copyAsImage(content) {\n if (!content) return;\n // 创建临时容器渲染 Markdown\n const 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;';\n div.innerHTML = this.renderMarkdown(content);\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(canvas => {\n canvas.toBlob(blob => {\n if (blob) {\n navigator.clipboard.write([new ClipboardItem({\n 'image/png': blob\n })]).then(() => {\n this.$message({\n message: '图片已复制到剪贴板',\n type: 'success',\n duration: 1500\n });\n }).catch(() => {\n this.$message({\n message: '复制图片失败',\n type: 'error',\n duration: 2000\n });\n });\n }\n }, 'image/png');\n }).catch(() => {\n this.$message({\n message: '生成图片失败',\n type: 'error',\n duration: 2000\n });\n }).finally(() => {\n document.body.removeChild(div);\n });\n },\n formatTime(t) {\n if (!t) return '';\n const d = new Date(t.replace(' ', 'T'));\n const now = new Date();\n const 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 getInitial(name) {\n if (!name) return '?';\n return name.charAt(0);\n },\n renderMarkdown(text) {\n if (!text) return '';\n try {\n return md.render(text);\n } catch (err) {\n return this.escapeHtml(text);\n }\n },\n renderStreaming(text, msgKey) {\n if (!text) return '';\n console.log('进入');\n const cache = this.contentCache[msgKey];\n const lines = text.split('\\n');\n const lastLineIdx = lines.length - 1;\n if (!cache) {\n try {\n const html = md.render(text);\n this.$set(this.contentCache, msgKey, {\n renderedLines: lastLineIdx,\n html,\n fullText: text\n });\n return html;\n } catch {\n return this.escapeHtml(text);\n }\n }\n if (text === cache.fullText) return cache.html;\n cache.fullText = text;\n\n // 行数没变,仅末尾追加字符,直接拼接尾行(原有逻辑不变)\n if (lastLineIdx === cache.renderedLines) {\n return cache.html + this.escapeHtml(lines[lastLineIdx]);\n }\n\n // 场景1:行数变少/文本回退截断,全量重渲染(原有分支保留,内部修复)\n if (lastLineIdx < cache.renderedLines) {\n try {\n // 重新截取所有完整行生成全新基础html,清空旧叠加内容\n const fullLines = lines.slice(0, lastLineIdx);\n let newBaseHtml = '';\n if (fullLines.length > 0) {\n newBaseHtml = md.render(fullLines.join('\\n'));\n }\n cache.html = newBaseHtml;\n cache.renderedLines = lastLineIdx;\n // 拼接尾行\n const lastLine = this.escapeHtml(lines[lastLineIdx]);\n return cache.html + (lastLine || '');\n } catch {\n return this.escapeHtml(text);\n }\n }\n\n // 场景2:新增完整行,修复:不再累加旧html,重新从0生成完整行基础\n if (cache.renderedLines < lastLineIdx) {\n // 关键修复:重新切片所有完整行,抛弃之前叠加的旧html,杜绝重复\n const allFullLines = lines.slice(0, lastLineIdx);\n let newBaseHtml = '';\n if (allFullLines.length > 0) {\n newBaseHtml = md.render(allFullLines.join('\\n'));\n }\n cache.html = newBaseHtml;\n cache.renderedLines = lastLineIdx;\n }\n const lastLine = this.escapeHtml(lines[lastLineIdx]);\n cache.renderedLines = lastLineIdx;\n return cache.html + (lastLine || '');\n },\n escapeHtml(text) {\n if (!text) return '';\n return text.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>');\n },\n scrollToTop() {\n const el = this.$refs.messagesRef;\n if (el) el.scrollTop = 0;\n },\n scrollToBottom(force = false) {\n if (this.showDownBtn && !force) return;\n this.$nextTick(() => {\n const el = this.$refs.messagesRef;\n if (el) {\n el.scrollTop = el.scrollHeight;\n this.lastScrollTop = el.scrollTop;\n this.showDownBtn = false; // 滚动到底部后立刻隐藏箭头\n }\n });\n },\n scrollToBottomOnce() {\n // 清理旧定时器,防止任何泄漏\n clearTimeout(this._scrollTimer);\n this.$nextTick(() => {\n let retry = 0;\n const maxRetry = 6; // 重试6次,足够覆盖所有渲染延迟\n\n const tryScroll = () => {\n var _this$$refs;\n const el = (_this$$refs = this.$refs) === null || _this$$refs === void 0 ? void 0 : _this$$refs.messagesRef;\n if (!el) {\n this._scrollTimer = setTimeout(tryScroll, 50);\n return;\n }\n\n // 临时禁用平滑滚动,立即跳到底部\n const originalScrollBehavior = el.style.scrollBehavior;\n el.style.scrollBehavior = 'auto';\n el.scrollTop = el.scrollHeight - el.clientHeight;\n el.style.scrollBehavior = originalScrollBehavior;\n this.showDownBtn = false;\n };\n tryScroll();\n });\n }\n },\n beforeDestroy() {\n window.removeEventListener('resize', this.updateViewportState);\n this.contentCache = {};\n clearTimeout(this._scrollTimer);\n if (this.eventSource) {\n this.eventSource.onerror = null;\n this.eventSource.close();\n this.eventSource = null;\n }\n if (this.waitTimer) {\n clearInterval(this.waitTimer);\n this.waitTimer = null;\n }\n if (this._typeTimer) {\n clearInterval(this._typeTimer);\n this._typeTimer = null;\n }\n }\n};\n\n//# sourceURL=webpack://ZjPluginIntelligent/./src/lib/components/chatMain/index.vue?./node_modules/_cache-loader@4.1.0@cache-loader/dist/cjs.js??ref--13-0!./node_modules/_babel-loader@8.4.1@babel-loader/lib!./node_modules/_cache-loader@4.1.0@cache-loader/dist/cjs.js??ref--1-0!./node_modules/_vue-loader@15.11.1@vue-loader/lib??vue-loader-options");
|
|
942
|
+
eval("\n\nvar _interopRequireDefault = __webpack_require__(/*! ./node_modules/_@babel_runtime@7.28.4@@babel/runtime/helpers/interopRequireDefault.js */ \"./node_modules/_@babel_runtime@7.28.4@@babel/runtime/helpers/interopRequireDefault.js\").default;\nObject.defineProperty(exports, \"__esModule\", {\n value: true\n});\nexports.default = void 0;\n__webpack_require__(/*! core-js/modules/es.error.cause.js */ \"./node_modules/_core-js@3.45.1@core-js/modules/es.error.cause.js\");\n__webpack_require__(/*! core-js/modules/es.array.push.js */ \"./node_modules/_core-js@3.45.1@core-js/modules/es.array.push.js\");\n__webpack_require__(/*! core-js/modules/es.array-buffer.detached.js */ \"./node_modules/_core-js@3.45.1@core-js/modules/es.array-buffer.detached.js\");\n__webpack_require__(/*! core-js/modules/es.array-buffer.transfer.js */ \"./node_modules/_core-js@3.45.1@core-js/modules/es.array-buffer.transfer.js\");\n__webpack_require__(/*! core-js/modules/es.array-buffer.transfer-to-fixed-length.js */ \"./node_modules/_core-js@3.45.1@core-js/modules/es.array-buffer.transfer-to-fixed-length.js\");\n__webpack_require__(/*! core-js/modules/es.iterator.constructor.js */ \"./node_modules/_core-js@3.45.1@core-js/modules/es.iterator.constructor.js\");\n__webpack_require__(/*! core-js/modules/es.iterator.filter.js */ \"./node_modules/_core-js@3.45.1@core-js/modules/es.iterator.filter.js\");\n__webpack_require__(/*! core-js/modules/es.iterator.find.js */ \"./node_modules/_core-js@3.45.1@core-js/modules/es.iterator.find.js\");\n__webpack_require__(/*! core-js/modules/es.iterator.for-each.js */ \"./node_modules/_core-js@3.45.1@core-js/modules/es.iterator.for-each.js\");\n__webpack_require__(/*! core-js/modules/es.iterator.map.js */ \"./node_modules/_core-js@3.45.1@core-js/modules/es.iterator.map.js\");\n__webpack_require__(/*! core-js/modules/es.typed-array.at.js */ \"./node_modules/_core-js@3.45.1@core-js/modules/es.typed-array.at.js\");\n__webpack_require__(/*! core-js/modules/es.typed-array.find-last.js */ \"./node_modules/_core-js@3.45.1@core-js/modules/es.typed-array.find-last.js\");\n__webpack_require__(/*! core-js/modules/es.typed-array.find-last-index.js */ \"./node_modules/_core-js@3.45.1@core-js/modules/es.typed-array.find-last-index.js\");\n__webpack_require__(/*! core-js/modules/es.typed-array.set.js */ \"./node_modules/_core-js@3.45.1@core-js/modules/es.typed-array.set.js\");\n__webpack_require__(/*! core-js/modules/es.typed-array.to-reversed.js */ \"./node_modules/_core-js@3.45.1@core-js/modules/es.typed-array.to-reversed.js\");\n__webpack_require__(/*! core-js/modules/es.typed-array.to-sorted.js */ \"./node_modules/_core-js@3.45.1@core-js/modules/es.typed-array.to-sorted.js\");\n__webpack_require__(/*! core-js/modules/es.typed-array.with.js */ \"./node_modules/_core-js@3.45.1@core-js/modules/es.typed-array.with.js\");\nvar _apichat = __webpack_require__(/*! @lib/api/apichat */ \"./src/lib/api/apichat.js\");\nvar _markdownIt = _interopRequireDefault(__webpack_require__(/*! markdown-it */ \"./node_modules/_markdown-it@14.1.0@markdown-it/index.mjs\"));\nvar _html2canvas = _interopRequireDefault(__webpack_require__(/*! html2canvas */ \"./node_modules/_html2canvas@1.4.1@html2canvas/dist/html2canvas.js\"));\nvar _index = __webpack_require__(/*! @lib/socket/fileManager/obs/index */ \"./src/lib/socket/fileManager/obs/index.js\");\nvar _index2 = _interopRequireDefault(__webpack_require__(/*! @lib/socket/utils/index */ \"./src/lib/socket/utils/index.js\"));\nvar _cookie = __webpack_require__(/*! @lib/utils/cookie.js */ \"./src/lib/utils/cookie.js\");\nvar _apiObs = _interopRequireDefault(__webpack_require__(/*! @lib/api/apiObs */ \"./src/lib/api/apiObs.js\"));\nconst md = new _markdownIt.default({\n breaks: true,\n html: false,\n linkify: true,\n typographer: true\n});\nmd.enable('table');\nvar _default = exports.default = {\n name: 'ChatMain',\n props: {\n Ak: {\n type: String,\n default: ''\n },\n Sk: {\n type: String,\n default: ''\n },\n imAccount: {\n type: String,\n default: ''\n },\n companyNo: {\n type: String,\n default: ''\n },\n isIntelShow: {\n default: false,\n type: Boolean\n },\n chatImToken: {\n default: '',\n type: String\n }\n },\n data() {\n return {\n agentList: [],\n currentAgent: '',\n currentAgentDesc: '',\n sessionsLoaded: false,\n searchKeyword: '',\n agentSuggestions: [],\n showAgentSuggestions: false,\n sessionList: [],\n activeSessionId: '',\n messages: [],\n loadingMore: false,\n sending: false,\n waitTimer: null,\n waitSeconds: 0,\n canceling: false,\n msgPage: 1,\n msgMaxPage: 1,\n msgTotal: 0,\n inputText: '',\n eventSource: null,\n showToolInfo: false,\n showDownBtn: false,\n // 控制向下箭头显隐\n lastScrollTop: 0,\n scrollTimer: null,\n // 滚动防抖(新增)\n showAgentSelect: true,\n isMobile: false,\n showSidebar: false,\n showH5List: false,\n // H5列表模式(展示会话列表而非聊天详情)\n _scrollTimer: null,\n agentInfo: {},\n contentCache: {},\n // 流式分行缓存 key=msg._key\n loadingSessionMsg: false,\n // 会话消息加载中标记\n greeting: '',\n longPressTimer: null,\n longPressed: false,\n // H5 语音输入\n voiceMode: false,\n // true=语音模式,false=文字模式\n isRecording: false,\n // 是否正在录音\n recordDuration: 0,\n // 录音时长(秒)\n recordingTimer: null,\n // 时长计时器\n audioContext: null,\n // AudioContext 实例\n audioStream: null,\n // MediaStream(用于清理)\n audioProcessor: null,\n // ScriptProcessorNode\n audioChunks: [],\n // Float32Array 数据块\n isCancelSwipe: false,\n // 是否上滑取消\n recordStartY: 0 // 触摸起始Y坐标\n };\n },\n created() {\n if (this.Ak || this.Sk) {\n (0, _apichat.setApiAuth)(this.Ak, this.Sk, this.imAccount, this.companyNo, this.chatImToken);\n }\n this.loadAgents();\n this.loadSessions();\n },\n mounted() {\n this.updateViewportState();\n window.addEventListener('resize', this.updateViewportState, {\n passive: true\n });\n },\n computed: {\n 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 filteredSessions() {\n if (!this.searchKeyword) return this.sessionList;\n const kw = this.searchKeyword.toLowerCase();\n return this.sessionList.filter(s => {\n const name = (s.agentName || s.agentCode || '').toLowerCase();\n return name.includes(kw);\n });\n },\n currentAgentName() {\n if (!this.currentAgent) return '';\n const a = this.agentList.find(x => x.agentCode === this.currentAgent);\n return a ? a.agentName || a.agentCode : this.currentAgent;\n }\n },\n watch: {\n searchKeyword(val) {\n if (this.searchTimer) clearTimeout(this.searchTimer);\n if (!val.trim()) {\n this.agentSuggestions = [];\n this.showAgentSuggestions = false;\n this.closeSidebar();\n return;\n }\n this.searchTimer = setTimeout(() => {\n (0, _apichat.getChatAgents)(val.trim()).then(list => {\n this.agentSuggestions = list || [];\n this.showAgentSuggestions = this.agentSuggestions.length > 0;\n }).catch(() => {\n this.agentSuggestions = [];\n });\n }, 300);\n }\n // ak: {\n // handler(newVal) {\n // setApiAuth(newVal, this.sk)\n // },\n // immediate: true\n // },\n // sk: {\n // handler(newVal) {\n // setApiAuth(this.ak, newVal)\n // },\n // immediate: true\n // }\n },\n methods: {\n updateViewportState() {\n if (typeof window === 'undefined') return;\n const nextIsMobile = window.innerWidth <= 768;\n const wasMobile = this.isMobile;\n this.isMobile = nextIsMobile;\n if (!nextIsMobile) {\n this.showSidebar = false;\n this.showH5List = false;\n } else if (!wasMobile && nextIsMobile) {\n // 从桌面端切换到H5:如果加载了会话列表且无活跃会话,展示列表页\n if (this.sessionList.length > 0 && !this.activeSessionId) {\n this.showH5List = true;\n this.showAgentSelect = false;\n }\n }\n },\n toggleSidebar() {\n if (!this.isMobile) return;\n this.showSidebar = !this.showSidebar;\n },\n closeSidebar() {\n this.showSidebar = false;\n },\n // H5:调用原生返回上一级\n handleNativeBack() {\n if (this.$hybrid && typeof this.$hybrid.closePage === 'function') {\n this.$hybrid.closePage();\n } else if (window.history.length > 1) {\n window.history.back();\n }\n },\n // H5侧边栏返回按钮\n handleSidebarBack() {\n this.handleNativeBack();\n },\n agentjumpclick() {\n if (this.sending) {\n this.$message.warning('AI正在生成内容,暂时请不要切换对话');\n return;\n }\n this.currentAgent = '';\n this.currentAgentDesc = '';\n this.searchKeyword = '';\n this.activeSessionId = '';\n this.agentSuggestions = [];\n this.messages = [];\n this.showAgentSuggestions = false;\n this.showAgentSelect = true;\n this.showH5List = false;\n this.closeSidebar();\n },\n // H5:从详情页返回列表页\n goBackToList() {\n if (this.sending) {\n this.$message.warning('AI正在生成内容,暂时请不要切换对话');\n return;\n }\n // 关闭流连接\n if (this.eventSource) {\n this.eventSource.close();\n this.eventSource = null;\n }\n this.sending = false;\n this.clearWaitTimer();\n this.activeSessionId = '';\n this.messages = [];\n this.currentAgent = '';\n this.currentAgentDesc = '';\n this.agentInfo = {};\n this.contentCache = {};\n\n // 始终返回列表页\n this.showH5List = true;\n this.showAgentSelect = false;\n this.closeSidebar();\n },\n sendQuickMsg(message) {\n if (message) {\n this.inputText = message;\n this.sendMessage();\n }\n },\n formatMixText(str) {\n if (!str) return '';\n // 1. 中文 <=> 英文/数字 之间加空格\n let res = str.replace(/([a-zA-Z0-9])([\\u4e00-\\u9fff])/g, '$1 $2').replace(/([\\u4e00-\\u9fff])([a-zA-Z0-9])/g, '$1 $2');\n // 2. 连续英文单词分片粘连修复:字母紧跟字母中间加空格\n // 匹配 小写+大写 驼峰、连续分片拼接成一坨的英文\n res = res.replace(/([a-z])([A-Z])/g, '$1 $2');\n return res;\n },\n // 获取右侧头像样式(根据当前智能体在左侧列表中的位置决定颜色)\n getChatAvatarStyle(agent, avatar) {\n if (avatar) {\n return {\n backgroundImage: `url(${avatar})`,\n backgroundSize: 'cover',\n backgroundPosition: 'center',\n backgroundRepeat: 'no-repeat'\n };\n }\n const _agent = this.agentList.find(x => x.agentCode === agent);\n // 如果有网络图片,返回背景图样式\n if (agent.avatar) {\n return {\n backgroundImage: `url(${agent.avatar})`,\n backgroundSize: 'cover',\n backgroundPosition: 'center',\n backgroundRepeat: 'no-repeat'\n };\n }\n\n // 没有网络图片时,根据智能体在 agentList 中的索引位置决定颜色\n if (this.sessionList) {\n // 找到当前智能体在列表中的索引\n const index = this.sessionList.findIndex(item => item.agentCode === agent);\n if (index !== -1) {\n // 根据索引计算颜色类(4色循环)\n const colorIndex = index % 4 + 1;\n return {\n background: this.getGradientByColorIndex(colorIndex)\n };\n }\n }\n\n // 默认返回蓝色渐变\n return {\n background: 'linear-gradient(135deg, #1677ff, #4096ff)'\n };\n },\n // 根据颜色索引获取对应的渐变色\n getGradientByColorIndex(index) {\n const 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 selectAgent(agentItem) {\n this.showAgentSelect = false;\n this.currentAgent = agentItem.agentCode;\n this.currentAgentName = agentItem.agentName;\n // 查找历史会话\n const existSession = this.sessionList.find(s => s.agentCode === agentItem.agentCode);\n if (existSession) {\n this.activeSessionId = existSession.id;\n this.switchSession(existSession);\n } else {\n this.createNewSession(agentItem.agentCode);\n }\n },\n createNewSession(agentCode) {\n // 你原有新建会话逻辑\n },\n // 检测是否滚动到底部,控制向下箭头显示隐藏\n checkScrollBottom(forceShowWhenNotBottom = false) {\n const el = this.$refs.messagesRef;\n if (!el) {\n this.showDownBtn = false;\n return;\n }\n const {\n scrollHeight,\n scrollTop,\n clientHeight\n } = el;\n const remain = scrollHeight - scrollTop - clientHeight;\n const atBottom = remain <= 80;\n if (atBottom) {\n this.showDownBtn = false;\n } else if (this.sending && scrollTop >= this.lastScrollTop && !forceShowWhenNotBottom) {\n // 发送AI回答时,如果用户没有主动向上滚动,就不要显示下箭头闪烁\n this.showDownBtn = false;\n } else {\n this.showDownBtn = true;\n }\n this.lastScrollTop = scrollTop;\n },\n // 固定最小高度:单行不撑开,超出才增高\n autoResizeTextarea() {\n const ta = this.$refs.taRef;\n if (!ta) return;\n // 根据端适配基准高度和最大高度\n const isMobile = this.isMobile;\n const baseH = isMobile ? 36 : 100;\n const maxH = isMobile ? 100 : 180;\n ta.style.height = `${baseH}px`;\n // 内容真实高度\n const realH = ta.scrollHeight;\n // 只有内容高度>基准才撑开,否则保持初始高度\n if (realH > baseH) {\n ta.style.height = `${Math.min(realH, maxH)}px`;\n }\n this.$nextTick(() => {\n this.checkScrollBottom(true);\n });\n },\n // Shift+Enter换行\n newLine(e) {\n // 取消浏览器默认行为\n e.preventDefault();\n // 拿到光标位置\n const ta = this.$refs.taRef;\n const start = ta.selectionStart;\n const end = ta.selectionEnd;\n // 在光标处插入换行符\n this.inputText = this.inputText.slice(0, start) + '\\n' + this.inputText.slice(end);\n // 光标定位到换行后\n this.$nextTick(() => {\n ta.selectionStart = ta.selectionEnd = start + 1;\n // 自动调整输入框高度\n this.autoResizeTextarea();\n });\n },\n toggleVoiceMode() {\n this.voiceMode = !this.voiceMode;\n if (!this.voiceMode) {\n // 切回文字模式时清理录音状态\n this.cancelRecording();\n }\n },\n // H5语音录制 - 触摸开始\n async onRecordTouchStart(e) {\n if (this.sending) return;\n this.isCancelSwipe = false;\n this.recordStartY = e.touches[0].clientY;\n this.recordDuration = 0;\n this.audioChunks = [];\n this.isRecording = true;\n\n // 启动时长计时\n this.recordingTimer = setInterval(() => {\n this.recordDuration++;\n if (this.recordDuration >= 60) {\n this.onRecordTouchEnd();\n }\n }, 1000);\n\n // 检测麦克风是否可用(非 HTTPS 或 WebView 不支持时 mediaDevices 为 undefined)\n if (!navigator.mediaDevices || !navigator.mediaDevices.getUserMedia) {\n this.isRecording = false;\n clearInterval(this.recordingTimer);\n this.recordingTimer = null;\n alert('当前环境不支持麦克风访问');\n return;\n }\n\n // 使用 AudioContext 采集 PCM 数据,输出 WAV 格式\n try {\n const stream = await navigator.mediaDevices.getUserMedia({\n audio: true\n });\n this.audioStream = stream;\n const audioContext = new (window.AudioContext || window.webkitAudioContext)({\n sampleRate: 16000\n });\n this.audioContext = audioContext;\n const source = audioContext.createMediaStreamSource(stream);\n // bufferSize=4096, 1 input channel, 1 output channel\n const processor = audioContext.createScriptProcessor(4096, 1, 1);\n this.audioProcessor = processor;\n processor.onaudioprocess = e => {\n if (!this.isRecording) return;\n const inputData = e.inputBuffer.getChannelData(0);\n // 保存 float32 采样数据\n this.audioChunks.push(new Float32Array(inputData));\n };\n source.connect(processor);\n processor.connect(audioContext.destination);\n } catch (err) {\n console.error('麦克风访问失败:', err);\n this.$message.warning('麦克风权限被拒绝');\n this.cancelRecording();\n }\n },\n // H5语音录制 - 触摸移动(检测上滑取消)\n onRecordTouchMove(e) {\n if (!this.isRecording) return;\n const touch = e.touches[0];\n const moveY = touch.clientY;\n const cancelThreshold = 60; // 上滑60px进入取消区域\n this.isCancelSwipe = this.recordStartY - moveY > cancelThreshold;\n },\n // H5语音录制 - 触摸结束\n onRecordTouchEnd() {\n if (!this.isRecording) return;\n this.isRecording = false;\n if (this.recordingTimer) {\n clearInterval(this.recordingTimer);\n this.recordingTimer = null;\n }\n this.stopAudioCapture(!this.isCancelSwipe);\n },\n // 停止音频采集并输出 WAV\n stopAudioCapture(shouldSend) {\n // 断开并清理音频节点\n if (this.audioProcessor) {\n this.audioProcessor.disconnect();\n this.audioProcessor = null;\n }\n if (this.audioContext) {\n this.audioContext.close().catch(() => {});\n this.audioContext = null;\n }\n if (this.audioStream) {\n this.audioStream.getTracks().forEach(t => t.stop());\n this.audioStream = null;\n }\n if (shouldSend && this.audioChunks.length > 0) {\n const wavBlob = this.encodePCMToWav(this.audioChunks, 16000);\n this.sendAudioBlob(wavBlob);\n }\n this.audioChunks = [];\n },\n // 取消录音\n cancelRecording() {\n this.isRecording = false;\n if (this.recordingTimer) {\n clearInterval(this.recordingTimer);\n this.recordingTimer = null;\n }\n this.stopAudioCapture(false);\n this.recordDuration = 0;\n this.isCancelSwipe = false;\n },\n // 将 Float32 PCM 数据编码为 WAV Blob\n encodePCMToWav(chunks, sampleRate) {\n // 计算总采样数\n let totalLength = 0;\n for (const chunk of chunks) {\n totalLength += chunk.length;\n }\n\n // 转换为 Int16 PCM\n const pcmData = new Int16Array(totalLength);\n let offset = 0;\n for (const chunk of chunks) {\n for (let i = 0; i < chunk.length; i++) {\n const s = Math.max(-1, Math.min(1, chunk[i]));\n pcmData[offset++] = s < 0 ? s * 0x8000 : s * 0x7FFF;\n }\n }\n const numChannels = 1;\n const bitsPerSample = 16;\n const byteRate = sampleRate * numChannels * bitsPerSample / 8;\n const blockAlign = numChannels * bitsPerSample / 8;\n const dataSize = pcmData.length * (bitsPerSample / 8);\n const headerSize = 44;\n const totalSize = headerSize + dataSize;\n const buffer = new ArrayBuffer(totalSize);\n const view = new DataView(buffer);\n\n // RIFF header\n this._wavWriteString(view, 0, 'RIFF');\n view.setUint32(4, totalSize - 8, true);\n this._wavWriteString(view, 8, 'WAVE');\n\n // fmt chunk\n this._wavWriteString(view, 12, 'fmt ');\n view.setUint32(16, 16, true); // chunk size\n view.setUint16(20, 1, true); // PCM format\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 // data chunk\n this._wavWriteString(view, 36, 'data');\n view.setUint32(40, dataSize, true);\n\n // 写入 PCM 数据\n const pcmView = new Int16Array(buffer, headerSize, pcmData.length);\n pcmView.set(pcmData);\n return new Blob([buffer], {\n type: 'audio/wav'\n });\n },\n _wavWriteString(view, offset, str) {\n for (let i = 0; i < str.length; i++) {\n view.setUint8(offset + i, str.charCodeAt(i));\n }\n },\n // 发送音频\n sendAudioBlob(blob) {\n let appSeqId = _index2.default.getAppSeqId();\n let name = appSeqId + '.wav';\n const file = new File([blob], name, {\n type: 'audio/wav'\n });\n // TODO: 上传音频文件并调用 STT 接口\n this.sendAudioMessage(file);\n },\n sendAudioMessage(file) {\n // 插入本地 pending 消息\n const sttKey = 'stt_' + Date.now();\n const 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(resp => {\n if (resp.CommonMsg.Status === 200) {\n // 调用语音转文字接口\n return _apiObs.default.aliAudioToText({\n url: resp.obs_upload_data.obsUrl\n }).then(result => {\n if (result.code === '200' && result.data) {\n // 成功:删除 pending 消息,发送给后端\n const idx = this.messages.findIndex(m => m._sttKey === sttKey);\n if (idx !== -1) {\n this.messages.splice(idx, 1);\n }\n this.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(err => {\n console.error('语音转文字失败:', err);\n // 失败:更新为错误状态\n const idx = this.messages.findIndex(m => m._sttKey === sttKey);\n if (idx !== -1) {\n this.$set(this.messages, idx, {\n ...this.messages[idx],\n _sttStatus: 'error',\n content: '语音转文字失败'\n });\n }\n this.$message.error('语音转文字失败');\n });\n this.$message.success(`录音完成 (${this.recordDuration}s)`);\n },\n clearWaitTimer() {\n if (this.waitTimer) {\n clearInterval(this.waitTimer);\n this.waitTimer = null;\n }\n },\n loadAgents() {\n (0, _apichat.getChatAgents)().then(list => {\n this.agentList = list || [];\n // if (this.agentList.length > 0 && !this.currentAgent) {\n // const first = this.agentList[0]\n // this.currentAgent = first.agentCode\n // this.currentAgentDesc = first.description || ''\n // }\n }).catch(() => {});\n },\n loadSessions() {\n (0, _apichat.getSessionList)().then(list => {\n if (!this.activeSessionId) {\n this.sessionList = list || [];\n if (this.sessionList.length > 0) {\n if (this.isMobile) {\n // H5模式:不自动选中会话,展示列表页\n this.showAgentSelect = false;\n this.showH5List = true;\n this.showSidebar = false;\n } else {\n this.switchSession(this.sessionList[0]);\n }\n }\n if (this.sessionList.length === 0) {\n this.showAgentSelect = true;\n this.showH5List = false;\n }\n } else {\n this.sessionList = list || [];\n let _item = list.find(res => res.sessionId == this.activeSessionId);\n try {\n if (_item.suggestedQuestions) {\n _item.suggestedQuestions = JSON.parse(_item.suggestedQuestions);\n } else {\n _item.suggestedQuestions = [];\n }\n _item && (this.agentInfo = _item);\n } catch (err) {\n // JSON格式错误兜底空数组,防止页面报错\n this.agentInfo.questionArr = [];\n console.warn('快捷提问解析失败', err);\n }\n }\n }).catch(() => {});\n },\n onSearchClear() {\n this.agentSuggestions = [];\n this.showAgentSuggestions = false;\n },\n startChatWithAgent(agent) {\n console.log('选择了助手', agent.agentCode, this.currentAgent);\n if (agent.agentCode == this.currentAgent) {\n this.searchKeyword = '';\n this.agentSuggestions = [];\n this.showAgentSuggestions = false;\n return;\n }\n this.currentAgent = agent.agentCode;\n this.currentAgentDesc = agent.description || '';\n this.searchKeyword = '';\n this.agentInfo = {};\n this.agentSuggestions = [];\n this.messages = [];\n this.showAgentSuggestions = false;\n this.showAgentSelect = false;\n this.closeSidebar();\n if (this.isMobile) {\n this.showH5List = false; // H5:进入详情页,隐藏列表\n }\n const existing = this.sessionList.find(s => s.agentCode === agent.agentCode);\n if (existing) {\n this.switchSession(existing);\n } else {\n this.handleNewSession();\n }\n },\n handleNewSession() {\n if (!this.currentAgent) return;\n if (this.activeSessionId) this.closeOldSession();\n (0, _apichat.startSession)(this.currentAgent).then(res => {\n console.log(res, 'startChatWithAgentstartChatWithAgentstartChatWithAgent', this.agentInfo);\n this.activeSessionId = res.sessionId || '';\n this.loadSessions();\n const agent = this.agentList.find(a => a.agentCode === this.currentAgent);\n if (agent) this.addWelcomeMessage(agent);\n }).catch(() => {});\n },\n // H5长按删除 - 触摸开始\n onSessionTouchStart(s, e) {\n if (!this.isMobile) return;\n this.longPressed = false;\n this.longPressTimer = setTimeout(() => {\n this.longPressed = true;\n this.handleDeleteSession(s);\n }, 600);\n },\n // H5长按删除 - 触摸结束/移动(取消长按)\n onSessionTouchEnd() {\n if (this.longPressTimer) {\n clearTimeout(this.longPressTimer);\n this.longPressTimer = null;\n }\n },\n onSessionTouchMove() {\n if (this.longPressTimer) {\n clearTimeout(this.longPressTimer);\n this.longPressTimer = null;\n }\n },\n async switchSession(s) {\n if (this.longPressed) {\n this.longPressed = false;\n return;\n }\n if (this.sending) {\n this.$message.warning('AI正在生成内容,暂时请不要切换对话');\n return;\n }\n this.showAgentSelect = false;\n this.closeSidebar();\n if (this.isMobile) {\n this.showH5List = false; // H5:进入详情页,隐藏列表\n }\n if (this.activeSessionId === s.sessionId) return;\n this.contentCache = {};\n this.activeSessionId = s.sessionId;\n this.currentAgent = s.agentCode;\n console.log('进入');\n this.agentInfo = s;\n console.log('进入', this.agentInfo);\n try {\n if (s.suggestedQuestions) {\n this.agentInfo.suggestedQuestions = JSON.parse(s.suggestedQuestions);\n } else {\n this.agentInfo.suggestedQuestions = [];\n }\n } catch (err) {\n // JSON格式错误兜底空数组,防止页面报错\n this.agentInfo.questionArr = [];\n console.warn('快捷提问解析失败', err);\n }\n const agent = this.agentList.find(a => a.agentCode === s.agentCode);\n this.currentAgentDesc = agent ? agent.description || '' : '';\n this.msgPage = 1;\n this.msgTotal = 0;\n this.messages = []; // 先清空,但开启加载锁屏蔽空白页\n this.loadingSessionMsg = true; // 开启加载标记\n (0, _apichat.syncToken)((0, _cookie.getToken)(), s.sessionId);\n try {\n const res = await (0, _apichat.getSessionMessages)(s.sessionId, 1, 10);\n const list = Array.isArray(res) ? res : res.list || [];\n this.msgTotal = res.total || list.length;\n this.msgPage = 1;\n const asAsc = (list || []).slice().reverse();\n this.messages = asAsc.map(m => ({\n role: m.role,\n content: m.content || '',\n thinking: m.thinking || '',\n toolCalls: [],\n agentName: m.role === 'assistant' ? s.agentName || '' : '',\n createTime: m.createTime || null,\n _key: m.createTime ? 'msg_' + m.createTime : 'msg_' + Date.now() + '_' + Math.random()\n }));\n if (this.messages.length === 0 && agent) this.addWelcomeMessage(agent);\n await this.$nextTick();\n this.$nextTick(() => {\n this.scrollToBottomOnce();\n this.checkScrollBottom();\n });\n } catch (e) {\n this.messages = [];\n } finally {\n // 无论成功失败,结束后关闭加载锁\n this.loadingSessionMsg = false;\n }\n },\n loadMoreMessages() {\n const nextPage = this.msgPage + 1;\n const maxPage = Math.ceil(this.msgTotal / 10);\n if (nextPage > maxPage) {\n this.loadingMore = false;\n return;\n }\n (0, _apichat.getSessionMessages)(this.activeSessionId, nextPage, 10).then(res => {\n const list = Array.isArray(res) ? res : res.list || [];\n this.msgPage = nextPage;\n const asAsc = (list || []).slice().reverse();\n const prepend = asAsc.map(m => ({\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 }));\n const container = this.$refs.messagesRef;\n const oldScrollHeight = container ? container.scrollHeight : 0;\n const oldScrollTop = container ? container.scrollTop : 0;\n this.messages = [...prepend, ...this.messages];\n this.$nextTick(() => {\n if (container) {\n container.scrollTop = oldScrollTop + (container.scrollHeight - oldScrollHeight);\n }\n this.loadingMore = false;\n });\n }).catch(() => {\n this.loadingMore = false;\n });\n },\n onScrollMessages() {\n const container = this.$refs.messagesRef;\n if (!container || this.loadingMore) return;\n const isAtBottom = container.scrollTop + container.clientHeight >= container.scrollHeight - 100;\n this.checkScrollBottom();\n if (isAtBottom) return;\n if (container.scrollTop < 50 && this.msgPage < Math.ceil(this.msgTotal / 10)) {\n this.loadingMore = true;\n this.loadMoreMessages();\n }\n },\n handleDeleteSession(s) {\n this.$confirm(`确认删除「${s.agentName || s.agentCode}」的会话?`, '提示', {\n type: 'warning'\n }).then(() => {\n (0, _apichat.deleteSession)(s.sessionId).then(() => {\n if (this.activeSessionId === s.sessionId) {\n this.activeSessionId = '';\n this.messages = [];\n this.currentAgent = '';\n this.currentAgentDesc = '';\n if (this.isMobile) {\n this.showH5List = false;\n this.showAgentSelect = true;\n } else {\n this.showAgentSelect = true;\n }\n }\n this.loadSessions();\n });\n }).catch(() => {});\n },\n closeOldSession() {},\n onAgentChange(code) {\n const agent = this.agentList.find(a => a.agentCode === code);\n this.currentAgentDesc = agent ? agent.description || '' : '';\n this.handleNewSession();\n },\n addWelcomeMessage(agent) {\n this.greeting = '';\n // if (!agent) return\n // const name = agent.agentName || '助手';\n const _agent = this.agentList.find(x => x.agentCode === this.currentAgent);\n this.greeting = _agent.greeting || `很高兴为您服务,请问有什么可以帮到您?`;\n // this.messages.push({\n // role: 'assistant',\n // content: _content,\n // thinking: '',\n // agentName: name,\n // _key: 'welcome_' + Date.now()\n // })\n },\n async sendMessage() {\n const text = this.inputText.trim();\n if (!text || this.sending) return;\n if (!this.activeSessionId) {\n await (0, _apichat.startSession)(this.currentAgent).then(res => {\n this.activeSessionId = res.sessionId || '';\n this.loadSessions();\n });\n if (!this.activeSessionId) return;\n }\n this.inputText = '';\n const ta = this.$refs.taRef;\n const isMobile = this.isMobile;\n const baseH = isMobile ? 36 : 100;\n if (ta) {\n ta.style.height = baseH + 'px'; // 强制恢复初始高度\n }\n this.showDownBtn = false;\n this.messages.push({\n role: 'user',\n content: text,\n createTime: new Date().toISOString(),\n _key: 'user_' + Date.now() + '_' + Math.random()\n });\n const agentName = this.currentAgentName;\n const msgIdx = this.messages.push({\n role: \"assistant\",\n content: \"\",\n thinking: \"\",\n loading: true,\n toolCalls: [],\n agentName,\n createTime: new Date().toISOString(),\n _key: 'asst_' + Date.now() + '_' + Math.random()\n }) - 1;\n this.scrollToBottom(true);\n this.sending = true;\n this.waitSeconds = 0;\n if (this.waitTimer) clearInterval(this.waitTimer);\n this.waitTimer = setInterval(() => {\n this.waitSeconds++;\n }, 1000);\n let thinkingBuffer = '';\n let finalContent = '';\n let answerBuffer = '';\n let thinkDisplayed = 0;\n let typeTimer = null;\n typeTimer = setInterval(() => {\n if (!this.messages[msgIdx]) return;\n if (thinkDisplayed < thinkingBuffer.length) {\n thinkDisplayed += 50;\n if (thinkDisplayed > thinkingBuffer.length) thinkDisplayed = thinkingBuffer.length;\n this.messages[msgIdx].thinking = thinkingBuffer.substring(0, thinkDisplayed);\n this.scrollToBottom();\n } else if (finalContent && !this.messages[msgIdx].content) {\n clearInterval(typeTimer);\n const key = this.messages[msgIdx]._key;\n if (key) {\n this.$delete(this.contentCache, key);\n this.$delete(this.contentCache, key + '_t');\n }\n typeTimer = null;\n this.messages[msgIdx].content = finalContent;\n this.messages[msgIdx].thinking = thinkingBuffer;\n this.messages[msgIdx].loading = false;\n this.sending = false;\n this.clearWaitTimer();\n this.scrollToBottom();\n this.loadSessions();\n }\n }, 30);\n const url = (0, _apichat.createStreamUrl)(this.activeSessionId, text);\n if (this.eventSource) {\n this.eventSource.close();\n }\n this.eventSource = new EventSource(url);\n const es = this.eventSource;\n es.addEventListener('reasoning', e => {\n if (e.data) {\n const chunk = e.data;\n // 1. 先处理当前分片内部的中英文、数字、标点空格\n let 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\n // 2. 关键:判断前一段末尾 + 当前段开头都是英文,补空格分隔\n const lastChar = thinkingBuffer.slice(-1);\n const firstChar = cleanChunk.slice(0, 1);\n const isLetter = c => /[a-zA-Z]/.test(c);\n if (isLetter(lastChar) && isLetter(firstChar)) {\n // 两段都是英文衔接,中间加空格\n thinkingBuffer += ' ' + cleanChunk;\n } else {\n thinkingBuffer += cleanChunk;\n }\n }\n });\n es.addEventListener('reasoning_result', e => {\n if (e.data) {\n thinkingBuffer = e.data;\n }\n });\n es.addEventListener('answer', e => {\n if (e.data) {\n answerBuffer += e.data;\n if (this.messages[msgIdx]) {\n this.messages[msgIdx].content += 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 this.scrollToBottom();\n }\n }\n });\n es.addEventListener('tool_result', e => {\n if (e.data && this.messages[msgIdx]) {\n if (!this.messages[msgIdx].toolCalls) this.messages[msgIdx].toolCalls = [];\n this.messages[msgIdx].toolCalls.push(e.data);\n this.scrollToBottom();\n }\n });\n es.addEventListener('agent_result', e => {\n finalContent = e.data || '';\n es.close();\n this.eventSource = null;\n if (this.messages[msgIdx]) {\n const key = this.messages[msgIdx]._key;\n if (key) this.$delete(this.contentCache, key);\n this.messages[msgIdx].content = finalContent;\n this.messages[msgIdx].thinking = thinkingBuffer;\n this.messages[msgIdx].loading = false;\n }\n this.sending = false;\n this.clearWaitTimer();\n if (typeTimer) {\n clearInterval(typeTimer);\n typeTimer = null;\n }\n this.scrollToBottom();\n this.loadSessions();\n });\n es.onerror = err => {\n console.log('[SSE] onerror', err);\n if (thinkingBuffer.length > 0 && !finalContent) finalContent = thinkingBuffer;\n if (!finalContent) finalContent = '❌ 连接中断';\n es.close();\n this.eventSource = null;\n if (this.messages[msgIdx]) {\n const key = this.messages[msgIdx]._key;\n if (key) this.$delete(this.contentCache, key);\n this.messages[msgIdx].content = finalContent;\n this.messages[msgIdx].thinking = thinkingBuffer;\n this.messages[msgIdx].loading = false;\n }\n this.sending = false;\n this.clearWaitTimer();\n if (typeTimer) {\n clearInterval(typeTimer);\n typeTimer = null;\n }\n this.scrollToBottom();\n };\n },\n stopAgent() {\n if (this.eventSource) {\n this.eventSource.close();\n this.eventSource = null;\n }\n if (this.activeSessionId) {\n (0, _apichat.stopStream)(this.activeSessionId).catch(() => {});\n }\n if (this.messages.length > 0) {\n const last = this.messages[this.messages.length - 1];\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 this.sending = false;\n this.clearWaitTimer();\n },\n copyText(content) {\n if (!content) return;\n navigator.clipboard.writeText(content.replace(/<[^>]+>/g, '')).then(() => {\n this.$message({\n message: '已复制到剪贴板',\n type: 'success',\n duration: 1500\n });\n }).catch(() => {\n this.$message({\n message: '复制失败',\n type: 'error',\n duration: 2000\n });\n });\n },\n copyAsImage(content) {\n if (!content) return;\n // 创建临时容器渲染 Markdown\n const 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;';\n div.innerHTML = this.renderMarkdown(content);\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(canvas => {\n canvas.toBlob(blob => {\n if (blob) {\n navigator.clipboard.write([new ClipboardItem({\n 'image/png': blob\n })]).then(() => {\n this.$message({\n message: '图片已复制到剪贴板',\n type: 'success',\n duration: 1500\n });\n }).catch(() => {\n this.$message({\n message: '复制图片失败',\n type: 'error',\n duration: 2000\n });\n });\n }\n }, 'image/png');\n }).catch(() => {\n this.$message({\n message: '生成图片失败',\n type: 'error',\n duration: 2000\n });\n }).finally(() => {\n document.body.removeChild(div);\n });\n },\n formatTime(t) {\n if (!t) return '';\n const d = new Date(t.replace(' ', 'T'));\n const now = new Date();\n const 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 getInitial(name) {\n if (!name) return '?';\n return name.charAt(0);\n },\n renderMarkdown(text) {\n if (!text) return '';\n try {\n return md.render(text);\n } catch (err) {\n return this.escapeHtml(text);\n }\n },\n renderStreaming(text, msgKey) {\n if (!text) return '';\n console.log('进入');\n const cache = this.contentCache[msgKey];\n const lines = text.split('\\n');\n const lastLineIdx = lines.length - 1;\n if (!cache) {\n try {\n const html = md.render(text);\n this.$set(this.contentCache, msgKey, {\n renderedLines: lastLineIdx,\n html,\n fullText: text\n });\n return html;\n } catch {\n return this.escapeHtml(text);\n }\n }\n if (text === cache.fullText) return cache.html;\n cache.fullText = text;\n\n // 行数没变,仅末尾追加字符,直接拼接尾行(原有逻辑不变)\n if (lastLineIdx === cache.renderedLines) {\n return cache.html + this.escapeHtml(lines[lastLineIdx]);\n }\n\n // 场景1:行数变少/文本回退截断,全量重渲染(原有分支保留,内部修复)\n if (lastLineIdx < cache.renderedLines) {\n try {\n // 重新截取所有完整行生成全新基础html,清空旧叠加内容\n const fullLines = lines.slice(0, lastLineIdx);\n let newBaseHtml = '';\n if (fullLines.length > 0) {\n newBaseHtml = md.render(fullLines.join('\\n'));\n }\n cache.html = newBaseHtml;\n cache.renderedLines = lastLineIdx;\n // 拼接尾行\n const lastLine = this.escapeHtml(lines[lastLineIdx]);\n return cache.html + (lastLine || '');\n } catch {\n return this.escapeHtml(text);\n }\n }\n\n // 场景2:新增完整行,修复:不再累加旧html,重新从0生成完整行基础\n if (cache.renderedLines < lastLineIdx) {\n // 关键修复:重新切片所有完整行,抛弃之前叠加的旧html,杜绝重复\n const allFullLines = lines.slice(0, lastLineIdx);\n let newBaseHtml = '';\n if (allFullLines.length > 0) {\n newBaseHtml = md.render(allFullLines.join('\\n'));\n }\n cache.html = newBaseHtml;\n cache.renderedLines = lastLineIdx;\n }\n const lastLine = this.escapeHtml(lines[lastLineIdx]);\n cache.renderedLines = lastLineIdx;\n return cache.html + (lastLine || '');\n },\n escapeHtml(text) {\n if (!text) return '';\n return text.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>');\n },\n scrollToTop() {\n const el = this.$refs.messagesRef;\n if (el) el.scrollTop = 0;\n },\n scrollToBottom(force = false) {\n if (this.showDownBtn && !force) return;\n this.$nextTick(() => {\n const el = this.$refs.messagesRef;\n if (el) {\n el.scrollTop = el.scrollHeight;\n this.lastScrollTop = el.scrollTop;\n this.showDownBtn = false; // 滚动到底部后立刻隐藏箭头\n }\n });\n },\n scrollToBottomOnce() {\n // 清理旧定时器,防止任何泄漏\n clearTimeout(this._scrollTimer);\n this.$nextTick(() => {\n let retry = 0;\n const maxRetry = 6; // 重试6次,足够覆盖所有渲染延迟\n\n const tryScroll = () => {\n var _this$$refs;\n const el = (_this$$refs = this.$refs) === null || _this$$refs === void 0 ? void 0 : _this$$refs.messagesRef;\n if (!el) {\n this._scrollTimer = setTimeout(tryScroll, 50);\n return;\n }\n\n // 临时禁用平滑滚动,立即跳到底部\n const originalScrollBehavior = el.style.scrollBehavior;\n el.style.scrollBehavior = 'auto';\n el.scrollTop = el.scrollHeight - el.clientHeight;\n el.style.scrollBehavior = originalScrollBehavior;\n this.showDownBtn = false;\n };\n tryScroll();\n });\n }\n },\n beforeDestroy() {\n window.removeEventListener('resize', this.updateViewportState);\n this.contentCache = {};\n clearTimeout(this._scrollTimer);\n if (this.eventSource) {\n this.eventSource.onerror = null;\n this.eventSource.close();\n this.eventSource = null;\n }\n if (this.waitTimer) {\n clearInterval(this.waitTimer);\n this.waitTimer = null;\n }\n if (this._typeTimer) {\n clearInterval(this._typeTimer);\n this._typeTimer = null;\n }\n }\n};\n\n//# sourceURL=webpack://ZjPluginIntelligent/./src/lib/components/chatMain/index.vue?./node_modules/_cache-loader@4.1.0@cache-loader/dist/cjs.js??ref--13-0!./node_modules/_babel-loader@8.4.1@babel-loader/lib!./node_modules/_cache-loader@4.1.0@cache-loader/dist/cjs.js??ref--1-0!./node_modules/_vue-loader@15.11.1@vue-loader/lib??vue-loader-options");
|
|
943
943
|
|
|
944
944
|
/***/ }),
|
|
945
945
|
|
|
@@ -3252,7 +3252,7 @@ eval("// Imports\nvar ___CSS_LOADER_API_IMPORT___ = __webpack_require__(/*! ../.
|
|
|
3252
3252
|
/*! no static exports found */
|
|
3253
3253
|
/***/ (function(module, exports, __webpack_require__) {
|
|
3254
3254
|
|
|
3255
|
-
eval("// Imports\nvar ___CSS_LOADER_API_IMPORT___ = __webpack_require__(/*! ../../../../node_modules/_css-loader@3.6.0@css-loader/dist/runtime/api.js */ \"./node_modules/_css-loader@3.6.0@css-loader/dist/runtime/api.js\");\nexports = ___CSS_LOADER_API_IMPORT___(false);\n// Module\nexports.push([module.i, \"\\n.chat-layout[data-v-bf6d760c] {\\r\\n display: flex;\\r\\n height: 100%;\\r\\n width: 100%;\\r\\n background: #fff;\\r\\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei', sans-serif;\\n}\\r\\n\\r\\n/* ── Sidebar ── */\\n.chat-sidebar[data-v-bf6d760c] {\\r\\n width: 300px;\\r\\n min-width: 300px;\\r\\n background: #fff;\\r\\n border-right: 1px solid #e8e8e8;\\r\\n display: flex;\\r\\n flex-direction: column;\\r\\n overflow: hidden;\\n}\\n.sidebar-header[data-v-bf6d760c] {\\r\\n display: flex;\\r\\n align-items: center;\\r\\n justify-content: space-between;\\r\\n padding: 14px 8px 14px 16px;\\r\\n border-bottom: 1px solid #e8e8e8;\\r\\n flex-shrink: 0;\\n}\\n.sidebar-header i[data-v-bf6d760c]{\\r\\n font-size: 20px;\\r\\n cursor: pointer;\\n}\\n.sidebar-header img[data-v-bf6d760c]{\\r\\n cursor: pointer;\\n}\\n.sidebar-title[data-v-bf6d760c] {\\r\\n font-size: 15px;\\r\\n font-weight: 600;\\r\\n color: #333;\\n}\\n.sidebar-search[data-v-bf6d760c] {\\r\\n padding: 8px 16px;\\r\\n flex-shrink: 0;\\r\\n position: relative;\\r\\n z-index: 20;\\n}\\n.sidebar-search .search-wrap[data-v-bf6d760c] {\\r\\n display: flex;\\r\\n align-items: center;\\r\\n position: relative;\\n}\\n.sidebar-search .search-icon[data-v-bf6d760c] {\\r\\n position: absolute;\\r\\n left: 12px;\\r\\n flex-shrink: 0;\\r\\n pointer-events: none;\\n}\\n.sidebar-search .search-input[data-v-bf6d760c] {\\r\\n width: 100%;\\r\\n height: 32px;\\r\\n border-radius: 16px;\\r\\n background: #f5f5f5;\\r\\n border: 1px solid transparent;\\r\\n font-size: 13px;\\r\\n padding: 0 32px 0 34px;\\r\\n outline: none;\\r\\n box-sizing: border-box;\\r\\n transition: all 0.2s;\\n}\\n.sidebar-search .search-input[data-v-bf6d760c]:focus {\\r\\n background: #fff;\\r\\n border: 1px solid #1677ff;\\n}\\n.sidebar-search .search-clear[data-v-bf6d760c] {\\r\\n position: absolute;\\r\\n right: 10px;\\r\\n cursor: pointer;\\r\\n flex-shrink: 0;\\n}\\n.search-suggestions[data-v-bf6d760c] {\\r\\n position: absolute;\\r\\n top: 100%;\\r\\n left: 16px;\\r\\n right: 16px;\\r\\n background: #fff;\\r\\n border: 1px solid #e8e8e8;\\r\\n border-radius: 8px;\\r\\n box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);\\r\\n z-index: 100;\\r\\n max-height: 240px;\\r\\n overflow-y: auto;\\r\\n margin-top: 4px;\\n}\\n.suggestion-item[data-v-bf6d760c] {\\r\\n display: flex;\\r\\n align-items: center;\\r\\n gap: 10px;\\r\\n padding: 10px 12px;\\r\\n cursor: pointer;\\r\\n transition: background 0.15s;\\n}\\n.suggestion-item[data-v-bf6d760c]:hover {\\r\\n background: #f5f7fa;\\n}\\n.suggestion-avatar[data-v-bf6d760c] {\\r\\n width: 28px;\\r\\n height: 28px;\\r\\n border-radius: 6px;\\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: 13px;\\r\\n font-weight: 600;\\r\\n flex-shrink: 0;\\n}\\n.suggestion-name[data-v-bf6d760c] {\\r\\n font-size: 14px;\\r\\n font-weight: 500;\\r\\n color: #333;\\r\\n white-space: nowrap;\\n}\\n.suggestion-desc[data-v-bf6d760c] {\\r\\n font-size: 12px;\\r\\n color: #999;\\r\\n overflow: hidden;\\r\\n text-overflow: ellipsis;\\r\\n white-space: nowrap;\\n}\\n.sidebar-list[data-v-bf6d760c] {\\r\\n flex: 1;\\r\\n overflow-y: auto;\\r\\n padding: 8px 0;\\n}\\n.session-item[data-v-bf6d760c] {\\r\\n display: flex;\\r\\n align-items: center;\\r\\n padding: 6px 16px;\\r\\n /* 顶部留白,匹配UI顶部空隙 */\\r\\n padding-bottom: 10px;\\r\\n cursor: pointer;\\r\\n border-bottom: 1px solid #f5f5f5;\\r\\n transition: background 0.15s;\\r\\n position: relative;\\r\\n gap: 10px;\\r\\n border-radius: 4px;\\n}\\n.session-left-item[data-v-bf6d760c]{\\r\\n margin-left: 5px;\\n}\\n.session-item[data-v-bf6d760c]:hover {\\r\\n background: #f5f7fa;\\n}\\n.session-item.active[data-v-bf6d760c] {\\r\\n background: #F5F5F5\\n}\\n.session-avatar[data-v-bf6d760c] {\\r\\n width: 44px!important;\\r\\n height: 44px!important;\\r\\n /* UI是圆形头像,把8px圆角改成50% */\\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}\\r\\n/* 头像图片样式,居中完整展示,四周露出底色 */\\n.avatar-pic[data-v-bf6d760c] {\\r\\n width: 85%;\\r\\n height: 85%;\\r\\n -o-object-fit: contain;\\r\\n object-fit: contain;\\n}\\n.session-info[data-v-bf6d760c] {\\r\\n flex: 1;\\r\\n min-width: 0;\\n}\\n.session-agent[data-v-bf6d760c] {\\r\\n font-size: 15px;\\r\\n font-weight: 500;\\r\\n color: #333;\\r\\n margin-bottom: 2px;\\r\\n overflow: hidden;\\r\\n text-overflow: ellipsis;\\r\\n white-space: nowrap;\\n}\\n.session-preview[data-v-bf6d760c] {\\r\\n font-size: 12px;\\r\\n color: #999;\\r\\n overflow: hidden;\\r\\n text-overflow: ellipsis;\\r\\n white-space: nowrap;\\n}\\n.session-time[data-v-bf6d760c] {\\r\\n font-size: 11px;\\r\\n color: #bbb;\\r\\n flex-shrink: 0;\\r\\n margin-left: 8px;\\r\\n margin-right: 4px;\\n}\\n.session-delete[data-v-bf6d760c] {\\r\\n position: absolute;\\r\\n right: 4px;\\r\\n top: 20px;\\r\\n transform: translateY(-50%);\\r\\n opacity: 0;\\r\\n transition: opacity 0.15s;\\r\\n width: 28px;\\r\\n height: 28px;\\r\\n display: flex;\\r\\n align-items: center;\\r\\n justify-content: center;\\r\\n border: none;\\r\\n background: transparent;\\r\\n padding: 0;\\r\\n color: #333;\\r\\n cursor: pointer;\\n}\\n.session-delete svg[data-v-bf6d760c] {\\r\\n color: #333;\\n}\\n.session-item:hover .session-delete[data-v-bf6d760c] {\\r\\n opacity: 1;\\n}\\n.sidebar-list[data-v-bf6d760c] {\\r\\n flex: 1;\\r\\n overflow-y: auto;\\r\\n padding: 8px 0;\\n}\\n.sidebar-empty[data-v-bf6d760c] {\\r\\n flex: 1;\\r\\n display: flex;\\r\\n flex-direction: column;\\r\\n align-items: center;\\r\\n justify-content: center;\\r\\n color: #bbb;\\r\\n font-size: 14px;\\r\\n padding-bottom: 40px;\\n}\\n.empty-icon[data-v-bf6d760c] {\\r\\n font-size: 36px;\\r\\n margin-bottom: 8px;\\n}\\n.empty-hint[data-v-bf6d760c] {\\r\\n font-size: 12px;\\r\\n color: #d9d9d9;\\r\\n margin-top: 4px;\\n}\\r\\n/* ── Main ── */\\n.chat-main[data-v-bf6d760c] {\\r\\n flex: 1;\\r\\n display: flex;\\r\\n flex-direction: column;\\r\\n min-width: 0;\\n}\\r\\n\\r\\n/* ── Header ── */\\n.chat-header[data-v-bf6d760c] {\\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-bf6d760c] {\\r\\n display: flex;\\r\\n align-items: center;\\r\\n gap: 10px;\\r\\n min-width: 0;\\n}\\n.agent-info[data-v-bf6d760c] {\\r\\n display: flex;\\r\\n align-items: center;\\r\\n gap: 10px;\\n}\\n.agent-icon[data-v-bf6d760c] {\\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}\\r\\n/* 和左侧会话头像保持 4 色循环背景 */\\n.agent-info:nth-child(4n + 2) .agent-icon-avatar[data-v-bf6d760c] {\\r\\n background: linear-gradient(135deg, #52c41a, #73d13d);\\n}\\n.agent-info:nth-child(4n + 3) .agent-icon-avatar[data-v-bf6d760c] {\\r\\n background: linear-gradient(135deg, #fa8c16, #ffa940);\\n}\\n.agent-info:nth-child(4n + 4) .agent-icon-avatar[data-v-bf6d760c] {\\r\\n background: linear-gradient(135deg, #722ed1, #b37feb);\\n}\\n.agent-text[data-v-bf6d760c] {\\r\\n min-width: 0;\\n}\\n.agent-name[data-v-bf6d760c] {\\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-bf6d760c] {\\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: 300px;\\n}\\n.header-right[data-v-bf6d760c] {\\r\\n flex-shrink: 0;\\n}\\n.manage-link[data-v-bf6d760c] {\\r\\n font-size: 13px;\\r\\n color: #1677ff;\\r\\n text-decoration: none;\\n}\\n.manage-link[data-v-bf6d760c]:hover {\\r\\n color: #4096ff;\\n}\\r\\n\\r\\n/* ── Chat Body ── */\\n.chat-body[data-v-bf6d760c] {\\r\\n flex: 1;\\r\\n overflow-y: auto;\\r\\n padding: 16px 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%;\\n}\\n.welcome[data-v-bf6d760c] {\\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-bf6d760c] {\\r\\n margin-bottom: 12px;\\r\\n opacity: 0.7;\\n}\\n.welcome-text[data-v-bf6d760c] {\\r\\n font-size: 15px;\\n}\\n.welcome-default .welcome-icon[data-v-bf6d760c] {\\r\\n margin-bottom: 16px;\\n}\\n.welcome-title[data-v-bf6d760c] {\\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-bf6d760c] {\\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-bf6d760c] {\\r\\n display: flex;\\r\\n align-items: center;\\r\\n gap: 10px;\\r\\n max-width: 85%;\\r\\n /* 最大内容宽度限制,避免超宽 */\\r\\n width: 800px;\\n}\\n.msg-row.user .msg-main[data-v-bf6d760c] {\\r\\n flex-direction: row-reverse;\\n}\\n.msg-row.assistant[data-v-bf6d760c] {\\r\\n justify-content: center;\\n}\\n.load-more[data-v-bf6d760c] {\\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-bf6d760c] {\\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-bf6d760c] {\\r\\n text-align: right;\\r\\n padding-right: 4px;\\n}\\n.msg-actions[data-v-bf6d760c] {\\r\\n display: flex;\\r\\n gap: 4px;\\r\\n margin-top: 4px;\\r\\n padding-left: 4px;\\n}\\n.action-btn[data-v-bf6d760c] {\\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 user-select: none;\\n}\\n.action-btn[data-v-bf6d760c]:hover {\\r\\n color: #1677ff;\\r\\n background: #f0f5ff;\\n}\\r\\n\\r\\n/* ── STT 语音转文字状态 ── */\\n.stt-status-block[data-v-bf6d760c] {\\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}\\r\\n/* ── STT 状态(图标紧贴气泡左侧,文字在气泡内) ── */\\n.stt-bubble-wrap[data-v-bf6d760c] {\\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-bf6d760c] {\\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-bf6d760c] {\\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 animation: stt-spin-bf6d760c 0.6s linear infinite;\\r\\n flex-shrink: 0;\\r\\n box-sizing: border-box;\\n}\\n@keyframes stt-spin-bf6d760c {\\nto { transform: rotate(360deg);\\n}\\n}\\n.stt-error-icon[data-v-bf6d760c] {\\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-bf6d760c] {\\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-main[data-v-bf6d760c] {\\r\\n display: flex;\\r\\n align-items: flex-start;\\r\\n gap: 10px;\\r\\n width: 800px;\\n}\\n.msg-row.user .msg-main[data-v-bf6d760c] {\\r\\n flex-direction: row-reverse;\\n}\\n.msg-avatar[data-v-bf6d760c] {\\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-bf6d760c] {\\r\\n background: linear-gradient(135deg, #1677ff, #4096ff);\\r\\n color: #fff;\\n}\\n.msg-avatar.assistant[data-v-bf6d760c] {\\r\\n background: linear-gradient(135deg, #52c41a, #73d13d);\\r\\n color: #fff;\\n}\\n.msg-agent-label[data-v-bf6d760c] {\\r\\n font-size: 12px;\\r\\n color: #999;\\r\\n margin-bottom: 2px;\\n}\\n.msg-content[data-v-bf6d760c] {\\r\\n width: 800px;\\r\\n box-sizing: border-box;\\r\\n overflow: hidden;\\n}\\r\\n\\r\\n/* ── Bubble ── */\\n.bubble[data-v-bf6d760c] {\\r\\n max-width: 100%;\\r\\n min-width: 30px;\\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;\\n}\\n.bubble[data-v-bf6d760c]:has(.typing) {\\r\\n padding: 16px 20px;\\n}\\n.bubble.user[data-v-bf6d760c] {\\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: right;\\n}\\n.bubble.assistant[data-v-bf6d760c] {\\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-bf6d760c] 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-bf6d760c] th,\\r\\n.bubble[data-v-bf6d760c] td {\\r\\n border: 1px solid #e8e8e8;\\r\\n padding: 5px 8px;\\r\\n text-align: left;\\n}\\n.bubble[data-v-bf6d760c] th {\\r\\n background: #fafafa;\\r\\n font-weight: 600;\\n}\\n.bubble[data-v-bf6d760c] code {\\r\\n /* background: #f0f2f5; */\\r\\n padding: 1px 5px;\\r\\n border-radius: 3px;\\r\\n font-size: 14px;\\n}\\n.bubble[data-v-bf6d760c] 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-bf6d760c] ul,\\r\\n.bubble[data-v-bf6d760c] ol {\\r\\n padding-left: 20px;\\r\\n margin: 4px 0;\\n}\\n.bubble[data-v-bf6d760c] li {\\r\\n margin: 2px 0;\\n}\\n.bubble[data-v-bf6d760c] p{\\r\\n margin: 6px 0;\\n}\\r\\n\\r\\n/* ── Thinking ── */\\n.thinking-details[data-v-bf6d760c] {\\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-bf6d760c] {\\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 user-select: none;\\n}\\n.thinking-summary[data-v-bf6d760c]:hover {\\r\\n color: #1677ff;\\n}\\n.thinking-body[data-v-bf6d760c] {\\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 /* 兼容中英文混合断行优化 */\\r\\n overflow-wrap: break-word;\\n}\\n.final-content[data-v-bf6d760c]{\\r\\n /* white-space: pre-wrap; */\\r\\n word-break: break-word;\\r\\n overflow-wrap: break-word;\\n}\\n.thinking-body[data-v-bf6d760c] p {\\r\\n margin: 4px 0;\\n}\\r\\n\\r\\n/* ── Typing ── */\\n.typing[data-v-bf6d760c] {\\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-bf6d760c] {\\r\\n font-size: 14px;\\r\\n color: #888;\\r\\n white-space: nowrap;\\r\\n animation: phraseFade-bf6d760c 0.5s ease;\\r\\n letter-spacing: 0.5px;\\n}\\n.typing .dots[data-v-bf6d760c] {\\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-bf6d760c] {\\r\\n width: 8px;\\r\\n height: 8px;\\r\\n background: #bbb;\\r\\n border-radius: 50%;\\r\\n animation: dtTyping-bf6d760c 1.3s infinite ease-in-out;\\n}\\n.typing .dots span[data-v-bf6d760c]:nth-child(2) {\\r\\n animation-delay: 0.16s;\\n}\\n.typing .dots span[data-v-bf6d760c]:nth-child(3) {\\r\\n animation-delay: 0.32s;\\n}\\n@keyframes phraseFade-bf6d760c {\\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 dtTyping-bf6d760c {\\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/* ── Scroll Buttons ── */\\n.scroll-btns[data-v-bf6d760c] {\\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-bf6d760c] {\\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-bf6d760c] {\\r\\n font-size: 16px;\\r\\n color: #333;\\n}\\r\\n/* ── Wait Timer ── */\\n.typing.wait-5 .dots span[data-v-bf6d760c] {\\r\\n width: 8px;\\r\\n height: 8px;\\r\\n animation-duration: 1s;\\n}\\n.typing.wait-5 .phrase[data-v-bf6d760c] {\\r\\n color: #888;\\n}\\n.typing.wait-10 .dots span[data-v-bf6d760c] {\\r\\n width: 9px;\\r\\n height: 9px;\\r\\n animation-duration: 0.8s;\\r\\n background: #909399;\\n}\\n.typing.wait-10 .phrase[data-v-bf6d760c] {\\r\\n color: #909399;\\n}\\n.typing.wait-10 .dots[data-v-bf6d760c] {\\r\\n animation: dtPulse-bf6d760c 1s infinite ease-in-out;\\n}\\n.typing.wait-15 .dots span[data-v-bf6d760c] {\\r\\n width: 10px;\\r\\n height: 10px;\\r\\n animation-duration: 0.6s;\\r\\n background: #1677ff;\\n}\\n.typing.wait-15 .phrase[data-v-bf6d760c] {\\r\\n color: #1677ff;\\n}\\n.typing.wait-15 .dots[data-v-bf6d760c] {\\r\\n animation: dtPulse-bf6d760c 0.6s infinite ease-in-out;\\n}\\n@keyframes dtPulse-bf6d760c {\\n0%,\\r\\n 100% {\\r\\n transform: scale(1);\\n}\\n50% {\\r\\n transform: scale(1.05);\\n}\\n}\\n.tool-calls[data-v-bf6d760c] {\\r\\n margin-top: 8px;\\n}\\n.tool-item[data-v-bf6d760c] {\\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-bf6d760c] {\\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-bf6d760c] {\\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/* ── Footer ── */\\n.chat-footer[data-v-bf6d760c] {\\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;\\n}\\n.input-area[data-v-bf6d760c] {\\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 /* 左右留白,实现居中效果,和截图边距一致 */\\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: 1000px;\\n}\\r\\n/* 原有悬浮滚动按钮逻辑完全保留不动 */\\n.scroll-bottom-wrap[data-v-bf6d760c] {\\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-bf6d760c] {\\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-bf6d760c] {\\r\\n color: #4e5969;\\n}\\r\\n/* 加载转圈动画原样保留 */\\n.loading-circle[data-v-bf6d760c] {\\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 animation: circle-spin-bf6d760c 1.5s linear infinite;\\n}\\n@keyframes circle-spin-bf6d760c {\\nfrom {\\r\\n transform: rotate(0deg);\\n}\\nto {\\r\\n transform: rotate(360deg);\\n}\\n}\\r\\n/* 聚焦仅变色,取消阴影 */\\n.input-area[data-v-bf6d760c]:focus-within {\\r\\n border-color: #1677ff;\\r\\n background: #fff;\\r\\n box-shadow: none;\\n}\\n.chat-textarea[data-v-bf6d760c] {\\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;\\n}\\n.chat-textarea[data-v-bf6d760c]::-moz-placeholder {\\r\\n color: #999;\\r\\n font-size: 16px;\\n}\\n.chat-textarea[data-v-bf6d760c]::placeholder {\\r\\n color: #999;\\r\\n font-size: 16px;\\n}\\r\\n/* 发送按钮 纯蓝色矩形,隐藏svg图标,显示文字发送 */\\n.send-btn[data-v-bf6d760c] {\\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-bf6d760c] {\\r\\n display: none;\\n}\\n.send-btn[data-v-bf6d760c]::after {\\r\\n content: \\\"发送\\\";\\n}\\n.send-btn.active[data-v-bf6d760c] {\\r\\n background: #1677ff;\\n}\\n.send-btn.active[data-v-bf6d760c]:hover {\\r\\n background: #4096ff;\\n}\\n.send-btn[data-v-bf6d760c]:disabled {\\r\\n background: #88bfff;\\r\\n cursor: not-allowed;\\n}\\n.stop-btn[data-v-bf6d760c] {\\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-bf6d760c]:hover {\\r\\n background: #ff7875;\\n}\\r\\n/* 右下角提示文字,精准定位在按钮左侧,和截图位置完全对齐 */\\n.input-area[data-v-bf6d760c]::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}\\r\\n/* 滚动到底部按钮样式 */\\n.scroll-bottom-btn[data-v-bf6d760c] {\\r\\n width: 38px;\\r\\n height: 38px;\\r\\n border-radius: 50%;\\r\\n background: #ffffff;\\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;\\r\\n transition: all 0.2s ease;\\n}\\n.scroll-bottom-btn[data-v-bf6d760c]:hover {\\r\\n transform: scale(1.1);\\n}\\n.scroll-bottom-btn svg[data-v-bf6d760c] {\\r\\n color: #333;\\n}\\r\\n\\r\\n\\r\\n/* 外层页面容器 对应box_9区域 */\\n.agent-select-page[data-v-bf6d760c] {\\r\\n width: 100%;\\r\\n height: 100%;\\r\\n background: url(https://qiguanbang.obs.cn-east-3.myhuaweicloud.com/production/image/AlAgent/background.png) 100% no-repeat;\\r\\n background-size: 100% 100%;\\r\\n box-sizing: border-box;\\r\\n /* 内部全部居中 */\\r\\n display: flex;\\r\\n flex-direction: column;\\r\\n align-items: center;\\n}\\r\\n\\r\\n/* 内容容器,限制最大宽度,自适应,居中 */\\n.agent-wrap[data-v-bf6d760c] {\\r\\n width: 100%;\\r\\n max-width: 1200px;\\n}\\r\\n\\r\\n/* 标题区域居中 */\\n.agent-title[data-v-bf6d760c] {\\r\\n text-align: center;\\r\\n margin-bottom: 116px;\\n}\\n.agent-title h2[data-v-bf6d760c] {\\r\\n font-size: 28px!important;\\r\\n color: #000;\\r\\n font-weight: 500!important;\\r\\n font-family: PingFangSC-Medium;\\r\\n margin: 0;\\r\\n line-height: 40px;\\n}\\r\\n\\r\\n/* 智能助手列表:一行2个自适应等分,自动换行 */\\n.agent-list[data-v-bf6d760c] {\\r\\n display: grid;\\r\\n grid-template-columns: repeat(2, 1fr);\\r\\n gap: 76px 30px;\\r\\n width: 100%;\\n}\\r\\n\\r\\n/* 卡片基础样式,无固定宽度,自适应网格列宽 */\\n.agent-item[data-v-bf6d760c] {\\r\\n position: relative;\\r\\n border-radius: 11px;\\r\\n height: 90px;\\r\\n padding: 20px 20px 19px 116px;\\r\\n box-sizing: border-box;\\r\\n cursor: pointer;\\r\\n transition: all 0.3s ease;\\n}\\n.agent-item[data-v-bf6d760c]:hover {\\r\\n transform: translateY(-4px);\\r\\n box-shadow: 0 8px 20px rgba(0, 0, 0, 0.06);\\n}\\r\\n\\r\\n/* 上浮头像容器 */\\n.agent-avatar-wrapper[data-v-bf6d760c] {\\r\\n position: absolute;\\r\\n left: 3px;\\r\\n top: -36px;\\n}\\r\\n\\r\\n/* 头像默认样式 */\\n.agent-list-avatar[data-v-bf6d760c] {\\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}\\r\\n/* 有头像图片:大尺寸 */\\n.agent-list-avatar.has-agent-img[data-v-bf6d760c] {\\r\\n width: 97px;\\r\\n height: 126px;\\r\\n background-size: cover;\\n}\\r\\n/* 无头像文字首字母:小尺寸,偏移适配 */\\n.agent-list-avatar[data-v-bf6d760c]:not(.has-agent-img) {\\r\\n width: 76px;\\r\\n height: 108px;\\r\\n transform: translateX(9px);\\n}\\r\\n\\r\\n/* 文字内容区 */\\n.agent-info-content[data-v-bf6d760c] {\\r\\n display: flex;\\r\\n flex-direction: column;\\n}\\n.name[data-v-bf6d760c] {\\r\\n font-size: 16px;\\r\\n font-family: PingFangSC-Medium;\\r\\n color: #000;\\r\\n line-height: 22px;\\r\\n margin-bottom: 8px;\\n}\\n.desc[data-v-bf6d760c] {\\r\\n font-size: 15px;\\r\\n font-family: PingFangSC-Regular;\\r\\n color: #666;\\r\\n line-height: 21px;\\r\\n /* 核心三行单行省略,文字超出自动... */\\r\\n overflow: hidden;\\r\\n white-space: nowrap;\\r\\n text-overflow: ellipsis;\\r\\n /* 关键:继承父容器宽度,不会超出父盒子 */\\r\\n width: 100%;\\r\\n display: block;\\n}\\r\\n/* 响应式适配:小屏幕自动变为单列 */\\n@media screen and (max-width: 768px) {\\n.agent-list[data-v-bf6d760c] {\\r\\n grid-template-columns: 1fr;\\n}\\n.agent-selector[data-v-bf6d760c] {\\r\\n padding: 40px 15px;\\n}\\n.agent-title[data-v-bf6d760c] {\\r\\n margin-bottom: 60px;\\n}\\n.agent-title h2[data-v-bf6d760c] {\\r\\n font-size: 22px;\\n}\\n}\\r\\n\\r\\n\\r\\n/* ── 聊天空白欢迎页(匹配蓝湖移动端聊天首页) ── */\\n.chat-empty-welcome[data-v-bf6d760c] {\\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-bf6d760c] {\\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-bf6d760c] {\\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-bf6d760c] {\\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-bf6d760c] {\\r\\n background: transparent;\\r\\n background-repeat: no-repeat;\\r\\n background-position: center;\\n}\\n.welcome-text-group[data-v-bf6d760c] {\\r\\n display: flex;\\r\\n flex-direction: column;\\r\\n gap: 6px;\\n}\\n.welcome-text-group .text-sm[data-v-bf6d760c] {\\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-bf6d760c] {\\r\\n \\r\\n font-weight: 500;\\r\\nfont-size: 16px;\\r\\ncolor: #000000;\\n}\\r\\n\\r\\n/* 猜你想问容器 */\\n.guess-box[data-v-bf6d760c] {\\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-bf6d760c] {\\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-bf6d760c] {\\r\\n display: flex;\\r\\n flex-wrap: wrap;\\r\\n gap: 10px;\\n}\\n.quick-tag[data-v-bf6d760c] {\\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-bf6d760c]{\\r\\n width: 44px;\\r\\n height: 44px;\\n}\\r\\n\\r\\n\\r\\n\\r\\n/* 外层大容器,本地渐变背景铺满全屏,内部全部居中 */\\n.agent-selector[data-v-bf6d760c] {\\r\\n width: 100%;\\r\\n min-height: 100%;\\r\\n padding: 80px 20px;\\r\\n /* 本地背景图铺满 */\\r\\n background: url(https://qiguanbang.obs.cn-east-3.myhuaweicloud.com/production/image/AlAgent/background.png) no-repeat;\\r\\n background-size: 100% 100%;\\r\\n box-sizing: border-box;\\r\\n display: flex;\\r\\n flex-direction: column;\\r\\n align-items: center;\\n}\\r\\n\\r\\n/* 内容容器,限制最大宽度,自适应居中,无固定宽 */\\n.agent-wrap[data-v-bf6d760c] {\\r\\n width: 100%;\\r\\n max-width: 920px;\\n}\\r\\n\\r\\n/* 标题样式,居中、字号、间距匹配效果图 */\\n.agent-title[data-v-bf6d760c] {\\r\\n text-align: center;\\r\\n margin-bottom: 116px;\\n}\\n.agent-title h2[data-v-bf6d760c] {\\r\\n font-size: 26px;\\r\\n color: #222;\\r\\n font-weight: 500;\\r\\n margin: 0;\\r\\n line-height: 40px;\\n}\\r\\n\\r\\n/* 卡片网格:一行2等分,行列间距对齐效果图 */\\n.agent-list[data-v-bf6d760c] {\\r\\n display: grid;\\r\\n grid-template-columns: repeat(2, 1fr);\\r\\n gap: 76px 30px;\\r\\n width: 100%;\\n}\\r\\n\\r\\n/* 卡片核心样式:圆角、内边距、相对定位,无固定宽度 */\\n.agent-item[data-v-bf6d760c] {\\r\\n position: relative;\\r\\n border-radius: 11px;\\r\\n height: 90px;\\r\\n /* 左侧留出头像位置,文字靠右内缩 */\\r\\n padding: 22px 20px 20px 110px;\\r\\n box-sizing: border-box;\\r\\n cursor: pointer;\\r\\n transition: all 0.25s ease;\\r\\n /* 轻微柔和阴影,和效果图一致 */\\r\\n box-shadow: 0 2px 12px rgba(0, 0, 0, 0.05);\\n}\\n.agent-item[data-v-bf6d760c]:hover {\\r\\n transform: translateY(-4px);\\r\\n box-shadow: 0 8px 20px rgba(0, 0, 0, 0.08);\\n}\\r\\n\\r\\n\\r\\n/* 头像本体通用样式 */\\n.agent-list-avatar[data-v-bf6d760c] {\\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;\\r\\n /* 效果图统一卡通头像尺寸 */\\r\\n width: 92px;\\r\\n height: 106px;\\n}\\r\\n/* 有头像图片完整展示,不裁切 */\\n.agent-list-avatar.has-agent-img[data-v-bf6d760c] {\\r\\n background-size: cover;\\n}\\r\\n\\r\\n/* 文字区域垂直排列 */\\n.agent-info-content[data-v-bf6d760c] {\\r\\n display: flex;\\r\\n flex-direction: column;\\r\\n max-width: 300px;\\r\\n flex-shrink: 0; /* 如果是flex布局,禁止自身被压缩 */\\n}\\r\\n/* 助手名称 */\\n.name[data-v-bf6d760c] {\\r\\n font-size: 16px;\\r\\n font-weight: 500;\\r\\n color: #111;\\r\\n line-height: 22px;\\r\\n margin-bottom: 6px;\\n}\\r\\n/* 描述文本 */\\n.desc[data-v-bf6d760c] {\\r\\n font-size: 14px;\\r\\n color: #666;\\r\\n line-height: 20px;\\r\\n /* 超长描述单行省略 */\\r\\n overflow: hidden;\\r\\n white-space: nowrap;\\r\\n text-overflow: ellipsis;\\n}\\r\\n\\r\\n/* 移动端适配:小屏幕自动单列 */\\n@media screen and (max-width: 768px) {\\n.agent-list[data-v-bf6d760c] {\\r\\n grid-template-columns: 1fr;\\n}\\n.agent-selector[data-v-bf6d760c] {\\r\\n padding: 40px 15px;\\n}\\n.agent-title[data-v-bf6d760c] {\\r\\n margin-bottom: 40px;\\n}\\n.agent-title h2[data-v-bf6d760c] {\\r\\n font-size: 22px;\\n}\\n}\\n.chat-layout[data-v-bf6d760c] {\\r\\n position: relative;\\r\\n min-height: 0;\\r\\n overflow: hidden;\\n}\\n.sidebar-mask[data-v-bf6d760c] {\\r\\n position: absolute;\\r\\n inset: 0;\\r\\n background: rgba(15, 23, 42, 0.28);\\r\\n z-index: 29;\\n}\\n.suggestion-avatar[data-v-bf6d760c] {\\r\\n width: 28px !important;\\r\\n height: 28px !important;\\r\\n border-radius: 8px !important;\\r\\n font-size: 12px !important;\\r\\n font-weight: 600;\\r\\n flex-shrink: 0;\\n}\\n.chat-main[data-v-bf6d760c],\\r\\n.chat-body[data-v-bf6d760c] {\\r\\n min-height: 0;\\n}\\n.header-left[data-v-bf6d760c],\\r\\n.header-actions[data-v-bf6d760c] {\\r\\n display: flex;\\r\\n align-items: center;\\n}\\n.header-left[data-v-bf6d760c] {\\r\\n flex: 1;\\r\\n min-width: 0;\\r\\n gap: 10px;\\n}\\n.header-actions[data-v-bf6d760c] {\\r\\n flex-shrink: 0;\\n}\\n.mobile-menu-btn[data-v-bf6d760c],\\r\\n.mobile-back-btn[data-v-bf6d760c],\\r\\n.mobile-header-btn[data-v-bf6d760c] {\\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-bf6d760c],\\r\\n.mobile-back-btn i[data-v-bf6d760c],\\r\\n.mobile-header-btn i[data-v-bf6d760c] {\\r\\n font-size: 18px;\\n}\\n.mobile-back-btn i[data-v-bf6d760c] {\\r\\n font-size: 20px;\\r\\n font-weight: 600;\\n}\\n.chat-sidebar[data-v-bf6d760c] {\\r\\n width: min(300px, 32vw);\\n}\\n.chat-body[data-v-bf6d760c] {\\r\\n padding: 16px clamp(12px, 3vw, 40px);\\r\\n background-position: center;\\r\\n background-size: cover;\\n}\\n.agent-desc[data-v-bf6d760c] {\\r\\n max-width: min(300px, 45vw);\\n}\\n.msg-row[data-v-bf6d760c] {\\r\\n padding: 18px 0;\\n}\\n.msg-main[data-v-bf6d760c] {\\r\\n width: min(100%, 860px) !important;\\r\\n max-width: 860px;\\n}\\n.msg-content[data-v-bf6d760c] {\\r\\n width: 100% !important;\\r\\n max-width: 100%;\\n}\\n.bubble.user[data-v-bf6d760c] {\\r\\n float: none;\\r\\n margin-left: auto;\\r\\n max-width: min(100%, 520px);\\n}\\n.final-content[data-v-bf6d760c],\\r\\n.thinking-body[data-v-bf6d760c],\\r\\n.bubble[data-v-bf6d760c] {\\r\\n overflow-wrap: anywhere;\\n}\\n.chat-footer[data-v-bf6d760c] {\\r\\n width: 100%;\\r\\n padding: 24px 0;\\r\\n flex-shrink: 0;\\n}\\n.input-area[data-v-bf6d760c] {\\r\\n width: min(100%, 1000px) !important;\\r\\n box-sizing: border-box;\\n}\\n.chat-textarea[data-v-bf6d760c] {\\r\\n flex: 1 1 320px;\\r\\n min-width: 0;\\n}\\n@media screen and (max-width: 768px) {\\n.chat-layout.is-mobile[data-v-bf6d760c] {\\r\\n display: flex;\\r\\n height: 100dvh;\\n}\\r\\n\\r\\n /* agent-selector H5 顶部栏 */\\n.agent-selector[data-v-bf6d760c] {\\r\\n padding: 0 !important;\\n}\\n.agent-selector .agent-wrap[data-v-bf6d760c] {\\r\\n padding: 40px 16px 0;\\r\\n box-sizing: border-box;\\n}\\n.mobile-agent-select-header[data-v-bf6d760c] {\\r\\n width: 100%;\\r\\n display: flex;\\r\\n align-items: center;\\r\\n justify-content: center;\\r\\n position: relative;\\r\\n padding: 10px 0;\\r\\n min-height: 44px;\\n}\\n.mobile-agent-select-header .mobile-agent-back[data-v-bf6d760c] {\\r\\n position: absolute;\\r\\n left: 4px;\\r\\n top: 50%;\\r\\n transform: translateY(-50%);\\r\\n background: transparent;\\r\\n border: none;\\r\\n width: 44px;\\r\\n height: 44px;\\r\\n display: inline-flex;\\r\\n align-items: center;\\r\\n justify-content: center;\\r\\n cursor: pointer;\\r\\n padding: 0;\\r\\n color: #333;\\n}\\n.mobile-agent-select-header .mobile-agent-back i[data-v-bf6d760c] {\\r\\n font-size: 22px;\\r\\n font-weight: 600;\\n}\\n.mobile-agent-select-header .mobile-agent-title-text[data-v-bf6d760c] {\\r\\n font-size: 17px;\\r\\n font-weight: 500;\\r\\n color: #000;\\n}\\n.agent-selector .agent-title[data-v-bf6d760c] {\\r\\n display: none;\\n}\\r\\n\\r\\n /* H5列表模式:侧边栏全屏展示 */\\n.chat-layout.h5-list-mode .chat-sidebar[data-v-bf6d760c] {\\r\\n position: relative !important;\\r\\n width: 100% !important;\\r\\n max-width: 100% !important;\\r\\n min-width: 100% !important;\\r\\n height: 100%;\\r\\n transform: translateX(0) !important;\\r\\n box-shadow: none !important;\\r\\n border-right: none;\\n}\\n.chat-layout.h5-list-mode .chat-sidebar .sidebar-header[data-v-bf6d760c] {\\r\\n display: flex;\\r\\n align-items: center;\\r\\n justify-content: center;\\r\\n padding: 14px 16px;\\r\\n position: relative;\\n}\\n.sidebar-back-btn[data-v-bf6d760c] {\\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: transparent;\\r\\n color: #333;\\r\\n cursor: pointer;\\r\\n flex-shrink: 0;\\r\\n position: absolute;\\r\\n left: 8px;\\r\\n top: 50%;\\r\\n transform: translateY(-50%);\\r\\n padding: 0;\\n}\\n.sidebar-back-btn svg[data-v-bf6d760c] {\\r\\n display: block;\\n}\\n.chat-layout.h5-list-mode .chat-sidebar .sidebar-header img[data-v-bf6d760c] {\\r\\n position: absolute;\\r\\n right: 16px;\\r\\n top: 50%;\\r\\n transform: translateY(-50%);\\r\\n width: 22px;\\r\\n height: 22px;\\r\\n -o-object-fit: contain;\\r\\n object-fit: contain;\\r\\n cursor: pointer;\\n}\\n.chat-sidebar[data-v-bf6d760c] {\\r\\n position: absolute;\\r\\n inset: 0 auto 0 0;\\r\\n width: min(82vw, 320px);\\r\\n min-width: auto;\\r\\n max-width: 320px;\\r\\n height: 100%;\\r\\n border-right: none;\\r\\n box-shadow: 8px 0 24px rgba(15, 23, 42, 0.12);\\r\\n transform: translateX(-100%);\\r\\n transition: transform 0.24s ease;\\n}\\n.chat-sidebar.open[data-v-bf6d760c] {\\r\\n transform: translateX(0);\\n}\\n.chat-header[data-v-bf6d760c] {\\r\\n padding: 10px 12px;\\r\\n background: transparent;\\r\\n border-bottom: none;\\n}\\n.chat-header .chat-agent-avatar-wrapper[data-v-bf6d760c] {\\r\\n display: none;\\n}\\n.chat-header .agent-desc[data-v-bf6d760c] {\\r\\n display: none;\\n}\\n.chat-header .header-left[data-v-bf6d760c] {\\r\\n flex: 1;\\r\\n justify-content: center;\\r\\n position: relative;\\n}\\n.chat-header .header-left .mobile-back-btn[data-v-bf6d760c] {\\r\\n position: absolute;\\r\\n left: 12px;\\r\\n background: transparent;\\n}\\n.chat-header .header-actions .mobile-header-btn[data-v-bf6d760c] {\\r\\n background: transparent;\\n}\\n.chat-body[data-v-bf6d760c] {\\r\\n padding: 12px;\\r\\n background-position: center top;\\n}\\n.msg-row[data-v-bf6d760c] {\\r\\n padding: 12px 0;\\n}\\n.msg-main[data-v-bf6d760c] {\\r\\n width: 100% !important;\\r\\n max-width: 100%;\\n}\\n.bubble[data-v-bf6d760c] {\\r\\n font-size: 14px;\\n}\\n.bubble.user[data-v-bf6d760c] {\\r\\n max-width: 88%;\\n}\\n.chat-footer[data-v-bf6d760c] {\\r\\n padding: 12px 0 max(12px, env(safe-area-inset-bottom));\\r\\n flex-shrink: 0;\\n}\\n.input-area[data-v-bf6d760c] {\\r\\n width: calc(100% - 24px) !important;\\r\\n margin: 0 12px;\\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-bf6d760c]: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-bf6d760c]::after {\\r\\n display: none;\\n}\\n.voice-btn[data-v-bf6d760c] {\\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-bf6d760c]:active {\\r\\n background: rgba(0,0,0,0.05);\\n}\\n.voice-btn[data-v-bf6d760c]:disabled {\\r\\n opacity: 0.4;\\r\\n cursor: not-allowed;\\n}\\n.chat-textarea[data-v-bf6d760c] {\\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-bf6d760c]::-moz-placeholder {\\r\\n color: #999;\\r\\n font-size: 15px;\\n}\\n.chat-textarea[data-v-bf6d760c]::placeholder {\\r\\n color: #999;\\r\\n font-size: 15px;\\n}\\n.send-btn[data-v-bf6d760c] {\\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-bf6d760c] {\\r\\n display: block;\\n}\\n.send-btn[data-v-bf6d760c]::after {\\r\\n content: none;\\n}\\n.send-btn.active[data-v-bf6d760c] {\\r\\n background: #1677ff;\\n}\\n.send-btn[data-v-bf6d760c]:disabled {\\r\\n background: #88bfff;\\r\\n cursor: not-allowed;\\n}\\n.send-btn[data-v-bf6d760c]:active {\\r\\n transform: scale(0.92);\\n}\\r\\n\\r\\n /* 移动端停止按钮 */\\n.stop-btn[data-v-bf6d760c] {\\r\\n width: 36px;\\r\\n height: 36px;\\r\\n min-width: 36px;\\n}\\n.agent-selector[data-v-bf6d760c] {\\r\\n padding: 28px 12px;\\n}\\n.agent-list[data-v-bf6d760c] {\\r\\n grid-template-columns: 1fr;\\r\\n gap: 52px 0;\\n}\\n.agent-item[data-v-bf6d760c] {\\r\\n height: auto;\\r\\n min-height: 84px;\\r\\n padding: 18px 16px 18px 96px;\\n}\\n.agent-avatar-wrapper[data-v-bf6d760c] {\\r\\n left: 8px;\\r\\n top: -18px;\\n}\\n.agent-list-avatar.has-agent-img[data-v-bf6d760c] {\\r\\n width: 74px;\\r\\n height: 88px;\\n}\\n.agent-list-avatar[data-v-bf6d760c]:not(.has-agent-img) {\\r\\n width: 62px;\\r\\n height: 78px;\\n}\\n.desc[data-v-bf6d760c] {\\r\\n white-space: normal;\\r\\n display: -webkit-box;\\r\\n -webkit-line-clamp: 2;\\r\\n -webkit-box-orient: vertical;\\n}\\n.guess-box[data-v-bf6d760c] {\\r\\n padding: 16px;\\n}\\n.session-delete[data-v-bf6d760c] {\\r\\n display: none;\\n}\\r\\n\\r\\n /* ── H5 语音模式 ── */\\n.hold-talk-btn[data-v-bf6d760c] {\\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 user-select: none;\\r\\n -webkit-user-select: none;\\r\\n transition: background 0.15s;\\n}\\n.hold-talk-btn[data-v-bf6d760c]:active {\\r\\n background: #ddd;\\n}\\n.hold-talk-btn.recording[data-v-bf6d760c] {\\r\\n background: #e8f0fe;\\r\\n color: #333;\\n}\\n.hold-talk-btn .hold-talk-icon[data-v-bf6d760c] {\\r\\n flex-shrink: 0;\\n}\\r\\n\\r\\n /* 语音录制浮层 */\\n.voice-recording-overlay[data-v-bf6d760c] {\\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 animation: fadeIn-bf6d760c 0.15s ease;\\n}\\n.voice-recording-card[data-v-bf6d760c] {\\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-bf6d760c] {\\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-bf6d760c] {\\r\\n width: 4px;\\r\\n background: #1677ff;\\r\\n border-radius: 2px;\\r\\n animation: waveAnim-bf6d760c 0.6s ease-in-out infinite alternate;\\n}\\n.voice-recording-wave span[data-v-bf6d760c]:nth-child(1) { height: 16px; animation-delay: 0s;\\n}\\n.voice-recording-wave span[data-v-bf6d760c]:nth-child(2) { height: 28px; animation-delay: 0.1s;\\n}\\n.voice-recording-wave span[data-v-bf6d760c]:nth-child(3) { height: 40px; animation-delay: 0.2s;\\n}\\n.voice-recording-wave span[data-v-bf6d760c]:nth-child(4) { height: 28px; animation-delay: 0.3s;\\n}\\n.voice-recording-wave span[data-v-bf6d760c]:nth-child(5) { height: 16px; animation-delay: 0.4s;\\n}\\n@keyframes waveAnim-bf6d760c {\\n0% { transform: scaleY(0.6);\\n}\\n100% { transform: scaleY(1);\\n}\\n}\\n.voice-recording-duration[data-v-bf6d760c] {\\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-bf6d760c] {\\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-bf6d760c] {\\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-bf6d760c] {\\r\\n color: #ff4d4f;\\n}\\n@keyframes fadeIn-bf6d760c {\\nfrom { opacity: 0;\\n}\\nto { opacity: 1;\\n}\\n}\\n}\\n@media screen and (max-width: 480px) {\\n.agent-name[data-v-bf6d760c] {\\r\\n font-size: 14px;\\n}\\n.agent-desc[data-v-bf6d760c] {\\r\\n max-width: calc(100vw - 132px);\\n}\\n.mobile-menu-btn[data-v-bf6d760c],\\r\\n .mobile-header-btn[data-v-bf6d760c] {\\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/index.vue?./node_modules/_css-loader@3.6.0@css-loader/dist/cjs.js??ref--7-oneOf-1-1!./node_modules/_vue-loader@15.11.1@vue-loader/lib/loaders/stylePostLoader.js!./node_modules/_postcss-loader@3.0.0@postcss-loader/src??ref--7-oneOf-1-2!./node_modules/_cache-loader@4.1.0@cache-loader/dist/cjs.js??ref--1-0!./node_modules/_vue-loader@15.11.1@vue-loader/lib??vue-loader-options");
|
|
3255
|
+
eval("// Imports\nvar ___CSS_LOADER_API_IMPORT___ = __webpack_require__(/*! ../../../../node_modules/_css-loader@3.6.0@css-loader/dist/runtime/api.js */ \"./node_modules/_css-loader@3.6.0@css-loader/dist/runtime/api.js\");\nexports = ___CSS_LOADER_API_IMPORT___(false);\n// Module\nexports.push([module.i, \"\\n.chat-layout[data-v-bf6d760c] {\\r\\n display: flex;\\r\\n height: 100%;\\r\\n width: 100%;\\r\\n background: #fff;\\r\\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei', sans-serif;\\n}\\r\\n\\r\\n/* ── Sidebar ── */\\n.chat-sidebar[data-v-bf6d760c] {\\r\\n width: 300px;\\r\\n min-width: 300px;\\r\\n background: #fff;\\r\\n border-right: 1px solid #e8e8e8;\\r\\n display: flex;\\r\\n flex-direction: column;\\r\\n overflow: hidden;\\n}\\n.sidebar-header[data-v-bf6d760c] {\\r\\n display: flex;\\r\\n align-items: center;\\r\\n justify-content: space-between;\\r\\n padding: 14px 8px 14px 16px;\\r\\n border-bottom: 1px solid #e8e8e8;\\r\\n flex-shrink: 0;\\n}\\n.sidebar-header i[data-v-bf6d760c]{\\r\\n font-size: 20px;\\r\\n cursor: pointer;\\n}\\n.sidebar-header img[data-v-bf6d760c]{\\r\\n cursor: pointer;\\n}\\n.sidebar-title[data-v-bf6d760c] {\\r\\n font-size: 15px;\\r\\n font-weight: 600;\\r\\n color: #333;\\n}\\n.sidebar-search[data-v-bf6d760c] {\\r\\n padding: 8px 16px;\\r\\n flex-shrink: 0;\\r\\n position: relative;\\r\\n z-index: 20;\\n}\\n.sidebar-search .search-wrap[data-v-bf6d760c] {\\r\\n display: flex;\\r\\n align-items: center;\\r\\n position: relative;\\n}\\n.sidebar-search .search-icon[data-v-bf6d760c] {\\r\\n position: absolute;\\r\\n left: 12px;\\r\\n flex-shrink: 0;\\r\\n pointer-events: none;\\n}\\n.sidebar-search .search-input[data-v-bf6d760c] {\\r\\n width: 100%;\\r\\n height: 32px;\\r\\n border-radius: 16px;\\r\\n background: #f5f5f5;\\r\\n border: 1px solid transparent;\\r\\n font-size: 13px;\\r\\n padding: 0 32px 0 34px;\\r\\n outline: none;\\r\\n box-sizing: border-box;\\r\\n transition: all 0.2s;\\n}\\n.sidebar-search .search-input[data-v-bf6d760c]:focus {\\r\\n background: #fff;\\r\\n border: 1px solid #1677ff;\\n}\\n.sidebar-search .search-clear[data-v-bf6d760c] {\\r\\n position: absolute;\\r\\n right: 10px;\\r\\n cursor: pointer;\\r\\n flex-shrink: 0;\\n}\\n.search-suggestions[data-v-bf6d760c] {\\r\\n position: absolute;\\r\\n top: 100%;\\r\\n left: 16px;\\r\\n right: 16px;\\r\\n background: #fff;\\r\\n border: 1px solid #e8e8e8;\\r\\n border-radius: 8px;\\r\\n box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);\\r\\n z-index: 100;\\r\\n max-height: 240px;\\r\\n overflow-y: auto;\\r\\n margin-top: 4px;\\n}\\n.suggestion-item[data-v-bf6d760c] {\\r\\n display: flex;\\r\\n align-items: center;\\r\\n gap: 10px;\\r\\n padding: 10px 12px;\\r\\n cursor: pointer;\\r\\n transition: background 0.15s;\\n}\\n.suggestion-item[data-v-bf6d760c]:hover {\\r\\n background: #f5f7fa;\\n}\\n.suggestion-avatar[data-v-bf6d760c] {\\r\\n width: 28px;\\r\\n height: 28px;\\r\\n border-radius: 6px;\\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: 13px;\\r\\n font-weight: 600;\\r\\n flex-shrink: 0;\\n}\\n.suggestion-name[data-v-bf6d760c] {\\r\\n font-size: 14px;\\r\\n font-weight: 500;\\r\\n color: #333;\\r\\n white-space: nowrap;\\n}\\n.suggestion-desc[data-v-bf6d760c] {\\r\\n font-size: 12px;\\r\\n color: #999;\\r\\n overflow: hidden;\\r\\n text-overflow: ellipsis;\\r\\n white-space: nowrap;\\n}\\n.sidebar-list[data-v-bf6d760c] {\\r\\n flex: 1;\\r\\n overflow-y: auto;\\r\\n padding: 8px 0;\\n}\\n.session-item[data-v-bf6d760c] {\\r\\n display: flex;\\r\\n align-items: center;\\r\\n padding: 6px 16px;\\r\\n /* 顶部留白,匹配UI顶部空隙 */\\r\\n padding-bottom: 10px;\\r\\n cursor: pointer;\\r\\n border-bottom: 1px solid #f5f5f5;\\r\\n transition: background 0.15s;\\r\\n position: relative;\\r\\n gap: 10px;\\r\\n border-radius: 4px;\\n}\\n.session-left-item[data-v-bf6d760c]{\\r\\n margin-left: 5px;\\n}\\n.session-item[data-v-bf6d760c]:hover {\\r\\n background: #f5f7fa;\\n}\\n.session-item.active[data-v-bf6d760c] {\\r\\n background: #F5F5F5\\n}\\n.session-avatar[data-v-bf6d760c] {\\r\\n width: 44px!important;\\r\\n height: 44px!important;\\r\\n /* UI是圆形头像,把8px圆角改成50% */\\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}\\r\\n/* 头像图片样式,居中完整展示,四周露出底色 */\\n.avatar-pic[data-v-bf6d760c] {\\r\\n width: 85%;\\r\\n height: 85%;\\r\\n -o-object-fit: contain;\\r\\n object-fit: contain;\\n}\\n.session-info[data-v-bf6d760c] {\\r\\n flex: 1;\\r\\n min-width: 0;\\n}\\n.session-agent[data-v-bf6d760c] {\\r\\n font-size: 15px;\\r\\n font-weight: 500;\\r\\n color: #333;\\r\\n margin-bottom: 2px;\\r\\n overflow: hidden;\\r\\n text-overflow: ellipsis;\\r\\n white-space: nowrap;\\n}\\n.session-preview[data-v-bf6d760c] {\\r\\n font-size: 12px;\\r\\n color: #999;\\r\\n overflow: hidden;\\r\\n text-overflow: ellipsis;\\r\\n white-space: nowrap;\\n}\\n.session-time[data-v-bf6d760c] {\\r\\n font-size: 11px;\\r\\n color: #bbb;\\r\\n flex-shrink: 0;\\r\\n margin-left: 8px;\\r\\n margin-right: 4px;\\n}\\n.session-delete[data-v-bf6d760c] {\\r\\n position: absolute;\\r\\n right: 4px;\\r\\n top: 20px;\\r\\n transform: translateY(-50%);\\r\\n opacity: 0;\\r\\n transition: opacity 0.15s;\\r\\n width: 28px;\\r\\n height: 28px;\\r\\n display: flex;\\r\\n align-items: center;\\r\\n justify-content: center;\\r\\n border: none;\\r\\n background: transparent;\\r\\n padding: 0;\\r\\n color: #333;\\r\\n cursor: pointer;\\n}\\n.session-delete svg[data-v-bf6d760c] {\\r\\n color: #333;\\n}\\n.session-item:hover .session-delete[data-v-bf6d760c] {\\r\\n opacity: 1;\\n}\\n.sidebar-list[data-v-bf6d760c] {\\r\\n flex: 1;\\r\\n overflow-y: auto;\\r\\n padding: 8px 0;\\n}\\n.sidebar-empty[data-v-bf6d760c] {\\r\\n flex: 1;\\r\\n display: flex;\\r\\n flex-direction: column;\\r\\n align-items: center;\\r\\n justify-content: center;\\r\\n color: #bbb;\\r\\n font-size: 14px;\\r\\n padding-bottom: 40px;\\n}\\n.empty-icon[data-v-bf6d760c] {\\r\\n font-size: 36px;\\r\\n margin-bottom: 8px;\\n}\\n.empty-hint[data-v-bf6d760c] {\\r\\n font-size: 12px;\\r\\n color: #d9d9d9;\\r\\n margin-top: 4px;\\n}\\r\\n/* ── Main ── */\\n.chat-main[data-v-bf6d760c] {\\r\\n flex: 1;\\r\\n display: flex;\\r\\n flex-direction: column;\\r\\n min-width: 0;\\n}\\r\\n\\r\\n/* ── Header ── */\\n.chat-header[data-v-bf6d760c] {\\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-bf6d760c] {\\r\\n display: flex;\\r\\n align-items: center;\\r\\n gap: 10px;\\r\\n min-width: 0;\\n}\\n.agent-info[data-v-bf6d760c] {\\r\\n display: flex;\\r\\n align-items: center;\\r\\n gap: 10px;\\n}\\n.agent-icon[data-v-bf6d760c] {\\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}\\r\\n/* 和左侧会话头像保持 4 色循环背景 */\\n.agent-info:nth-child(4n + 2) .agent-icon-avatar[data-v-bf6d760c] {\\r\\n background: linear-gradient(135deg, #52c41a, #73d13d);\\n}\\n.agent-info:nth-child(4n + 3) .agent-icon-avatar[data-v-bf6d760c] {\\r\\n background: linear-gradient(135deg, #fa8c16, #ffa940);\\n}\\n.agent-info:nth-child(4n + 4) .agent-icon-avatar[data-v-bf6d760c] {\\r\\n background: linear-gradient(135deg, #722ed1, #b37feb);\\n}\\n.agent-text[data-v-bf6d760c] {\\r\\n min-width: 0;\\n}\\n.agent-name[data-v-bf6d760c] {\\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-bf6d760c] {\\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: 300px;\\n}\\n.header-right[data-v-bf6d760c] {\\r\\n flex-shrink: 0;\\n}\\n.manage-link[data-v-bf6d760c] {\\r\\n font-size: 13px;\\r\\n color: #1677ff;\\r\\n text-decoration: none;\\n}\\n.manage-link[data-v-bf6d760c]:hover {\\r\\n color: #4096ff;\\n}\\r\\n\\r\\n/* ── Chat Body ── */\\n.chat-body[data-v-bf6d760c] {\\r\\n flex: 1;\\r\\n overflow-y: auto;\\r\\n padding: 16px 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%;\\n}\\n.welcome[data-v-bf6d760c] {\\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-bf6d760c] {\\r\\n margin-bottom: 12px;\\r\\n opacity: 0.7;\\n}\\n.welcome-text[data-v-bf6d760c] {\\r\\n font-size: 15px;\\n}\\n.welcome-default .welcome-icon[data-v-bf6d760c] {\\r\\n margin-bottom: 16px;\\n}\\n.welcome-title[data-v-bf6d760c] {\\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-bf6d760c] {\\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-bf6d760c] {\\r\\n display: flex;\\r\\n align-items: center;\\r\\n gap: 10px;\\r\\n max-width: 85%;\\r\\n /* 最大内容宽度限制,避免超宽 */\\r\\n width: 800px;\\n}\\n.msg-row.user .msg-main[data-v-bf6d760c] {\\r\\n flex-direction: row-reverse;\\n}\\n.msg-row.assistant[data-v-bf6d760c] {\\r\\n justify-content: center;\\n}\\n.load-more[data-v-bf6d760c] {\\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-bf6d760c] {\\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-bf6d760c] {\\r\\n text-align: right;\\r\\n padding-right: 4px;\\n}\\n.msg-actions[data-v-bf6d760c] {\\r\\n display: flex;\\r\\n gap: 4px;\\r\\n margin-top: 4px;\\r\\n padding-left: 4px;\\n}\\n.action-btn[data-v-bf6d760c] {\\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 user-select: none;\\n}\\n.action-btn[data-v-bf6d760c]:hover {\\r\\n color: #1677ff;\\r\\n background: #f0f5ff;\\n}\\r\\n\\r\\n/* ── STT 语音转文字状态 ── */\\n.stt-status-block[data-v-bf6d760c] {\\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}\\r\\n/* ── STT 状态(图标紧贴气泡左侧,文字在气泡内) ── */\\n.stt-bubble-wrap[data-v-bf6d760c] {\\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-bf6d760c] {\\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-bf6d760c] {\\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 animation: stt-spin-bf6d760c 0.6s linear infinite;\\r\\n flex-shrink: 0;\\r\\n box-sizing: border-box;\\n}\\n@keyframes stt-spin-bf6d760c {\\nto { transform: rotate(360deg);\\n}\\n}\\n.stt-error-icon[data-v-bf6d760c] {\\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-bf6d760c] {\\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-main[data-v-bf6d760c] {\\r\\n display: flex;\\r\\n align-items: flex-start;\\r\\n gap: 10px;\\r\\n width: 800px;\\n}\\n.msg-row.user .msg-main[data-v-bf6d760c] {\\r\\n flex-direction: row-reverse;\\n}\\n.msg-avatar[data-v-bf6d760c] {\\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-bf6d760c] {\\r\\n background: linear-gradient(135deg, #1677ff, #4096ff);\\r\\n color: #fff;\\n}\\n.msg-avatar.assistant[data-v-bf6d760c] {\\r\\n background: linear-gradient(135deg, #52c41a, #73d13d);\\r\\n color: #fff;\\n}\\n.msg-agent-label[data-v-bf6d760c] {\\r\\n font-size: 12px;\\r\\n color: #999;\\r\\n margin-bottom: 2px;\\n}\\n.msg-content[data-v-bf6d760c] {\\r\\n width: 800px;\\r\\n box-sizing: border-box;\\r\\n overflow: hidden;\\n}\\r\\n\\r\\n/* ── Bubble ── */\\n.bubble[data-v-bf6d760c] {\\r\\n max-width: 100%;\\r\\n min-width: 30px;\\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;\\n}\\n.bubble[data-v-bf6d760c]:has(.typing) {\\r\\n padding: 16px 20px;\\n}\\n.bubble.user[data-v-bf6d760c] {\\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: right;\\n}\\n.bubble.assistant[data-v-bf6d760c] {\\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-bf6d760c] 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-bf6d760c] th,\\r\\n.bubble[data-v-bf6d760c] td {\\r\\n border: 1px solid #e8e8e8;\\r\\n padding: 5px 8px;\\r\\n text-align: left;\\n}\\n.bubble[data-v-bf6d760c] th {\\r\\n background: #fafafa;\\r\\n font-weight: 600;\\n}\\n.bubble[data-v-bf6d760c] code {\\r\\n /* background: #f0f2f5; */\\r\\n padding: 1px 5px;\\r\\n border-radius: 3px;\\r\\n font-size: 14px;\\n}\\n.bubble[data-v-bf6d760c] 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-bf6d760c] ul,\\r\\n.bubble[data-v-bf6d760c] ol {\\r\\n padding-left: 20px;\\r\\n margin: 4px 0;\\n}\\n.bubble[data-v-bf6d760c] li {\\r\\n margin: 2px 0;\\n}\\n.bubble[data-v-bf6d760c] p{\\r\\n margin: 6px 0;\\n}\\r\\n\\r\\n/* ── Thinking ── */\\n.thinking-details[data-v-bf6d760c] {\\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-bf6d760c] {\\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 user-select: none;\\n}\\n.thinking-summary[data-v-bf6d760c]:hover {\\r\\n color: #1677ff;\\n}\\n.thinking-body[data-v-bf6d760c] {\\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 /* 兼容中英文混合断行优化 */\\r\\n overflow-wrap: break-word;\\n}\\n.final-content[data-v-bf6d760c]{\\r\\n /* white-space: pre-wrap; */\\r\\n word-break: break-word;\\r\\n overflow-wrap: break-word;\\n}\\n.thinking-body[data-v-bf6d760c] p {\\r\\n margin: 4px 0;\\n}\\r\\n\\r\\n/* ── Typing ── */\\n.typing[data-v-bf6d760c] {\\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-bf6d760c] {\\r\\n font-size: 14px;\\r\\n color: #888;\\r\\n white-space: nowrap;\\r\\n animation: phraseFade-bf6d760c 0.5s ease;\\r\\n letter-spacing: 0.5px;\\n}\\n.typing .dots[data-v-bf6d760c] {\\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-bf6d760c] {\\r\\n width: 8px;\\r\\n height: 8px;\\r\\n background: #bbb;\\r\\n border-radius: 50%;\\r\\n animation: dtTyping-bf6d760c 1.3s infinite ease-in-out;\\n}\\n.typing .dots span[data-v-bf6d760c]:nth-child(2) {\\r\\n animation-delay: 0.16s;\\n}\\n.typing .dots span[data-v-bf6d760c]:nth-child(3) {\\r\\n animation-delay: 0.32s;\\n}\\n@keyframes phraseFade-bf6d760c {\\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 dtTyping-bf6d760c {\\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/* ── Scroll Buttons ── */\\n.scroll-btns[data-v-bf6d760c] {\\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-bf6d760c] {\\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-bf6d760c] {\\r\\n font-size: 16px;\\r\\n color: #333;\\n}\\r\\n/* ── Wait Timer ── */\\n.typing.wait-5 .dots span[data-v-bf6d760c] {\\r\\n width: 8px;\\r\\n height: 8px;\\r\\n animation-duration: 1s;\\n}\\n.typing.wait-5 .phrase[data-v-bf6d760c] {\\r\\n color: #888;\\n}\\n.typing.wait-10 .dots span[data-v-bf6d760c] {\\r\\n width: 9px;\\r\\n height: 9px;\\r\\n animation-duration: 0.8s;\\r\\n background: #909399;\\n}\\n.typing.wait-10 .phrase[data-v-bf6d760c] {\\r\\n color: #909399;\\n}\\n.typing.wait-10 .dots[data-v-bf6d760c] {\\r\\n animation: dtPulse-bf6d760c 1s infinite ease-in-out;\\n}\\n.typing.wait-15 .dots span[data-v-bf6d760c] {\\r\\n width: 10px;\\r\\n height: 10px;\\r\\n animation-duration: 0.6s;\\r\\n background: #1677ff;\\n}\\n.typing.wait-15 .phrase[data-v-bf6d760c] {\\r\\n color: #1677ff;\\n}\\n.typing.wait-15 .dots[data-v-bf6d760c] {\\r\\n animation: dtPulse-bf6d760c 0.6s infinite ease-in-out;\\n}\\n@keyframes dtPulse-bf6d760c {\\n0%,\\r\\n 100% {\\r\\n transform: scale(1);\\n}\\n50% {\\r\\n transform: scale(1.05);\\n}\\n}\\n.tool-calls[data-v-bf6d760c] {\\r\\n margin-top: 8px;\\n}\\n.tool-item[data-v-bf6d760c] {\\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-bf6d760c] {\\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-bf6d760c] {\\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/* ── Footer ── */\\n.chat-footer[data-v-bf6d760c] {\\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;\\n}\\n.input-area[data-v-bf6d760c] {\\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 /* 左右留白,实现居中效果,和截图边距一致 */\\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: 1000px;\\n}\\r\\n/* 原有悬浮滚动按钮逻辑完全保留不动 */\\n.scroll-bottom-wrap[data-v-bf6d760c] {\\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-bf6d760c] {\\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-bf6d760c] {\\r\\n color: #4e5969;\\n}\\r\\n/* 加载转圈动画原样保留 */\\n.loading-circle[data-v-bf6d760c] {\\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 animation: circle-spin-bf6d760c 1.5s linear infinite;\\n}\\n@keyframes circle-spin-bf6d760c {\\nfrom {\\r\\n transform: rotate(0deg);\\n}\\nto {\\r\\n transform: rotate(360deg);\\n}\\n}\\r\\n/* 聚焦仅变色,取消阴影 */\\n.input-area[data-v-bf6d760c]:focus-within {\\r\\n border-color: #1677ff;\\r\\n background: #fff;\\r\\n box-shadow: none;\\n}\\n.chat-textarea[data-v-bf6d760c] {\\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;\\n}\\n.chat-textarea[data-v-bf6d760c]::-moz-placeholder {\\r\\n color: #999;\\r\\n font-size: 16px;\\n}\\n.chat-textarea[data-v-bf6d760c]::placeholder {\\r\\n color: #999;\\r\\n font-size: 16px;\\n}\\r\\n/* 发送按钮 纯蓝色矩形,隐藏svg图标,显示文字发送 */\\n.send-btn[data-v-bf6d760c] {\\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-bf6d760c] {\\r\\n display: none;\\n}\\n.send-btn[data-v-bf6d760c]::after {\\r\\n content: \\\"发送\\\";\\n}\\n.send-btn.active[data-v-bf6d760c] {\\r\\n background: #1677ff;\\n}\\n.send-btn.active[data-v-bf6d760c]:hover {\\r\\n background: #4096ff;\\n}\\n.send-btn[data-v-bf6d760c]:disabled {\\r\\n background: #88bfff;\\r\\n cursor: not-allowed;\\n}\\n.stop-btn[data-v-bf6d760c] {\\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-bf6d760c]:hover {\\r\\n background: #ff7875;\\n}\\r\\n/* 右下角提示文字,精准定位在按钮左侧,和截图位置完全对齐 */\\n.input-area[data-v-bf6d760c]::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}\\r\\n/* 滚动到底部按钮样式 */\\n.scroll-bottom-btn[data-v-bf6d760c] {\\r\\n width: 38px;\\r\\n height: 38px;\\r\\n border-radius: 50%;\\r\\n background: #ffffff;\\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;\\r\\n transition: all 0.2s ease;\\n}\\n.scroll-bottom-btn[data-v-bf6d760c]:hover {\\r\\n transform: scale(1.1);\\n}\\n.scroll-bottom-btn svg[data-v-bf6d760c] {\\r\\n color: #333;\\n}\\r\\n\\r\\n\\r\\n/* 外层页面容器 对应box_9区域 */\\n.agent-select-page[data-v-bf6d760c] {\\r\\n width: 100%;\\r\\n height: 100%;\\r\\n background: url(https://qiguanbang.obs.cn-east-3.myhuaweicloud.com/production/image/AlAgent/background.png) 100% no-repeat;\\r\\n background-size: 100% 100%;\\r\\n box-sizing: border-box;\\r\\n /* 内部全部居中 */\\r\\n display: flex;\\r\\n flex-direction: column;\\r\\n align-items: center;\\n}\\r\\n\\r\\n/* 内容容器,限制最大宽度,自适应,居中 */\\n.agent-wrap[data-v-bf6d760c] {\\r\\n width: 100%;\\r\\n max-width: 1200px;\\n}\\r\\n\\r\\n/* 标题区域居中 */\\n.agent-title[data-v-bf6d760c] {\\r\\n text-align: center;\\r\\n margin-bottom: 116px;\\n}\\n.agent-title h2[data-v-bf6d760c] {\\r\\n font-size: 28px!important;\\r\\n color: #000;\\r\\n font-weight: 500!important;\\r\\n font-family: PingFangSC-Medium;\\r\\n margin: 0;\\r\\n line-height: 40px;\\n}\\r\\n\\r\\n/* 智能助手列表:一行2个自适应等分,自动换行 */\\n.agent-list[data-v-bf6d760c] {\\r\\n display: grid;\\r\\n grid-template-columns: repeat(2, 1fr);\\r\\n gap: 76px 30px;\\r\\n width: 100%;\\n}\\r\\n\\r\\n/* 卡片基础样式,无固定宽度,自适应网格列宽 */\\n.agent-item[data-v-bf6d760c] {\\r\\n position: relative;\\r\\n border-radius: 11px;\\r\\n height: 90px;\\r\\n padding: 20px 20px 19px 116px;\\r\\n box-sizing: border-box;\\r\\n cursor: pointer;\\r\\n transition: all 0.3s ease;\\n}\\n.agent-item[data-v-bf6d760c]:hover {\\r\\n transform: translateY(-4px);\\r\\n box-shadow: 0 8px 20px rgba(0, 0, 0, 0.06);\\n}\\r\\n\\r\\n/* 上浮头像容器 */\\n.agent-avatar-wrapper[data-v-bf6d760c] {\\r\\n position: absolute;\\r\\n left: 3px;\\r\\n top: -36px;\\n}\\r\\n\\r\\n/* 头像默认样式 */\\n.agent-list-avatar[data-v-bf6d760c] {\\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}\\r\\n/* 有头像图片:大尺寸 */\\n.agent-list-avatar.has-agent-img[data-v-bf6d760c] {\\r\\n width: 97px;\\r\\n height: 126px;\\r\\n background-size: cover;\\n}\\r\\n/* 无头像文字首字母:小尺寸,偏移适配 */\\n.agent-list-avatar[data-v-bf6d760c]:not(.has-agent-img) {\\r\\n width: 76px;\\r\\n height: 108px;\\r\\n transform: translateX(9px);\\n}\\r\\n\\r\\n/* 文字内容区 */\\n.agent-info-content[data-v-bf6d760c] {\\r\\n display: flex;\\r\\n flex-direction: column;\\n}\\n.name[data-v-bf6d760c] {\\r\\n font-size: 16px;\\r\\n font-family: PingFangSC-Medium;\\r\\n color: #000;\\r\\n line-height: 22px;\\r\\n margin-bottom: 8px;\\n}\\n.desc[data-v-bf6d760c] {\\r\\n font-size: 15px;\\r\\n font-family: PingFangSC-Regular;\\r\\n color: #666;\\r\\n line-height: 21px;\\r\\n /* 核心三行单行省略,文字超出自动... */\\r\\n overflow: hidden;\\r\\n white-space: nowrap;\\r\\n text-overflow: ellipsis;\\r\\n /* 关键:继承父容器宽度,不会超出父盒子 */\\r\\n width: 100%;\\r\\n display: block;\\n}\\r\\n/* 响应式适配:小屏幕自动变为单列 */\\n@media screen and (max-width: 768px) {\\n.agent-list[data-v-bf6d760c] {\\r\\n grid-template-columns: 1fr;\\n}\\n.agent-selector[data-v-bf6d760c] {\\r\\n padding: 40px 15px;\\n}\\n.agent-title[data-v-bf6d760c] {\\r\\n margin-bottom: 60px;\\n}\\n.agent-title h2[data-v-bf6d760c] {\\r\\n font-size: 22px;\\n}\\n}\\r\\n\\r\\n\\r\\n/* ── 聊天空白欢迎页(匹配蓝湖移动端聊天首页) ── */\\n.chat-empty-welcome[data-v-bf6d760c] {\\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-bf6d760c] {\\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-bf6d760c] {\\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-bf6d760c] {\\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-bf6d760c] {\\r\\n background: transparent;\\r\\n background-repeat: no-repeat;\\r\\n background-position: center;\\n}\\n.welcome-text-group[data-v-bf6d760c] {\\r\\n display: flex;\\r\\n flex-direction: column;\\r\\n gap: 6px;\\n}\\n.welcome-text-group .text-sm[data-v-bf6d760c] {\\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-bf6d760c] {\\r\\n \\r\\n font-weight: 500;\\r\\nfont-size: 16px;\\r\\ncolor: #000000;\\n}\\r\\n\\r\\n/* 猜你想问容器 */\\n.guess-box[data-v-bf6d760c] {\\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-bf6d760c] {\\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-bf6d760c] {\\r\\n display: flex;\\r\\n flex-wrap: wrap;\\r\\n gap: 10px;\\n}\\n.quick-tag[data-v-bf6d760c] {\\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-bf6d760c]{\\r\\n width: 44px;\\r\\n height: 44px;\\n}\\r\\n\\r\\n\\r\\n\\r\\n/* 外层大容器,本地渐变背景铺满全屏,内部全部居中 */\\n.agent-selector[data-v-bf6d760c] {\\r\\n width: 100%;\\r\\n min-height: 100%;\\r\\n padding: 80px 20px;\\r\\n /* 本地背景图铺满 */\\r\\n background: url(https://qiguanbang.obs.cn-east-3.myhuaweicloud.com/production/image/AlAgent/background.png) no-repeat;\\r\\n background-size: 100% 100%;\\r\\n box-sizing: border-box;\\r\\n display: flex;\\r\\n flex-direction: column;\\r\\n align-items: center;\\n}\\r\\n\\r\\n/* 内容容器,限制最大宽度,自适应居中,无固定宽 */\\n.agent-wrap[data-v-bf6d760c] {\\r\\n width: 100%;\\r\\n max-width: 920px;\\n}\\r\\n\\r\\n/* 标题样式,居中、字号、间距匹配效果图 */\\n.agent-title[data-v-bf6d760c] {\\r\\n text-align: center;\\r\\n margin-bottom: 116px;\\n}\\n.agent-title h2[data-v-bf6d760c] {\\r\\n font-size: 26px;\\r\\n color: #222;\\r\\n font-weight: 500;\\r\\n margin: 0;\\r\\n line-height: 40px;\\n}\\r\\n\\r\\n/* 卡片网格:一行2等分,行列间距对齐效果图 */\\n.agent-list[data-v-bf6d760c] {\\r\\n display: grid;\\r\\n grid-template-columns: repeat(2, 1fr);\\r\\n gap: 76px 30px;\\r\\n width: 100%;\\n}\\r\\n\\r\\n/* 卡片核心样式:圆角、内边距、相对定位,无固定宽度 */\\n.agent-item[data-v-bf6d760c] {\\r\\n position: relative;\\r\\n border-radius: 11px;\\r\\n height: 90px;\\r\\n /* 左侧留出头像位置,文字靠右内缩 */\\r\\n padding: 22px 20px 20px 110px;\\r\\n box-sizing: border-box;\\r\\n cursor: pointer;\\r\\n transition: all 0.25s ease;\\r\\n /* 轻微柔和阴影,和效果图一致 */\\r\\n box-shadow: 0 2px 12px rgba(0, 0, 0, 0.05);\\n}\\n.agent-item[data-v-bf6d760c]:hover {\\r\\n transform: translateY(-4px);\\r\\n box-shadow: 0 8px 20px rgba(0, 0, 0, 0.08);\\n}\\r\\n\\r\\n\\r\\n/* 头像本体通用样式 */\\n.agent-list-avatar[data-v-bf6d760c] {\\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;\\r\\n /* 效果图统一卡通头像尺寸 */\\r\\n width: 92px;\\r\\n height: 106px;\\n}\\r\\n/* 有头像图片完整展示,不裁切 */\\n.agent-list-avatar.has-agent-img[data-v-bf6d760c] {\\r\\n background-size: cover;\\n}\\r\\n\\r\\n/* 文字区域垂直排列 */\\n.agent-info-content[data-v-bf6d760c] {\\r\\n display: flex;\\r\\n flex-direction: column;\\r\\n max-width: 300px;\\r\\n flex-shrink: 0; /* 如果是flex布局,禁止自身被压缩 */\\n}\\r\\n/* 助手名称 */\\n.name[data-v-bf6d760c] {\\r\\n font-size: 16px;\\r\\n font-weight: 500;\\r\\n color: #111;\\r\\n line-height: 22px;\\r\\n margin-bottom: 6px;\\n}\\r\\n/* 描述文本 */\\n.desc[data-v-bf6d760c] {\\r\\n font-size: 14px;\\r\\n color: #666;\\r\\n line-height: 20px;\\r\\n /* 超长描述单行省略 */\\r\\n overflow: hidden;\\r\\n white-space: nowrap;\\r\\n text-overflow: ellipsis;\\n}\\r\\n\\r\\n/* 移动端适配:小屏幕自动单列 */\\n@media screen and (max-width: 768px) {\\n.agent-list[data-v-bf6d760c] {\\r\\n grid-template-columns: 1fr;\\n}\\n.agent-selector[data-v-bf6d760c] {\\r\\n padding: 40px 15px;\\n}\\n.agent-title[data-v-bf6d760c] {\\r\\n margin-bottom: 40px;\\n}\\n.agent-title h2[data-v-bf6d760c] {\\r\\n font-size: 22px;\\n}\\n}\\n.chat-layout[data-v-bf6d760c] {\\r\\n position: relative;\\r\\n min-height: 0;\\r\\n overflow: hidden;\\n}\\n.sidebar-mask[data-v-bf6d760c] {\\r\\n position: absolute;\\r\\n inset: 0;\\r\\n background: rgba(15, 23, 42, 0.28);\\r\\n z-index: 29;\\n}\\n.suggestion-avatar[data-v-bf6d760c] {\\r\\n width: 28px !important;\\r\\n height: 28px !important;\\r\\n border-radius: 8px !important;\\r\\n font-size: 12px !important;\\r\\n font-weight: 600;\\r\\n flex-shrink: 0;\\n}\\n.chat-main[data-v-bf6d760c],\\r\\n.chat-body[data-v-bf6d760c] {\\r\\n min-height: 0;\\n}\\n.header-left[data-v-bf6d760c],\\r\\n.header-actions[data-v-bf6d760c] {\\r\\n display: flex;\\r\\n align-items: center;\\n}\\n.header-left[data-v-bf6d760c] {\\r\\n flex: 1;\\r\\n min-width: 0;\\r\\n gap: 10px;\\n}\\n.header-actions[data-v-bf6d760c] {\\r\\n flex-shrink: 0;\\n}\\n.mobile-menu-btn[data-v-bf6d760c],\\r\\n.mobile-back-btn[data-v-bf6d760c],\\r\\n.mobile-header-btn[data-v-bf6d760c] {\\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-bf6d760c],\\r\\n.mobile-back-btn i[data-v-bf6d760c],\\r\\n.mobile-header-btn i[data-v-bf6d760c] {\\r\\n font-size: 18px;\\n}\\n.mobile-back-btn i[data-v-bf6d760c] {\\r\\n font-size: 20px;\\r\\n font-weight: 600;\\n}\\n.chat-sidebar[data-v-bf6d760c] {\\r\\n width: min(300px, 32vw);\\n}\\n.chat-body[data-v-bf6d760c] {\\r\\n padding: 16px clamp(12px, 3vw, 40px);\\r\\n background-position: center;\\r\\n background-size: cover;\\n}\\n.agent-desc[data-v-bf6d760c] {\\r\\n max-width: min(300px, 45vw);\\n}\\n.msg-row[data-v-bf6d760c] {\\r\\n padding: 18px 0;\\n}\\n.msg-main[data-v-bf6d760c] {\\r\\n width: min(100%, 860px) !important;\\r\\n max-width: 860px;\\n}\\n.msg-content[data-v-bf6d760c] {\\r\\n width: 100% !important;\\r\\n max-width: 100%;\\n}\\n.bubble.user[data-v-bf6d760c] {\\r\\n float: none;\\r\\n margin-left: auto;\\r\\n max-width: min(100%, 520px);\\n}\\n.final-content[data-v-bf6d760c],\\r\\n.thinking-body[data-v-bf6d760c],\\r\\n.bubble[data-v-bf6d760c] {\\r\\n overflow-wrap: anywhere;\\n}\\n.chat-footer[data-v-bf6d760c] {\\r\\n width: 100%;\\r\\n padding: 24px 0;\\r\\n flex-shrink: 0;\\n}\\n.input-area[data-v-bf6d760c] {\\r\\n width: min(100%, 1000px) !important;\\r\\n box-sizing: border-box;\\n}\\n.chat-textarea[data-v-bf6d760c] {\\r\\n flex: 1 1 320px;\\r\\n min-width: 0;\\n}\\n@media screen and (max-width: 768px) {\\n.chat-layout.is-mobile[data-v-bf6d760c] {\\r\\n display: flex;\\r\\n height: 100%;\\n}\\r\\n\\r\\n /* agent-selector H5 顶部栏 */\\n.agent-selector[data-v-bf6d760c] {\\r\\n padding: 0 !important;\\n}\\n.agent-selector .agent-wrap[data-v-bf6d760c] {\\r\\n padding: 40px 16px 0;\\r\\n box-sizing: border-box;\\n}\\n.mobile-agent-select-header[data-v-bf6d760c] {\\r\\n width: 100%;\\r\\n display: flex;\\r\\n align-items: center;\\r\\n justify-content: center;\\r\\n position: relative;\\r\\n padding: 10px 0;\\r\\n min-height: 44px;\\n}\\n.mobile-agent-select-header .mobile-agent-back[data-v-bf6d760c] {\\r\\n position: absolute;\\r\\n left: 4px;\\r\\n top: 50%;\\r\\n transform: translateY(-50%);\\r\\n background: transparent;\\r\\n border: none;\\r\\n width: 44px;\\r\\n height: 44px;\\r\\n display: inline-flex;\\r\\n align-items: center;\\r\\n justify-content: center;\\r\\n cursor: pointer;\\r\\n padding: 0;\\r\\n color: #333;\\n}\\n.mobile-agent-select-header .mobile-agent-back i[data-v-bf6d760c] {\\r\\n font-size: 22px;\\r\\n font-weight: 600;\\n}\\n.mobile-agent-select-header .mobile-agent-title-text[data-v-bf6d760c] {\\r\\n font-size: 17px;\\r\\n font-weight: 500;\\r\\n color: #000;\\n}\\n.agent-selector .agent-title[data-v-bf6d760c] {\\r\\n display: none;\\n}\\r\\n\\r\\n /* H5列表模式:侧边栏全屏展示 */\\n.chat-layout.h5-list-mode .chat-sidebar[data-v-bf6d760c] {\\r\\n position: relative !important;\\r\\n width: 100% !important;\\r\\n max-width: 100% !important;\\r\\n min-width: 100% !important;\\r\\n height: 100%;\\r\\n transform: translateX(0) !important;\\r\\n box-shadow: none !important;\\r\\n border-right: none;\\n}\\n.chat-layout.h5-list-mode .chat-sidebar .sidebar-header[data-v-bf6d760c] {\\r\\n display: flex;\\r\\n align-items: center;\\r\\n justify-content: center;\\r\\n padding: 14px 16px;\\r\\n position: relative;\\n}\\n.sidebar-back-btn[data-v-bf6d760c] {\\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: transparent;\\r\\n color: #333;\\r\\n cursor: pointer;\\r\\n flex-shrink: 0;\\r\\n position: absolute;\\r\\n left: 8px;\\r\\n top: 50%;\\r\\n transform: translateY(-50%);\\r\\n padding: 0;\\n}\\n.sidebar-back-btn svg[data-v-bf6d760c] {\\r\\n display: block;\\n}\\n.chat-layout.h5-list-mode .chat-sidebar .sidebar-header img[data-v-bf6d760c] {\\r\\n position: absolute;\\r\\n right: 16px;\\r\\n top: 50%;\\r\\n transform: translateY(-50%);\\r\\n width: 22px;\\r\\n height: 22px;\\r\\n -o-object-fit: contain;\\r\\n object-fit: contain;\\r\\n cursor: pointer;\\n}\\n.chat-sidebar[data-v-bf6d760c] {\\r\\n position: absolute;\\r\\n inset: 0 auto 0 0;\\r\\n width: min(82vw, 320px);\\r\\n min-width: auto;\\r\\n max-width: 320px;\\r\\n height: 100%;\\r\\n border-right: none;\\r\\n box-shadow: 8px 0 24px rgba(15, 23, 42, 0.12);\\r\\n transform: translateX(-100%);\\r\\n transition: transform 0.24s ease;\\n}\\n.chat-sidebar.open[data-v-bf6d760c] {\\r\\n transform: translateX(0);\\n}\\n.chat-header[data-v-bf6d760c] {\\r\\n padding: 10px 12px;\\r\\n background: transparent;\\r\\n border-bottom: none;\\n}\\n.chat-header .chat-agent-avatar-wrapper[data-v-bf6d760c] {\\r\\n display: none;\\n}\\n.chat-header .agent-desc[data-v-bf6d760c] {\\r\\n display: none;\\n}\\n.chat-header .header-left[data-v-bf6d760c] {\\r\\n flex: 1;\\r\\n justify-content: center;\\r\\n position: relative;\\n}\\n.chat-header .header-left .mobile-back-btn[data-v-bf6d760c] {\\r\\n position: absolute;\\r\\n left: 12px;\\r\\n background: transparent;\\n}\\n.chat-header .header-actions .mobile-header-btn[data-v-bf6d760c] {\\r\\n background: transparent;\\n}\\n.chat-body[data-v-bf6d760c] {\\r\\n padding: 12px;\\r\\n background-position: center top;\\n}\\n.msg-row[data-v-bf6d760c] {\\r\\n padding: 12px 0;\\n}\\n.msg-main[data-v-bf6d760c] {\\r\\n width: 100% !important;\\r\\n max-width: 100%;\\n}\\n.bubble[data-v-bf6d760c] {\\r\\n font-size: 14px;\\n}\\n.bubble.user[data-v-bf6d760c] {\\r\\n max-width: 88%;\\n}\\n.chat-footer[data-v-bf6d760c] {\\r\\n padding: 12px 0 max(12px, env(safe-area-inset-bottom));\\r\\n flex-shrink: 0;\\n}\\n.input-area[data-v-bf6d760c] {\\r\\n width: calc(100% - 24px) !important;\\r\\n margin: 0 12px;\\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-bf6d760c]: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-bf6d760c]::after {\\r\\n display: none;\\n}\\n.voice-btn[data-v-bf6d760c] {\\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-bf6d760c]:active {\\r\\n background: rgba(0,0,0,0.05);\\n}\\n.voice-btn[data-v-bf6d760c]:disabled {\\r\\n opacity: 0.4;\\r\\n cursor: not-allowed;\\n}\\n.chat-textarea[data-v-bf6d760c] {\\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-bf6d760c]::-moz-placeholder {\\r\\n color: #999;\\r\\n font-size: 15px;\\n}\\n.chat-textarea[data-v-bf6d760c]::placeholder {\\r\\n color: #999;\\r\\n font-size: 15px;\\n}\\n.send-btn[data-v-bf6d760c] {\\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-bf6d760c] {\\r\\n display: block;\\n}\\n.send-btn[data-v-bf6d760c]::after {\\r\\n content: none;\\n}\\n.send-btn.active[data-v-bf6d760c] {\\r\\n background: #1677ff;\\n}\\n.send-btn[data-v-bf6d760c]:disabled {\\r\\n background: #88bfff;\\r\\n cursor: not-allowed;\\n}\\n.send-btn[data-v-bf6d760c]:active {\\r\\n transform: scale(0.92);\\n}\\r\\n\\r\\n /* 移动端停止按钮 */\\n.stop-btn[data-v-bf6d760c] {\\r\\n width: 36px;\\r\\n height: 36px;\\r\\n min-width: 36px;\\n}\\n.agent-selector[data-v-bf6d760c] {\\r\\n padding: 28px 12px;\\n}\\n.agent-list[data-v-bf6d760c] {\\r\\n grid-template-columns: 1fr;\\r\\n gap: 52px 0;\\n}\\n.agent-item[data-v-bf6d760c] {\\r\\n height: auto;\\r\\n min-height: 84px;\\r\\n padding: 18px 16px 18px 96px;\\n}\\n.agent-avatar-wrapper[data-v-bf6d760c] {\\r\\n left: 8px;\\r\\n top: -18px;\\n}\\n.agent-list-avatar.has-agent-img[data-v-bf6d760c] {\\r\\n width: 74px;\\r\\n height: 88px;\\n}\\n.agent-list-avatar[data-v-bf6d760c]:not(.has-agent-img) {\\r\\n width: 62px;\\r\\n height: 78px;\\n}\\n.desc[data-v-bf6d760c] {\\r\\n white-space: normal;\\r\\n display: -webkit-box;\\r\\n -webkit-line-clamp: 2;\\r\\n -webkit-box-orient: vertical;\\n}\\n.guess-box[data-v-bf6d760c] {\\r\\n padding: 16px;\\n}\\n.session-delete[data-v-bf6d760c] {\\r\\n display: none;\\n}\\r\\n\\r\\n /* ── H5 语音模式 ── */\\n.hold-talk-btn[data-v-bf6d760c] {\\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 user-select: none;\\r\\n -webkit-user-select: none;\\r\\n transition: background 0.15s;\\n}\\n.hold-talk-btn[data-v-bf6d760c]:active {\\r\\n background: #ddd;\\n}\\n.hold-talk-btn.recording[data-v-bf6d760c] {\\r\\n background: #e8f0fe;\\r\\n color: #333;\\n}\\n.hold-talk-btn .hold-talk-icon[data-v-bf6d760c] {\\r\\n flex-shrink: 0;\\n}\\r\\n\\r\\n /* 语音录制浮层 */\\n.voice-recording-overlay[data-v-bf6d760c] {\\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 animation: fadeIn-bf6d760c 0.15s ease;\\n}\\n.voice-recording-card[data-v-bf6d760c] {\\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-bf6d760c] {\\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-bf6d760c] {\\r\\n width: 4px;\\r\\n background: #1677ff;\\r\\n border-radius: 2px;\\r\\n animation: waveAnim-bf6d760c 0.6s ease-in-out infinite alternate;\\n}\\n.voice-recording-wave span[data-v-bf6d760c]:nth-child(1) { height: 16px; animation-delay: 0s;\\n}\\n.voice-recording-wave span[data-v-bf6d760c]:nth-child(2) { height: 28px; animation-delay: 0.1s;\\n}\\n.voice-recording-wave span[data-v-bf6d760c]:nth-child(3) { height: 40px; animation-delay: 0.2s;\\n}\\n.voice-recording-wave span[data-v-bf6d760c]:nth-child(4) { height: 28px; animation-delay: 0.3s;\\n}\\n.voice-recording-wave span[data-v-bf6d760c]:nth-child(5) { height: 16px; animation-delay: 0.4s;\\n}\\n@keyframes waveAnim-bf6d760c {\\n0% { transform: scaleY(0.6);\\n}\\n100% { transform: scaleY(1);\\n}\\n}\\n.voice-recording-duration[data-v-bf6d760c] {\\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-bf6d760c] {\\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-bf6d760c] {\\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-bf6d760c] {\\r\\n color: #ff4d4f;\\n}\\n@keyframes fadeIn-bf6d760c {\\nfrom { opacity: 0;\\n}\\nto { opacity: 1;\\n}\\n}\\n}\\n@media screen and (max-width: 480px) {\\n.agent-name[data-v-bf6d760c] {\\r\\n font-size: 14px;\\n}\\n.agent-desc[data-v-bf6d760c] {\\r\\n max-width: calc(100vw - 132px);\\n}\\n.mobile-menu-btn[data-v-bf6d760c],\\r\\n .mobile-header-btn[data-v-bf6d760c] {\\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/index.vue?./node_modules/_css-loader@3.6.0@css-loader/dist/cjs.js??ref--7-oneOf-1-1!./node_modules/_vue-loader@15.11.1@vue-loader/lib/loaders/stylePostLoader.js!./node_modules/_postcss-loader@3.0.0@postcss-loader/src??ref--7-oneOf-1-2!./node_modules/_cache-loader@4.1.0@cache-loader/dist/cjs.js??ref--1-0!./node_modules/_vue-loader@15.11.1@vue-loader/lib??vue-loader-options");
|
|
3256
3256
|
|
|
3257
3257
|
/***/ }),
|
|
3258
3258
|
|
|
@@ -12448,7 +12448,7 @@ eval("module.exports = function(originalModule) {\n\tif (!originalModule.webpack
|
|
|
12448
12448
|
/*! exports provided: name, version, main, private, scripts, dependencies, devDependencies, browserslist, directories, keywords, license, default */
|
|
12449
12449
|
/***/ (function(module) {
|
|
12450
12450
|
|
|
12451
|
-
eval("module.exports = JSON.parse(\"{\\\"name\\\":\\\"zj-plugin-intelligent\\\",\\\"version\\\":\\\"1.2.5-beta.
|
|
12451
|
+
eval("module.exports = JSON.parse(\"{\\\"name\\\":\\\"zj-plugin-intelligent\\\",\\\"version\\\":\\\"1.2.5-beta.6\\\",\\\"main\\\":\\\"lib/ZjPluginIntelligent.umd.min.js\\\",\\\"private\\\":false,\\\"scripts\\\":{\\\"serve\\\":\\\"vue-cli-service serve\\\",\\\"build\\\":\\\"vue-cli-service build\\\",\\\"lib\\\":\\\"vue-cli-service build --target lib --name ZjPluginIntelligent --dest lib src/lib/index.js\\\",\\\"lib:test\\\":\\\"vue-cli-service build --mode test --target lib --name ZjPluginIntelligent --dest lib src/lib/index.js\\\"},\\\"dependencies\\\":{\\\"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\\\",\\\"node-sass\\\":\\\"^4.12.0\\\",\\\"obs-upload\\\":\\\"^1.0.4-alpha.0\\\",\\\"reconnecting-websocket\\\":\\\"^4.4.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\\\",\\\"pako\\\":\\\"^2.1.0\\\",\\\"webpack-bundle-analyzer\\\":\\\"^4.4.2\\\"},\\\"browserslist\\\":[\\\"> 1%\\\",\\\"last 2 versions\\\",\\\"not dead\\\"],\\\"directories\\\":{\\\"lib\\\":\\\"lib\\\"},\\\"keywords\\\":[],\\\"license\\\":\\\"ISC\\\"}\");\n\n//# sourceURL=webpack://ZjPluginIntelligent/./package.json?");
|
|
12452
12452
|
|
|
12453
12453
|
/***/ }),
|
|
12454
12454
|
|