zj-plugin-ai-assistant 0.2.0-beta.9 → 0.3.0-beta.1
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,19 +229,19 @@ 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//\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");
|
|
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//\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 // 当前登录态 token:init 接口(Authorization 头)用于读取 low-code 表单快照,服务端不落库保存\n authToken: {\n type: String,\n default: \"\"\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 authToken: this.authToken\n });\n },\n // 登录态 token 变化时同步注入(保留当前 baseUrl)\n authToken: function authToken(val) {\n aiApi.configureAI({\n baseUrl: this.baseUrl,\n authToken: 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 // 边界基于浏览器视口,允许在整个页面内自由定位\n var vw = window.innerWidth;\n var vh = window.innerHeight; // 默认贴右下角完整展开:右侧留 20px\n\n if (!this.tucked && !this.btnLeft) {\n this.btnLeft = Math.max(0, vw - 20 - 46);\n } // 若按钮在可视范围外则修正\n\n\n this.btnLeft = Math.max(0, Math.min(this.btnLeft, vw - 46));\n this.btnBottom = Math.max(this.barBottomOffset(), Math.min(this.btnBottom, vh - 44 - 8));\n },\n snapPanel: function snapPanel() {\n // 用户已手动拖动过面板,再次打开保持其位置,不再吸附到按钮附近\n if (this.panelMoved) return;\n var el = this.$el.querySelector(\".ai-panel\");\n if (!el) return;\n var vw = window.innerWidth;\n var vh = window.innerHeight;\n var margin = 24; // 上下安全距离,避免遮挡\n\n var pw = el.clientWidth || 420;\n var ph = el.clientHeight || 560; // 默认 left:面板右上角落在视口右缘外 74px\n\n if (!this.panelLeft) {\n this.panelLeft = Math.max(0, vw - pw - 74);\n }\n\n var desired = this.btnBottom + 62;\n this.panelBottom = Math.max(margin, Math.min(desired, vh - 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 el = this.$el.querySelector(\".ai-panel\");\n var pw = el ? el.clientWidth : 420;\n var ph = el ? el.clientHeight : 560;\n var vw = window.innerWidth;\n var vh = window.innerHeight;\n var p = this.point(e) || {};\n var dx = (p.clientX || 0) - this._pdStartX;\n var dy = (p.clientY || 0) - this._pdStartY;\n var margin = 8; // 视口安全边距,避免完全贴边\n\n var maxLeft = Math.max(0, vw - pw - margin);\n var maxBottom = Math.max(margin, vh - ph - margin);\n this.panelLeft = Math.max(0, Math.min(this._pdStartLeft + dx, maxLeft));\n this.panelBottom = Math.max(margin, 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 hasSummary, data, intro, initSummary, initRes, _intro;\n\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 hasSummary = false;\n\n if (!(_this4.aiEnabled() && _this4.id)) {\n _context.next = 14;\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 data.records.forEach(function (r) {\n _this4.messages.push({\n id: ++msgSeq,\n role: r.role === \"user\" ? \"user\" : \"assistant\",\n content: r.content || \"\",\n thinking: r.thinking || \"\" // 历史记录新增 thinking 字段:反显为可折叠思考过程\n\n });\n\n if (r.id != null && _this4.histLoadedIds.indexOf(r.id) < 0) {\n _this4.histLoadedIds.push(r.id);\n }\n });\n } // 关键:history 接口返回的 summary 是后端共享总结缓存\n // 只要 summary 非空(无论 records 是否为空),说明已有总结,跳过 init + SSE\n\n\n if (data && 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 hasSummary = true;\n }\n\n case 14:\n if (!hasSummary) {\n _context.next = 19;\n break;\n }\n\n // 已有共享总结:内容已就绪,关闭 loading\n _this4.greetingLoading = false;\n\n _this4.scrollBottom();\n\n _context.next = 35;\n break;\n\n case 19:\n // history 无总结(接口异常 / 存量单据未入库 / 后端缓存 miss):\n // 先调 /init(幂等),根据返回 initialized 决定后续路径——\n // initialized=false → 已有缓存,summary 非空,直接用,跳过 SSE\n // initialized=true → 刚初始化,summary 为 null,继续走 SSE 流式总结\n initSummary = null;\n\n if (!(_this4.aiEnabled() && _this4.id)) {\n _context.next = 26;\n break;\n }\n\n _this4.greetingLoadingText = \"正在初始化审批数据\";\n _context.next = 24;\n return aiApi.initInstance(_this4.id);\n\n case 24:\n initRes = _context.sent;\n\n if (initRes && initRes.initialized === false && initRes.summary && String(initRes.summary).trim()) {\n initSummary = String(initRes.summary).trim();\n }\n\n case 26:\n if (!initSummary) {\n _context.next = 33;\n break;\n }\n\n // init 返回已有缓存总结,直接置顶开场白\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 + initSummary\n });\n\n _this4.greetingLoading = false;\n\n _this4.scrollBottom();\n\n _context.next = 35;\n break;\n\n case 33:\n _context.next = 35;\n return _this4.greetSummary();\n\n case 35:\n _context.prev = 35;\n // 兜底关闭 loading(总结流内部也会在内容就绪时提前关闭)\n _this4.greetingLoading = false;\n\n _this4.scrollBottom();\n\n return _context.finish(35);\n\n case 39:\n case \"end\":\n return _context.stop();\n }\n }\n }, _callee, null, [[4,, 35, 39]]);\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 thinking: r.thinking || \"\" // 历史记录新增 thinking 字段:反显为可折叠思考过程\n\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 thinking: \"\",\n _thinkingOpen: true,\n _thinkingLoading: false,\n _thinkingSegs: []\n };\n this.messages.push(msg);\n this.streaming = true;\n this.scrollBottom();\n }\n\n this.getReply(text, function (chunk, isReasoning) {\n if (msg) {\n if (isReasoning) {\n // 思考过程:写入独立字段并切分为段落,逐段淡入上浮展示\n msg.thinking += chunk;\n if (chunk) msg._thinkingSegs.push(chunk);\n msg._thinkingLoading = true;\n msg._thinkingOpen = true;\n } else {\n // 正式回答:正常追加\n msg.content += chunk;\n }\n\n _this8.followBottom();\n\n _this8.scrollThinkingToBottom();\n }\n }).then(function (reply) {\n if (msg) {\n if (!msg.content) msg.content = reply || _this8.fallbackReply(text); // 思考过程结束:停止滚动跟随并自动折叠\n\n msg._thinkingLoading = false;\n msg._thinkingOpen = false;\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 // 思考内容是否已拆分成段落(含分段数组时按段渲染;历史/未分段消息退化为整体一段)\n hasThinkingSegs: function hasThinkingSegs(m) {\n return !!(m && m._thinkingSegs && m._thinkingSegs.length);\n },\n // details 原生折叠状态与数据同步,展开时滚动贴底\n syncThinkingOpen: function syncThinkingOpen(m, e) {\n var open = !!e.target.open;\n\n if (m._thinkingOpen !== open) {\n m._thinkingOpen = open;\n if (open) this.scrollThinkingToBottom();\n }\n },\n // DeepSeek 移动端风格:让思考框内容向上滚动,始终保持最新内容贴底可见\n scrollThinkingToBottom: function scrollThinkingToBottom() {\n var _this9 = this;\n\n this.$nextTick(function () {\n var container = _this9.$refs.chatBody;\n if (!container) return;\n var bodies = container.querySelectorAll(\".thinking-body.thinking-scroll\");\n var last = bodies[bodies.length - 1];\n if (last) last.scrollTop = last.scrollHeight;\n });\n },\n // 获取 AI 回复:已接入后端走流式接口;未接入时返回本地兜底\n getReply: function getReply(question, onDelta) {\n var _this10 = 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: _this10.type,\n status: _this10.status,\n typeName: _this10.typeName,\n id: _this10.id,\n summary: _this10.buildSummary(),\n fields: _this10.fields,\n detailData: _this10.rawDetail\n },\n question: question\n };\n _context5.next = 3;\n return _this10.requestAi(payload, onDelta);\n\n case 3:\n aiReply = _context5.sent;\n return _context5.abrupt(\"return\", aiReply && String(aiReply).trim() ? String(aiReply) : _this10.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 _this11 = 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 (!_this11.sessionId) {\n _context6.next = 2;\n break;\n }\n\n return _context6.abrupt(\"return\", _this11.sessionId);\n\n case 2:\n u = _this11.userInfo();\n _context6.next = 5;\n return aiApi.createChatSession({\n approvalNo: _this11.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 _this11.sessionId = res.data.sessionId;\n return _context6.abrupt(\"return\", _this11.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 _this12 = 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 (_this12.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 _this12.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: _this12.userInfo().no,\n userName: _this12.userInfo().name,\n onEvent: function onEvent(event, data) {\n if (event === \"reasoning\") {\n // 思考过程:单独回调(isReasoning=true),不写入回答文本\n if (onDelta) onDelta(data, true);\n } else if (event === \"answer\") {\n text += data;\n if (onDelta) onDelta(data, false);\n } else if (event === \"agent_result\") {\n text = data;\n if (onDelta) onDelta(data, false);\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 _this13 = this;\n\n var list = [];\n var seen = new Set();\n\n var pushEntry = function pushEntry(label, value) {\n var v = _this13.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 _this14 = 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: _this14.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 _this15 = this;\n\n this.$nextTick(function () {\n var el = _this15.$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\n var vw = window.innerWidth;\n var vh = window.innerHeight;\n var minBottom = this.barBottomOffset();\n var left = Math.max(0, Math.min(this.startLeft + dx, vw - 46));\n var bottom = Math.max(minBottom, Math.min(this.startBottom - dy, vh - 44 - 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 vw = window.innerWidth;\n\n if (vw - (left + 46) <= 30) {\n this.tucked = true;\n this.btnLeft = vw - 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
|
|
|
236
|
-
/***/ "./node_modules/cache-loader/dist/cjs.js?{\"cacheDirectory\":\"node_modules/.cache/vue-loader\",\"cacheIdentifier\":\"
|
|
236
|
+
/***/ "./node_modules/cache-loader/dist/cjs.js?{\"cacheDirectory\":\"node_modules/.cache/vue-loader\",\"cacheIdentifier\":\"02165064-vue-loader-template\"}!./node_modules/vue-loader/lib/loaders/templateLoader.js?!./node_modules/cache-loader/dist/cjs.js?!./node_modules/vue-loader/lib/index.js?!./src/lib/components/approvalAi/index.vue?vue&type=template&id=5d775cd8&scoped=true&":
|
|
237
237
|
/*!*************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************!*\
|
|
238
|
-
!*** ./node_modules/cache-loader/dist/cjs.js?{"cacheDirectory":"node_modules/.cache/vue-loader","cacheIdentifier":"
|
|
238
|
+
!*** ./node_modules/cache-loader/dist/cjs.js?{"cacheDirectory":"node_modules/.cache/vue-loader","cacheIdentifier":"02165064-vue-loader-template"}!./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!./src/lib/components/approvalAi/index.vue?vue&type=template&id=5d775cd8&scoped=true& ***!
|
|
239
239
|
\*************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************/
|
|
240
240
|
/*! exports provided: render, staticRenderFns */
|
|
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.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");
|
|
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 ? [\n _c(\"div\", { staticClass: \"msg__avatar\" }, [\n _c(\"img\", {\n attrs: { src: _vm.iconUrl, alt: \"AI\" }\n })\n ]),\n _c(\"div\", { staticClass: \"msg__body\" }, [\n _c(\n \"div\",\n {\n staticClass:\n \"msg__bubble msg__bubble--assistant\",\n on: { click: _vm.onBubbleClick }\n },\n [\n m.thinking\n ? _c(\n \"details\",\n {\n staticClass: \"thinking-details\",\n attrs: {\n open: !!m._thinkingOpen\n },\n on: {\n toggle: function($event) {\n return _vm.syncThinkingOpen(\n m,\n $event\n )\n }\n }\n },\n [\n _c(\n \"summary\",\n {\n staticClass:\n \"thinking-summary\"\n },\n [_vm._v(\"💭 思考过程\")]\n ),\n _c(\n \"div\",\n {\n staticClass:\n \"thinking-body\",\n class: {\n \"thinking-scroll\":\n m._thinkingLoading\n }\n },\n [\n _vm.hasThinkingSegs(m)\n ? _vm._l(\n m._thinkingSegs,\n function(\n seg,\n segIdx\n ) {\n return _c(\n \"span\",\n {\n key:\n \"seg_\" +\n segIdx,\n staticClass:\n \"thinking-seg\"\n },\n [\n _vm._v(\n _vm._s(seg)\n )\n ]\n )\n }\n )\n : _c(\n \"span\",\n {\n staticClass:\n \"thinking-text\"\n },\n [\n _vm._v(\n _vm._s(m.thinking)\n )\n ]\n ),\n m._thinkingLoading\n ? _c(\"span\", {\n staticClass:\n \"thinking-cursor\",\n attrs: {\n \"aria-label\":\n \"思考中\"\n }\n })\n : _vm._e()\n ],\n 2\n )\n ]\n )\n : _vm._e(),\n _c(\"div\", {\n domProps: {\n innerHTML: _vm._s(\n _vm.renderBubble(m)\n )\n }\n })\n ]\n )\n ])\n ]\n : _c(\"div\", {\n staticClass: \"msg__bubble msg__bubble--user\",\n domProps: {\n innerHTML: _vm._s(_vm.renderBubble(m))\n },\n on: { click: _vm.onBubbleClick }\n })\n ],\n 2\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:%2202165064-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
245
|
|
|
246
246
|
/***/ }),
|
|
247
247
|
|
|
@@ -252,7 +252,7 @@ eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export (binding) *
|
|
|
252
252
|
/*! no static exports found */
|
|
253
253
|
/***/ (function(module, exports, __webpack_require__) {
|
|
254
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
|
|
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\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\n\\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 注入的元素(h1-li-a-strong-code 等)不带 scoped data 属性,\\r\\n scoped 规则(.msg__bubble xxx[data-v-*])对其完全不生效,必须用非 scoped 样式。\\r\\n 用户气泡内容经 escapeHtml 转义不会产生真实标签,此规则仅作用于助手气泡的 markdown 渲染。 */\\r\\n\\r\\n/* Markdown 内容排版 */\\n.ai-panel .msg__bubble h1,\\r\\n.ai-panel .msg__bubble h2,\\r\\n.ai-panel .msg__bubble h3,\\r\\n.ai-panel .msg__bubble h4,\\r\\n.ai-panel .msg__bubble h5,\\r\\n.ai-panel .msg__bubble h6 {\\r\\n font-size: 14px;\\r\\n font-weight: 600;\\r\\n color: #1f2329;\\r\\n margin: 8px 0 4px;\\r\\n padding-left: 8px;\\r\\n border-left: 3px solid #3067d9;\\r\\n line-height: 1.5;\\n}\\n.ai-panel .msg__bubble h1:first-child,\\r\\n.ai-panel .msg__bubble h2:first-child,\\r\\n.ai-panel .msg__bubble h3:first-child,\\r\\n.ai-panel .msg__bubble h4:first-child,\\r\\n.ai-panel .msg__bubble h5:first-child,\\r\\n.ai-panel .msg__bubble h6:first-child {\\r\\n margin-top: 0;\\n}\\n.ai-panel .msg__bubble p {\\r\\n /* margin: 4px 0; */\\n}\\n.ai-panel .msg__bubble p:first-child {\\r\\n margin-top: 0;\\n}\\n.ai-panel .msg__bubble ul,\\r\\n.ai-panel .msg__bubble ol {\\r\\n margin: 6px 0;\\r\\n padding-left: 20px;\\r\\n list-style-position: outside;\\n}\\n.ai-panel .msg__bubble ul {\\r\\n list-style: disc;\\n}\\n.ai-panel .msg__bubble ol {\\r\\n list-style: decimal;\\n}\\n.ai-panel .msg__bubble li {\\r\\n margin: 3px 0;\\r\\n padding: 4px 2px;\\n}\\r\\n\\r\\n/* 紧凑 <li> 与 <li><p> 结构视觉一致:<p> 的间距统一转移到 li 内边距,避免条目高度不一 */\\n.ai-panel .msg__bubble li > p {\\r\\n margin: 0;\\n}\\n.ai-panel .msg__bubble li > p + p {\\r\\n margin-top: 4px;\\n}\\n.ai-panel .msg__bubble blockquote {\\r\\n margin: 8px 0;\\r\\n padding: 2px 12px;\\r\\n border-left: 3px solid #dde3ee;\\r\\n background: #fafbfc;\\r\\n border-radius: 4px;\\r\\n color: #86909c;\\n}\\n.ai-panel .msg__bubble hr {\\r\\n border: none;\\r\\n border-top: 1px dashed #e4e7ed;\\r\\n margin: 10px 0;\\n}\\n.ai-panel .msg__bubble strong {\\r\\n color: #1f2329;\\r\\n font-weight: 600;\\n}\\n.ai-panel .msg__bubble code {\\r\\n background: #f0f2f5;\\r\\n color: #d83931;\\r\\n padding: 1px 4px;\\r\\n border-radius: 3px;\\r\\n font-size: 12px;\\n}\\n.ai-panel .msg__bubble pre {\\r\\n background: #f6f7f8;\\r\\n padding: 8px;\\r\\n border-radius: 6px;\\r\\n overflow-x: auto;\\r\\n margin: 6px 0;\\n}\\n.ai-panel .msg__bubble pre code {\\r\\n background: none;\\r\\n color: #1f2329;\\r\\n padding: 0;\\n}\\r\\n\\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\\r\\n/* H5 放大 markdown 标题/行内代码(同样需非 scoped 才能命中 v-html 内容) */\\n@media (max-width: 480px) {\\n.ai-panel .msg__bubble h1,\\r\\n .ai-panel .msg__bubble h2,\\r\\n .ai-panel .msg__bubble h3,\\r\\n .ai-panel .msg__bubble h4,\\r\\n .ai-panel .msg__bubble h5,\\r\\n .ai-panel .msg__bubble h6 {\\r\\n font-size: 17px;\\n}\\n.ai-panel .msg__bubble code {\\r\\n font-size: 14px;\\n}\\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");
|
|
256
256
|
|
|
257
257
|
/***/ }),
|
|
258
258
|
|
|
@@ -263,7 +263,7 @@ eval("// Imports\nvar ___CSS_LOADER_API_IMPORT___ = __webpack_require__(/*! ../.
|
|
|
263
263
|
/*! no static exports found */
|
|
264
264
|
/***/ (function(module, exports, __webpack_require__) {
|
|
265
265
|
|
|
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");
|
|
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 /* fixed:覆盖整个浏览器视口,面板/按钮可在视口任意位置拖拽 */\\n position: fixed;\\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__body[data-v-5d775cd8] {\\n flex: 1 1 auto;\\n min-width: 0;\\n display: flex;\\n flex-direction: column;\\n align-items: flex-start;\\n}\\n.msg .thinking-details[data-v-5d775cd8] {\\n width: 100%;\\n box-sizing: border-box;\\n margin-bottom: 8px;\\n padding-bottom: 10px;\\n border-bottom: 1px dashed #e5e6eb;\\n}\\n.msg .thinking-summary[data-v-5d775cd8] {\\n font-size: 12px;\\n color: #888;\\n cursor: pointer;\\n padding: 6px 0 0 0;\\n -webkit-user-select: none;\\n -moz-user-select: none;\\n -ms-user-select: none;\\n user-select: none;\\n /* H5 WebView 对原生 summary 箭头支持不完整,隐藏后改用自定义图标 */\\n list-style: none;\\n display: flex;\\n align-items: center;\\n gap: 4px;\\n}\\n.msg .thinking-summary[data-v-5d775cd8]::-webkit-details-marker {\\n display: none;\\n}\\n.msg .thinking-summary[data-v-5d775cd8]::before {\\n content: \\\"\\\";\\n width: 0;\\n height: 0;\\n border-top: 5px solid transparent;\\n border-bottom: 5px solid transparent;\\n border-left: 6px solid #888;\\n transition: transform 0.15s ease;\\n}\\n.msg .thinking-details[open] .thinking-summary[data-v-5d775cd8]::before {\\n transform: rotate(90deg);\\n}\\n.msg .thinking-summary[data-v-5d775cd8]:hover {\\n color: #1677ff;\\n}\\n.msg .thinking-body[data-v-5d775cd8] {\\n font-size: 14px;\\n color: #666;\\n padding: 8px 12px;\\n line-height: 1.6;\\n border-top: 1px solid #f0f0f0;\\n text-align: left;\\n white-space: pre-wrap;\\n word-break: break-word;\\n overflow-wrap: break-word;\\n overflow-wrap: anywhere;\\n}\\n.msg[data-v-5d775cd8] {\\n /* DeepSeek 风格「思考」效果:思考内容分段淡入上浮,末尾闪烁光标,生成结束光标消失 */\\n}\\n.msg .thinking-body .thinking-text[data-v-5d775cd8] {\\n display: inline;\\n}\\n.msg .thinking-seg[data-v-5d775cd8] {\\n display: inline-block;\\n -webkit-animation: thinking-seg-rise-data-v-5d775cd8 0.4s ease-out both;\\n animation: thinking-seg-rise-data-v-5d775cd8 0.4s ease-out both;\\n white-space: pre-wrap;\\n}\\n@-webkit-keyframes thinking-seg-rise-data-v-5d775cd8 {\\nfrom {\\n opacity: 0;\\n transform: translateY(4px);\\n}\\nto {\\n opacity: 1;\\n transform: translateY(0);\\n}\\n}\\n@keyframes thinking-seg-rise-data-v-5d775cd8 {\\nfrom {\\n opacity: 0;\\n transform: translateY(4px);\\n}\\nto {\\n opacity: 1;\\n transform: translateY(0);\\n}\\n}\\n.msg .thinking-cursor[data-v-5d775cd8] {\\n display: inline-block;\\n width: 2px;\\n height: 14px;\\n margin-left: 4px;\\n vertical-align: -2px;\\n background: #1677ff;\\n border-radius: 1px;\\n -webkit-animation: thinking-cursor-blink-data-v-5d775cd8 1s ease-in-out infinite;\\n animation: thinking-cursor-blink-data-v-5d775cd8 1s ease-in-out infinite;\\n}\\n@-webkit-keyframes thinking-cursor-blink-data-v-5d775cd8 {\\n0%, 100% {\\n opacity: 1;\\n}\\n50% {\\n opacity: 0;\\n}\\n}\\n@keyframes thinking-cursor-blink-data-v-5d775cd8 {\\n0%, 100% {\\n opacity: 1;\\n}\\n50% {\\n opacity: 0;\\n}\\n}\\n.msg[data-v-5d775cd8] {\\n /* 思考框滚动:仅在流式加载中(thinking-scroll 绑 _thinkingLoading)限高 96px、内容贴底滚动;\\n 手动展开(_thinkingOpen)时无该类,无限高全部展示 */\\n}\\n.msg .thinking-scroll[data-v-5d775cd8] {\\n max-height: 96px;\\n overflow-y: auto;\\n overflow-x: hidden;\\n -ms-scroll-chaining: none;\\n overscroll-behavior: contain;\\n -webkit-overflow-scrolling: touch;\\n scrollbar-width: none;\\n scroll-behavior: auto;\\n}\\n.msg .thinking-scroll[data-v-5d775cd8]::-webkit-scrollbar {\\n width: 0;\\n height: 0;\\n}\\n.msg__bubble[data-v-5d775cd8] {\\n max-width: 100%;\\n width: 100%;\\n box-sizing: border-box; /* 让 padding/border 计入宽度,像素级同宽 */\\n font-size: 14px;\\n line-height: 1.5;\\n word-break: break-word;\\n color: #333;\\n padding: 11px 14px;\\n border-radius: 8px;\\n background: #fafafa;\\n border: 1px solid #e8e8e8;\\n box-shadow: 0 1px 2px rgba(16, 24, 40, 0.04);\\n}\\n.msg--user .msg__bubble[data-v-5d775cd8] {\\n width: auto;\\n max-width: 76%;\\n margin-left: auto;\\n padding: 8px 14px;\\n border-radius: 12px;\\n border-bottom-right-radius: 4px;\\n background: #1677ff;\\n border-color: #1677ff;\\n color: #fff;\\n box-shadow: 0 2px 8px rgba(22, 119, 255, 0.15);\\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.msg__bubble--typing[data-v-5d775cd8], .msg__bubble--loading[data-v-5d775cd8] {\\n width: auto;\\n max-width: 76%;\\n border-radius: 8px;\\n background: #fafafa;\\n border: 1px solid #e8e8e8;\\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 放大审批详情/聊天文字,提升可读性(markdown 元素 h1-h6/code 的放大在文件末尾非 scoped 媒体查询中) */\\n.msg__bubble[data-v-5d775cd8] {\\n font-size: 15px;\\n line-height: 1.5;\\n}\\n.msg--user .msg__bubble[data-v-5d775cd8] {\\n padding: 11px 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");
|
|
267
267
|
|
|
268
268
|
/***/ }),
|
|
269
269
|
|
|
@@ -1199,7 +1199,7 @@ eval("module.exports = \"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAFgAAABYC
|
|
|
1199
1199
|
/***/ (function(module, exports, __webpack_require__) {
|
|
1200
1200
|
|
|
1201
1201
|
"use strict";
|
|
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?");
|
|
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.initInstance = initInstance;\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\"; // 登录态 token:init 接口需要 Authorization 头读取 low-code 表单快照(服务端不落库),\n// 通过 configureAI({ authToken }) 注入,req() 统一携带\n\nvar AUTH_TOKEN = \"\";\n/** 注入 AI 服务地址(覆盖式,可多次调用) */\n\nfunction configureAI() {\n var _ref = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {},\n baseUrl = _ref.baseUrl,\n authToken = _ref.authToken;\n\n BASE = (baseUrl || \"\").replace(/\\/+$/, \"\");\n if (authToken !== undefined) AUTH_TOKEN = authToken;\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 if (AUTH_TOKEN) init.headers[\"Authorization\"] = \"Bearer \".concat(AUTH_TOKEN);\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 = 9;\n _context.next = 12;\n return fetch(url, init);\n\n case 12:\n resp = _context.sent;\n _context.next = 15;\n return resp.text();\n\n case 15:\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 21:\n _context.prev = 21;\n _context.t0 = _context[\"catch\"](9);\n return _context.abrupt(\"return\", null);\n\n case 24:\n case \"end\":\n return _context.stop();\n }\n }\n }, _callee, null, [[9, 21]]);\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.2.1 审批单初始化(存量单据入库 + 生成缓存总结):\r\n * 历史接口无总结时调用,按数据源重建落库并同步生成 AI 总结进共享缓存;幂等 */\n\n\nfunction initInstance(approvalNo) {\n return req(\"/instances/\".concat(encodeURIComponent(approvalNo), \"/init\"), {\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?");
|
|
1203
1203
|
|
|
1204
1204
|
/***/ }),
|
|
1205
1205
|
|
|
@@ -1259,7 +1259,7 @@ eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _nod
|
|
|
1259
1259
|
/***/ (function(module, __webpack_exports__, __webpack_require__) {
|
|
1260
1260
|
|
|
1261
1261
|
"use strict";
|
|
1262
|
-
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var
|
|
1262
|
+
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _node_modules_cache_loader_dist_cjs_js_cacheDirectory_node_modules_cache_vue_loader_cacheIdentifier_02165064_vue_loader_template_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_index_js_vue_loader_options_index_vue_vue_type_template_id_5d775cd8_scoped_true___WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! -!../../../../node_modules/cache-loader/dist/cjs.js?{\"cacheDirectory\":\"node_modules/.cache/vue-loader\",\"cacheIdentifier\":\"02165064-vue-loader-template\"}!../../../../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!./index.vue?vue&type=template&id=5d775cd8&scoped=true& */ \"./node_modules/cache-loader/dist/cjs.js?{\\\"cacheDirectory\\\":\\\"node_modules/.cache/vue-loader\\\",\\\"cacheIdentifier\\\":\\\"02165064-vue-loader-template\\\"}!./node_modules/vue-loader/lib/loaders/templateLoader.js?!./node_modules/cache-loader/dist/cjs.js?!./node_modules/vue-loader/lib/index.js?!./src/lib/components/approvalAi/index.vue?vue&type=template&id=5d775cd8&scoped=true&\");\n/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, \"render\", function() { return _node_modules_cache_loader_dist_cjs_js_cacheDirectory_node_modules_cache_vue_loader_cacheIdentifier_02165064_vue_loader_template_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_index_js_vue_loader_options_index_vue_vue_type_template_id_5d775cd8_scoped_true___WEBPACK_IMPORTED_MODULE_0__[\"render\"]; });\n\n/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, \"staticRenderFns\", function() { return _node_modules_cache_loader_dist_cjs_js_cacheDirectory_node_modules_cache_vue_loader_cacheIdentifier_02165064_vue_loader_template_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_index_js_vue_loader_options_index_vue_vue_type_template_id_5d775cd8_scoped_true___WEBPACK_IMPORTED_MODULE_0__[\"staticRenderFns\"]; });\n\n\n\n//# sourceURL=webpack://ZjPluginAiAssistant/./src/lib/components/approvalAi/index.vue?");
|
|
1263
1263
|
|
|
1264
1264
|
/***/ }),
|
|
1265
1265
|
|