zj-plugin-ai-assistant 0.2.0-beta.7 → 0.2.0-beta.9
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.
package/lib/.gz
CHANGED
|
Binary file
|
|
@@ -229,7 +229,7 @@ eval("__webpack_require__.r(__webpack_exports__);\n// This file is imported into
|
|
|
229
229
|
/***/ (function(module, exports, __webpack_require__) {
|
|
230
230
|
|
|
231
231
|
"use strict";
|
|
232
|
-
eval("\n\nvar _interopRequireWildcard = __webpack_require__(/*! ./node_modules/@babel/runtime/helpers/interopRequireWildcard */ \"./node_modules/@babel/runtime/helpers/interopRequireWildcard.js\").default;\n\nvar _interopRequireDefault = __webpack_require__(/*! ./node_modules/@babel/runtime/helpers/interopRequireDefault */ \"./node_modules/@babel/runtime/helpers/interopRequireDefault.js\").default;\n\nObject.defineProperty(exports, \"__esModule\", {\n value: true\n});\nexports.default = void 0;\n\nvar _typeof2 = _interopRequireDefault(__webpack_require__(/*! ./node_modules/@babel/runtime/helpers/typeof */ \"./node_modules/@babel/runtime/helpers/typeof.js\"));\n\nvar _createForOfIteratorHelper2 = _interopRequireDefault(__webpack_require__(/*! ./node_modules/@babel/runtime/helpers/createForOfIteratorHelper */ \"./node_modules/@babel/runtime/helpers/createForOfIteratorHelper.js\"));\n\nvar _asyncToGenerator2 = _interopRequireDefault(__webpack_require__(/*! ./node_modules/@babel/runtime/helpers/asyncToGenerator */ \"./node_modules/@babel/runtime/helpers/asyncToGenerator.js\"));\n\nvar _aiAssistant = _interopRequireDefault(__webpack_require__(/*! ./ai-assistant.png */ \"./src/lib/components/approvalAi/ai-assistant.png\"));\n\nvar aiApi = _interopRequireWildcard(__webpack_require__(/*! ./apiApprovalAi */ \"./src/lib/components/approvalAi/apiApprovalAi.js\"));\n\nvar _markdownIt = _interopRequireDefault(__webpack_require__(/*! markdown-it */ \"./node_modules/markdown-it/index.js\"));\n\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\nvar md = new _markdownIt.default({\n html: false,\n linkify: true\n}); // 已知英文编码 -> 中文名称(进包时内嵌,避免依赖宿主项目的 approvalType 常量)\n\nvar VALUE_NAME = {\n comFeePlan: \"公司费用计划\",\n comFeeApplication: \"公司费用\",\n comFeeAccept: \"公司费用验收\",\n comFeeCredit: \"公司费用挂账\",\n comFeePay: \"公司费用支付\",\n employeeHonor: \"员工荣誉\",\n employeeRegularization: \"员工转正\",\n employeeTurnover: \"离职\",\n employeeturnoverhandover: \"离职交接\",\n employeeChangestation: \"调岗\",\n employeeChangesalary: \"调薪\",\n overTimeApply: \"加班\",\n carApproval: \"车辆\",\n reimburse: \"出差报销\",\n leave: \"请假\",\n patch: \"补卡\",\n trip: \"出差\",\n out: \"外出\",\n lan: \"借款\",\n officialDocument: \"公文\",\n notice: \"公告\",\n qgbCompanyPlanSummery: \"公司费用预算汇总\",\n sealApproval: \"印章\"\n}; // 审批状态码 -> 中文(内置映射,替代宿主项目全局 $approvalStatus)\n\nvar STATUS_MAP = {\n \"1\": \"审批中\",\n \"-1\": \"审批中\",\n \"0\": \"已拒绝\",\n \"2\": \"已通过\",\n \"-3\": \"已通过\",\n \"4\": \"草稿\",\n \"3\": \"已通过\",\n \"5\": \"已完成\",\n \"6\": \"已撤销\"\n}; // 概览文案启发式字段匹配\n\nvar FIELD_HINTS = [{\n key: \"applicant\",\n labels: [\"申请人\", \"提交人\", \"经办人\"]\n}, {\n key: \"unit\",\n labels: [\"申请单位\", \"公司\", \"单位\"]\n}, {\n key: \"dept\",\n labels: [\"申请部门\", \"部门\"]\n}, {\n key: \"reason\",\n labels: [\"原因\", \"事由\", \"用途\", \"摘要\", \"标题\", \"说明\", \"内容\", \"目的\"]\n}, {\n key: \"amount\",\n labels: [\"金额\", \"费用\", \"总计\", \"总金额\", \"合计\"]\n}];\n\nfunction normalizeLabel(label) {\n return String(label).trim().replace(/[::]\\s*$/g, \"\");\n}\n\nfunction resolveStatusText(status, override) {\n if (override) return override;\n if (!status && status !== 0) return \"待处理\";\n var mapped = STATUS_MAP[String(status)];\n return mapped || \"未知状态\";\n}\n\nvar msgSeq = 0;\nvar _default = {\n name: \"ApprovalAiAssistant\",\n props: {\n id: {\n type: String,\n default: \"\"\n },\n type: {\n type: String,\n default: \"\"\n },\n status: {\n type: String,\n default: \"0\"\n },\n index: {\n type: Number,\n default: 1\n },\n commentId: {\n type: String,\n default: \"\"\n },\n // ---- 以下为进包后新增的配置项,用于解耦宿主角色的上下文依赖 ----\n // AI 服务基础地址(示例 https://api.xxx.cn),未配置则走本地兜底\n baseUrl: {\n type: String,\n default: \"\"\n },\n // 当前用户信息(替代宿主 Vuex $store.state.user)\n userId: {\n type: String,\n default: \"\"\n },\n userName: {\n type: String,\n default: \"\"\n },\n // 审批状态文案覆盖(默认内置状态码映射;传入则优先使用)\n statusTextOverride: {\n type: String,\n default: \"\"\n },\n // 布局边界选择器(替代硬编码 .approval-content)\n containerSelector: {\n type: String,\n default: \".approval-content\"\n },\n // 详情采集根选择器(替代硬编码 .detail-root)\n detailRootSelector: {\n type: String,\n default: \".detail-root\"\n },\n // 机器人图标,不传时使用包内内置图标\n robotIconUrl: {\n type: String,\n default: \"\"\n },\n // H5 底部操作栏高度(px):作为兜底基准,用于把浮动按钮放在操作栏上方;PC 传 0 不受影响\n bottomBarHeight: {\n type: Number,\n default: 0\n },\n // H5 底部操作栏元素选择器:运行时测量该元素,把悬浮窗放在其正上方,避免遮挡(默认 .btn-wrapper)\n bottomBarSelector: {\n type: String,\n default: \".btn-wrapper\"\n }\n },\n data: function data() {\n return {\n defaultIcon: _aiAssistant.default,\n // 悬浮按钮右上角红点:初始化显示,进入面板后取消\n showRedDot: true,\n panelVisible: false,\n // 首次打开时审批详情/概览仍在加载中的提示开关\n greetingLoading: false,\n sending: false,\n streaming: false,\n autoFollow: true,\n sessionId: \"\",\n messages: [],\n fields: [],\n rawDetail: null,\n inputText: \"\",\n btnLeft: 0,\n btnBottom: 340,\n // 弹窗头部拖动:面板位置(PC 用 left + bottom 定位;H5 底部弹出仍走 CSS 固定)\n panelLeft: 0,\n panelBottom: 88,\n panelDragging: false,\n // 用户手动拖动过面板后,再次打开保持该位置(不再吸附到按钮附近)\n panelMoved: false,\n tucked: false,\n dragging: false,\n moved: false,\n isMobile: false,\n startX: 0,\n startY: 0,\n startLeft: 0,\n startBottom: 0\n };\n },\n computed: {\n iconUrl: function iconUrl() {\n return this.robotIconUrl || this.defaultIcon;\n },\n // 面板定位:PC 用 left + bottom 自由拖动;H5 底部弹出仅绑 bottom,\n // left/right/width 交给媒体查询,避免内联 left 覆盖掉 H5 的全宽定位\n panelStyle: function panelStyle() {\n var s = {\n bottom: this.panelBottom + \"px\"\n };\n if (!this.isMobile) s.left = this.panelLeft + \"px\";\n return s;\n },\n typeName: function typeName() {\n if (!this.type) return \"\";\n return VALUE_NAME[this.type] || this.type;\n },\n statusText: function statusText() {\n return resolveStatusText(this.status, this.statusTextOverride);\n },\n statusTone: function statusTone() {\n var t = this.statusText;\n if (t === \"已通过\" || t === \"已完成\") return \"ok\";\n if (t === \"已拒绝\" || t === \"已驳回\" || t === \"已退回\" || t === \"已终止\") return \"no\";\n return \"go\";\n }\n },\n created: function created() {// 注入 AI 服务地址\n },\n mounted: function mounted() {\n var _this = this;\n\n window.addEventListener(\"mousemove\", this.onDrag);\n window.addEventListener(\"mouseup\", this.endDrag);\n this.initMobile();\n this.$nextTick(function () {\n return _this.snapBtn();\n });\n },\n beforeDestroy: function beforeDestroy() {\n window.removeEventListener(\"mousemove\", this.onDrag);\n window.removeEventListener(\"mouseup\", this.endDrag);\n if (this.__mqUnlisten) this.__mqUnlisten();\n },\n watch: {\n // 切换审批单时重置对话上下文\n id: function id() {\n this.sessionId = \"\";\n this.messages = [];\n this.fields = [];\n this.rawDetail = null; // 切换审批单时重置面板位置(恢复到默认吸附)\n\n this.panelLeft = 0;\n this.panelBottom = 88;\n this.panelMoved = false;\n },\n // baseUrl 变化时同步注入 AI 服务\n baseUrl: function baseUrl(val) {\n aiApi.configureAI({\n baseUrl: val\n });\n }\n },\n methods: {\n // 统一取鼠标/触摸的坐标点\n point: function point(e) {\n var t = e && e.touches && e.touches[0] || e && e.changedTouches && e.changedTouches[0];\n return t ? {\n clientX: t.clientX,\n clientY: t.clientY\n } : {\n clientX: e.clientX,\n clientY: e.clientY\n };\n },\n // 按钮距容器底部的最小基准:8px + H5 底部操作栏高度,保证按钮在操作栏上方\n baseBottom: function baseBottom() {\n return 8 + (Number(this.bottomBarHeight) || 0);\n },\n // H5 下测量底部操作栏元素,返回“视口底部到该元素顶部”的距离 + 安全边距,\n // 使悬浮窗固定在该元素正上方、不遮挡其展示;PC/找不到时回退到 baseBottom()\n barBottomOffset: function barBottomOffset() {\n if (!this.isMobile) return this.baseBottom();\n var sel = this.bottomBarSelector;\n\n if (sel) {\n var el = null;\n\n try {\n el = document.querySelector(sel);\n } catch (e) {\n el = null;\n }\n\n var rect = el && el.getBoundingClientRect();\n\n if (rect && rect.top >= 0 && rect.top <= window.innerHeight) {\n return window.innerHeight - rect.top + 12;\n }\n }\n\n return this.baseBottom();\n },\n // 是否 H5 窄屏(与 CSS media query 保持一致的 480px 边界)\n initMobile: function initMobile() {\n var _this2 = this;\n\n var mq = window.matchMedia && window.matchMedia(\"(max-width: 480px)\");\n\n var apply = function apply() {\n _this2.isMobile = !mq || mq.matches;\n };\n\n apply();\n if (mq && mq.addEventListener) mq.addEventListener(\"change\", apply);else if (mq && mq.addListener) mq.addListener(apply);\n\n this.__mqUnlisten = function () {\n if (mq && mq.removeEventListener) mq.removeEventListener(\"change\", apply);else if (mq && mq.removeListener) mq.removeListener(apply);\n };\n },\n getContainer: function getContainer() {\n // 普通模式:以配置的审批容器为边界;找不到时回退到父级包裹容器\n var selector = this.containerSelector;\n var el = selector ? this.$el.closest(selector) : null;\n return el || this.$el.parentElement;\n },\n getDetailRoot: function getDetailRoot() {\n var box = this.getContainer();\n if (!box) return null;\n var explicit = this.detailRootSelector ? box.querySelector(this.detailRootSelector) : null;\n if (explicit) return explicit; // 子应用/iframe 模式:容器内可能没有 detail-root 标记,\n // 回退到首个详情子节点(排除 AI 面板自身)\n\n var kids = Array.from(box.children).filter(function (c) {\n return !c.classList.contains(\"ai-assistant\");\n });\n return kids.length ? kids[0] : null;\n },\n togglePanel: function togglePanel() {\n var _this3 = this;\n\n // 拖拽后松手会触发一次 click,这里拦截,避免误展开/收起面板\n if (this.moved) {\n this.moved = false;\n return;\n }\n\n if (this.panelVisible) {\n this.closePanel();\n return;\n }\n\n this.panelVisible = true; // 进入面板后取消红点\n\n this.showRedDot = false;\n this.$nextTick(function () {\n _this3.snapPanel();\n\n if (!_this3.messages.length) {\n _this3.greet();\n }\n\n _this3.scrollBottom();\n\n if (_this3.$refs.input) _this3.$refs.input.focus();\n });\n },\n closePanel: function closePanel() {\n this.panelVisible = false;\n },\n snapBtn: function snapBtn() {\n var box = this.getContainer();\n if (!box) return; // 默认贴右下角完整展开:右侧留 20px\n\n if (!this.tucked && !this.btnLeft) {\n this.btnLeft = Math.max(0, box.clientWidth - 20 - 46);\n } // 若按钮在可视范围外则修正\n\n\n this.btnLeft = Math.max(0, Math.min(this.btnLeft, box.clientWidth - 46));\n this.btnBottom = Math.max(this.barBottomOffset(), Math.min(this.btnBottom, box.clientHeight - 44 - 8));\n },\n snapPanel: function snapPanel() {\n // 用户已手动拖动过面板,再次打开保持其位置,不再吸附到按钮附近\n if (this.panelMoved) return;\n var box = this.getContainer();\n var el = this.$el.querySelector(\".ai-panel\");\n if (!box || !el) return;\n var margin = 24; // 上下安全距离,避免遮挡\n\n var pw = el.clientWidth || 420;\n var ph = el.clientHeight || 560; // 默认 left:面板右上角落在容器右缘外 74px(原 .ai-panel right:74px 的等价值)\n\n if (!this.panelLeft) {\n this.panelLeft = Math.max(0, box.clientWidth - pw - 74);\n }\n\n var desired = this.btnBottom + 62;\n this.panelBottom = Math.max(margin, Math.min(desired, box.clientHeight - ph - margin));\n },\n // 弹窗头部拖拽开始(PC 端可自由拖动;H5 底部弹层保持原定位不参与)\n startPanelDrag: function startPanelDrag(e) {\n if (this.isMobile) return;\n if (e.button !== undefined && e.button !== 0) return;\n var el = this.$el.querySelector(\".ai-panel\");\n if (!el) return;\n var p = this.point(e);\n if (!p) return;\n this.panelDragging = true;\n this._pdStartX = p.clientX;\n this._pdStartY = p.clientY;\n this._pdStartLeft = this.panelLeft || 0;\n this._pdStartBottom = this.panelBottom; // 拖动时防止选中 Header 文字导致跟手中断;仅鼠标 preventDefault\n\n if (e.type === \"mousedown\") e.preventDefault();\n },\n // 弹窗拖拽移动:随鼠标更新 left/bottom,并夹在容器安全边界内\n onPanelDrag: function onPanelDrag(e) {\n if (!this.panelDragging) return;\n var box = this.getContainer();\n if (!box) return;\n var el = this.$el.querySelector(\".ai-panel\");\n var pw = el ? el.clientWidth : 420;\n var ph = el ? el.clientHeight : 560;\n var p = this.point(e) || {};\n var dx = (p.clientX || 0) - this._pdStartX;\n var dy = (p.clientY || 0) - this._pdStartY;\n var maxLeft = Math.max(0, box.clientWidth - pw - 24);\n var maxBottom = Math.max(24, box.clientHeight - ph - 24);\n this.panelLeft = Math.max(0, Math.min(this._pdStartLeft + dx, maxLeft));\n this.panelBottom = Math.max(24, Math.min(this._pdStartBottom - dy, maxBottom));\n },\n // 打开时 AI 先总结当前审批(已接入后端走 SSE 流式边生成边渲染;未接入用本地兜底概览)\n greet: function greet() {\n var _this4 = this;\n\n return (0, _asyncToGenerator2.default)( /*#__PURE__*/regeneratorRuntime.mark(function _callee() {\n var localSummary, intro, msg, got;\n return regeneratorRuntime.wrap(function _callee$(_context) {\n while (1) {\n switch (_context.prev = _context.next) {\n case 0:\n _this4.greetingLoading = true;\n _context.prev = 1;\n\n _this4.collectDetail();\n\n localSummary = _this4.buildSummary();\n intro = \"\\u4F60\\u597D\\uFF0C\\u6211\\u662F AI \\u5BA1\\u6279\\u52A9\\u624B\\uD83D\\uDC4B\\n\\n\\u5DF2\\u7ECF\\u4E3A\\u4F60\\u68B3\\u7406\\u4E86\\u5F53\\u524D\\u5BA1\\u6279\\u7684\\u6982\\u89C8\\uFF1A\\n\\n\"; // 先推送开场语,总结随后增量追加,避免首屏等待总结 8~10 秒\n\n msg = {\n id: ++msgSeq,\n role: \"assistant\",\n content: intro\n };\n\n _this4.messages.push(msg);\n\n _this4.greetingLoading = false;\n\n _this4.scrollBottom();\n\n if (!(_this4.aiEnabled() && _this4.id)) {\n _context.next = 16;\n break;\n }\n\n got = false;\n _context.next = 13;\n return aiApi.streamSummary(_this4.id, {\n onEvent: function onEvent(event, data) {\n if (event === \"answer\") {\n got = true;\n msg.content += data;\n\n _this4.followBottom();\n } else if (event === \"agent_result\") {\n got = true;\n msg.content = intro + (data || \"\");\n\n _this4.followBottom();\n }\n }\n });\n\n case 13:\n // 流式未返回任何内容(失败/空)时回退到本地概览,避免空白\n if (!got || msg.content === intro) {\n msg.content = intro + localSummary;\n\n _this4.followBottom();\n }\n\n _context.next = 18;\n break;\n\n case 16:\n msg.content = intro + localSummary;\n\n _this4.followBottom();\n\n case 18:\n _context.prev = 18;\n _this4.greetingLoading = false;\n\n _this4.scrollBottom();\n\n return _context.finish(18);\n\n case 22:\n case \"end\":\n return _context.stop();\n }\n }\n }, _callee, null, [[1,, 18, 22]]);\n }))();\n },\n quickAsk: function quickAsk(q) {\n this.inputText = q;\n this.sendMessage();\n },\n // 审批详情气泡内的链接禁止跳转(markdown 渲染出的 <a> 不触发页面跳转)\n onBubbleClick: function onBubbleClick(e) {\n var el = e.target;\n var link = el && el.closest ? el.closest(\"a\") : null;\n if (!link) return;\n e.preventDefault();\n e.stopPropagation();\n },\n sendMessage: function sendMessage() {\n var _this5 = this;\n\n var text = (this.inputText || \"\").trim();\n if (!text || this.sending) return;\n this.push(\"user\", text);\n this.inputText = \"\";\n this.sending = true;\n this.collectDetail(); // 直接走后端流式问答(已接入时);未接入则返回本地兜底\n\n var msg = null;\n\n if (this.aiEnabled() && this.id) {\n msg = {\n id: ++msgSeq,\n role: \"assistant\",\n content: \"\"\n };\n this.messages.push(msg);\n this.streaming = true;\n this.scrollBottom();\n }\n\n this.getReply(text, function (chunk) {\n if (msg) {\n msg.content += chunk;\n\n _this5.followBottom();\n }\n }).then(function (reply) {\n if (msg) {\n if (!msg.content) msg.content = reply || _this5.fallbackReply(text);\n } else {\n _this5.push(\"assistant\", _this5.fallbackReply(text));\n }\n\n _this5.streaming = false;\n _this5.sending = false;\n\n _this5.followBottom();\n });\n },\n // 获取 AI 回复:已接入后端走流式接口;未接入时返回本地兜底\n getReply: function getReply(question, onDelta) {\n var _this6 = this;\n\n return (0, _asyncToGenerator2.default)( /*#__PURE__*/regeneratorRuntime.mark(function _callee2() {\n var payload, aiReply;\n return regeneratorRuntime.wrap(function _callee2$(_context2) {\n while (1) {\n switch (_context2.prev = _context2.next) {\n case 0:\n payload = {\n context: {\n type: _this6.type,\n status: _this6.status,\n typeName: _this6.typeName,\n id: _this6.id,\n summary: _this6.buildSummary(),\n fields: _this6.fields,\n detailData: _this6.rawDetail\n },\n question: question\n };\n _context2.next = 3;\n return _this6.requestAi(payload, onDelta);\n\n case 3:\n aiReply = _context2.sent;\n return _context2.abrupt(\"return\", aiReply && String(aiReply).trim() ? String(aiReply) : _this6.fallbackReply(question));\n\n case 5:\n case \"end\":\n return _context2.stop();\n }\n }\n }, _callee2);\n }))();\n },\n // AI 后端是否可用\n aiEnabled: function aiEnabled() {\n return aiApi.aiConfigured() && Boolean(this.id);\n },\n // 当前用户信息(来自 props,替代宿主 Vuex)\n userInfo: function userInfo() {\n return {\n no: this.userId || \"\",\n name: this.userName || \"\"\n };\n },\n // 创建/复用 AI 对话会话\n ensureSession: function ensureSession() {\n var _this7 = this;\n\n return (0, _asyncToGenerator2.default)( /*#__PURE__*/regeneratorRuntime.mark(function _callee3() {\n var u, res;\n return regeneratorRuntime.wrap(function _callee3$(_context3) {\n while (1) {\n switch (_context3.prev = _context3.next) {\n case 0:\n if (!_this7.sessionId) {\n _context3.next = 2;\n break;\n }\n\n return _context3.abrupt(\"return\", _this7.sessionId);\n\n case 2:\n u = _this7.userInfo();\n _context3.next = 5;\n return aiApi.createChatSession({\n approvalNo: _this7.id,\n userId: u.no,\n userName: u.name\n });\n\n case 5:\n res = _context3.sent;\n\n if (!(res && res.data && res.data.sessionId)) {\n _context3.next = 9;\n break;\n }\n\n _this7.sessionId = res.data.sessionId;\n return _context3.abrupt(\"return\", _this7.sessionId);\n\n case 9:\n return _context3.abrupt(\"return\", \"\");\n\n case 10:\n case \"end\":\n return _context3.stop();\n }\n }\n }, _callee3);\n }))();\n },\n // 对接后端 AI 流式问答接口:创建会话 + SSE 实时增量;异常时返回 null\n requestAi: function requestAi(payload, onDelta) {\n var _this8 = this;\n\n return (0, _asyncToGenerator2.default)( /*#__PURE__*/regeneratorRuntime.mark(function _callee4() {\n var sessionId, text, failed;\n return regeneratorRuntime.wrap(function _callee4$(_context4) {\n while (1) {\n switch (_context4.prev = _context4.next) {\n case 0:\n if (_this8.aiEnabled()) {\n _context4.next = 2;\n break;\n }\n\n return _context4.abrupt(\"return\", null);\n\n case 2:\n _context4.prev = 2;\n _context4.next = 5;\n return _this8.ensureSession();\n\n case 5:\n sessionId = _context4.sent;\n\n if (sessionId) {\n _context4.next = 8;\n break;\n }\n\n return _context4.abrupt(\"return\", null);\n\n case 8:\n text = \"\";\n failed = false;\n _context4.next = 12;\n return aiApi.streamChat({\n sessionId: sessionId,\n message: payload.question,\n userId: _this8.userInfo().no,\n userName: _this8.userInfo().name,\n onEvent: function onEvent(event, data) {\n if (event === \"reasoning\" || event === \"answer\") {\n text += data;\n if (onDelta) onDelta(data);\n } else if (event === \"agent_result\") {\n text = data;\n } else if (event === \"error\") {\n failed = true;\n }\n }\n });\n\n case 12:\n if (!failed) {\n _context4.next = 14;\n break;\n }\n\n return _context4.abrupt(\"return\", null);\n\n case 14:\n return _context4.abrupt(\"return\", text && text.trim() ? text : null);\n\n case 17:\n _context4.prev = 17;\n _context4.t0 = _context4[\"catch\"](2);\n return _context4.abrupt(\"return\", null);\n\n case 20:\n case \"end\":\n return _context4.stop();\n }\n }\n }, _callee4, null, [[2, 17]]);\n }))();\n },\n // 无法从数据中检索到时的兜底:诚实告知查询不到,不编造\n fallbackReply: function fallbackReply(question) {\n var q = String(question).trim();\n var list = '';\n return \"\\u6682\\u65F6\\u65E0\\u6CD5\\u67E5\\u8BE2\\u5230\\u4E0E\\u300C\".concat(q, \"\\u300D\\u5BF9\\u5E94\\u7684\\u4FE1\\u606F\\u3002\").concat(list);\n },\n findField: function findField(labels) {\n var _iterator = (0, _createForOfIteratorHelper2.default)(this.rawEntries()),\n _step;\n\n try {\n var _loop = function _loop() {\n var e = _step.value;\n if (labels.some(function (l) {\n return e.label.indexOf(l) > -1;\n })) return {\n v: e.value\n };\n };\n\n for (_iterator.s(); !(_step = _iterator.n()).done;) {\n var _ret = _loop();\n\n if ((0, _typeof2.default)(_ret) === \"object\") return _ret.v;\n }\n } catch (err) {\n _iterator.e(err);\n } finally {\n _iterator.f();\n }\n\n return \"\";\n },\n // 合并 DOM 采集字段 + 详情页完整原始业务对象,得到可检索的条目\n rawEntries: function rawEntries() {\n var _this9 = this;\n\n var list = [];\n var seen = new Set();\n\n var pushEntry = function pushEntry(label, value) {\n var v = _this9.stringify(value);\n\n if (!v) return;\n var k = \"\".concat(label, \"__\").concat(v);\n if (seen.has(k)) return;\n seen.add(k);\n list.push({\n label: label,\n value: v\n });\n };\n\n var _iterator2 = (0, _createForOfIteratorHelper2.default)(this.fields),\n _step2;\n\n try {\n for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {\n var f = _step2.value;\n pushEntry(f.label, f.value);\n }\n } catch (err) {\n _iterator2.e(err);\n } finally {\n _iterator2.f();\n }\n\n var raw = this.rawDetail && this.rawDetail.data;\n\n if (raw && (0, _typeof2.default)(raw) === \"object\") {\n for (var _i = 0, _Object$keys = Object.keys(raw); _i < _Object$keys.length; _i++) {\n var key = _Object$keys[_i];\n pushEntry(key, raw[key]);\n }\n }\n\n return list;\n },\n stringify: function stringify(v) {\n if (v === null || v === undefined) return \"\";\n\n if ((0, _typeof2.default)(v) === \"object\") {\n try {\n return JSON.stringify(v);\n } catch (e) {\n return \"\";\n }\n }\n\n return String(v);\n },\n // 通用采集详情页数据:兼容 el-form-item / el-descriptions / 自定义 span标签:值 / 表格,\n // 并尽量读取详情页组件的原始业务对象(info/form) 作为完整数据\n collectDetail: function collectDetail() {\n var root = this.getDetailRoot();\n var seen = {};\n\n var push = function push(label, value) {\n label = normalizeLabel(label);\n var v = String(value === null || value === undefined ? \"\" : value).replace(/\\s+/g, \" \").trim();\n if (!label || !v || v === \"暂无\" || label === \"图片\" || label === \"操作\") return;\n if (seen[label] !== undefined) return;\n seen[label] = v;\n };\n\n if (root) {\n // 1) el-form-item\n root.querySelectorAll(\".el-form-item\").forEach(function (item) {\n var labelEl = item.querySelector(\".el-form-item__label\");\n var contentEl = item.querySelector(\".el-form-item__content\");\n if (labelEl && contentEl) push(labelEl.textContent, contentEl.textContent);\n }); // 2) el-descriptions 描述项\n\n root.querySelectorAll(\".el-descriptions-item\").forEach(function (item) {\n var labelEl = item.querySelector(\".el-descriptions-item__label\");\n var contentEl = item.querySelector(\".el-descriptions-item__content\");\n if (labelEl && contentEl) push(labelEl.textContent, contentEl.textContent);\n }); // 3) 自定义 label:value(span 以「:」/「:」结尾,值在大括号内剩余文本)\n\n root.querySelectorAll(\"span\").forEach(function (span) {\n var txt = (span.textContent || \"\").trim();\n var m = txt.match(/^(.+?)([::])$/);\n if (!m) return;\n var parent = span.parentElement;\n if (!parent) return;\n var value = (parent.textContent || \"\").replace(txt, \"\").replace(/\\s+/g, \" \").trim();\n push(m[1], value);\n }); // 4) 表格:表头 -> 逐行数据\n\n root.querySelectorAll(\"table\").forEach(function (table) {\n var rows = table.querySelectorAll(\"tr\");\n var headers = [];\n\n if (rows.length) {\n headers = Array.from(rows[0].querySelectorAll(\"th,td\")).map(function (c) {\n return normalizeLabel(c.textContent);\n });\n }\n\n rows.forEach(function (tr, idx) {\n if (idx === 0) return;\n var cells = Array.from(tr.querySelectorAll(\"th,td\")).map(function (c) {\n return (c.textContent || \"\").replace(/\\s+/g, \" \").trim();\n });\n if (!cells.length) return;\n\n if (headers.length) {\n headers.forEach(function (h, j) {\n return h && cells[j] !== undefined && push(h, cells[j]);\n });\n } else {\n cells.forEach(function (c, j) {\n return c && push(\"\\u7B2C\".concat(idx, \"\\u884C\\u5B57\\u6BB5\").concat(j + 1), c);\n });\n }\n });\n });\n } // 5) 读取详情组件的原始业务对象,作为完整结构化数据补全\n\n\n var raw = this.readRawDetail();\n this.rawDetail = raw;\n if (raw) this.flattenTo(seen, raw);\n this.fields = Object.keys(seen).map(function (label) {\n return {\n label: label,\n value: seen[label]\n };\n }).slice(0, 40);\n },\n // 寻找详情页组件的业务数据对象(info / form 等)\n readRawDetail: function readRawDetail() {\n var _this10 = this;\n\n var root = this.getDetailRoot();\n if (!root) return null;\n\n var _iterator3 = (0, _createForOfIteratorHelper2.default)(root.querySelectorAll(\"*\")),\n _step3;\n\n try {\n for (_iterator3.s(); !(_step3 = _iterator3.n()).done;) {\n var el = _step3.value;\n var vm = el.__vue__;\n if (!vm || !vm.$data || (0, _typeof2.default)(vm.$data) !== \"object\") continue;\n var d = vm.$data;\n\n var _loop2 = function _loop2() {\n var key = _arr[_i2];\n var obj = d[key];\n\n if (obj && (0, _typeof2.default)(obj) === \"object\" && !Array.isArray(obj)) {\n var keys = Object.keys(obj).filter(function (k) {\n return obj[k] !== \"\" && obj[k] !== null && obj[k] !== undefined;\n });\n\n if (keys.length) {\n return {\n v: {\n key: key,\n data: _this10.jsonSafe(obj)\n }\n };\n }\n }\n };\n\n for (var _i2 = 0, _arr = [\"info\", \"form\"]; _i2 < _arr.length; _i2++) {\n var _ret2 = _loop2();\n\n if ((0, _typeof2.default)(_ret2) === \"object\") return _ret2.v;\n }\n }\n } catch (err) {\n _iterator3.e(err);\n } finally {\n _iterator3.f();\n }\n\n return null;\n },\n jsonSafe: function jsonSafe(obj) {\n try {\n return JSON.parse(JSON.stringify(obj, function (k, v) {\n return typeof v === \"function\" ? undefined : v;\n }));\n } catch (e) {\n return obj;\n }\n },\n // 把原始业务对象摊平成 label:value,补进已采集集合\n flattenTo: function flattenTo(seen, raw) {\n var walk = function walk(obj, path) {\n if (obj === null || obj === undefined) return;\n\n if (Array.isArray(obj)) {\n obj.forEach(function (item, i) {\n return walk(item, path ? \"\".concat(path, \"[\").concat(i, \"]\") : \"[\".concat(i, \"]\"));\n });\n return;\n }\n\n if ((0, _typeof2.default)(obj) === \"object\") {\n Object.keys(obj).forEach(function (k) {\n return walk(obj[k], path ? \"\".concat(path, \".\").concat(k) : k);\n });\n return;\n }\n\n var label = path || \"\";\n var v = String(obj).replace(/\\s+/g, \" \").trim();\n if (label && v && seen[label] === undefined) seen[label] = v;\n };\n\n walk(raw.data, raw.key);\n },\n // 依据采集字段生成“当前审批是做什么的”概览(启发式)\n buildSummary: function buildSummary() {\n var hits = {};\n FIELD_HINTS.forEach(function (hint) {\n hits[hint.key] = \"\";\n });\n this.fields.forEach(function (f) {\n var _iterator4 = (0, _createForOfIteratorHelper2.default)(FIELD_HINTS),\n _step4;\n\n try {\n for (_iterator4.s(); !(_step4 = _iterator4.n()).done;) {\n var hint = _step4.value;\n if (hits[hint.key]) continue;\n\n if (hint.labels.some(function (l) {\n return f.label.indexOf(l) > -1;\n })) {\n hits[hint.key] = f.value;\n break;\n }\n }\n } catch (err) {\n _iterator4.e(err);\n } finally {\n _iterator4.f();\n }\n });\n var name = this.typeName || \"该单据\";\n var parts = [];\n if (hits.applicant) parts.push(\"\\u7533\\u8BF7\\u4EBA\\u300C\".concat(hits.applicant, \"\\u300D\"));\n if (hits.unit) parts.push(\"\\u6240\\u5C5E\\u5355\\u4F4D\\u300C\".concat(hits.unit, \"\\u300D\"));\n var verb = \"\".concat(name === \"该单据\" ? \"该审批\" : \"\\u8BE5\\u300C\".concat(name, \"\\u300D\\u5BA1\\u6279\"));\n var summary = \"\".concat(verb, \"\\u662F\\u4E00\\u7B14\\u4E1A\\u52A1\\u5BA1\\u6279\");\n if (parts.length) summary += \"\\uFF0C\\u7531\".concat(parts.join(\",\"), \"\\u53D1\\u8D77\");\n if (hits.reason) summary += \"\\uFF0C\\u4E3B\\u8981\\u4E8B\\u7531\\uFF1A\".concat(hits.reason);\n if (hits.amount) summary += \"\\uFF0C\\u6D89\\u53CA\\u91D1\\u989D\\u300C\".concat(hits.amount, \"\\u300D\");\n summary += \"\\u3002\\u5F53\\u524D\\u5BA1\\u6279\\u72B6\\u6001\\u4E3A\\u300C\".concat(this.statusText, \"\\u300D\\u3002\");\n return summary;\n },\n push: function push(role, content) {\n this.messages.push({\n id: ++msgSeq,\n role: role,\n content: content\n });\n },\n // 气泡渲染:助手消息转 Markdown,用户消息按纯文本处理(转义防 XSS)\n renderBubble: function renderBubble(m) {\n var text = m && m.content != null ? String(m.content) : \"\";\n if (m && m.role === \"user\") return this.escapeHtml(text);\n return md.render(text || \"\");\n },\n escapeHtml: function escapeHtml(str) {\n return String(str).replace(/[&<>\"']/g, function (c) {\n return {\n \"&\": \"&\",\n \"<\": \"<\",\n \">\": \">\",\n '\"': \""\",\n \"'\": \"'\"\n }[c];\n });\n },\n scrollBottom: function scrollBottom() {\n var _this11 = this;\n\n this.$nextTick(function () {\n var el = _this11.$refs.chatBody;\n if (el) el.scrollTop = el.scrollHeight;\n });\n },\n // 用户手动滚动时记录是否仍停留底部;上滚离开底部即暂停自动跟随\n onChatScroll: function onChatScroll() {\n var el = this.$refs.chatBody;\n if (!el) return;\n var nearBottom = el.scrollHeight - el.scrollTop - el.clientHeight < 40;\n this.autoFollow = nearBottom;\n },\n // 仅当用户停留在底部时才自动滚到底,避免回答过程中打断用户向上查看\n followBottom: function followBottom() {\n if (!this.autoFollow) return;\n this.scrollBottom();\n },\n startDrag: function startDrag(e) {\n if (e.button !== undefined && e.button !== 0) return;\n var point = this.point(e);\n if (!point) return;\n this.dragging = true;\n this.moved = false;\n this.tucked = false;\n this.startX = point.clientX;\n this.startY = point.clientY;\n this.startLeft = this.btnLeft;\n this.startBottom = this.btnBottom; // 拖动时防止文本/图片被选中导致跟手中断;\n // 仅鼠标 preventDefault,触摸靠 touch-action:none,避免吞掉点击(打开/收起面板)\n\n if (e.type === \"mousedown\") e.preventDefault();\n },\n onDrag: function onDrag(e) {\n // 若正在拖动弹窗面板,走面板拖拽逻辑\n if (this.panelDragging) {\n this.onPanelDrag(e);\n return;\n }\n\n if (!this.dragging) return;\n var point = this.point(e);\n if (!point) return;\n var dx = point.clientX - this.startX;\n var dy = point.clientY - this.startY;\n\n if (!this.moved && (Math.abs(dx) > 3 || Math.abs(dy) > 3)) {\n this.moved = true;\n }\n\n var box = this.getContainer();\n var maxW = box ? box.clientWidth - 46 : 9999;\n var maxH = box ? box.clientHeight - 44 : 9999;\n var minBottom = this.barBottomOffset();\n var left = Math.max(0, Math.min(this.startLeft + dx, Math.max(0, maxW)));\n var bottom = Math.max(minBottom, Math.min(this.startBottom - dy, Math.max(minBottom, maxH - 8))); // 直接写 DOM,图标即时跟手,不经过 Vue 重渲染\n\n var el = this.$refs.floatEl;\n\n if (el) {\n el.style.left = left + \"px\";\n el.style.bottom = bottom + \"px\";\n }\n\n if (this.panelVisible) {\n this.snapPanel();\n }\n },\n stopDrag: function stopDrag() {},\n endDrag: function endDrag() {\n // 结束弹窗拖拽:记录已手动移动,再次打开保持位置\n if (this.panelDragging) {\n this.panelDragging = false;\n this.panelMoved = true;\n return;\n }\n\n if (!this.dragging) return;\n this.dragging = false;\n if (!this.moved) return; // 读取拖拽后的实际位置\n\n var el = this.$refs.floatEl;\n var left = el ? parseInt(el.style.left || \"0\", 10) : this.btnLeft;\n var bottom = el ? parseInt(el.style.bottom || \"0\", 10) : this.btnBottom;\n this.btnLeft = left;\n this.btnBottom = bottom; // 拖动过才吸附贴边;靠近右边时收成半角标\n\n var box = this.getContainer();\n if (!box) return;\n\n if (box.clientWidth - (left + 46) <= 30) {\n this.tucked = true;\n this.btnLeft = box.clientWidth - 46;\n }\n }\n }\n};\nexports.default = _default;\n\n//# sourceURL=webpack://ZjPluginAiAssistant/./src/lib/components/approvalAi/index.vue?./node_modules/cache-loader/dist/cjs.js??ref--12-0!./node_modules/babel-loader/lib!./node_modules/cache-loader/dist/cjs.js??ref--0-0!./node_modules/vue-loader/lib??vue-loader-options");
|
|
232
|
+
eval("\n\nvar _interopRequireWildcard = __webpack_require__(/*! ./node_modules/@babel/runtime/helpers/interopRequireWildcard */ \"./node_modules/@babel/runtime/helpers/interopRequireWildcard.js\").default;\n\nvar _interopRequireDefault = __webpack_require__(/*! ./node_modules/@babel/runtime/helpers/interopRequireDefault */ \"./node_modules/@babel/runtime/helpers/interopRequireDefault.js\").default;\n\nObject.defineProperty(exports, \"__esModule\", {\n value: true\n});\nexports.default = void 0;\n\nvar _typeof2 = _interopRequireDefault(__webpack_require__(/*! ./node_modules/@babel/runtime/helpers/typeof */ \"./node_modules/@babel/runtime/helpers/typeof.js\"));\n\nvar _createForOfIteratorHelper2 = _interopRequireDefault(__webpack_require__(/*! ./node_modules/@babel/runtime/helpers/createForOfIteratorHelper */ \"./node_modules/@babel/runtime/helpers/createForOfIteratorHelper.js\"));\n\nvar _asyncToGenerator2 = _interopRequireDefault(__webpack_require__(/*! ./node_modules/@babel/runtime/helpers/asyncToGenerator */ \"./node_modules/@babel/runtime/helpers/asyncToGenerator.js\"));\n\nvar _aiAssistant = _interopRequireDefault(__webpack_require__(/*! ./ai-assistant.png */ \"./src/lib/components/approvalAi/ai-assistant.png\"));\n\nvar aiApi = _interopRequireWildcard(__webpack_require__(/*! ./apiApprovalAi */ \"./src/lib/components/approvalAi/apiApprovalAi.js\"));\n\nvar _markdownIt = _interopRequireDefault(__webpack_require__(/*! markdown-it */ \"./node_modules/markdown-it/index.js\"));\n\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\nvar md = new _markdownIt.default({\n html: false,\n linkify: true\n}); // 已知英文编码 -> 中文名称(进包时内嵌,避免依赖宿主项目的 approvalType 常量)\n\nvar VALUE_NAME = {\n comFeePlan: \"公司费用计划\",\n comFeeApplication: \"公司费用\",\n comFeeAccept: \"公司费用验收\",\n comFeeCredit: \"公司费用挂账\",\n comFeePay: \"公司费用支付\",\n employeeHonor: \"员工荣誉\",\n employeeRegularization: \"员工转正\",\n employeeTurnover: \"离职\",\n employeeturnoverhandover: \"离职交接\",\n employeeChangestation: \"调岗\",\n employeeChangesalary: \"调薪\",\n overTimeApply: \"加班\",\n carApproval: \"车辆\",\n reimburse: \"出差报销\",\n leave: \"请假\",\n patch: \"补卡\",\n trip: \"出差\",\n out: \"外出\",\n lan: \"借款\",\n officialDocument: \"公文\",\n notice: \"公告\",\n qgbCompanyPlanSummery: \"公司费用预算汇总\",\n sealApproval: \"印章\"\n}; // 审批状态码 -> 中文(内置映射,替代宿主项目全局 $approvalStatus)\n\nvar STATUS_MAP = {\n \"1\": \"审批中\",\n \"-1\": \"审批中\",\n \"0\": \"已拒绝\",\n \"2\": \"已通过\",\n \"-3\": \"已通过\",\n \"4\": \"草稿\",\n \"3\": \"已通过\",\n \"5\": \"已完成\",\n \"6\": \"已撤销\"\n}; // 概览文案启发式字段匹配\n\nvar FIELD_HINTS = [{\n key: \"applicant\",\n labels: [\"申请人\", \"提交人\", \"经办人\"]\n}, {\n key: \"unit\",\n labels: [\"申请单位\", \"公司\", \"单位\"]\n}, {\n key: \"dept\",\n labels: [\"申请部门\", \"部门\"]\n}, {\n key: \"reason\",\n labels: [\"原因\", \"事由\", \"用途\", \"摘要\", \"标题\", \"说明\", \"内容\", \"目的\"]\n}, {\n key: \"amount\",\n labels: [\"金额\", \"费用\", \"总计\", \"总金额\", \"合计\"]\n}];\n\nfunction normalizeLabel(label) {\n return String(label).trim().replace(/[::]\\s*$/g, \"\");\n}\n\nfunction resolveStatusText(status, override) {\n if (override) return override;\n if (!status && status !== 0) return \"待处理\";\n var mapped = STATUS_MAP[String(status)];\n return mapped || \"未知状态\";\n}\n\nvar msgSeq = 0;\nvar _default = {\n name: \"ApprovalAiAssistant\",\n props: {\n id: {\n type: String,\n default: \"\"\n },\n type: {\n type: String,\n default: \"\"\n },\n status: {\n type: String,\n default: \"0\"\n },\n index: {\n type: Number,\n default: 1\n },\n commentId: {\n type: String,\n default: \"\"\n },\n // ---- 以下为进包后新增的配置项,用于解耦宿主角色的上下文依赖 ----\n // AI 服务基础地址(示例 https://api.xxx.cn),未配置则走本地兜底\n baseUrl: {\n type: String,\n default: \"\"\n },\n // 当前用户信息(替代宿主 Vuex $store.state.user)\n userId: {\n type: String,\n default: \"\"\n },\n userName: {\n type: String,\n default: \"\"\n },\n // 审批状态文案覆盖(默认内置状态码映射;传入则优先使用)\n statusTextOverride: {\n type: String,\n default: \"\"\n },\n // 布局边界选择器(替代硬编码 .approval-content)\n containerSelector: {\n type: String,\n default: \".approval-content\"\n },\n // 详情采集根选择器(替代硬编码 .detail-root)\n detailRootSelector: {\n type: String,\n default: \".detail-root\"\n },\n // 机器人图标,不传时使用包内内置图标\n robotIconUrl: {\n type: String,\n default: \"\"\n },\n // H5 底部操作栏高度(px):作为兜底基准,用于把浮动按钮放在操作栏上方;PC 传 0 不受影响\n bottomBarHeight: {\n type: Number,\n default: 0\n },\n // H5 底部操作栏元素选择器:运行时测量该元素,把悬浮窗放在其正上方,避免遮挡(默认 .btn-wrapper)\n bottomBarSelector: {\n type: String,\n default: \".btn-wrapper\"\n }\n },\n data: function data() {\n return {\n defaultIcon: _aiAssistant.default,\n // 悬浮按钮右上角红点:初始化显示,进入面板后取消\n showRedDot: true,\n panelVisible: false,\n // 首次打开时审批详情/概览仍在加载中的提示开关\n greetingLoading: false,\n // 加载提示文案(拉历史 / 生成概览两个阶段文案不同)\n greetingLoadingText: \"正在加载审批详情\",\n sending: false,\n streaming: false,\n autoFollow: true,\n sessionId: \"\",\n // 会话历史分页状态(GET /chat/history + 上拉加载更早消息)\n histPageNum: 1,\n histPageSize: 20,\n histTotal: 0,\n histHasMore: false,\n loadingHistory: false,\n histLoadedIds: [],\n messages: [],\n fields: [],\n rawDetail: null,\n inputText: \"\",\n btnLeft: 0,\n btnBottom: 340,\n // 弹窗头部拖动:面板位置(PC 用 left + bottom 定位;H5 底部弹出仍走 CSS 固定)\n panelLeft: 0,\n panelBottom: 88,\n panelDragging: false,\n // 用户手动拖动过面板后,再次打开保持该位置(不再吸附到按钮附近)\n panelMoved: false,\n tucked: false,\n dragging: false,\n moved: false,\n isMobile: false,\n startX: 0,\n startY: 0,\n startLeft: 0,\n startBottom: 0\n };\n },\n computed: {\n iconUrl: function iconUrl() {\n return this.robotIconUrl || this.defaultIcon;\n },\n // 面板定位:PC 用 left + bottom 自由拖动;H5 底部弹出仅绑 bottom,\n // left/right/width 交给媒体查询,避免内联 left 覆盖掉 H5 的全宽定位\n panelStyle: function panelStyle() {\n var s = {\n bottom: this.panelBottom + \"px\"\n };\n if (!this.isMobile) s.left = this.panelLeft + \"px\";\n return s;\n },\n typeName: function typeName() {\n if (!this.type) return \"\";\n return VALUE_NAME[this.type] || this.type;\n },\n statusText: function statusText() {\n return resolveStatusText(this.status, this.statusTextOverride);\n },\n statusTone: function statusTone() {\n var t = this.statusText;\n if (t === \"已通过\" || t === \"已完成\") return \"ok\";\n if (t === \"已拒绝\" || t === \"已驳回\" || t === \"已退回\" || t === \"已终止\") return \"no\";\n return \"go\";\n }\n },\n created: function created() {// 注入 AI 服务地址\n },\n mounted: function mounted() {\n var _this = this;\n\n window.addEventListener(\"mousemove\", this.onDrag);\n window.addEventListener(\"mouseup\", this.endDrag);\n this.initMobile();\n this.$nextTick(function () {\n return _this.snapBtn();\n });\n },\n beforeDestroy: function beforeDestroy() {\n window.removeEventListener(\"mousemove\", this.onDrag);\n window.removeEventListener(\"mouseup\", this.endDrag);\n if (this.__mqUnlisten) this.__mqUnlisten();\n },\n watch: {\n // 切换审批单时重置对话上下文\n id: function id() {\n this.sessionId = \"\";\n this.messages = [];\n this.fields = [];\n this.rawDetail = null; // 重置会话历史分页状态\n\n this.histPageNum = 1;\n this.histPageSize = 20;\n this.histTotal = 0;\n this.histHasMore = false;\n this.loadingHistory = false;\n this.histLoadedIds = [];\n this.greetingLoading = false; // 切换审批单时重置面板位置(恢复到默认吸附)\n\n this.panelLeft = 0;\n this.panelBottom = 88;\n this.panelMoved = false;\n },\n // baseUrl 变化时同步注入 AI 服务\n baseUrl: function baseUrl(val) {\n aiApi.configureAI({\n baseUrl: val\n });\n }\n },\n methods: {\n // 统一取鼠标/触摸的坐标点\n point: function point(e) {\n var t = e && e.touches && e.touches[0] || e && e.changedTouches && e.changedTouches[0];\n return t ? {\n clientX: t.clientX,\n clientY: t.clientY\n } : {\n clientX: e.clientX,\n clientY: e.clientY\n };\n },\n // 按钮距容器底部的最小基准:8px + H5 底部操作栏高度,保证按钮在操作栏上方\n baseBottom: function baseBottom() {\n return 8 + (Number(this.bottomBarHeight) || 0);\n },\n // H5 下测量底部操作栏元素,返回“视口底部到该元素顶部”的距离 + 安全边距,\n // 使悬浮窗固定在该元素正上方、不遮挡其展示;PC/找不到时回退到 baseBottom()\n barBottomOffset: function barBottomOffset() {\n if (!this.isMobile) return this.baseBottom();\n var sel = this.bottomBarSelector;\n\n if (sel) {\n var el = null;\n\n try {\n el = document.querySelector(sel);\n } catch (e) {\n el = null;\n }\n\n var rect = el && el.getBoundingClientRect();\n\n if (rect && rect.top >= 0 && rect.top <= window.innerHeight) {\n return window.innerHeight - rect.top + 12;\n }\n }\n\n return this.baseBottom();\n },\n // 是否 H5 窄屏(与 CSS media query 保持一致的 480px 边界)\n initMobile: function initMobile() {\n var _this2 = this;\n\n var mq = window.matchMedia && window.matchMedia(\"(max-width: 480px)\");\n\n var apply = function apply() {\n _this2.isMobile = !mq || mq.matches;\n };\n\n apply();\n if (mq && mq.addEventListener) mq.addEventListener(\"change\", apply);else if (mq && mq.addListener) mq.addListener(apply);\n\n this.__mqUnlisten = function () {\n if (mq && mq.removeEventListener) mq.removeEventListener(\"change\", apply);else if (mq && mq.removeListener) mq.removeListener(apply);\n };\n },\n getContainer: function getContainer() {\n // 普通模式:以配置的审批容器为边界;找不到时回退到父级包裹容器\n var selector = this.containerSelector;\n var el = selector ? this.$el.closest(selector) : null;\n return el || this.$el.parentElement;\n },\n getDetailRoot: function getDetailRoot() {\n var box = this.getContainer();\n if (!box) return null;\n var explicit = this.detailRootSelector ? box.querySelector(this.detailRootSelector) : null;\n if (explicit) return explicit; // 子应用/iframe 模式:容器内可能没有 detail-root 标记,\n // 回退到首个详情子节点(排除 AI 面板自身)\n\n var kids = Array.from(box.children).filter(function (c) {\n return !c.classList.contains(\"ai-assistant\");\n });\n return kids.length ? kids[0] : null;\n },\n togglePanel: function togglePanel() {\n var _this3 = this;\n\n // 拖拽后松手会触发一次 click,这里拦截,避免误展开/收起面板\n if (this.moved) {\n this.moved = false;\n return;\n }\n\n if (this.panelVisible) {\n this.closePanel();\n return;\n }\n\n this.panelVisible = true; // 进入面板后取消红点\n\n this.showRedDot = false;\n this.$nextTick(function () {\n _this3.snapPanel();\n\n if (!_this3.messages.length && !_this3.greetingLoading) {\n _this3.greet();\n }\n\n _this3.scrollBottom();\n\n if (_this3.$refs.input) _this3.$refs.input.focus();\n });\n },\n closePanel: function closePanel() {\n this.panelVisible = false;\n },\n snapBtn: function snapBtn() {\n var box = this.getContainer();\n if (!box) return; // 默认贴右下角完整展开:右侧留 20px\n\n if (!this.tucked && !this.btnLeft) {\n this.btnLeft = Math.max(0, box.clientWidth - 20 - 46);\n } // 若按钮在可视范围外则修正\n\n\n this.btnLeft = Math.max(0, Math.min(this.btnLeft, box.clientWidth - 46));\n this.btnBottom = Math.max(this.barBottomOffset(), Math.min(this.btnBottom, box.clientHeight - 44 - 8));\n },\n snapPanel: function snapPanel() {\n // 用户已手动拖动过面板,再次打开保持其位置,不再吸附到按钮附近\n if (this.panelMoved) return;\n var box = this.getContainer();\n var el = this.$el.querySelector(\".ai-panel\");\n if (!box || !el) return;\n var margin = 24; // 上下安全距离,避免遮挡\n\n var pw = el.clientWidth || 420;\n var ph = el.clientHeight || 560; // 默认 left:面板右上角落在容器右缘外 74px(原 .ai-panel right:74px 的等价值)\n\n if (!this.panelLeft) {\n this.panelLeft = Math.max(0, box.clientWidth - pw - 74);\n }\n\n var desired = this.btnBottom + 62;\n this.panelBottom = Math.max(margin, Math.min(desired, box.clientHeight - ph - margin));\n },\n // 弹窗头部拖拽开始(PC 端可自由拖动;H5 底部弹层保持原定位不参与)\n startPanelDrag: function startPanelDrag(e) {\n if (this.isMobile) return;\n if (e.button !== undefined && e.button !== 0) return;\n var el = this.$el.querySelector(\".ai-panel\");\n if (!el) return;\n var p = this.point(e);\n if (!p) return;\n this.panelDragging = true;\n this._pdStartX = p.clientX;\n this._pdStartY = p.clientY;\n this._pdStartLeft = this.panelLeft || 0;\n this._pdStartBottom = this.panelBottom; // 拖动时防止选中 Header 文字导致跟手中断;仅鼠标 preventDefault\n\n if (e.type === \"mousedown\") e.preventDefault();\n },\n // 弹窗拖拽移动:随鼠标更新 left/bottom,并夹在容器安全边界内\n onPanelDrag: function onPanelDrag(e) {\n if (!this.panelDragging) return;\n var box = this.getContainer();\n if (!box) return;\n var el = this.$el.querySelector(\".ai-panel\");\n var pw = el ? el.clientWidth : 420;\n var ph = el ? el.clientHeight : 560;\n var p = this.point(e) || {};\n var dx = (p.clientX || 0) - this._pdStartX;\n var dy = (p.clientY || 0) - this._pdStartY;\n var maxLeft = Math.max(0, box.clientWidth - pw - 24);\n var maxBottom = Math.max(24, box.clientHeight - ph - 24);\n this.panelLeft = Math.max(0, Math.min(this._pdStartLeft + dx, maxLeft));\n this.panelBottom = Math.max(24, Math.min(this._pdStartBottom - dy, maxBottom));\n },\n // 打开时初始化会话:优先拉取历史问答回显;无历史再走 SSE 总结(本地兜底)\n greet: function greet() {\n var _this4 = this;\n\n return (0, _asyncToGenerator2.default)( /*#__PURE__*/regeneratorRuntime.mark(function _callee() {\n var usedHistory, data, intro;\n return regeneratorRuntime.wrap(function _callee$(_context) {\n while (1) {\n switch (_context.prev = _context.next) {\n case 0:\n if (!_this4.greetingLoading) {\n _context.next = 2;\n break;\n }\n\n return _context.abrupt(\"return\");\n\n case 2:\n _this4.greetingLoading = true;\n _this4.greetingLoadingText = \"正在加载审批详情\";\n _context.prev = 4;\n\n _this4.collectDetail();\n\n usedHistory = false;\n\n if (!(_this4.aiEnabled() && _this4.id)) {\n _context.next = 13;\n break;\n }\n\n _context.next = 10;\n return _this4.loadHistory(1);\n\n case 10:\n data = _context.sent;\n if (data && data.sessionId) _this4.sessionId = data.sessionId;\n\n if (data && Array.isArray(data.records) && data.records.length) {\n // 有历史:回显记录;若后端有共享总结,作为开场白置顶\n data.records.forEach(function (r) {\n _this4.messages.push({\n id: ++msgSeq,\n role: r.role === \"user\" ? \"user\" : \"assistant\",\n content: r.content || \"\"\n });\n\n if (r.id != null && _this4.histLoadedIds.indexOf(r.id) < 0) {\n _this4.histLoadedIds.push(r.id);\n }\n });\n\n if (data.summary && String(data.summary).trim()) {\n intro = \"\\u4F60\\u597D\\uFF0C\\u6211\\u662F AI \\u5BA1\\u6279\\u52A9\\u624B\\uD83D\\uDC4B\\n\\n\\u5DF2\\u7ECF\\u4E3A\\u4F60\\u68B3\\u7406\\u4E86\\u5F53\\u524D\\u5BA1\\u6279\\u7684\\u6982\\u89C8\\uFF1A\\n\\n\";\n\n _this4.messages.unshift({\n id: ++msgSeq,\n role: \"assistant\",\n content: intro + data.summary\n });\n }\n\n usedHistory = true;\n }\n\n case 13:\n if (usedHistory) {\n _context.next = 18;\n break;\n }\n\n _context.next = 16;\n return _this4.greetSummary();\n\n case 16:\n _context.next = 20;\n break;\n\n case 18:\n // 有历史:内容已就绪,关闭 loading\n _this4.greetingLoading = false;\n\n _this4.scrollBottom();\n\n case 20:\n _context.prev = 20;\n // 兜底关闭 loading(总结流内部也会在内容就绪时提前关闭)\n _this4.greetingLoading = false;\n\n _this4.scrollBottom();\n\n return _context.finish(20);\n\n case 24:\n case \"end\":\n return _context.stop();\n }\n }\n }, _callee, null, [[4,, 20, 24]]);\n }))();\n },\n // 无历史时生成开场总结:接入后端走 SSE 流式;否则本地概览兜底。\n // 生成期间保持 loading 提示,首个内容到达后再展示开场语,避免出现只有半句的空气泡\n greetSummary: function greetSummary() {\n var _this5 = this;\n\n return (0, _asyncToGenerator2.default)( /*#__PURE__*/regeneratorRuntime.mark(function _callee2() {\n var localSummary, intro, msg, got;\n return regeneratorRuntime.wrap(function _callee2$(_context2) {\n while (1) {\n switch (_context2.prev = _context2.next) {\n case 0:\n localSummary = _this5.buildSummary();\n intro = \"\\u4F60\\u597D\\uFF0C\\u6211\\u662F AI \\u5BA1\\u6279\\u52A9\\u624B\\uD83D\\uDC4B\\n\\n\\u5DF2\\u7ECF\\u4E3A\\u4F60\\u68B3\\u7406\\u4E86\\u5F53\\u524D\\u5BA1\\u6279\\u7684\\u6982\\u89C8\\uFF1A\\n\\n\";\n\n if (!(_this5.aiEnabled() && _this5.id)) {\n _context2.next = 11;\n break;\n }\n\n _this5.greetingLoadingText = \"正在生成审批概览\";\n msg = null;\n got = false;\n _context2.next = 8;\n return aiApi.streamSummary(_this5.id, {\n onEvent: function onEvent(event, data) {\n if (event === \"answer\" || event === \"agent_result\") {\n got = true;\n\n if (!msg) {\n // 首个增量到达:隐藏 loading,推送开场语气泡,随后增量追加\n _this5.greetingLoading = false;\n msg = {\n id: ++msgSeq,\n role: \"assistant\",\n content: intro\n };\n\n _this5.messages.push(msg);\n }\n\n if (event === \"agent_result\") {\n msg.content = intro + (data || \"\");\n } else {\n msg.content += data;\n }\n\n _this5.followBottom();\n }\n }\n });\n\n case 8:\n // 流式未返回任何内容(失败/空)时回退到本地概览,避免空白\n if (!got) {\n _this5.greetingLoading = false;\n\n _this5.push(\"assistant\", intro + localSummary);\n\n _this5.followBottom();\n }\n\n _context2.next = 14;\n break;\n\n case 11:\n _this5.greetingLoading = false;\n\n _this5.push(\"assistant\", intro + localSummary);\n\n _this5.followBottom();\n\n case 14:\n case \"end\":\n return _context2.stop();\n }\n }\n }, _callee2);\n }))();\n },\n // 拉取会话历史(含分页信息回填)\n loadHistory: function loadHistory(pageNum) {\n var _this6 = this;\n\n return (0, _asyncToGenerator2.default)( /*#__PURE__*/regeneratorRuntime.mark(function _callee3() {\n var u, res;\n return regeneratorRuntime.wrap(function _callee3$(_context3) {\n while (1) {\n switch (_context3.prev = _context3.next) {\n case 0:\n u = _this6.userInfo();\n _context3.next = 3;\n return aiApi.getChatHistory({\n approvalNo: _this6.id,\n userId: u.no,\n userName: u.name,\n pageNum: pageNum,\n pageSize: _this6.histPageSize\n });\n\n case 3:\n res = _context3.sent;\n\n if (!(res && res.data)) {\n _context3.next = 10;\n break;\n }\n\n _this6.histPageNum = res.data.pageNum || pageNum;\n _this6.histPageSize = res.data.pageSize || _this6.histPageSize;\n _this6.histTotal = res.data.total || 0;\n _this6.histHasMore = _this6.histPageNum * _this6.histPageSize < _this6.histTotal;\n return _context3.abrupt(\"return\", res.data);\n\n case 10:\n return _context3.abrupt(\"return\", null);\n\n case 11:\n case \"end\":\n return _context3.stop();\n }\n }\n }, _callee3);\n }))();\n },\n // 上拉分页加载更早的历史消息(前插,并保持当前视口位置)\n loadPrevHistory: function loadPrevHistory() {\n var _this7 = this;\n\n return (0, _asyncToGenerator2.default)( /*#__PURE__*/regeneratorRuntime.mark(function _callee4() {\n var el, prevHeight, data, older;\n return regeneratorRuntime.wrap(function _callee4$(_context4) {\n while (1) {\n switch (_context4.prev = _context4.next) {\n case 0:\n if (!(_this7.loadingHistory || !_this7.histHasMore)) {\n _context4.next = 2;\n break;\n }\n\n return _context4.abrupt(\"return\");\n\n case 2:\n if (!(!_this7.aiEnabled() || !_this7.id)) {\n _context4.next = 4;\n break;\n }\n\n return _context4.abrupt(\"return\");\n\n case 4:\n _this7.loadingHistory = true;\n el = _this7.$refs.chatBody;\n prevHeight = el ? el.scrollHeight : 0;\n _context4.prev = 7;\n _context4.next = 10;\n return _this7.loadHistory(_this7.histPageNum + 1);\n\n case 10:\n data = _context4.sent;\n\n if (data && Array.isArray(data.records) && data.records.length) {\n // 前插更早记录并按其服务端 id 去重,防止后端重叠页/重复 id 造成重复展示\n older = [];\n data.records.forEach(function (r) {\n if (r.id != null && _this7.histLoadedIds.indexOf(r.id) >= 0) return;\n if (r.id != null) _this7.histLoadedIds.push(r.id);\n older.push({\n id: ++msgSeq,\n role: r.role === \"user\" ? \"user\" : \"assistant\",\n content: r.content || \"\"\n });\n });\n if (older.length) _this7.messages = older.concat(_this7.messages);\n }\n\n _this7.$nextTick(function () {\n var el2 = _this7.$refs.chatBody;\n if (el2) el2.scrollTop = el2.scrollHeight - prevHeight;\n });\n\n case 13:\n _context4.prev = 13;\n _this7.loadingHistory = false;\n return _context4.finish(13);\n\n case 16:\n case \"end\":\n return _context4.stop();\n }\n }\n }, _callee4, null, [[7,, 13, 16]]);\n }))();\n },\n quickAsk: function quickAsk(q) {\n this.inputText = q;\n this.sendMessage();\n },\n // 审批详情气泡内的链接禁止跳转(markdown 渲染出的 <a> 不触发页面跳转)\n onBubbleClick: function onBubbleClick(e) {\n var el = e.target;\n var link = el && el.closest ? el.closest(\"a\") : null;\n if (!link) return;\n e.preventDefault();\n e.stopPropagation();\n },\n sendMessage: function sendMessage() {\n var _this8 = this;\n\n var text = (this.inputText || \"\").trim();\n if (!text || this.sending) return; // 审批概览生成期间禁止提问:避免总结流与问答流并发,\n // 造成消息顺序错乱、滚动相互抢占,以及后端同单总结未完成时问答排队/上下文不完整\n\n if (this.greetingLoading) return;\n this.push(\"user\", text);\n this.inputText = \"\";\n this.sending = true;\n this.collectDetail(); // 直接走后端流式问答(已接入时);未接入则返回本地兜底\n\n var msg = null;\n\n if (this.aiEnabled() && this.id) {\n msg = {\n id: ++msgSeq,\n role: \"assistant\",\n content: \"\"\n };\n this.messages.push(msg);\n this.streaming = true;\n this.scrollBottom();\n }\n\n this.getReply(text, function (chunk) {\n if (msg) {\n msg.content += chunk;\n\n _this8.followBottom();\n }\n }).then(function (reply) {\n if (msg) {\n if (!msg.content) msg.content = reply || _this8.fallbackReply(text);\n } else {\n _this8.push(\"assistant\", _this8.fallbackReply(text));\n }\n\n _this8.streaming = false;\n _this8.sending = false;\n\n _this8.followBottom();\n });\n },\n // 获取 AI 回复:已接入后端走流式接口;未接入时返回本地兜底\n getReply: function getReply(question, onDelta) {\n var _this9 = this;\n\n return (0, _asyncToGenerator2.default)( /*#__PURE__*/regeneratorRuntime.mark(function _callee5() {\n var payload, aiReply;\n return regeneratorRuntime.wrap(function _callee5$(_context5) {\n while (1) {\n switch (_context5.prev = _context5.next) {\n case 0:\n payload = {\n context: {\n type: _this9.type,\n status: _this9.status,\n typeName: _this9.typeName,\n id: _this9.id,\n summary: _this9.buildSummary(),\n fields: _this9.fields,\n detailData: _this9.rawDetail\n },\n question: question\n };\n _context5.next = 3;\n return _this9.requestAi(payload, onDelta);\n\n case 3:\n aiReply = _context5.sent;\n return _context5.abrupt(\"return\", aiReply && String(aiReply).trim() ? String(aiReply) : _this9.fallbackReply(question));\n\n case 5:\n case \"end\":\n return _context5.stop();\n }\n }\n }, _callee5);\n }))();\n },\n // AI 后端是否可用\n aiEnabled: function aiEnabled() {\n return aiApi.aiConfigured() && Boolean(this.id);\n },\n // 当前用户信息(来自 props,替代宿主 Vuex)\n userInfo: function userInfo() {\n return {\n no: this.userId || \"\",\n name: this.userName || \"\"\n };\n },\n // 创建/复用 AI 对话会话\n ensureSession: function ensureSession() {\n var _this10 = this;\n\n return (0, _asyncToGenerator2.default)( /*#__PURE__*/regeneratorRuntime.mark(function _callee6() {\n var u, res;\n return regeneratorRuntime.wrap(function _callee6$(_context6) {\n while (1) {\n switch (_context6.prev = _context6.next) {\n case 0:\n if (!_this10.sessionId) {\n _context6.next = 2;\n break;\n }\n\n return _context6.abrupt(\"return\", _this10.sessionId);\n\n case 2:\n u = _this10.userInfo();\n _context6.next = 5;\n return aiApi.createChatSession({\n approvalNo: _this10.id,\n userId: u.no,\n userName: u.name\n });\n\n case 5:\n res = _context6.sent;\n\n if (!(res && res.data && res.data.sessionId)) {\n _context6.next = 9;\n break;\n }\n\n _this10.sessionId = res.data.sessionId;\n return _context6.abrupt(\"return\", _this10.sessionId);\n\n case 9:\n return _context6.abrupt(\"return\", \"\");\n\n case 10:\n case \"end\":\n return _context6.stop();\n }\n }\n }, _callee6);\n }))();\n },\n // 对接后端 AI 流式问答接口:创建会话 + SSE 实时增量;异常时返回 null\n requestAi: function requestAi(payload, onDelta) {\n var _this11 = this;\n\n return (0, _asyncToGenerator2.default)( /*#__PURE__*/regeneratorRuntime.mark(function _callee7() {\n var sessionId, text, failed;\n return regeneratorRuntime.wrap(function _callee7$(_context7) {\n while (1) {\n switch (_context7.prev = _context7.next) {\n case 0:\n if (_this11.aiEnabled()) {\n _context7.next = 2;\n break;\n }\n\n return _context7.abrupt(\"return\", null);\n\n case 2:\n _context7.prev = 2;\n _context7.next = 5;\n return _this11.ensureSession();\n\n case 5:\n sessionId = _context7.sent;\n\n if (sessionId) {\n _context7.next = 8;\n break;\n }\n\n return _context7.abrupt(\"return\", null);\n\n case 8:\n text = \"\";\n failed = false;\n _context7.next = 12;\n return aiApi.streamChat({\n sessionId: sessionId,\n message: payload.question,\n userId: _this11.userInfo().no,\n userName: _this11.userInfo().name,\n onEvent: function onEvent(event, data) {\n if (event === \"reasoning\" || event === \"answer\") {\n text += data;\n if (onDelta) onDelta(data);\n } else if (event === \"agent_result\") {\n text = data;\n } else if (event === \"error\") {\n failed = true;\n }\n }\n });\n\n case 12:\n if (!failed) {\n _context7.next = 14;\n break;\n }\n\n return _context7.abrupt(\"return\", null);\n\n case 14:\n return _context7.abrupt(\"return\", text && text.trim() ? text : null);\n\n case 17:\n _context7.prev = 17;\n _context7.t0 = _context7[\"catch\"](2);\n return _context7.abrupt(\"return\", null);\n\n case 20:\n case \"end\":\n return _context7.stop();\n }\n }\n }, _callee7, null, [[2, 17]]);\n }))();\n },\n // 无法从数据中检索到时的兜底:诚实告知查询不到,不编造\n fallbackReply: function fallbackReply(question) {\n var q = String(question).trim();\n var list = '';\n return \"\\u6682\\u65F6\\u65E0\\u6CD5\\u67E5\\u8BE2\\u5230\\u4E0E\\u300C\".concat(q, \"\\u300D\\u5BF9\\u5E94\\u7684\\u4FE1\\u606F\\u3002\").concat(list);\n },\n findField: function findField(labels) {\n var _iterator = (0, _createForOfIteratorHelper2.default)(this.rawEntries()),\n _step;\n\n try {\n var _loop = function _loop() {\n var e = _step.value;\n if (labels.some(function (l) {\n return e.label.indexOf(l) > -1;\n })) return {\n v: e.value\n };\n };\n\n for (_iterator.s(); !(_step = _iterator.n()).done;) {\n var _ret = _loop();\n\n if ((0, _typeof2.default)(_ret) === \"object\") return _ret.v;\n }\n } catch (err) {\n _iterator.e(err);\n } finally {\n _iterator.f();\n }\n\n return \"\";\n },\n // 合并 DOM 采集字段 + 详情页完整原始业务对象,得到可检索的条目\n rawEntries: function rawEntries() {\n var _this12 = this;\n\n var list = [];\n var seen = new Set();\n\n var pushEntry = function pushEntry(label, value) {\n var v = _this12.stringify(value);\n\n if (!v) return;\n var k = \"\".concat(label, \"__\").concat(v);\n if (seen.has(k)) return;\n seen.add(k);\n list.push({\n label: label,\n value: v\n });\n };\n\n var _iterator2 = (0, _createForOfIteratorHelper2.default)(this.fields),\n _step2;\n\n try {\n for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {\n var f = _step2.value;\n pushEntry(f.label, f.value);\n }\n } catch (err) {\n _iterator2.e(err);\n } finally {\n _iterator2.f();\n }\n\n var raw = this.rawDetail && this.rawDetail.data;\n\n if (raw && (0, _typeof2.default)(raw) === \"object\") {\n for (var _i = 0, _Object$keys = Object.keys(raw); _i < _Object$keys.length; _i++) {\n var key = _Object$keys[_i];\n pushEntry(key, raw[key]);\n }\n }\n\n return list;\n },\n stringify: function stringify(v) {\n if (v === null || v === undefined) return \"\";\n\n if ((0, _typeof2.default)(v) === \"object\") {\n try {\n return JSON.stringify(v);\n } catch (e) {\n return \"\";\n }\n }\n\n return String(v);\n },\n // 通用采集详情页数据:兼容 el-form-item / el-descriptions / 自定义 span标签:值 / 表格,\n // 并尽量读取详情页组件的原始业务对象(info/form) 作为完整数据\n collectDetail: function collectDetail() {\n var root = this.getDetailRoot();\n var seen = {};\n\n var push = function push(label, value) {\n label = normalizeLabel(label);\n var v = String(value === null || value === undefined ? \"\" : value).replace(/\\s+/g, \" \").trim();\n if (!label || !v || v === \"暂无\" || label === \"图片\" || label === \"操作\") return;\n if (seen[label] !== undefined) return;\n seen[label] = v;\n };\n\n if (root) {\n // 1) el-form-item\n root.querySelectorAll(\".el-form-item\").forEach(function (item) {\n var labelEl = item.querySelector(\".el-form-item__label\");\n var contentEl = item.querySelector(\".el-form-item__content\");\n if (labelEl && contentEl) push(labelEl.textContent, contentEl.textContent);\n }); // 2) el-descriptions 描述项\n\n root.querySelectorAll(\".el-descriptions-item\").forEach(function (item) {\n var labelEl = item.querySelector(\".el-descriptions-item__label\");\n var contentEl = item.querySelector(\".el-descriptions-item__content\");\n if (labelEl && contentEl) push(labelEl.textContent, contentEl.textContent);\n }); // 3) 自定义 label:value(span 以「:」/「:」结尾,值在大括号内剩余文本)\n\n root.querySelectorAll(\"span\").forEach(function (span) {\n var txt = (span.textContent || \"\").trim();\n var m = txt.match(/^(.+?)([::])$/);\n if (!m) return;\n var parent = span.parentElement;\n if (!parent) return;\n var value = (parent.textContent || \"\").replace(txt, \"\").replace(/\\s+/g, \" \").trim();\n push(m[1], value);\n }); // 4) 表格:表头 -> 逐行数据\n\n root.querySelectorAll(\"table\").forEach(function (table) {\n var rows = table.querySelectorAll(\"tr\");\n var headers = [];\n\n if (rows.length) {\n headers = Array.from(rows[0].querySelectorAll(\"th,td\")).map(function (c) {\n return normalizeLabel(c.textContent);\n });\n }\n\n rows.forEach(function (tr, idx) {\n if (idx === 0) return;\n var cells = Array.from(tr.querySelectorAll(\"th,td\")).map(function (c) {\n return (c.textContent || \"\").replace(/\\s+/g, \" \").trim();\n });\n if (!cells.length) return;\n\n if (headers.length) {\n headers.forEach(function (h, j) {\n return h && cells[j] !== undefined && push(h, cells[j]);\n });\n } else {\n cells.forEach(function (c, j) {\n return c && push(\"\\u7B2C\".concat(idx, \"\\u884C\\u5B57\\u6BB5\").concat(j + 1), c);\n });\n }\n });\n });\n } // 5) 读取详情组件的原始业务对象,作为完整结构化数据补全\n\n\n var raw = this.readRawDetail();\n this.rawDetail = raw;\n if (raw) this.flattenTo(seen, raw);\n this.fields = Object.keys(seen).map(function (label) {\n return {\n label: label,\n value: seen[label]\n };\n }).slice(0, 40);\n },\n // 寻找详情页组件的业务数据对象(info / form 等)\n readRawDetail: function readRawDetail() {\n var _this13 = this;\n\n var root = this.getDetailRoot();\n if (!root) return null;\n\n var _iterator3 = (0, _createForOfIteratorHelper2.default)(root.querySelectorAll(\"*\")),\n _step3;\n\n try {\n for (_iterator3.s(); !(_step3 = _iterator3.n()).done;) {\n var el = _step3.value;\n var vm = el.__vue__;\n if (!vm || !vm.$data || (0, _typeof2.default)(vm.$data) !== \"object\") continue;\n var d = vm.$data;\n\n var _loop2 = function _loop2() {\n var key = _arr[_i2];\n var obj = d[key];\n\n if (obj && (0, _typeof2.default)(obj) === \"object\" && !Array.isArray(obj)) {\n var keys = Object.keys(obj).filter(function (k) {\n return obj[k] !== \"\" && obj[k] !== null && obj[k] !== undefined;\n });\n\n if (keys.length) {\n return {\n v: {\n key: key,\n data: _this13.jsonSafe(obj)\n }\n };\n }\n }\n };\n\n for (var _i2 = 0, _arr = [\"info\", \"form\"]; _i2 < _arr.length; _i2++) {\n var _ret2 = _loop2();\n\n if ((0, _typeof2.default)(_ret2) === \"object\") return _ret2.v;\n }\n }\n } catch (err) {\n _iterator3.e(err);\n } finally {\n _iterator3.f();\n }\n\n return null;\n },\n jsonSafe: function jsonSafe(obj) {\n try {\n return JSON.parse(JSON.stringify(obj, function (k, v) {\n return typeof v === \"function\" ? undefined : v;\n }));\n } catch (e) {\n return obj;\n }\n },\n // 把原始业务对象摊平成 label:value,补进已采集集合\n flattenTo: function flattenTo(seen, raw) {\n var walk = function walk(obj, path) {\n if (obj === null || obj === undefined) return;\n\n if (Array.isArray(obj)) {\n obj.forEach(function (item, i) {\n return walk(item, path ? \"\".concat(path, \"[\").concat(i, \"]\") : \"[\".concat(i, \"]\"));\n });\n return;\n }\n\n if ((0, _typeof2.default)(obj) === \"object\") {\n Object.keys(obj).forEach(function (k) {\n return walk(obj[k], path ? \"\".concat(path, \".\").concat(k) : k);\n });\n return;\n }\n\n var label = path || \"\";\n var v = String(obj).replace(/\\s+/g, \" \").trim();\n if (label && v && seen[label] === undefined) seen[label] = v;\n };\n\n walk(raw.data, raw.key);\n },\n // 依据采集字段生成“当前审批是做什么的”概览(启发式)\n buildSummary: function buildSummary() {\n var hits = {};\n FIELD_HINTS.forEach(function (hint) {\n hits[hint.key] = \"\";\n });\n this.fields.forEach(function (f) {\n var _iterator4 = (0, _createForOfIteratorHelper2.default)(FIELD_HINTS),\n _step4;\n\n try {\n for (_iterator4.s(); !(_step4 = _iterator4.n()).done;) {\n var hint = _step4.value;\n if (hits[hint.key]) continue;\n\n if (hint.labels.some(function (l) {\n return f.label.indexOf(l) > -1;\n })) {\n hits[hint.key] = f.value;\n break;\n }\n }\n } catch (err) {\n _iterator4.e(err);\n } finally {\n _iterator4.f();\n }\n });\n var name = this.typeName || \"该单据\";\n var parts = [];\n if (hits.applicant) parts.push(\"\\u7533\\u8BF7\\u4EBA\\u300C\".concat(hits.applicant, \"\\u300D\"));\n if (hits.unit) parts.push(\"\\u6240\\u5C5E\\u5355\\u4F4D\\u300C\".concat(hits.unit, \"\\u300D\"));\n var verb = \"\".concat(name === \"该单据\" ? \"该审批\" : \"\\u8BE5\\u300C\".concat(name, \"\\u300D\\u5BA1\\u6279\"));\n var summary = \"\".concat(verb, \"\\u662F\\u4E00\\u7B14\\u4E1A\\u52A1\\u5BA1\\u6279\");\n if (parts.length) summary += \"\\uFF0C\\u7531\".concat(parts.join(\",\"), \"\\u53D1\\u8D77\");\n if (hits.reason) summary += \"\\uFF0C\\u4E3B\\u8981\\u4E8B\\u7531\\uFF1A\".concat(hits.reason);\n if (hits.amount) summary += \"\\uFF0C\\u6D89\\u53CA\\u91D1\\u989D\\u300C\".concat(hits.amount, \"\\u300D\");\n summary += \"\\u3002\\u5F53\\u524D\\u5BA1\\u6279\\u72B6\\u6001\\u4E3A\\u300C\".concat(this.statusText, \"\\u300D\\u3002\");\n return summary;\n },\n push: function push(role, content) {\n this.messages.push({\n id: ++msgSeq,\n role: role,\n content: content\n });\n },\n // 气泡渲染:助手消息转 Markdown,用户消息按纯文本处理(转义防 XSS)\n renderBubble: function renderBubble(m) {\n var text = m && m.content != null ? String(m.content) : \"\";\n if (m && m.role === \"user\") return this.escapeHtml(text);\n return md.render(text || \"\");\n },\n escapeHtml: function escapeHtml(str) {\n return String(str).replace(/[&<>\"']/g, function (c) {\n return {\n \"&\": \"&\",\n \"<\": \"<\",\n \">\": \">\",\n '\"': \""\",\n \"'\": \"'\"\n }[c];\n });\n },\n scrollBottom: function scrollBottom() {\n var _this14 = this;\n\n this.$nextTick(function () {\n var el = _this14.$refs.chatBody;\n if (el) el.scrollTop = el.scrollHeight;\n });\n },\n // 用户手动滚动时记录是否仍停留底部;上滚离开底部即暂停自动跟随\n onChatScroll: function onChatScroll() {\n var el = this.$refs.chatBody;\n if (!el) return;\n var nearBottom = el.scrollHeight - el.scrollTop - el.clientHeight < 40;\n this.autoFollow = nearBottom; // 上拉到顶部时加载更早的历史消息\n\n if (!this.loadingHistory && this.histHasMore && el.scrollTop < 60) {\n this.loadPrevHistory();\n }\n },\n // 仅当用户停留在底部时才自动滚到底,避免回答过程中打断用户向上查看\n followBottom: function followBottom() {\n if (!this.autoFollow) return;\n this.scrollBottom();\n },\n startDrag: function startDrag(e) {\n if (e.button !== undefined && e.button !== 0) return;\n var point = this.point(e);\n if (!point) return;\n this.dragging = true;\n this.moved = false;\n this.tucked = false;\n this.startX = point.clientX;\n this.startY = point.clientY;\n this.startLeft = this.btnLeft;\n this.startBottom = this.btnBottom; // 拖动时防止文本/图片被选中导致跟手中断;\n // 仅鼠标 preventDefault,触摸靠 touch-action:none,避免吞掉点击(打开/收起面板)\n\n if (e.type === \"mousedown\") e.preventDefault();\n },\n onDrag: function onDrag(e) {\n // 若正在拖动弹窗面板,走面板拖拽逻辑\n if (this.panelDragging) {\n this.onPanelDrag(e);\n return;\n }\n\n if (!this.dragging) return;\n var point = this.point(e);\n if (!point) return;\n var dx = point.clientX - this.startX;\n var dy = point.clientY - this.startY;\n\n if (!this.moved && (Math.abs(dx) > 3 || Math.abs(dy) > 3)) {\n this.moved = true;\n }\n\n var box = this.getContainer();\n var maxW = box ? box.clientWidth - 46 : 9999;\n var maxH = box ? box.clientHeight - 44 : 9999;\n var minBottom = this.barBottomOffset();\n var left = Math.max(0, Math.min(this.startLeft + dx, Math.max(0, maxW)));\n var bottom = Math.max(minBottom, Math.min(this.startBottom - dy, Math.max(minBottom, maxH - 8))); // 直接写 DOM,图标即时跟手,不经过 Vue 重渲染\n\n var el = this.$refs.floatEl;\n\n if (el) {\n el.style.left = left + \"px\";\n el.style.bottom = bottom + \"px\";\n }\n\n if (this.panelVisible) {\n this.snapPanel();\n }\n },\n stopDrag: function stopDrag() {},\n endDrag: function endDrag() {\n // 结束弹窗拖拽:记录已手动移动,再次打开保持位置\n if (this.panelDragging) {\n this.panelDragging = false;\n this.panelMoved = true;\n return;\n }\n\n if (!this.dragging) return;\n this.dragging = false;\n if (!this.moved) return; // 读取拖拽后的实际位置\n\n var el = this.$refs.floatEl;\n var left = el ? parseInt(el.style.left || \"0\", 10) : this.btnLeft;\n var bottom = el ? parseInt(el.style.bottom || \"0\", 10) : this.btnBottom;\n this.btnLeft = left;\n this.btnBottom = bottom; // 拖动过才吸附贴边;靠近右边时收成半角标\n\n var box = this.getContainer();\n if (!box) return;\n\n if (box.clientWidth - (left + 46) <= 30) {\n this.tucked = true;\n this.btnLeft = box.clientWidth - 46;\n }\n }\n }\n};\nexports.default = _default;\n\n//# sourceURL=webpack://ZjPluginAiAssistant/./src/lib/components/approvalAi/index.vue?./node_modules/cache-loader/dist/cjs.js??ref--12-0!./node_modules/babel-loader/lib!./node_modules/cache-loader/dist/cjs.js??ref--0-0!./node_modules/vue-loader/lib??vue-loader-options");
|
|
233
233
|
|
|
234
234
|
/***/ }),
|
|
235
235
|
|
|
@@ -241,7 +241,18 @@ eval("\n\nvar _interopRequireWildcard = __webpack_require__(/*! ./node_modules/@
|
|
|
241
241
|
/***/ (function(module, __webpack_exports__, __webpack_require__) {
|
|
242
242
|
|
|
243
243
|
"use strict";
|
|
244
|
-
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"render\", function() { return render; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"staticRenderFns\", function() { return staticRenderFns; });\nvar render = function() {\n var _vm = this\n var _h = _vm.$createElement\n var _c = _vm._self._c || _h\n return _c(\n \"div\",\n { staticClass: \"ai-assistant\" },\n [\n _vm.panelVisible && _vm.isMobile\n ? _c(\"div\", { staticClass: \"ai-mask\", on: { click: _vm.closePanel } })\n : _vm._e(),\n _c(\"transition\", { attrs: { name: \"ai-fade\" } }, [\n _vm.panelVisible\n ? _c(\n \"div\",\n {\n staticClass: \"ai-panel\",\n class: { dragging: _vm.panelDragging },\n style: _vm.panelStyle,\n on: {\n click: function($event) {\n $event.stopPropagation()\n }\n }\n },\n [\n _c(\n \"div\",\n {\n staticClass: \"ai-panel__header\",\n on: { mousedown: _vm.startPanelDrag }\n },\n [\n _c(\"span\", { staticClass: \"ai-panel__icon\" }, [\n _c(\"img\", { attrs: { src: _vm.iconUrl, alt: \"AI\" } })\n ]),\n _c(\"span\", { staticClass: \"ai-panel__title\" }, [\n _vm._v(\"AI 审批助手\")\n ]),\n _c(\n \"span\",\n {\n staticClass: \"ai-panel__status\",\n class: \"status-\" + _vm.statusTone\n },\n [_vm._v(_vm._s(_vm.statusText))]\n ),\n _c(\n \"span\",\n {\n staticClass: \"ai-panel__close\",\n on: { click: _vm.closePanel }\n },\n [_vm._v(\"✕\")]\n )\n ]\n ),\n _c(\n \"div\",\n {\n ref: \"chatBody\",\n staticClass: \"ai-chat\",\n on: {\n \"&scroll\": function($event) {\n return _vm.onChatScroll.apply(null, arguments)\n }\n }\n },\n [\n _vm._l(_vm.messages, function(m) {\n return [\n _c(\n \"div\",\n {\n key: m.id,\n staticClass: \"msg\",\n class: \"msg--\" + m.role\n },\n [\n m.role === \"assistant\"\n ? _c(\"div\", { staticClass: \"msg__avatar\" }, [\n _c(\"img\", {\n attrs: { src: _vm.iconUrl, alt: \"AI\" }\n })\n ])\n : _vm._e(),\n _c(\"div\", {\n staticClass: \"msg__bubble\",\n domProps: {\n innerHTML: _vm._s(_vm.renderBubble(m))\n },\n on: { click: _vm.onBubbleClick }\n })\n ]\n )\n ]\n }),\n _vm.sending && !_vm.streaming\n ? _c(\"div\", { staticClass: \"msg msg--assistant\" }, [\n _c(\"div\", { staticClass: \"msg__avatar\" }, [\n _c(\"img\", {\n attrs: { src: _vm.iconUrl, alt: \"AI\" }\n })\n ]),\n _c(\n \"div\",\n { staticClass: \"msg__bubble msg__bubble--typing\" },\n [_c(\"span\"), _c(\"span\"), _c(\"span\")]\n )\n ])\n : _vm._e(),\n _vm.greetingLoading\n ? _c(\"div\", { staticClass: \"msg msg--assistant\" }, [\n _c(\"div\", { staticClass: \"msg__avatar\" }, [\n _c(\"img\", {\n attrs: { src: _vm.iconUrl, alt: \"AI\" }\n })\n ]),\n _c(\n \"div\",\n { staticClass: \"msg__bubble msg__bubble--loading\" },\n [\n _c(\"span\", { staticClass: \"loading-text\" }, [\n _vm._v(\"正在加载审批详情\")\n ]),\n _c(\"span\", { staticClass: \"loading-dots\" }, [\n _c(\"i\"),\n _c(\"i\"),\n _c(\"i\")\n ])\n ]\n )\n ])\n : _vm._e()\n ],\n 2\n ),\n _c(\"div\", { staticClass: \"ai-input\" }, [\n _c(\"textarea\", {\n directives: [\n {\n name: \"model\",\n rawName: \"v-model\",\n value: _vm.inputText,\n expression: \"inputText\"\n }\n ],\n ref: \"input\",\n staticClass: \"ai-input__box\",\n attrs: { rows: \"1\", placeholder: \"输入你的问题\" },\n domProps: { value: _vm.inputText },\n on: {\n keydown: function($event) {\n if (\n !$event.type.indexOf(\"key\") &&\n _vm._k(\n $event.keyCode,\n \"enter\",\n 13,\n $event.key,\n \"Enter\"\n )\n ) {\n return null\n }\n if (\n $event.ctrlKey ||\n $event.shiftKey ||\n $event.altKey ||\n $event.metaKey\n ) {\n return null\n }\n $event.preventDefault()\n return _vm.sendMessage.apply(null, arguments)\n },\n input: function($event) {\n if ($event.target.composing) {\n return\n }\n _vm.inputText = $event.target.value\n }\n }\n }),\n _c(\n \"button\",\n {\n staticClass: \"ai-input__send\",\n attrs: { disabled: _vm.sending || !_vm.inputText.trim() },\n on: { click: _vm.sendMessage }\n },\n [_vm._v(\"发送\")]\n )\n ])\n ]\n )\n : _vm._e()\n ]),\n _c(\n \"div\",\n {\n ref: \"floatEl\",\n staticClass: \"ai-float\",\n class: {\n tucked: _vm.tucked,\n \"is-open\": _vm.panelVisible,\n dragging: _vm.dragging\n },\n style: { left: _vm.btnLeft + \"px\", bottom: _vm.btnBottom + \"px\" },\n on: {\n mousedown: _vm.startDrag,\n touchstart: _vm.startDrag,\n touchmove: _vm.onDrag,\n touchend: _vm.endDrag,\n touchcancel: _vm.endDrag\n }\n },\n [\n _c(\n \"button\",\n {\n staticClass: \"ai-float__btn\",\n class: { \"is-active\": _vm.panelVisible },\n attrs: {\n title: _vm.panelVisible ? \"收起 AI 助手\" : \"打开 AI 助手\"\n },\n on: { click: _vm.togglePanel, mouseup: _vm.stopDrag }\n },\n [\n _c(\"img\", {\n staticClass: \"ai-float__img\",\n attrs: { src: _vm.iconUrl, alt: \"AI\" }\n }),\n _vm.showRedDot\n ? _c(\"span\", { staticClass: \"ai-float__dot\" })\n : _vm._e()\n ]\n )\n ]\n )\n ],\n 1\n )\n}\nvar staticRenderFns = []\nrender._withStripped = true\n\n\n\n//# sourceURL=webpack://ZjPluginAiAssistant/./src/lib/components/approvalAi/index.vue?./node_modules/cache-loader/dist/cjs.js?%7B%22cacheDirectory%22:%22node_modules/.cache/vue-loader%22,%22cacheIdentifier%22:%22361a8753-vue-loader-template%22%7D!./node_modules/vue-loader/lib/loaders/templateLoader.js??vue-loader-options!./node_modules/cache-loader/dist/cjs.js??ref--0-0!./node_modules/vue-loader/lib??vue-loader-options");
|
|
244
|
+
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"render\", function() { return render; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"staticRenderFns\", function() { return staticRenderFns; });\nvar render = function() {\n var _vm = this\n var _h = _vm.$createElement\n var _c = _vm._self._c || _h\n return _c(\n \"div\",\n { staticClass: \"ai-assistant\" },\n [\n _vm.panelVisible && _vm.isMobile\n ? _c(\"div\", { staticClass: \"ai-mask\", on: { click: _vm.closePanel } })\n : _vm._e(),\n _c(\"transition\", { attrs: { name: \"ai-fade\" } }, [\n _vm.panelVisible\n ? _c(\n \"div\",\n {\n staticClass: \"ai-panel\",\n class: { dragging: _vm.panelDragging },\n style: _vm.panelStyle,\n on: {\n click: function($event) {\n $event.stopPropagation()\n }\n }\n },\n [\n _c(\n \"div\",\n {\n staticClass: \"ai-panel__header\",\n on: { mousedown: _vm.startPanelDrag }\n },\n [\n _c(\"span\", { staticClass: \"ai-panel__icon\" }, [\n _c(\"img\", { attrs: { src: _vm.iconUrl, alt: \"AI\" } })\n ]),\n _c(\"span\", { staticClass: \"ai-panel__title\" }, [\n _vm._v(\"AI 审批助手\")\n ]),\n _c(\n \"span\",\n {\n staticClass: \"ai-panel__status\",\n class: \"status-\" + _vm.statusTone\n },\n [_vm._v(_vm._s(_vm.statusText))]\n ),\n _c(\n \"span\",\n {\n staticClass: \"ai-panel__close\",\n on: { click: _vm.closePanel }\n },\n [_vm._v(\"✕\")]\n )\n ]\n ),\n _c(\n \"div\",\n {\n ref: \"chatBody\",\n staticClass: \"ai-chat\",\n on: {\n \"&scroll\": function($event) {\n return _vm.onChatScroll.apply(null, arguments)\n }\n }\n },\n [\n _vm.loadingHistory\n ? _c(\"div\", { staticClass: \"msg-loading-more\" }, [\n _vm._v(\"加载更早消息…\")\n ])\n : _vm._e(),\n _vm._l(_vm.messages, function(m) {\n return [\n _c(\n \"div\",\n {\n key: m.id,\n staticClass: \"msg\",\n class: \"msg--\" + m.role\n },\n [\n m.role === \"assistant\"\n ? _c(\"div\", { staticClass: \"msg__avatar\" }, [\n _c(\"img\", {\n attrs: { src: _vm.iconUrl, alt: \"AI\" }\n })\n ])\n : _vm._e(),\n _c(\"div\", {\n staticClass: \"msg__bubble\",\n domProps: {\n innerHTML: _vm._s(_vm.renderBubble(m))\n },\n on: { click: _vm.onBubbleClick }\n })\n ]\n )\n ]\n }),\n _vm.sending && !_vm.streaming\n ? _c(\"div\", { staticClass: \"msg msg--assistant\" }, [\n _c(\"div\", { staticClass: \"msg__avatar\" }, [\n _c(\"img\", {\n attrs: { src: _vm.iconUrl, alt: \"AI\" }\n })\n ]),\n _c(\n \"div\",\n { staticClass: \"msg__bubble msg__bubble--typing\" },\n [_c(\"span\"), _c(\"span\"), _c(\"span\")]\n )\n ])\n : _vm._e(),\n _vm.greetingLoading\n ? _c(\"div\", { staticClass: \"msg msg--assistant\" }, [\n _c(\"div\", { staticClass: \"msg__avatar\" }, [\n _c(\"img\", {\n attrs: { src: _vm.iconUrl, alt: \"AI\" }\n })\n ]),\n _c(\n \"div\",\n { staticClass: \"msg__bubble msg__bubble--loading\" },\n [\n _c(\"span\", { staticClass: \"loading-text\" }, [\n _vm._v(_vm._s(_vm.greetingLoadingText))\n ]),\n _c(\"span\", { staticClass: \"loading-dots\" }, [\n _c(\"i\"),\n _c(\"i\"),\n _c(\"i\")\n ])\n ]\n )\n ])\n : _vm._e()\n ],\n 2\n ),\n _c(\"div\", { staticClass: \"ai-input\" }, [\n _c(\"textarea\", {\n directives: [\n {\n name: \"model\",\n rawName: \"v-model\",\n value: _vm.inputText,\n expression: \"inputText\"\n }\n ],\n ref: \"input\",\n staticClass: \"ai-input__box\",\n attrs: { rows: \"1\", placeholder: \"输入你的问题\" },\n domProps: { value: _vm.inputText },\n on: {\n keydown: function($event) {\n if (\n !$event.type.indexOf(\"key\") &&\n _vm._k(\n $event.keyCode,\n \"enter\",\n 13,\n $event.key,\n \"Enter\"\n )\n ) {\n return null\n }\n if (\n $event.ctrlKey ||\n $event.shiftKey ||\n $event.altKey ||\n $event.metaKey\n ) {\n return null\n }\n $event.preventDefault()\n return _vm.sendMessage.apply(null, arguments)\n },\n input: function($event) {\n if ($event.target.composing) {\n return\n }\n _vm.inputText = $event.target.value\n }\n }\n }),\n _c(\n \"button\",\n {\n staticClass: \"ai-input__send\",\n attrs: {\n disabled:\n _vm.sending ||\n _vm.greetingLoading ||\n !_vm.inputText.trim()\n },\n on: { click: _vm.sendMessage }\n },\n [_vm._v(\"发送\")]\n )\n ])\n ]\n )\n : _vm._e()\n ]),\n _c(\n \"div\",\n {\n ref: \"floatEl\",\n staticClass: \"ai-float\",\n class: {\n tucked: _vm.tucked,\n \"is-open\": _vm.panelVisible,\n dragging: _vm.dragging\n },\n style: { left: _vm.btnLeft + \"px\", bottom: _vm.btnBottom + \"px\" },\n on: {\n mousedown: _vm.startDrag,\n touchstart: _vm.startDrag,\n touchmove: _vm.onDrag,\n touchend: _vm.endDrag,\n touchcancel: _vm.endDrag\n }\n },\n [\n _c(\n \"button\",\n {\n staticClass: \"ai-float__btn\",\n class: { \"is-active\": _vm.panelVisible },\n attrs: {\n title: _vm.panelVisible ? \"收起 AI 助手\" : \"打开 AI 助手\"\n },\n on: { click: _vm.togglePanel, mouseup: _vm.stopDrag }\n },\n [\n _c(\"img\", {\n staticClass: \"ai-float__img\",\n attrs: { src: _vm.iconUrl, alt: \"AI\" }\n }),\n _vm.showRedDot\n ? _c(\"span\", { staticClass: \"ai-float__dot\" })\n : _vm._e()\n ]\n )\n ]\n )\n ],\n 1\n )\n}\nvar staticRenderFns = []\nrender._withStripped = true\n\n\n\n//# sourceURL=webpack://ZjPluginAiAssistant/./src/lib/components/approvalAi/index.vue?./node_modules/cache-loader/dist/cjs.js?%7B%22cacheDirectory%22:%22node_modules/.cache/vue-loader%22,%22cacheIdentifier%22:%22361a8753-vue-loader-template%22%7D!./node_modules/vue-loader/lib/loaders/templateLoader.js??vue-loader-options!./node_modules/cache-loader/dist/cjs.js??ref--0-0!./node_modules/vue-loader/lib??vue-loader-options");
|
|
245
|
+
|
|
246
|
+
/***/ }),
|
|
247
|
+
|
|
248
|
+
/***/ "./node_modules/css-loader/dist/cjs.js?!./node_modules/vue-loader/lib/loaders/stylePostLoader.js!./node_modules/postcss-loader/src/index.js?!./node_modules/cache-loader/dist/cjs.js?!./node_modules/vue-loader/lib/index.js?!./src/lib/components/approvalAi/index.vue?vue&type=style&index=1&lang=css&":
|
|
249
|
+
/*!***********************************************************************************************************************************************************************************************************************************************************************************************************************************************************!*\
|
|
250
|
+
!*** ./node_modules/css-loader/dist/cjs.js??ref--6-oneOf-1-1!./node_modules/vue-loader/lib/loaders/stylePostLoader.js!./node_modules/postcss-loader/src??ref--6-oneOf-1-2!./node_modules/cache-loader/dist/cjs.js??ref--0-0!./node_modules/vue-loader/lib??vue-loader-options!./src/lib/components/approvalAi/index.vue?vue&type=style&index=1&lang=css& ***!
|
|
251
|
+
\***********************************************************************************************************************************************************************************************************************************************************************************************************************************************************/
|
|
252
|
+
/*! no static exports found */
|
|
253
|
+
/***/ (function(module, exports, __webpack_require__) {
|
|
254
|
+
|
|
255
|
+
eval("// Imports\nvar ___CSS_LOADER_API_IMPORT___ = __webpack_require__(/*! ../../../../node_modules/css-loader/dist/runtime/api.js */ \"./node_modules/css-loader/dist/runtime/api.js\");\nexports = ___CSS_LOADER_API_IMPORT___(false);\n// Module\nexports.push([module.i, \"\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\r\\n/* 审批气泡内 markdown 链接去样式化:v-html 注入的 <a> 不在 scoped 作用域内,\\r\\n 必须用非 scoped 样式覆盖(scoped 规则只会匹配带 data 属性的模板元素)。\\r\\n 与正文同色、无下划线、非手型,配合 onBubbleClick 完全禁用跳转。 */\\n.ai-panel .msg__bubble a,\\r\\n.ai-panel .msg__bubble a:hover,\\r\\n.ai-panel .msg__bubble a:visited {\\r\\n color: inherit;\\r\\n text-decoration: none;\\r\\n cursor: default;\\n}\\r\\n\", \"\"]);\n// Exports\nmodule.exports = exports;\n\n\n//# sourceURL=webpack://ZjPluginAiAssistant/./src/lib/components/approvalAi/index.vue?./node_modules/css-loader/dist/cjs.js??ref--6-oneOf-1-1!./node_modules/vue-loader/lib/loaders/stylePostLoader.js!./node_modules/postcss-loader/src??ref--6-oneOf-1-2!./node_modules/cache-loader/dist/cjs.js??ref--0-0!./node_modules/vue-loader/lib??vue-loader-options");
|
|
245
256
|
|
|
246
257
|
/***/ }),
|
|
247
258
|
|
|
@@ -252,7 +263,7 @@ eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export (binding) *
|
|
|
252
263
|
/*! no static exports found */
|
|
253
264
|
/***/ (function(module, exports, __webpack_require__) {
|
|
254
265
|
|
|
255
|
-
eval("// Imports\nvar ___CSS_LOADER_API_IMPORT___ = __webpack_require__(/*! ../../../../node_modules/css-loader/dist/runtime/api.js */ \"./node_modules/css-loader/dist/runtime/api.js\");\nexports = ___CSS_LOADER_API_IMPORT___(false);\n// Module\nexports.push([module.i, \"@charset \\\"UTF-8\\\";\\n.ai-assistant[data-v-5d775cd8] {\\n position: absolute;\\n top: 0;\\n right: 0;\\n bottom: 0;\\n left: 0;\\n pointer-events: none;\\n z-index: 20;\\n}\\n.ai-float[data-v-5d775cd8] {\\n position: absolute;\\n pointer-events: auto;\\n z-index: 21;\\n transition: transform 0.25s ease;\\n touch-action: none; /* 触摸拖拽时不触发页面滚动/手势,保证跟手 */\\n}\\n.ai-float.dragging[data-v-5d775cd8] {\\n transition: none;\\n}\\n.ai-float.tucked[data-v-5d775cd8] {\\n transform: translateX(50%);\\n}\\n.ai-float.tucked[data-v-5d775cd8]:hover, .ai-float.tucked.is-open[data-v-5d775cd8] {\\n transform: translateX(0);\\n}\\n.ai-float__btn[data-v-5d775cd8] {\\n position: relative;\\n width: 46px;\\n height: 46px;\\n border-radius: 50%;\\n border: 1px solid #e4e7ed;\\n background: #fff;\\n box-shadow: 0 2px 10px rgba(0, 0, 0, 0.14);\\n display: flex;\\n align-items: center;\\n justify-content: center;\\n cursor: pointer;\\n color: #3067d9;\\n transition: box-shadow 0.2s, transform 0.2s;\\n}\\n.ai-float__btn[data-v-5d775cd8]:hover {\\n box-shadow: 0 4px 16px rgba(48, 103, 217, 0.3);\\n}\\n.ai-float__btn.is-active[data-v-5d775cd8] {\\n background: #fff;\\n color: #3067d9;\\n transform: none;\\n}\\n.ai-float__btn .ai-float__img[data-v-5d775cd8] {\\n width: 28px;\\n height: 28px;\\n border-radius: 50%;\\n}\\n.ai-float__dot[data-v-5d775cd8] {\\n position: absolute;\\n top: 2px;\\n right: 2px;\\n width: 10px;\\n height: 10px;\\n border-radius: 50%;\\n background: #f5222d;\\n border: 2px solid #fff;\\n box-sizing: border-box;\\n}\\n.ai-panel[data-v-5d775cd8] {\\n position: absolute;\\n width: 420px;\\n height: 560px; /* 默认高度 */\\n max-height: calc(100% - 48px); /* 上下各留 24px 安全距离,容器不够高时自动压缩 */\\n max-width: calc(100% - 98px); /* 右侧留按钮位(74px)+左侧 24px 安全,窄容器不溢出遮挡 */\\n background: #fff;\\n border: 1px solid #e4e7ed;\\n border-radius: 10px;\\n box-shadow: 0 8px 28px rgba(0, 0, 0, 0.16);\\n pointer-events: auto;\\n z-index: 22;\\n display: flex;\\n flex-direction: column;\\n overflow: hidden;\\n}\\n.ai-panel.dragging[data-v-5d775cd8], .ai-panel.dragging .ai-panel__header[data-v-5d775cd8] {\\n cursor: -webkit-grabbing;\\n cursor: grabbing;\\n}\\n.ai-panel__header[data-v-5d775cd8] {\\n height: 46px;\\n padding: 0 12px;\\n display: flex;\\n align-items: center;\\n background: #fafbfc;\\n border-bottom: 1px solid #f0f2f5;\\n gap: 8px;\\n cursor: -webkit-grab;\\n cursor: grab;\\n -webkit-user-select: none;\\n -moz-user-select: none;\\n -ms-user-select: none;\\n user-select: none;\\n}\\n.ai-panel__icon[data-v-5d775cd8] {\\n color: #3067d9;\\n display: flex;\\n}\\n.ai-panel__icon img[data-v-5d775cd8] {\\n width: 22px;\\n height: 22px;\\n border-radius: 50%;\\n}\\n.ai-panel__title[data-v-5d775cd8] {\\n font-size: 15px;\\n font-weight: 600;\\n color: #1f2329;\\n}\\n.ai-panel__status[data-v-5d775cd8] {\\n font-size: 12px;\\n padding: 1px 8px;\\n border-radius: 10px;\\n}\\n.ai-panel__status.status-ok[data-v-5d775cd8] {\\n color: #1a7f37;\\n background: #e6f4ea;\\n}\\n.ai-panel__status.status-no[data-v-5d775cd8] {\\n color: #d83931;\\n background: #fdeeee;\\n}\\n.ai-panel__status.status-go[data-v-5d775cd8] {\\n color: #3067d9;\\n background: #e8efff;\\n}\\n.ai-panel__close[data-v-5d775cd8] {\\n margin-left: auto;\\n cursor: pointer;\\n color: #86909c;\\n font-size: 16px;\\n line-height: 1;\\n padding: 0 2px;\\n}\\n.ai-panel__close[data-v-5d775cd8]:hover {\\n color: #1f2329;\\n}\\n.ai-chat[data-v-5d775cd8] {\\n flex: 1;\\n min-height: 120px;\\n padding: 14px;\\n overflow-y: auto;\\n background: #fff;\\n}\\n.ai-chat[data-v-5d775cd8]::-webkit-scrollbar {\\n width: 6px;\\n}\\n.ai-chat[data-v-5d775cd8]::-webkit-scrollbar-thumb {\\n background: #e4e7ed;\\n border-radius: 3px;\\n}\\n.msg[data-v-5d775cd8] {\\n display: flex;\\n margin-bottom: 14px;\\n}\\n.msg--assistant[data-v-5d775cd8] {\\n align-items: flex-start;\\n}\\n.msg--user[data-v-5d775cd8] {\\n justify-content: flex-end;\\n}\\n.msg__avatar[data-v-5d775cd8] {\\n flex: 0 0 auto;\\n width: 30px;\\n height: 30px;\\n margin-right: 8px;\\n border-radius: 50%;\\n background: #e8efff;\\n display: flex;\\n align-items: center;\\n justify-content: center;\\n}\\n.msg__avatar img[data-v-5d775cd8] {\\n width: 30px;\\n height: 30px;\\n border-radius: 50%;\\n}\\n.msg__bubble[data-v-5d775cd8] {\\n max-width: 76%;\\n padding: 11px 13px;\\n border-radius: 12px;\\n border: 1px solid #eceef2;\\n box-shadow: 0 1px 2px rgba(16, 24, 40, 0.04);\\n font-size: 13px;\\n line-height: 1.7;\\n word-break: break-word;\\n color: #4e5969;\\n background: #f7f8fa;\\n}\\n.msg__bubble h1[data-v-5d775cd8],\\n.msg__bubble h2[data-v-5d775cd8],\\n.msg__bubble h3[data-v-5d775cd8],\\n.msg__bubble h4[data-v-5d775cd8],\\n.msg__bubble h5[data-v-5d775cd8],\\n.msg__bubble h6[data-v-5d775cd8] {\\n font-size: 14px;\\n font-weight: 600;\\n color: #1f2329;\\n margin: 8px 0 4px;\\n padding-left: 8px;\\n border-left: 3px solid #3067d9;\\n line-height: 1.5;\\n}\\n.msg__bubble h1[data-v-5d775cd8]:first-child,\\n.msg__bubble h2[data-v-5d775cd8]:first-child,\\n.msg__bubble h3[data-v-5d775cd8]:first-child,\\n.msg__bubble h4[data-v-5d775cd8]:first-child,\\n.msg__bubble h5[data-v-5d775cd8]:first-child,\\n.msg__bubble h6[data-v-5d775cd8]:first-child {\\n margin-top: 0;\\n}\\n.msg__bubble p[data-v-5d775cd8] {\\n margin: 4px 0;\\n}\\n.msg__bubble p[data-v-5d775cd8]:first-child {\\n margin-top: 0;\\n}\\n.msg__bubble ul[data-v-5d775cd8],\\n.msg__bubble ol[data-v-5d775cd8] {\\n margin: 6px 0;\\n padding-left: 0;\\n list-style-position: inside;\\n}\\n.msg__bubble ul[data-v-5d775cd8] {\\n list-style: disc;\\n}\\n.msg__bubble ol[data-v-5d775cd8] {\\n list-style: decimal;\\n}\\n.msg__bubble li[data-v-5d775cd8] {\\n margin: 3px 0;\\n padding-left: 2px;\\n}\\n.msg__bubble blockquote[data-v-5d775cd8] {\\n margin: 8px 0;\\n padding: 2px 12px;\\n border-left: 3px solid #dde3ee;\\n background: #fafbfc;\\n border-radius: 4px;\\n color: #86909c;\\n}\\n.msg__bubble hr[data-v-5d775cd8] {\\n border: none;\\n border-top: 1px dashed #e4e7ed;\\n margin: 10px 0;\\n}\\n.msg__bubble strong[data-v-5d775cd8] {\\n color: #1f2329;\\n font-weight: 600;\\n}\\n.msg__bubble a[data-v-5d775cd8] {\\n color: #3067d9;\\n text-decoration: none;\\n}\\n.msg__bubble code[data-v-5d775cd8] {\\n background: #f0f2f5;\\n color: #d83931;\\n padding: 1px 4px;\\n border-radius: 3px;\\n font-size: 12px;\\n}\\n.msg__bubble pre[data-v-5d775cd8] {\\n background: #f6f7f8;\\n padding: 8px;\\n border-radius: 6px;\\n overflow-x: auto;\\n margin: 6px 0;\\n}\\n.msg__bubble pre code[data-v-5d775cd8] {\\n background: none;\\n color: #1f2329;\\n padding: 0;\\n}\\n.msg--user .msg__bubble[data-v-5d775cd8] {\\n color: #fff;\\n background: #3067d9;\\n border-color: #2a5ccf;\\n box-shadow: none;\\n}\\n.msg__bubble--typing[data-v-5d775cd8] {\\n display: flex;\\n gap: 4px;\\n padding: 12px;\\n}\\n.msg__bubble--typing span[data-v-5d775cd8] {\\n width: 6px;\\n height: 6px;\\n border-radius: 50%;\\n background: #86909c;\\n -webkit-animation: ai-blink-data-v-5d775cd8 1.2s infinite;\\n animation: ai-blink-data-v-5d775cd8 1.2s infinite;\\n}\\n.msg__bubble--typing span[data-v-5d775cd8]:nth-child(2) {\\n -webkit-animation-delay: 0.2s;\\n animation-delay: 0.2s;\\n}\\n.msg__bubble--typing span[data-v-5d775cd8]:nth-child(3) {\\n -webkit-animation-delay: 0.4s;\\n animation-delay: 0.4s;\\n}\\n.msg__bubble--loading[data-v-5d775cd8] {\\n display: flex;\\n align-items: center;\\n padding: 10px 12px;\\n}\\n.msg__bubble--loading .loading-text[data-v-5d775cd8] {\\n color: #86909c;\\n}\\n.msg__bubble--loading .loading-dots[data-v-5d775cd8] {\\n display: inline-flex;\\n margin-left: 6px;\\n}\\n.msg__bubble--loading .loading-dots i[data-v-5d775cd8] {\\n width: 4px;\\n height: 4px;\\n border-radius: 50%;\\n background: #86909c;\\n display: inline-block;\\n margin-right: 3px;\\n -webkit-animation: ai-blink-data-v-5d775cd8 1.2s infinite;\\n animation: ai-blink-data-v-5d775cd8 1.2s infinite;\\n}\\n.msg__bubble--loading .loading-dots i[data-v-5d775cd8]:nth-child(2) {\\n -webkit-animation-delay: 0.2s;\\n animation-delay: 0.2s;\\n}\\n.msg__bubble--loading .loading-dots i[data-v-5d775cd8]:nth-child(3) {\\n -webkit-animation-delay: 0.4s;\\n animation-delay: 0.4s;\\n}\\n@-webkit-keyframes ai-blink-data-v-5d775cd8 {\\n0%, 60%, 100% {\\n opacity: 0.35;\\n transform: translateY(0);\\n}\\n30% {\\n opacity: 1;\\n transform: translateY(-3px);\\n}\\n}\\n@keyframes ai-blink-data-v-5d775cd8 {\\n0%, 60%, 100% {\\n opacity: 0.35;\\n transform: translateY(0);\\n}\\n30% {\\n opacity: 1;\\n transform: translateY(-3px);\\n}\\n}\\n.ai-quick[data-v-5d775cd8] {\\n display: flex;\\n flex-wrap: wrap;\\n gap: 6px;\\n padding: 0 14px 10px;\\n background: #fff;\\n}\\n.ai-quick__item[data-v-5d775cd8] {\\n border: 1px solid #dce3f0;\\n background: #f7f9ff;\\n color: #3067d9;\\n font-size: 12px;\\n padding: 4px 10px;\\n border-radius: 14px;\\n cursor: pointer;\\n}\\n.ai-quick__item[data-v-5d775cd8]:hover {\\n border-color: #3067d9;\\n background: #eef3ff;\\n}\\n.ai-input[data-v-5d775cd8] {\\n display: flex;\\n align-items: flex-end;\\n gap: 8px;\\n padding: 10px 12px;\\n border-top: 1px solid #f0f2f5;\\n background: #fafbfc;\\n}\\n.ai-input__box[data-v-5d775cd8] {\\n flex: 1;\\n resize: none;\\n border: 1px solid #e4e7ed;\\n border-radius: 6px;\\n padding: 7px 10px;\\n font-size: 13px;\\n line-height: 1.5;\\n font-family: inherit;\\n color: #1f2329;\\n background: #fff;\\n outline: none;\\n max-height: 96px;\\n}\\n.ai-input__box[data-v-5d775cd8]:focus {\\n border-color: #3067d9;\\n}\\n.ai-input__send[data-v-5d775cd8] {\\n flex: 0 0 auto;\\n border: none;\\n background: #3067d9;\\n color: #fff;\\n font-size: 13px;\\n padding: 7px 16px;\\n border-radius: 6px;\\n cursor: pointer;\\n}\\n.ai-input__send[data-v-5d775cd8]:disabled {\\n opacity: 0.5;\\n cursor: not-allowed;\\n}\\n.ai-fade-enter-active[data-v-5d775cd8],\\n.ai-fade-leave-active[data-v-5d775cd8] {\\n transition: opacity 0.2s, transform 0.2s;\\n}\\n.ai-fade-enter[data-v-5d775cd8],\\n.ai-fade-leave-to[data-v-5d775cd8] {\\n opacity: 0;\\n transform: translateY(10px);\\n}\\n\\n/* ============ H5 兼容:点击 AI 后从底部弹出,占 80% 高度、宽度占满 ============ */\\n/* 仅影响窄屏移动端,不影响 PC 端逻辑(PC 宽度 > 480px 仍走上方右侧悬浮面板) */\\n@media (max-width: 480px) {\\n /* 整层提到宿主底部操作栏(通常 z-index 高)之上,保证浮球/面板/遮罩不被遮挡 */\\n.ai-assistant[data-v-5d775cd8] {\\n z-index: 3000;\\n}\\n /* 审批面板打开时的阴影遮罩层 */\\n.ai-mask[data-v-5d775cd8] {\\n position: fixed;\\n top: 0;\\n right: 0;\\n bottom: 0;\\n left: 0;\\n background: rgba(0, 0, 0, 0.45);\\n pointer-events: auto;\\n z-index: 999;\\n}\\n /* 浮球改为视口固定:在可滚动的 H5 长详情页上始终贴在当前视口,并保持置顶 */\\n.ai-float[data-v-5d775cd8] {\\n position: fixed;\\n z-index: 1000;\\n}\\n.ai-panel[data-v-5d775cd8] {\\n /* 脱离容器,固定到视口底部,宽度占满、高度占视口 80% */\\n position: fixed;\\n top: auto;\\n left: 0;\\n right: 0;\\n bottom: 0 !important; /* 覆盖内联面板 bottom 绑定,始终贴底 */\\n width: 100%;\\n max-width: 100%;\\n height: 85%;\\n max-height: 85%; /* 兼容个别不允许 vh 的旧内核 */\\n border-radius: 16px 16px 0 0;\\n z-index: 1001; /* 位于遮罩层之上 */\\n}\\n /* 底部弹出/收起动画:从视口底部滑入 */\\n.ai-fade-enter-active[data-v-5d775cd8],\\n .ai-fade-leave-active[data-v-5d775cd8] {\\n transition: transform 0.28s ease;\\n}\\n.ai-fade-enter[data-v-5d775cd8],\\n .ai-fade-leave-to[data-v-5d775cd8] {\\n opacity: 1;\\n transform: translateY(100%);\\n}\\n /* H5 放大审批详情/聊天文字,提升可读性 */\\n.msg__bubble[data-v-5d775cd8] {\\n font-size: 15px;\\n line-height: 1.8;\\n padding: 11px 14px;\\n}\\n.msg__bubble h1[data-v-5d775cd8],\\n .msg__bubble h2[data-v-5d775cd8],\\n .msg__bubble h3[data-v-5d775cd8],\\n .msg__bubble h4[data-v-5d775cd8],\\n .msg__bubble h5[data-v-5d775cd8],\\n .msg__bubble h6[data-v-5d775cd8] {\\n font-size: 17px;\\n}\\n.msg__bubble code[data-v-5d775cd8] {\\n font-size: 14px;\\n}\\n /* 输入区针对全面屏 Home 指示条预留安全距离 */\\n.ai-input[data-v-5d775cd8] {\\n padding-bottom: calc(10px + env(safe-area-inset-bottom));\\n}\\n}\", \"\"]);\n// Exports\nmodule.exports = exports;\n\n\n//# sourceURL=webpack://ZjPluginAiAssistant/./src/lib/components/approvalAi/index.vue?./node_modules/css-loader/dist/cjs.js??ref--8-oneOf-1-1!./node_modules/vue-loader/lib/loaders/stylePostLoader.js!./node_modules/postcss-loader/src??ref--8-oneOf-1-2!./node_modules/sass-loader/dist/cjs.js??ref--8-oneOf-1-3!./node_modules/cache-loader/dist/cjs.js??ref--0-0!./node_modules/vue-loader/lib??vue-loader-options");
|
|
266
|
+
eval("// Imports\nvar ___CSS_LOADER_API_IMPORT___ = __webpack_require__(/*! ../../../../node_modules/css-loader/dist/runtime/api.js */ \"./node_modules/css-loader/dist/runtime/api.js\");\nexports = ___CSS_LOADER_API_IMPORT___(false);\n// Module\nexports.push([module.i, \"@charset \\\"UTF-8\\\";\\n.ai-assistant[data-v-5d775cd8] {\\n position: absolute;\\n top: 0;\\n right: 0;\\n bottom: 0;\\n left: 0;\\n pointer-events: none;\\n z-index: 20;\\n}\\n.ai-float[data-v-5d775cd8] {\\n position: absolute;\\n pointer-events: auto;\\n z-index: 21;\\n transition: transform 0.25s ease;\\n touch-action: none; /* 触摸拖拽时不触发页面滚动/手势,保证跟手 */\\n}\\n.ai-float.dragging[data-v-5d775cd8] {\\n transition: none;\\n}\\n.ai-float.tucked[data-v-5d775cd8] {\\n transform: translateX(50%);\\n}\\n.ai-float.tucked[data-v-5d775cd8]:hover, .ai-float.tucked.is-open[data-v-5d775cd8] {\\n transform: translateX(0);\\n}\\n.ai-float__btn[data-v-5d775cd8] {\\n position: relative;\\n width: 46px;\\n height: 46px;\\n border-radius: 50%;\\n border: 1px solid #e4e7ed;\\n background: #fff;\\n box-shadow: 0 2px 10px rgba(0, 0, 0, 0.14);\\n display: flex;\\n align-items: center;\\n justify-content: center;\\n cursor: pointer;\\n color: #3067d9;\\n transition: box-shadow 0.2s, transform 0.2s;\\n}\\n.ai-float__btn[data-v-5d775cd8]:hover {\\n box-shadow: 0 4px 16px rgba(48, 103, 217, 0.3);\\n}\\n.ai-float__btn.is-active[data-v-5d775cd8] {\\n background: #fff;\\n color: #3067d9;\\n transform: none;\\n}\\n.ai-float__btn .ai-float__img[data-v-5d775cd8] {\\n width: 28px;\\n height: 28px;\\n border-radius: 50%;\\n}\\n.ai-float__dot[data-v-5d775cd8] {\\n position: absolute;\\n top: 2px;\\n right: 2px;\\n width: 10px;\\n height: 10px;\\n border-radius: 50%;\\n background: #f5222d;\\n border: 2px solid #fff;\\n box-sizing: border-box;\\n}\\n.ai-panel[data-v-5d775cd8] {\\n position: absolute;\\n width: 420px;\\n height: 560px; /* 默认高度 */\\n max-height: calc(100% - 48px); /* 上下各留 24px 安全距离,容器不够高时自动压缩 */\\n max-width: calc(100% - 98px); /* 右侧留按钮位(74px)+左侧 24px 安全,窄容器不溢出遮挡 */\\n background: #fff;\\n border: 1px solid #e4e7ed;\\n border-radius: 10px;\\n box-shadow: 0 8px 28px rgba(0, 0, 0, 0.16);\\n pointer-events: auto;\\n z-index: 22;\\n display: flex;\\n flex-direction: column;\\n overflow: hidden;\\n}\\n.ai-panel.dragging[data-v-5d775cd8], .ai-panel.dragging .ai-panel__header[data-v-5d775cd8] {\\n cursor: -webkit-grabbing;\\n cursor: grabbing;\\n}\\n.ai-panel__header[data-v-5d775cd8] {\\n height: 46px;\\n padding: 0 12px;\\n display: flex;\\n align-items: center;\\n background: #fafbfc;\\n border-bottom: 1px solid #f0f2f5;\\n gap: 8px;\\n cursor: -webkit-grab;\\n cursor: grab;\\n -webkit-user-select: none;\\n -moz-user-select: none;\\n -ms-user-select: none;\\n user-select: none;\\n}\\n.ai-panel__icon[data-v-5d775cd8] {\\n color: #3067d9;\\n display: flex;\\n}\\n.ai-panel__icon img[data-v-5d775cd8] {\\n width: 22px;\\n height: 22px;\\n border-radius: 50%;\\n}\\n.ai-panel__title[data-v-5d775cd8] {\\n font-size: 15px;\\n font-weight: 600;\\n color: #1f2329;\\n}\\n.ai-panel__status[data-v-5d775cd8] {\\n font-size: 12px;\\n padding: 1px 8px;\\n border-radius: 10px;\\n}\\n.ai-panel__status.status-ok[data-v-5d775cd8] {\\n color: #1a7f37;\\n background: #e6f4ea;\\n}\\n.ai-panel__status.status-no[data-v-5d775cd8] {\\n color: #d83931;\\n background: #fdeeee;\\n}\\n.ai-panel__status.status-go[data-v-5d775cd8] {\\n color: #3067d9;\\n background: #e8efff;\\n}\\n.ai-panel__close[data-v-5d775cd8] {\\n margin-left: auto;\\n cursor: pointer;\\n color: #86909c;\\n font-size: 16px;\\n line-height: 1;\\n padding: 0 2px;\\n}\\n.ai-panel__close[data-v-5d775cd8]:hover {\\n color: #1f2329;\\n}\\n.msg-loading-more[data-v-5d775cd8] {\\n padding: 6px 0;\\n text-align: center;\\n font-size: 12px;\\n color: #a9b0bb;\\n}\\n.ai-chat[data-v-5d775cd8] {\\n flex: 1;\\n min-height: 120px;\\n padding: 14px;\\n overflow-y: auto;\\n background: #fff;\\n}\\n.ai-chat[data-v-5d775cd8]::-webkit-scrollbar {\\n width: 6px;\\n}\\n.ai-chat[data-v-5d775cd8]::-webkit-scrollbar-thumb {\\n background: #e4e7ed;\\n border-radius: 3px;\\n}\\n.msg[data-v-5d775cd8] {\\n display: flex;\\n margin-bottom: 14px;\\n}\\n.msg--assistant[data-v-5d775cd8] {\\n align-items: flex-start;\\n}\\n.msg--user[data-v-5d775cd8] {\\n justify-content: flex-end;\\n}\\n.msg__avatar[data-v-5d775cd8] {\\n flex: 0 0 auto;\\n width: 30px;\\n height: 30px;\\n margin-right: 8px;\\n border-radius: 50%;\\n background: #e8efff;\\n display: flex;\\n align-items: center;\\n justify-content: center;\\n}\\n.msg__avatar img[data-v-5d775cd8] {\\n width: 30px;\\n height: 30px;\\n border-radius: 50%;\\n}\\n.msg__bubble[data-v-5d775cd8] {\\n max-width: 76%;\\n padding: 11px 13px;\\n border-radius: 12px;\\n border: 1px solid #eceef2;\\n box-shadow: 0 1px 2px rgba(16, 24, 40, 0.04);\\n font-size: 13px;\\n line-height: 1.7;\\n word-break: break-word;\\n color: #4e5969;\\n background: #f7f8fa;\\n}\\n.msg__bubble h1[data-v-5d775cd8],\\n.msg__bubble h2[data-v-5d775cd8],\\n.msg__bubble h3[data-v-5d775cd8],\\n.msg__bubble h4[data-v-5d775cd8],\\n.msg__bubble h5[data-v-5d775cd8],\\n.msg__bubble h6[data-v-5d775cd8] {\\n font-size: 14px;\\n font-weight: 600;\\n color: #1f2329;\\n margin: 8px 0 4px;\\n padding-left: 8px;\\n border-left: 3px solid #3067d9;\\n line-height: 1.5;\\n}\\n.msg__bubble h1[data-v-5d775cd8]:first-child,\\n.msg__bubble h2[data-v-5d775cd8]:first-child,\\n.msg__bubble h3[data-v-5d775cd8]:first-child,\\n.msg__bubble h4[data-v-5d775cd8]:first-child,\\n.msg__bubble h5[data-v-5d775cd8]:first-child,\\n.msg__bubble h6[data-v-5d775cd8]:first-child {\\n margin-top: 0;\\n}\\n.msg__bubble p[data-v-5d775cd8] {\\n margin: 4px 0;\\n}\\n.msg__bubble p[data-v-5d775cd8]:first-child {\\n margin-top: 0;\\n}\\n.msg__bubble ul[data-v-5d775cd8],\\n.msg__bubble ol[data-v-5d775cd8] {\\n margin: 6px 0;\\n padding-left: 0;\\n list-style-position: inside;\\n}\\n.msg__bubble ul[data-v-5d775cd8] {\\n list-style: disc;\\n}\\n.msg__bubble ol[data-v-5d775cd8] {\\n list-style: decimal;\\n}\\n.msg__bubble li[data-v-5d775cd8] {\\n margin: 3px 0;\\n padding-left: 2px;\\n}\\n.msg__bubble blockquote[data-v-5d775cd8] {\\n margin: 8px 0;\\n padding: 2px 12px;\\n border-left: 3px solid #dde3ee;\\n background: #fafbfc;\\n border-radius: 4px;\\n color: #86909c;\\n}\\n.msg__bubble hr[data-v-5d775cd8] {\\n border: none;\\n border-top: 1px dashed #e4e7ed;\\n margin: 10px 0;\\n}\\n.msg__bubble strong[data-v-5d775cd8] {\\n color: #1f2329;\\n font-weight: 600;\\n}\\n.msg__bubble code[data-v-5d775cd8] {\\n background: #f0f2f5;\\n color: #d83931;\\n padding: 1px 4px;\\n border-radius: 3px;\\n font-size: 12px;\\n}\\n.msg__bubble pre[data-v-5d775cd8] {\\n background: #f6f7f8;\\n padding: 8px;\\n border-radius: 6px;\\n overflow-x: auto;\\n margin: 6px 0;\\n}\\n.msg__bubble pre code[data-v-5d775cd8] {\\n background: none;\\n color: #1f2329;\\n padding: 0;\\n}\\n.msg--user .msg__bubble[data-v-5d775cd8] {\\n color: #fff;\\n background: #3067d9;\\n border-color: #2a5ccf;\\n box-shadow: none;\\n}\\n.msg__bubble--typing[data-v-5d775cd8] {\\n display: flex;\\n gap: 4px;\\n padding: 12px;\\n}\\n.msg__bubble--typing span[data-v-5d775cd8] {\\n width: 6px;\\n height: 6px;\\n border-radius: 50%;\\n background: #86909c;\\n -webkit-animation: ai-blink-data-v-5d775cd8 1.2s infinite;\\n animation: ai-blink-data-v-5d775cd8 1.2s infinite;\\n}\\n.msg__bubble--typing span[data-v-5d775cd8]:nth-child(2) {\\n -webkit-animation-delay: 0.2s;\\n animation-delay: 0.2s;\\n}\\n.msg__bubble--typing span[data-v-5d775cd8]:nth-child(3) {\\n -webkit-animation-delay: 0.4s;\\n animation-delay: 0.4s;\\n}\\n.msg__bubble--loading[data-v-5d775cd8] {\\n display: flex;\\n align-items: center;\\n padding: 10px 12px;\\n}\\n.msg__bubble--loading .loading-text[data-v-5d775cd8] {\\n color: #86909c;\\n}\\n.msg__bubble--loading .loading-dots[data-v-5d775cd8] {\\n display: inline-flex;\\n margin-left: 6px;\\n}\\n.msg__bubble--loading .loading-dots i[data-v-5d775cd8] {\\n width: 4px;\\n height: 4px;\\n border-radius: 50%;\\n background: #86909c;\\n display: inline-block;\\n margin-right: 3px;\\n -webkit-animation: ai-blink-data-v-5d775cd8 1.2s infinite;\\n animation: ai-blink-data-v-5d775cd8 1.2s infinite;\\n}\\n.msg__bubble--loading .loading-dots i[data-v-5d775cd8]:nth-child(2) {\\n -webkit-animation-delay: 0.2s;\\n animation-delay: 0.2s;\\n}\\n.msg__bubble--loading .loading-dots i[data-v-5d775cd8]:nth-child(3) {\\n -webkit-animation-delay: 0.4s;\\n animation-delay: 0.4s;\\n}\\n@-webkit-keyframes ai-blink-data-v-5d775cd8 {\\n0%, 60%, 100% {\\n opacity: 0.35;\\n transform: translateY(0);\\n}\\n30% {\\n opacity: 1;\\n transform: translateY(-3px);\\n}\\n}\\n@keyframes ai-blink-data-v-5d775cd8 {\\n0%, 60%, 100% {\\n opacity: 0.35;\\n transform: translateY(0);\\n}\\n30% {\\n opacity: 1;\\n transform: translateY(-3px);\\n}\\n}\\n.ai-quick[data-v-5d775cd8] {\\n display: flex;\\n flex-wrap: wrap;\\n gap: 6px;\\n padding: 0 14px 10px;\\n background: #fff;\\n}\\n.ai-quick__item[data-v-5d775cd8] {\\n border: 1px solid #dce3f0;\\n background: #f7f9ff;\\n color: #3067d9;\\n font-size: 12px;\\n padding: 4px 10px;\\n border-radius: 14px;\\n cursor: pointer;\\n}\\n.ai-quick__item[data-v-5d775cd8]:hover {\\n border-color: #3067d9;\\n background: #eef3ff;\\n}\\n.ai-input[data-v-5d775cd8] {\\n display: flex;\\n align-items: flex-end;\\n gap: 8px;\\n padding: 10px 12px;\\n border-top: 1px solid #f0f2f5;\\n background: #fafbfc;\\n}\\n.ai-input__box[data-v-5d775cd8] {\\n flex: 1;\\n resize: none;\\n border: 1px solid #e4e7ed;\\n border-radius: 6px;\\n padding: 7px 10px;\\n font-size: 13px;\\n line-height: 1.5;\\n font-family: inherit;\\n color: #1f2329;\\n background: #fff;\\n outline: none;\\n max-height: 96px;\\n}\\n.ai-input__box[data-v-5d775cd8]:focus {\\n border-color: #3067d9;\\n}\\n.ai-input__send[data-v-5d775cd8] {\\n flex: 0 0 auto;\\n border: none;\\n background: #3067d9;\\n color: #fff;\\n font-size: 13px;\\n padding: 7px 16px;\\n border-radius: 6px;\\n cursor: pointer;\\n}\\n.ai-input__send[data-v-5d775cd8]:disabled {\\n opacity: 0.5;\\n cursor: not-allowed;\\n}\\n.ai-fade-enter-active[data-v-5d775cd8],\\n.ai-fade-leave-active[data-v-5d775cd8] {\\n transition: opacity 0.2s, transform 0.2s;\\n}\\n.ai-fade-enter[data-v-5d775cd8],\\n.ai-fade-leave-to[data-v-5d775cd8] {\\n opacity: 0;\\n transform: translateY(10px);\\n}\\n\\n/* ============ H5 兼容:点击 AI 后从底部弹出,占 80% 高度、宽度占满 ============ */\\n/* 仅影响窄屏移动端,不影响 PC 端逻辑(PC 宽度 > 480px 仍走上方右侧悬浮面板) */\\n@media (max-width: 480px) {\\n /* 整层提到宿主底部操作栏(通常 z-index 高)之上,保证浮球/面板/遮罩不被遮挡 */\\n.ai-assistant[data-v-5d775cd8] {\\n z-index: 3000;\\n}\\n /* 审批面板打开时的阴影遮罩层 */\\n.ai-mask[data-v-5d775cd8] {\\n position: fixed;\\n top: 0;\\n right: 0;\\n bottom: 0;\\n left: 0;\\n background: rgba(0, 0, 0, 0.45);\\n pointer-events: auto;\\n z-index: 999;\\n}\\n /* 浮球改为视口固定:在可滚动的 H5 长详情页上始终贴在当前视口,并保持置顶 */\\n.ai-float[data-v-5d775cd8] {\\n position: fixed;\\n z-index: 1000;\\n}\\n.ai-panel[data-v-5d775cd8] {\\n /* 脱离容器,固定到视口底部,宽度占满、高度占视口 80% */\\n position: fixed;\\n top: auto;\\n left: 0;\\n right: 0;\\n bottom: 0 !important; /* 覆盖内联面板 bottom 绑定,始终贴底 */\\n width: 100%;\\n max-width: 100%;\\n height: 85%;\\n max-height: 85%; /* 兼容个别不允许 vh 的旧内核 */\\n border-radius: 16px 16px 0 0;\\n z-index: 1001; /* 位于遮罩层之上 */\\n}\\n /* 底部弹出/收起动画:从视口底部滑入 */\\n.ai-fade-enter-active[data-v-5d775cd8],\\n .ai-fade-leave-active[data-v-5d775cd8] {\\n transition: transform 0.28s ease;\\n}\\n.ai-fade-enter[data-v-5d775cd8],\\n .ai-fade-leave-to[data-v-5d775cd8] {\\n opacity: 1;\\n transform: translateY(100%);\\n}\\n /* H5 放大审批详情/聊天文字,提升可读性 */\\n.msg__bubble[data-v-5d775cd8] {\\n font-size: 15px;\\n line-height: 1.8;\\n padding: 11px 14px;\\n}\\n.msg__bubble h1[data-v-5d775cd8],\\n .msg__bubble h2[data-v-5d775cd8],\\n .msg__bubble h3[data-v-5d775cd8],\\n .msg__bubble h4[data-v-5d775cd8],\\n .msg__bubble h5[data-v-5d775cd8],\\n .msg__bubble h6[data-v-5d775cd8] {\\n font-size: 17px;\\n}\\n.msg__bubble code[data-v-5d775cd8] {\\n font-size: 14px;\\n}\\n /* 输入区针对全面屏 Home 指示条预留安全距离 */\\n.ai-input[data-v-5d775cd8] {\\n padding-bottom: calc(10px + env(safe-area-inset-bottom));\\n}\\n}\", \"\"]);\n// Exports\nmodule.exports = exports;\n\n\n//# sourceURL=webpack://ZjPluginAiAssistant/./src/lib/components/approvalAi/index.vue?./node_modules/css-loader/dist/cjs.js??ref--8-oneOf-1-1!./node_modules/vue-loader/lib/loaders/stylePostLoader.js!./node_modules/postcss-loader/src??ref--8-oneOf-1-2!./node_modules/sass-loader/dist/cjs.js??ref--8-oneOf-1-3!./node_modules/cache-loader/dist/cjs.js??ref--0-0!./node_modules/vue-loader/lib??vue-loader-options");
|
|
256
267
|
|
|
257
268
|
/***/ }),
|
|
258
269
|
|
|
@@ -1101,6 +1112,17 @@ eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export (binding) *
|
|
|
1101
1112
|
|
|
1102
1113
|
/***/ }),
|
|
1103
1114
|
|
|
1115
|
+
/***/ "./node_modules/vue-style-loader/index.js?!./node_modules/css-loader/dist/cjs.js?!./node_modules/vue-loader/lib/loaders/stylePostLoader.js!./node_modules/postcss-loader/src/index.js?!./node_modules/cache-loader/dist/cjs.js?!./node_modules/vue-loader/lib/index.js?!./src/lib/components/approvalAi/index.vue?vue&type=style&index=1&lang=css&":
|
|
1116
|
+
/*!*************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************!*\
|
|
1117
|
+
!*** ./node_modules/vue-style-loader??ref--6-oneOf-1-0!./node_modules/css-loader/dist/cjs.js??ref--6-oneOf-1-1!./node_modules/vue-loader/lib/loaders/stylePostLoader.js!./node_modules/postcss-loader/src??ref--6-oneOf-1-2!./node_modules/cache-loader/dist/cjs.js??ref--0-0!./node_modules/vue-loader/lib??vue-loader-options!./src/lib/components/approvalAi/index.vue?vue&type=style&index=1&lang=css& ***!
|
|
1118
|
+
\*************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************/
|
|
1119
|
+
/*! no static exports found */
|
|
1120
|
+
/***/ (function(module, exports, __webpack_require__) {
|
|
1121
|
+
|
|
1122
|
+
eval("// style-loader: Adds some css to the DOM by adding a <style> tag\n\n// load the styles\nvar content = __webpack_require__(/*! !../../../../node_modules/css-loader/dist/cjs.js??ref--6-oneOf-1-1!../../../../node_modules/vue-loader/lib/loaders/stylePostLoader.js!../../../../node_modules/postcss-loader/src??ref--6-oneOf-1-2!../../../../node_modules/cache-loader/dist/cjs.js??ref--0-0!../../../../node_modules/vue-loader/lib??vue-loader-options!./index.vue?vue&type=style&index=1&lang=css& */ \"./node_modules/css-loader/dist/cjs.js?!./node_modules/vue-loader/lib/loaders/stylePostLoader.js!./node_modules/postcss-loader/src/index.js?!./node_modules/cache-loader/dist/cjs.js?!./node_modules/vue-loader/lib/index.js?!./src/lib/components/approvalAi/index.vue?vue&type=style&index=1&lang=css&\");\nif(content.__esModule) content = content.default;\nif(typeof content === 'string') content = [[module.i, content, '']];\nif(content.locals) module.exports = content.locals;\n// add the styles to the DOM\nvar add = __webpack_require__(/*! ../../../../node_modules/vue-style-loader/lib/addStylesClient.js */ \"./node_modules/vue-style-loader/lib/addStylesClient.js\").default\nvar update = add(\"076304e8\", content, false, {\"sourceMap\":false,\"shadowMode\":false});\n// Hot Module Replacement\nif(false) {}\n\n//# sourceURL=webpack://ZjPluginAiAssistant/./src/lib/components/approvalAi/index.vue?./node_modules/vue-style-loader??ref--6-oneOf-1-0!./node_modules/css-loader/dist/cjs.js??ref--6-oneOf-1-1!./node_modules/vue-loader/lib/loaders/stylePostLoader.js!./node_modules/postcss-loader/src??ref--6-oneOf-1-2!./node_modules/cache-loader/dist/cjs.js??ref--0-0!./node_modules/vue-loader/lib??vue-loader-options");
|
|
1123
|
+
|
|
1124
|
+
/***/ }),
|
|
1125
|
+
|
|
1104
1126
|
/***/ "./node_modules/vue-style-loader/index.js?!./node_modules/css-loader/dist/cjs.js?!./node_modules/vue-loader/lib/loaders/stylePostLoader.js!./node_modules/postcss-loader/src/index.js?!./node_modules/sass-loader/dist/cjs.js?!./node_modules/cache-loader/dist/cjs.js?!./node_modules/vue-loader/lib/index.js?!./src/lib/components/approvalAi/index.vue?vue&type=style&index=0&id=5d775cd8&scoped=true&lang=scss&":
|
|
1105
1127
|
/*!***********************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************!*\
|
|
1106
1128
|
!*** ./node_modules/vue-style-loader??ref--8-oneOf-1-0!./node_modules/css-loader/dist/cjs.js??ref--8-oneOf-1-1!./node_modules/vue-loader/lib/loaders/stylePostLoader.js!./node_modules/postcss-loader/src??ref--8-oneOf-1-2!./node_modules/sass-loader/dist/cjs.js??ref--8-oneOf-1-3!./node_modules/cache-loader/dist/cjs.js??ref--0-0!./node_modules/vue-loader/lib??vue-loader-options!./src/lib/components/approvalAi/index.vue?vue&type=style&index=0&id=5d775cd8&scoped=true&lang=scss& ***!
|
|
@@ -1177,7 +1199,7 @@ eval("module.exports = \"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAFgAAABYC
|
|
|
1177
1199
|
/***/ (function(module, exports, __webpack_require__) {
|
|
1178
1200
|
|
|
1179
1201
|
"use strict";
|
|
1180
|
-
eval("\n\nvar _interopRequireDefault = __webpack_require__(/*! ./node_modules/@babel/runtime/helpers/interopRequireDefault */ \"./node_modules/@babel/runtime/helpers/interopRequireDefault.js\").default;\n\nObject.defineProperty(exports, \"__esModule\", {\n value: true\n});\nexports.configureAI = configureAI;\nexports.aiConfigured = aiConfigured;\nexports.getInstance = getInstance;\nexports.getSummary = getSummary;\nexports.extractApprovalInfo = extractApprovalInfo;\nexports.getRiskTips = getRiskTips;\nexports.generateOpinion = generateOpinion;\nexports.createChatSession = createChatSession;\nexports.streamChat = streamChat;\nexports.streamSummary = streamSummary;\n\nvar _objectSpread2 = _interopRequireDefault(__webpack_require__(/*! ./node_modules/@babel/runtime/helpers/objectSpread2 */ \"./node_modules/@babel/runtime/helpers/objectSpread2.js\"));\n\nvar _typeof2 = _interopRequireDefault(__webpack_require__(/*! ./node_modules/@babel/runtime/helpers/typeof */ \"./node_modules/@babel/runtime/helpers/typeof.js\"));\n\nvar _createForOfIteratorHelper2 = _interopRequireDefault(__webpack_require__(/*! ./node_modules/@babel/runtime/helpers/createForOfIteratorHelper */ \"./node_modules/@babel/runtime/helpers/createForOfIteratorHelper.js\"));\n\nvar _asyncToGenerator2 = _interopRequireDefault(__webpack_require__(/*! ./node_modules/@babel/runtime/helpers/asyncToGenerator */ \"./node_modules/@babel/runtime/helpers/asyncToGenerator.js\"));\n\n/**\r\n * AI 审批助手 接口模块(外部系统 zj-ai-agent)\r\n * 对接文档:外部对接-AI审批助手API文档.md\r\n * 说明:\r\n * - 该服务为独立后端,基础地址通过 configureAI({ baseUrl }) 注入(示例:https://api.xxx.cn)\r\n * - 接口统一前缀 /api/v1/approval-ai 已在此拼接,只填 host\r\n * - 未配置 baseUrl 时返回 null,由调用方走本地兜底\r\n */\nvar BASE = \"https://ai.jybtech.cn\" || false;\nvar PREFIX = \"/api/v1/approval-ai\";\n/** 注入 AI 服务地址(覆盖式,可多次调用) */\n\nfunction configureAI() {\n var _ref = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {},\n baseUrl = _ref.baseUrl;\n\n BASE = (baseUrl || \"\").replace(/\\/+$/, \"\");\n}\n/** 是否已配置 AI 服务地址 */\n\n\nfunction aiConfigured() {\n console.log(BASE);\n return Boolean(BASE);\n}\n\nfunction checkCode(data, ref) {\n if (data && (data.code === 200 || data.code === \"200\")) return data;\n if (ref && ref.data) ref.data = data;\n return null;\n}\n\nfunction req(_x) {\n return _req.apply(this, arguments);\n}\n/** 3.1 获取审批单完整数据 */\n\n\nfunction _req() {\n _req = (0, _asyncToGenerator2.default)( /*#__PURE__*/regeneratorRuntime.mark(function _callee(path) {\n var options,\n url,\n params,\n _options$method,\n method,\n body,\n q,\n qs,\n init,\n resp,\n text,\n json,\n _args = arguments;\n\n return regeneratorRuntime.wrap(function _callee$(_context) {\n while (1) {\n switch (_context.prev = _context.next) {\n case 0:\n options = _args.length > 1 && _args[1] !== undefined ? _args[1] : {};\n\n if (BASE) {\n _context.next = 3;\n break;\n }\n\n return _context.abrupt(\"return\", null);\n\n case 3:\n url = BASE + PREFIX + path;\n params = options.params, _options$method = options.method, method = _options$method === void 0 ? \"GET\" : _options$method, body = options.body;\n\n if (params && (0, _typeof2.default)(params) === \"object\") {\n q = new URLSearchParams();\n Object.keys(params).forEach(function (k) {\n var v = params[k];\n if (v !== undefined && v !== null) q.append(k, v);\n });\n qs = q.toString();\n if (qs) url += (url.includes(\"?\") ? \"&\" : \"?\") + qs;\n }\n\n init = {\n method: method,\n headers: {\n Accept: \"application/json\"\n }\n };\n\n if (body !== undefined) {\n init.headers[\"Content-Type\"] = \"application/json\";\n init.body = typeof body === \"string\" ? body : JSON.stringify(body);\n }\n\n _context.prev = 8;\n _context.next = 11;\n return fetch(url, init);\n\n case 11:\n resp = _context.sent;\n _context.next = 14;\n return resp.text();\n\n case 14:\n text = _context.sent;\n json = null;\n\n try {\n json = text ? JSON.parse(text) : null;\n } catch (e) {\n json = null;\n }\n\n return _context.abrupt(\"return\", checkCode(json));\n\n case 20:\n _context.prev = 20;\n _context.t0 = _context[\"catch\"](8);\n return _context.abrupt(\"return\", null);\n\n case 23:\n case \"end\":\n return _context.stop();\n }\n }\n }, _callee, null, [[8, 20]]);\n }));\n return _req.apply(this, arguments);\n}\n\nfunction getInstance(approvalNo) {\n return req(\"/instances/\".concat(encodeURIComponent(approvalNo)));\n}\n/** 3.2 AI 生成审批单总结 */\n\n\nfunction getSummary(approvalNo) {\n return req(\"/instances/\".concat(encodeURIComponent(approvalNo), \"/summary\"), {\n method: \"POST\"\n });\n}\n/** 3.3 AI 信息抽取(结构化) */\n\n\nfunction extractApprovalInfo(approvalNo) {\n return req(\"/instances/\".concat(encodeURIComponent(approvalNo), \"/extract\"), {\n method: \"POST\"\n });\n}\n/** 3.4 AI 风险提示 */\n\n\nfunction getRiskTips(approvalNo) {\n return req(\"/instances/\".concat(encodeURIComponent(approvalNo), \"/risk-tips\"), {\n method: \"POST\"\n });\n}\n/** 3.5 AI 生成审批意见 */\n\n\nfunction generateOpinion(approvalNo) {\n var _ref2 = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {},\n action = _ref2.action,\n hint = _ref2.hint;\n\n return req(\"/instances/\".concat(encodeURIComponent(approvalNo), \"/generate-opinion\"), {\n method: \"POST\",\n body: {\n action: action,\n hint: hint\n }\n });\n}\n/** 3.6 创建 AI 对话会话 */\n\n\nfunction createChatSession(_ref3) {\n var approvalNo = _ref3.approvalNo,\n userId = _ref3.userId,\n userName = _ref3.userName;\n return req(\"/chat/sessions\", {\n method: \"POST\",\n body: {\n approvalNo: approvalNo,\n userId: userId,\n userName: userName\n }\n });\n}\n/**\r\n * 通用 SSE 读取:fetch + ReadableStream,按空行切块并派发事件文本\r\n * @param {string} url\r\n * @param {(event: string, data: string) => void} onEvent\r\n */\n\n\nfunction readSSE(_x2, _x3) {\n return _readSSE.apply(this, arguments);\n}\n/**\r\n * 3.7 AI 流式问答(SSE)\r\n * @param {object} opts { sessionId, message, userId, userName, onEvent }\r\n * onEvent(event, data):event ∈ reasoning | answer | msgKey | agent_result | error\r\n * 返回 Promise,完成时 resolve。\r\n */\n\n\nfunction _readSSE() {\n _readSSE = (0, _asyncToGenerator2.default)( /*#__PURE__*/regeneratorRuntime.mark(function _callee2(url, onEvent) {\n var resp, reader, decoder, buf, _yield$reader$read, done, value, idx, block;\n\n return regeneratorRuntime.wrap(function _callee2$(_context2) {\n while (1) {\n switch (_context2.prev = _context2.next) {\n case 0:\n _context2.prev = 0;\n _context2.next = 3;\n return fetch(url, {\n headers: {\n Accept: \"text/event-stream\"\n }\n });\n\n case 3:\n resp = _context2.sent;\n\n if (!(!resp.ok || !resp.body)) {\n _context2.next = 7;\n break;\n }\n\n onEvent(\"error\", \"SSE \\u8BF7\\u6C42\\u5931\\u8D25\\uFF1AHTTP \".concat(resp.status));\n return _context2.abrupt(\"return\", false);\n\n case 7:\n reader = resp.body.getReader();\n decoder = new TextDecoder(\"utf-8\");\n buf = \"\";\n\n case 10:\n if (false) {}\n\n _context2.next = 13;\n return reader.read();\n\n case 13:\n _yield$reader$read = _context2.sent;\n done = _yield$reader$read.done;\n value = _yield$reader$read.value;\n\n if (!done) {\n _context2.next = 18;\n break;\n }\n\n return _context2.abrupt(\"break\", 23);\n\n case 18:\n buf += decoder.decode(value, {\n stream: true\n }); // SSE 事件以空行分隔\n\n idx = void 0;\n\n while ((idx = buf.indexOf(\"\\n\\n\")) >= 0) {\n block = buf.slice(0, idx);\n buf = buf.slice(idx + 2);\n emitBlock(normalizeBlock(block), onEvent);\n }\n\n _context2.next = 10;\n break;\n\n case 23:\n // 末尾残留块\n if (buf.trim()) emitBlock(normalizeBlock(buf), onEvent);\n return _context2.abrupt(\"return\", true);\n\n case 27:\n _context2.prev = 27;\n _context2.t0 = _context2[\"catch\"](0);\n onEvent(\"error\", \"SSE 连接异常\");\n return _context2.abrupt(\"return\", false);\n\n case 31:\n case \"end\":\n return _context2.stop();\n }\n }\n }, _callee2, null, [[0, 27]]);\n }));\n return _readSSE.apply(this, arguments);\n}\n\nfunction streamChat(_x4) {\n return _streamChat.apply(this, arguments);\n}\n/**\r\n * 3.3 AI 生成审批单总结(SSE 流式)\r\n * 命中缓存时一次性推送完整文本(agent_result);未命中时逐段推送增量文本(answer)。\r\n * @param {string} approvalNo 审批单号\r\n * @param {object} opts { onEvent }\r\n * onEvent(event, data):event ∈ answer | agent_result | error\r\n * 返回 Promise<boolean>,完成时 resolve。\r\n */\n\n\nfunction _streamChat() {\n _streamChat = (0, _asyncToGenerator2.default)( /*#__PURE__*/regeneratorRuntime.mark(function _callee3(_ref4) {\n var sessionId, message, userId, userName, _ref4$onEvent, onEvent, url;\n\n return regeneratorRuntime.wrap(function _callee3$(_context3) {\n while (1) {\n switch (_context3.prev = _context3.next) {\n case 0:\n sessionId = _ref4.sessionId, message = _ref4.message, userId = _ref4.userId, userName = _ref4.userName, _ref4$onEvent = _ref4.onEvent, onEvent = _ref4$onEvent === void 0 ? function () {} : _ref4$onEvent;\n\n if (BASE) {\n _context3.next = 4;\n break;\n }\n\n onEvent(\"error\", \"AI 服务未配置\");\n return _context3.abrupt(\"return\", false);\n\n case 4:\n url = BASE + PREFIX + \"/chat/stream?\" + new URLSearchParams((0, _objectSpread2.default)((0, _objectSpread2.default)({\n sessionId: sessionId,\n message: message\n }, userId ? {\n userId: userId\n } : {}), userName ? {\n userName: userName\n } : {})).toString();\n return _context3.abrupt(\"return\", readSSE(url, onEvent));\n\n case 6:\n case \"end\":\n return _context3.stop();\n }\n }\n }, _callee3);\n }));\n return _streamChat.apply(this, arguments);\n}\n\nfunction streamSummary(_x5) {\n return _streamSummary.apply(this, arguments);\n}\n\nfunction _streamSummary() {\n _streamSummary = (0, _asyncToGenerator2.default)( /*#__PURE__*/regeneratorRuntime.mark(function _callee4(approvalNo) {\n var _ref5,\n _ref5$onEvent,\n onEvent,\n url,\n _args4 = arguments;\n\n return regeneratorRuntime.wrap(function _callee4$(_context4) {\n while (1) {\n switch (_context4.prev = _context4.next) {\n case 0:\n _ref5 = _args4.length > 1 && _args4[1] !== undefined ? _args4[1] : {}, _ref5$onEvent = _ref5.onEvent, onEvent = _ref5$onEvent === void 0 ? function () {} : _ref5$onEvent;\n\n if (BASE) {\n _context4.next = 4;\n break;\n }\n\n onEvent(\"error\", \"AI 服务未配置\");\n return _context4.abrupt(\"return\", false);\n\n case 4:\n url = BASE + PREFIX + \"/instances/\".concat(encodeURIComponent(approvalNo), \"/summary/stream\");\n return _context4.abrupt(\"return\", readSSE(url, onEvent));\n\n case 6:\n case \"end\":\n return _context4.stop();\n }\n }\n }, _callee4);\n }));\n return _streamSummary.apply(this, arguments);\n}\n\nfunction normalizeBlock(block) {\n var event = \"message\";\n var data = [];\n\n var _iterator = (0, _createForOfIteratorHelper2.default)(block.split(\"\\n\")),\n _step;\n\n try {\n for (_iterator.s(); !(_step = _iterator.n()).done;) {\n var line = _step.value;\n\n if (line.startsWith(\"event:\")) {\n event = line.slice(6).trim();\n } else if (line.startsWith(\"data:\")) {\n data.push(line.slice(5).trim());\n }\n }\n } catch (err) {\n _iterator.e(err);\n } finally {\n _iterator.f();\n }\n\n return {\n event: event,\n data: data.join(\"\\n\")\n };\n}\n\nfunction emitBlock(_ref6, onEvent) {\n var event = _ref6.event,\n data = _ref6.data;\n if (!data) return;\n onEvent(event, data);\n}\n\n//# sourceURL=webpack://ZjPluginAiAssistant/./src/lib/components/approvalAi/apiApprovalAi.js?");
|
|
1202
|
+
eval("\n\nvar _interopRequireDefault = __webpack_require__(/*! ./node_modules/@babel/runtime/helpers/interopRequireDefault */ \"./node_modules/@babel/runtime/helpers/interopRequireDefault.js\").default;\n\nObject.defineProperty(exports, \"__esModule\", {\n value: true\n});\nexports.configureAI = configureAI;\nexports.aiConfigured = aiConfigured;\nexports.getInstance = getInstance;\nexports.getSummary = getSummary;\nexports.extractApprovalInfo = extractApprovalInfo;\nexports.getRiskTips = getRiskTips;\nexports.generateOpinion = generateOpinion;\nexports.createChatSession = createChatSession;\nexports.getChatHistory = getChatHistory;\nexports.streamChat = streamChat;\nexports.streamSummary = streamSummary;\n\nvar _objectSpread2 = _interopRequireDefault(__webpack_require__(/*! ./node_modules/@babel/runtime/helpers/objectSpread2 */ \"./node_modules/@babel/runtime/helpers/objectSpread2.js\"));\n\nvar _typeof2 = _interopRequireDefault(__webpack_require__(/*! ./node_modules/@babel/runtime/helpers/typeof */ \"./node_modules/@babel/runtime/helpers/typeof.js\"));\n\nvar _createForOfIteratorHelper2 = _interopRequireDefault(__webpack_require__(/*! ./node_modules/@babel/runtime/helpers/createForOfIteratorHelper */ \"./node_modules/@babel/runtime/helpers/createForOfIteratorHelper.js\"));\n\nvar _asyncToGenerator2 = _interopRequireDefault(__webpack_require__(/*! ./node_modules/@babel/runtime/helpers/asyncToGenerator */ \"./node_modules/@babel/runtime/helpers/asyncToGenerator.js\"));\n\n/**\r\n * AI 审批助手 接口模块(外部系统 zj-ai-agent)\r\n * 对接文档:外部对接-AI审批助手API文档.md\r\n * 说明:\r\n * - 该服务为独立后端,基础地址通过 configureAI({ baseUrl }) 注入(示例:https://api.xxx.cn)\r\n * - 接口统一前缀 /api/v1/approval-ai 已在此拼接,只填 host\r\n * - 未配置 baseUrl 时返回 null,由调用方走本地兜底\r\n */\nvar BASE = \"https://ai.jybtech.cn\" || false;\nvar PREFIX = \"/api/v1/approval-ai\";\n/** 注入 AI 服务地址(覆盖式,可多次调用) */\n\nfunction configureAI() {\n var _ref = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {},\n baseUrl = _ref.baseUrl;\n\n BASE = (baseUrl || \"\").replace(/\\/+$/, \"\");\n}\n/** 是否已配置 AI 服务地址 */\n\n\nfunction aiConfigured() {\n console.log(BASE);\n return Boolean(BASE);\n}\n\nfunction checkCode(data, ref) {\n if (data && (data.code === 200 || data.code === \"200\")) return data;\n if (ref && ref.data) ref.data = data;\n return null;\n}\n\nfunction req(_x) {\n return _req.apply(this, arguments);\n}\n/** 3.1 获取审批单完整数据 */\n\n\nfunction _req() {\n _req = (0, _asyncToGenerator2.default)( /*#__PURE__*/regeneratorRuntime.mark(function _callee(path) {\n var options,\n url,\n params,\n _options$method,\n method,\n body,\n q,\n qs,\n init,\n resp,\n text,\n json,\n _args = arguments;\n\n return regeneratorRuntime.wrap(function _callee$(_context) {\n while (1) {\n switch (_context.prev = _context.next) {\n case 0:\n options = _args.length > 1 && _args[1] !== undefined ? _args[1] : {};\n\n if (BASE) {\n _context.next = 3;\n break;\n }\n\n return _context.abrupt(\"return\", null);\n\n case 3:\n url = BASE + PREFIX + path;\n params = options.params, _options$method = options.method, method = _options$method === void 0 ? \"GET\" : _options$method, body = options.body;\n\n if (params && (0, _typeof2.default)(params) === \"object\") {\n q = new URLSearchParams();\n Object.keys(params).forEach(function (k) {\n var v = params[k];\n if (v !== undefined && v !== null) q.append(k, v);\n });\n qs = q.toString();\n if (qs) url += (url.includes(\"?\") ? \"&\" : \"?\") + qs;\n }\n\n init = {\n method: method,\n headers: {\n Accept: \"application/json\"\n }\n };\n\n if (body !== undefined) {\n init.headers[\"Content-Type\"] = \"application/json\";\n init.body = typeof body === \"string\" ? body : JSON.stringify(body);\n }\n\n _context.prev = 8;\n _context.next = 11;\n return fetch(url, init);\n\n case 11:\n resp = _context.sent;\n _context.next = 14;\n return resp.text();\n\n case 14:\n text = _context.sent;\n json = null;\n\n try {\n json = text ? JSON.parse(text) : null;\n } catch (e) {\n json = null;\n }\n\n return _context.abrupt(\"return\", checkCode(json));\n\n case 20:\n _context.prev = 20;\n _context.t0 = _context[\"catch\"](8);\n return _context.abrupt(\"return\", null);\n\n case 23:\n case \"end\":\n return _context.stop();\n }\n }\n }, _callee, null, [[8, 20]]);\n }));\n return _req.apply(this, arguments);\n}\n\nfunction getInstance(approvalNo) {\n return req(\"/instances/\".concat(encodeURIComponent(approvalNo)));\n}\n/** 3.2 AI 生成审批单总结 */\n\n\nfunction getSummary(approvalNo) {\n return req(\"/instances/\".concat(encodeURIComponent(approvalNo), \"/summary\"), {\n method: \"POST\"\n });\n}\n/** 3.3 AI 信息抽取(结构化) */\n\n\nfunction extractApprovalInfo(approvalNo) {\n return req(\"/instances/\".concat(encodeURIComponent(approvalNo), \"/extract\"), {\n method: \"POST\"\n });\n}\n/** 3.4 AI 风险提示 */\n\n\nfunction getRiskTips(approvalNo) {\n return req(\"/instances/\".concat(encodeURIComponent(approvalNo), \"/risk-tips\"), {\n method: \"POST\"\n });\n}\n/** 3.5 AI 生成审批意见 */\n\n\nfunction generateOpinion(approvalNo) {\n var _ref2 = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {},\n action = _ref2.action,\n hint = _ref2.hint;\n\n return req(\"/instances/\".concat(encodeURIComponent(approvalNo), \"/generate-opinion\"), {\n method: \"POST\",\n body: {\n action: action,\n hint: hint\n }\n });\n}\n/** 3.6 创建 AI 对话会话 */\n\n\nfunction createChatSession(_ref3) {\n var approvalNo = _ref3.approvalNo,\n userId = _ref3.userId,\n userName = _ref3.userName;\n return req(\"/chat/sessions\", {\n method: \"POST\",\n body: {\n approvalNo: approvalNo,\n userId: userId,\n userName: userName\n }\n });\n}\n/**\r\n * 3.9 获取当前用户的会话与历史问答(一个接口完成会话初始化 + 历史回显)\r\n * 会话不存在时自动创建;summary 命中缓存直接返回、未命中为空串;\r\n * records 为空表示该用户还没有问答记录。\r\n * @param {object} params { approvalNo, userId, userName?, pageNum?, pageSize? }\r\n * 返回 { sessionId, summary, total, pageNum, pageSize, records[] }\r\n */\n\n\nfunction getChatHistory() {\n var _ref4 = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {},\n approvalNo = _ref4.approvalNo,\n userId = _ref4.userId,\n userName = _ref4.userName,\n _ref4$pageNum = _ref4.pageNum,\n pageNum = _ref4$pageNum === void 0 ? 1 : _ref4$pageNum,\n _ref4$pageSize = _ref4.pageSize,\n pageSize = _ref4$pageSize === void 0 ? 20 : _ref4$pageSize;\n\n var query = new URLSearchParams({\n approvalNo: approvalNo,\n userId: userId\n });\n if (userName) query.set(\"userName\", userName);\n query.set(\"pageNum\", String(pageNum));\n query.set(\"pageSize\", String(pageSize));\n return req(\"/chat/history?\".concat(query.toString()), {\n method: \"GET\"\n });\n}\n/**\r\n * 通用 SSE 读取:fetch + ReadableStream,按空行切块并派发事件文本\r\n * @param {string} url\r\n * @param {(event: string, data: string) => void} onEvent\r\n */\n\n\nfunction readSSE(_x2, _x3) {\n return _readSSE.apply(this, arguments);\n}\n/**\r\n * 3.7 AI 流式问答(SSE)\r\n * @param {object} opts { sessionId, message, userId, userName, onEvent }\r\n * onEvent(event, data):event ∈ reasoning | answer | msgKey | agent_result | error\r\n * 返回 Promise,完成时 resolve。\r\n */\n\n\nfunction _readSSE() {\n _readSSE = (0, _asyncToGenerator2.default)( /*#__PURE__*/regeneratorRuntime.mark(function _callee2(url, onEvent) {\n var resp, reader, decoder, buf, _yield$reader$read, done, value, idx, block;\n\n return regeneratorRuntime.wrap(function _callee2$(_context2) {\n while (1) {\n switch (_context2.prev = _context2.next) {\n case 0:\n _context2.prev = 0;\n _context2.next = 3;\n return fetch(url, {\n headers: {\n Accept: \"text/event-stream\"\n }\n });\n\n case 3:\n resp = _context2.sent;\n\n if (!(!resp.ok || !resp.body)) {\n _context2.next = 7;\n break;\n }\n\n onEvent(\"error\", \"SSE \\u8BF7\\u6C42\\u5931\\u8D25\\uFF1AHTTP \".concat(resp.status));\n return _context2.abrupt(\"return\", false);\n\n case 7:\n reader = resp.body.getReader();\n decoder = new TextDecoder(\"utf-8\");\n buf = \"\";\n\n case 10:\n if (false) {}\n\n _context2.next = 13;\n return reader.read();\n\n case 13:\n _yield$reader$read = _context2.sent;\n done = _yield$reader$read.done;\n value = _yield$reader$read.value;\n\n if (!done) {\n _context2.next = 18;\n break;\n }\n\n return _context2.abrupt(\"break\", 23);\n\n case 18:\n buf += decoder.decode(value, {\n stream: true\n }); // SSE 事件以空行分隔\n\n idx = void 0;\n\n while ((idx = buf.indexOf(\"\\n\\n\")) >= 0) {\n block = buf.slice(0, idx);\n buf = buf.slice(idx + 2);\n emitBlock(normalizeBlock(block), onEvent);\n }\n\n _context2.next = 10;\n break;\n\n case 23:\n // 末尾残留块\n if (buf.trim()) emitBlock(normalizeBlock(buf), onEvent);\n return _context2.abrupt(\"return\", true);\n\n case 27:\n _context2.prev = 27;\n _context2.t0 = _context2[\"catch\"](0);\n onEvent(\"error\", \"SSE 连接异常\");\n return _context2.abrupt(\"return\", false);\n\n case 31:\n case \"end\":\n return _context2.stop();\n }\n }\n }, _callee2, null, [[0, 27]]);\n }));\n return _readSSE.apply(this, arguments);\n}\n\nfunction streamChat(_x4) {\n return _streamChat.apply(this, arguments);\n}\n/**\r\n * 3.3 AI 生成审批单总结(SSE 流式)\r\n * 命中缓存时一次性推送完整文本(agent_result);未命中时逐段推送增量文本(answer)。\r\n * @param {string} approvalNo 审批单号\r\n * @param {object} opts { onEvent }\r\n * onEvent(event, data):event ∈ answer | agent_result | error\r\n * 返回 Promise<boolean>,完成时 resolve。\r\n */\n\n\nfunction _streamChat() {\n _streamChat = (0, _asyncToGenerator2.default)( /*#__PURE__*/regeneratorRuntime.mark(function _callee3(_ref5) {\n var sessionId, message, userId, userName, _ref5$onEvent, onEvent, url;\n\n return regeneratorRuntime.wrap(function _callee3$(_context3) {\n while (1) {\n switch (_context3.prev = _context3.next) {\n case 0:\n sessionId = _ref5.sessionId, message = _ref5.message, userId = _ref5.userId, userName = _ref5.userName, _ref5$onEvent = _ref5.onEvent, onEvent = _ref5$onEvent === void 0 ? function () {} : _ref5$onEvent;\n\n if (BASE) {\n _context3.next = 4;\n break;\n }\n\n onEvent(\"error\", \"AI 服务未配置\");\n return _context3.abrupt(\"return\", false);\n\n case 4:\n url = BASE + PREFIX + \"/chat/stream?\" + new URLSearchParams((0, _objectSpread2.default)((0, _objectSpread2.default)({\n sessionId: sessionId,\n message: message\n }, userId ? {\n userId: userId\n } : {}), userName ? {\n userName: userName\n } : {})).toString();\n return _context3.abrupt(\"return\", readSSE(url, onEvent));\n\n case 6:\n case \"end\":\n return _context3.stop();\n }\n }\n }, _callee3);\n }));\n return _streamChat.apply(this, arguments);\n}\n\nfunction streamSummary(_x5) {\n return _streamSummary.apply(this, arguments);\n}\n\nfunction _streamSummary() {\n _streamSummary = (0, _asyncToGenerator2.default)( /*#__PURE__*/regeneratorRuntime.mark(function _callee4(approvalNo) {\n var _ref6,\n _ref6$onEvent,\n onEvent,\n url,\n _args4 = arguments;\n\n return regeneratorRuntime.wrap(function _callee4$(_context4) {\n while (1) {\n switch (_context4.prev = _context4.next) {\n case 0:\n _ref6 = _args4.length > 1 && _args4[1] !== undefined ? _args4[1] : {}, _ref6$onEvent = _ref6.onEvent, onEvent = _ref6$onEvent === void 0 ? function () {} : _ref6$onEvent;\n\n if (BASE) {\n _context4.next = 4;\n break;\n }\n\n onEvent(\"error\", \"AI 服务未配置\");\n return _context4.abrupt(\"return\", false);\n\n case 4:\n url = BASE + PREFIX + \"/instances/\".concat(encodeURIComponent(approvalNo), \"/summary/stream\");\n return _context4.abrupt(\"return\", readSSE(url, onEvent));\n\n case 6:\n case \"end\":\n return _context4.stop();\n }\n }\n }, _callee4);\n }));\n return _streamSummary.apply(this, arguments);\n}\n\nfunction normalizeBlock(block) {\n var event = \"message\";\n var data = [];\n\n var _iterator = (0, _createForOfIteratorHelper2.default)(block.split(\"\\n\")),\n _step;\n\n try {\n for (_iterator.s(); !(_step = _iterator.n()).done;) {\n var line = _step.value;\n\n if (line.startsWith(\"event:\")) {\n event = line.slice(6).trim();\n } else if (line.startsWith(\"data:\")) {\n data.push(line.slice(5).trim());\n }\n }\n } catch (err) {\n _iterator.e(err);\n } finally {\n _iterator.f();\n }\n\n return {\n event: event,\n data: data.join(\"\\n\")\n };\n}\n\nfunction emitBlock(_ref7, onEvent) {\n var event = _ref7.event,\n data = _ref7.data;\n if (!data) return;\n onEvent(event, data);\n}\n\n//# sourceURL=webpack://ZjPluginAiAssistant/./src/lib/components/approvalAi/apiApprovalAi.js?");
|
|
1181
1203
|
|
|
1182
1204
|
/***/ }),
|
|
1183
1205
|
|
|
@@ -1189,7 +1211,7 @@ eval("\n\nvar _interopRequireDefault = __webpack_require__(/*! ./node_modules/@b
|
|
|
1189
1211
|
/***/ (function(module, __webpack_exports__, __webpack_require__) {
|
|
1190
1212
|
|
|
1191
1213
|
"use strict";
|
|
1192
|
-
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _index_vue_vue_type_template_id_5d775cd8_scoped_true___WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./index.vue?vue&type=template&id=5d775cd8&scoped=true& */ \"./src/lib/components/approvalAi/index.vue?vue&type=template&id=5d775cd8&scoped=true&\");\n/* harmony import */ var _index_vue_vue_type_script_lang_js___WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./index.vue?vue&type=script&lang=js& */ \"./src/lib/components/approvalAi/index.vue?vue&type=script&lang=js&\");\n/* harmony reexport (unknown) */ for(var __WEBPACK_IMPORT_KEY__ in _index_vue_vue_type_script_lang_js___WEBPACK_IMPORTED_MODULE_1__) if([\"default\"].indexOf(__WEBPACK_IMPORT_KEY__) < 0) (function(key) { __webpack_require__.d(__webpack_exports__, key, function() { return _index_vue_vue_type_script_lang_js___WEBPACK_IMPORTED_MODULE_1__[key]; }) }(__WEBPACK_IMPORT_KEY__));\n/* harmony import */ var _index_vue_vue_type_style_index_0_id_5d775cd8_scoped_true_lang_scss___WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./index.vue?vue&type=style&index=0&id=5d775cd8&scoped=true&lang=scss& */ \"./src/lib/components/approvalAi/index.vue?vue&type=style&index=0&id=5d775cd8&scoped=true&lang=scss&\");\n/* harmony import */ var
|
|
1214
|
+
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _index_vue_vue_type_template_id_5d775cd8_scoped_true___WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./index.vue?vue&type=template&id=5d775cd8&scoped=true& */ \"./src/lib/components/approvalAi/index.vue?vue&type=template&id=5d775cd8&scoped=true&\");\n/* harmony import */ var _index_vue_vue_type_script_lang_js___WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./index.vue?vue&type=script&lang=js& */ \"./src/lib/components/approvalAi/index.vue?vue&type=script&lang=js&\");\n/* harmony reexport (unknown) */ for(var __WEBPACK_IMPORT_KEY__ in _index_vue_vue_type_script_lang_js___WEBPACK_IMPORTED_MODULE_1__) if([\"default\"].indexOf(__WEBPACK_IMPORT_KEY__) < 0) (function(key) { __webpack_require__.d(__webpack_exports__, key, function() { return _index_vue_vue_type_script_lang_js___WEBPACK_IMPORTED_MODULE_1__[key]; }) }(__WEBPACK_IMPORT_KEY__));\n/* harmony import */ var _index_vue_vue_type_style_index_0_id_5d775cd8_scoped_true_lang_scss___WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./index.vue?vue&type=style&index=0&id=5d775cd8&scoped=true&lang=scss& */ \"./src/lib/components/approvalAi/index.vue?vue&type=style&index=0&id=5d775cd8&scoped=true&lang=scss&\");\n/* harmony import */ var _index_vue_vue_type_style_index_1_lang_css___WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./index.vue?vue&type=style&index=1&lang=css& */ \"./src/lib/components/approvalAi/index.vue?vue&type=style&index=1&lang=css&\");\n/* harmony import */ var _node_modules_vue_loader_lib_runtime_componentNormalizer_js__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ../../../../node_modules/vue-loader/lib/runtime/componentNormalizer.js */ \"./node_modules/vue-loader/lib/runtime/componentNormalizer.js\");\n\n\n\n\n\n\n\n/* normalize component */\n\nvar component = Object(_node_modules_vue_loader_lib_runtime_componentNormalizer_js__WEBPACK_IMPORTED_MODULE_4__[\"default\"])(\n _index_vue_vue_type_script_lang_js___WEBPACK_IMPORTED_MODULE_1__[\"default\"],\n _index_vue_vue_type_template_id_5d775cd8_scoped_true___WEBPACK_IMPORTED_MODULE_0__[\"render\"],\n _index_vue_vue_type_template_id_5d775cd8_scoped_true___WEBPACK_IMPORTED_MODULE_0__[\"staticRenderFns\"],\n false,\n null,\n \"5d775cd8\",\n null\n \n)\n\n/* hot reload */\nif (false) { var api; }\ncomponent.options.__file = \"src/lib/components/approvalAi/index.vue\"\n/* harmony default export */ __webpack_exports__[\"default\"] = (component.exports);\n\n//# sourceURL=webpack://ZjPluginAiAssistant/./src/lib/components/approvalAi/index.vue?");
|
|
1193
1215
|
|
|
1194
1216
|
/***/ }),
|
|
1195
1217
|
|
|
@@ -1217,6 +1239,18 @@ eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _nod
|
|
|
1217
1239
|
|
|
1218
1240
|
/***/ }),
|
|
1219
1241
|
|
|
1242
|
+
/***/ "./src/lib/components/approvalAi/index.vue?vue&type=style&index=1&lang=css&":
|
|
1243
|
+
/*!**********************************************************************************!*\
|
|
1244
|
+
!*** ./src/lib/components/approvalAi/index.vue?vue&type=style&index=1&lang=css& ***!
|
|
1245
|
+
\**********************************************************************************/
|
|
1246
|
+
/*! no static exports found */
|
|
1247
|
+
/***/ (function(module, __webpack_exports__, __webpack_require__) {
|
|
1248
|
+
|
|
1249
|
+
"use strict";
|
|
1250
|
+
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _node_modules_vue_style_loader_index_js_ref_6_oneOf_1_0_node_modules_css_loader_dist_cjs_js_ref_6_oneOf_1_1_node_modules_vue_loader_lib_loaders_stylePostLoader_js_node_modules_postcss_loader_src_index_js_ref_6_oneOf_1_2_node_modules_cache_loader_dist_cjs_js_ref_0_0_node_modules_vue_loader_lib_index_js_vue_loader_options_index_vue_vue_type_style_index_1_lang_css___WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! -!../../../../node_modules/vue-style-loader??ref--6-oneOf-1-0!../../../../node_modules/css-loader/dist/cjs.js??ref--6-oneOf-1-1!../../../../node_modules/vue-loader/lib/loaders/stylePostLoader.js!../../../../node_modules/postcss-loader/src??ref--6-oneOf-1-2!../../../../node_modules/cache-loader/dist/cjs.js??ref--0-0!../../../../node_modules/vue-loader/lib??vue-loader-options!./index.vue?vue&type=style&index=1&lang=css& */ \"./node_modules/vue-style-loader/index.js?!./node_modules/css-loader/dist/cjs.js?!./node_modules/vue-loader/lib/loaders/stylePostLoader.js!./node_modules/postcss-loader/src/index.js?!./node_modules/cache-loader/dist/cjs.js?!./node_modules/vue-loader/lib/index.js?!./src/lib/components/approvalAi/index.vue?vue&type=style&index=1&lang=css&\");\n/* harmony import */ var _node_modules_vue_style_loader_index_js_ref_6_oneOf_1_0_node_modules_css_loader_dist_cjs_js_ref_6_oneOf_1_1_node_modules_vue_loader_lib_loaders_stylePostLoader_js_node_modules_postcss_loader_src_index_js_ref_6_oneOf_1_2_node_modules_cache_loader_dist_cjs_js_ref_0_0_node_modules_vue_loader_lib_index_js_vue_loader_options_index_vue_vue_type_style_index_1_lang_css___WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(_node_modules_vue_style_loader_index_js_ref_6_oneOf_1_0_node_modules_css_loader_dist_cjs_js_ref_6_oneOf_1_1_node_modules_vue_loader_lib_loaders_stylePostLoader_js_node_modules_postcss_loader_src_index_js_ref_6_oneOf_1_2_node_modules_cache_loader_dist_cjs_js_ref_0_0_node_modules_vue_loader_lib_index_js_vue_loader_options_index_vue_vue_type_style_index_1_lang_css___WEBPACK_IMPORTED_MODULE_0__);\n/* harmony reexport (unknown) */ for(var __WEBPACK_IMPORT_KEY__ in _node_modules_vue_style_loader_index_js_ref_6_oneOf_1_0_node_modules_css_loader_dist_cjs_js_ref_6_oneOf_1_1_node_modules_vue_loader_lib_loaders_stylePostLoader_js_node_modules_postcss_loader_src_index_js_ref_6_oneOf_1_2_node_modules_cache_loader_dist_cjs_js_ref_0_0_node_modules_vue_loader_lib_index_js_vue_loader_options_index_vue_vue_type_style_index_1_lang_css___WEBPACK_IMPORTED_MODULE_0__) if([\"default\"].indexOf(__WEBPACK_IMPORT_KEY__) < 0) (function(key) { __webpack_require__.d(__webpack_exports__, key, function() { return _node_modules_vue_style_loader_index_js_ref_6_oneOf_1_0_node_modules_css_loader_dist_cjs_js_ref_6_oneOf_1_1_node_modules_vue_loader_lib_loaders_stylePostLoader_js_node_modules_postcss_loader_src_index_js_ref_6_oneOf_1_2_node_modules_cache_loader_dist_cjs_js_ref_0_0_node_modules_vue_loader_lib_index_js_vue_loader_options_index_vue_vue_type_style_index_1_lang_css___WEBPACK_IMPORTED_MODULE_0__[key]; }) }(__WEBPACK_IMPORT_KEY__));\n\n\n//# sourceURL=webpack://ZjPluginAiAssistant/./src/lib/components/approvalAi/index.vue?");
|
|
1251
|
+
|
|
1252
|
+
/***/ }),
|
|
1253
|
+
|
|
1220
1254
|
/***/ "./src/lib/components/approvalAi/index.vue?vue&type=template&id=5d775cd8&scoped=true&":
|
|
1221
1255
|
/*!********************************************************************************************!*\
|
|
1222
1256
|
!*** ./src/lib/components/approvalAi/index.vue?vue&type=template&id=5d775cd8&scoped=true& ***!
|