zhangqi hace 5 meses
padre
commit
95e4a240b2

+ 625 - 0
src/components/AIDialog/data.js

@@ -0,0 +1,625 @@
+// 模拟对话数据与工具函数
+// 可与 AIDialog/index.vue 配合使用,作为初始数据或回退模拟
+
+// 预设问题(可根据业务扩展)
+export const presets = [
+  '查询近30天销售线索',
+  '查询近30天未跟进项目',
+  '查询近30天未跟进客户',
+  '查询签到记录',
+  '查询今日任务',
+  '查询项目跟进记录',
+  '查询报备项目',
+]
+
+// 示例消息列表(用于初始化展示)
+export const sampleMessages = [
+]
+
+// FAQ/快捷问法(可在界面展示成标签或菜单)
+export const quickFaq = [
+  {
+    q: '如何筛选未发货订单?',
+    a: '在查询条件中,将“发货状态”设置为“未发货”,并按时间区间筛选。',
+  },
+  {
+    q: '表格字段含义说明',
+    a: '例如“accountno”为账户编号,“amount”为金额,支持统一格式化展示。',
+  },
+  {
+    q: '导出报表建议',
+    a: '建议先设置好筛选条件,然后导出当前视图的数据,以保证数据一致性。',
+  },
+]
+
+// 模拟 AI 回复(前端本地逻辑,接口失败时可作为回退)
+export function simulateAIReply(text) {
+  const templates = [
+    (t) => `这是基于你的问题的思路:\n1) 明确目标\n2) 列出关键点\n3) 给出执行步骤\n\n问题:${t}`,
+    (t) => `我已理解你的问题:“${t}”。建议:\n- 分析数据来源\n- 明确条件与边界\n- 输出结构化结果`,
+    (t) => `为你生成的初步答案:\n${t}\n—— 如需更详细,请补充更多上下文。`,
+  ]
+  const idx = Math.floor(Math.random() * templates.length)
+  return templates[idx](text)
+}
+
+// 本地模拟请求(不替代实际 Api.requested,仅用于开发/演示)
+export function mockRequested(question) {
+  const q = String(question || '').toLowerCase()
+
+  // 构造“最近订单表格”示例数据
+  const buildRecentOrders = () => ({
+    content: '为你查询到最近的订单:',
+    table: {
+      columns: [
+        { title: '订单号', dataIndex: 'sonum', width: 180, ellipsis: true },
+        { title: 'ERP单号', dataIndex: 'erpbillno', width: 160, ellipsis: true },
+        { title: '订单类型', dataIndex: 'type', width: 120, ellipsis: true },
+        { title: '订单状态', dataIndex: 'status', width: 120, ellipsis: true },
+        { title: '领域', dataIndex: 'tradefield', width: 120, ellipsis: true },
+        { title: '企业名称', dataIndex: 'enterprisename', width: 200, ellipsis: true },
+        { title: '项目名称', dataIndex: 'projectname', width: 260, ellipsis: true },
+        { title: '数量', dataIndex: 'qty', width: 100, ellipsis: true },
+        { title: '总金额(元)', dataIndex: 'amount', width: 140, ellipsis: true },
+        { title: '备注', dataIndex: 'remarks', width: 260, ellipsis: true },
+        { title: '备货状态', dataIndex: 'goodsstatus', width: 120, ellipsis: true },
+        { title: '核销状态', dataIndex: 'writeoffstatus', width: 120, ellipsis: true },
+        { title: '开票状态', dataIndex: 'invoicestatus', width: 120, ellipsis: true },
+        { title: '业务员', dataIndex: 'salename', width: 120, ellipsis: true },        
+        { title: '是否退货', dataIndex: 'isreturn', width: 120, ellipsis: true },
+        { title: '是否变更', dataIndex: 'ischange', width: 120, ellipsis: true },
+        { title: '审核时间', dataIndex: 'checkdate', width: 180, ellipsis: true },
+      ],
+      dataSource: [
+        {
+          key: 'SO-202409120030',
+          invoicestatus: '已开票',
+          ischange: '0',
+          sys_enterpriseid: 4370,
+          writeoffamount: 583588.20,
+          enterprisename: '四川青石建设有限公司',
+          brandname: '',
+          type: '项目订单',
+          isreturn: '0',
+          invoiceamount: 972647.00,
+          defaultamount: 972647.00,
+          returnamount: 0.00,
+          rowindex: 1,
+          erpbillno: 'ASO1-24090154',
+          sonum: 'SO-202409120030',
+          amount: 972647.00,
+          projectname: '涿州市城区地表水厂灾后恢复工程-气动及电动阀门',
+          salename: '柏为东',
+          sa_orderid: 65368,
+          goodsstatus: '未备货',
+          writeoffstatus: '部分核销',
+          qty: 29.0000,
+          submitdate: '2024-09-18 12:01:27',
+          remarks: ' 出货资料一式两份',
+          checkdate: '2024-09-18 15:23:00',
+          tradefield: '全领域',
+          status: '关闭'
+        },
+        {
+            "invoicestatus": "已开票",
+            "ischange": "0",
+            "sys_enterpriseid": 4370,
+            "writeoffamount": 127585.20,
+            "enterprisename": "四川青石建设有限公司",
+            "brandname": "",
+            "type": "项目订单",
+            "isreturn": "0",
+            "invoiceamount": 212642.00,
+            "defaultamount": 212642.00,
+            "returnamount": 0.00,
+            "rowindex": 2,
+            "erpbillno": "ASO1-23120149",
+            "sonum": "SO-202312120033",
+            "amount": 212642.00,
+            "projectname": "涿州市松店镇地表水厂增容工程—电动及气动阀门",
+            "salename": "刘伟",
+            "sa_orderid": 55377,
+            "goodsstatus": "未备货",
+            "writeoffstatus": "部分核销",
+            "qty": 4.0000,
+            "submitdate": "2023-12-18 14:13:37",
+            "remarks": "03-送水泵房(阀门);出货资料一式两份;",
+            "checkdate": "2023-12-18 15:50:02",
+            "tradefield": "全领域",
+            "status": "关闭"
+        },
+        {
+            "invoicestatus": "已开票",
+            "ischange": "0",
+            "sys_enterpriseid": 4370,
+            "writeoffamount": 286206.00,
+            "enterprisename": "四川青石建设有限公司",
+            "brandname": "",
+            "type": "项目订单",
+            "isreturn": "0",
+            "invoiceamount": 477010.00,
+            "defaultamount": 477010.00,
+            "returnamount": 0.00,
+            "rowindex": 3,
+            "erpbillno": "ASO1-23120148",
+            "sonum": "SO-202312120032",
+            "amount": 477010.00,
+            "projectname": "涿州市松店镇地表水厂增容工程—电动及气动阀门",
+            "salename": "刘伟",
+            "sa_orderid": 55376,
+            "goodsstatus": "未备货",
+            "writeoffstatus": "部分核销",
+            "qty": 54.0000,
+            "submitdate": "2023-12-18 14:13:29",
+            "remarks": "02-净水间2(阀门): 1、出货资料一式两份;2、第1-2项气动角型隔膜排泥阀产品及其配件,出货要求见附件; 3、气动蝶阀安装方式如附件;",
+            "checkdate": "2023-12-18 15:49:40",
+            "tradefield": "全领域",
+            "status": "关闭"
+        },
+        {
+            "invoicestatus": "已开票",
+            "ischange": "0",
+            "sys_enterpriseid": 4370,
+            "writeoffamount": 143103.00,
+            "enterprisename": "四川青石建设有限公司",
+            "brandname": "",
+            "type": "项目订单",
+            "isreturn": "0",
+            "invoiceamount": 238505.00,
+            "defaultamount": 238505.00,
+            "returnamount": 0.00,
+            "rowindex": 4,
+            "erpbillno": "ASO1-23120147",
+            "sonum": "SO-202312120031",
+            "amount": 238505.00,
+            "projectname": "涿州市松店镇地表水厂增容工程—电动及气动阀门",
+            "salename": "刘伟",
+            "sa_orderid": 55375,
+            "goodsstatus": "未备货",
+            "writeoffstatus": "部分核销",
+            "qty": 27.0000,
+            "submitdate": "2023-12-18 14:13:19",
+            "remarks": "01-净水间1(阀门):1、出货资料一式两份;2、第1-2项气动角型隔膜排泥阀产品及其配件,出货要求见附件; 3、气动蝶阀安装方式如附件;",
+            "checkdate": "2023-12-18 15:49:27",
+            "tradefield": "全领域",
+            "status": "关闭"
+        },
+        {
+            "invoicestatus": "已开票",
+            "ischange": "0",
+            "sys_enterpriseid": 4370,
+            "writeoffamount": 1204810.20,
+            "enterprisename": "四川青石建设有限公司",
+            "brandname": "",
+            "type": "项目订单",
+            "isreturn": "0",
+            "invoiceamount": 2008017.00,
+            "defaultamount": 2008017.00,
+            "returnamount": 0.00,
+            "rowindex": 5,
+            "erpbillno": "ASO1-23120146",
+            "sonum": "SO-202312120025",
+            "amount": 2008017.00,
+            "projectname": "涿州市城区地表水厂增容工程—电动、气动阀门",
+            "salename": "刘伟",
+            "sa_orderid": 55369,
+            "goodsstatus": "未备货",
+            "writeoffstatus": "部分核销",
+            "qty": 57.0000,
+            "submitdate": "2023-12-18 14:13:10",
+            "remarks": "1、出货资料一式两份;2、第1-3项电动蝶阀为立式安装(如附件),出厂时请将支脚安装于阀体上; 3、气动蝶阀安装方式如附件;",
+            "checkdate": "2023-12-18 15:49:09",
+            "tradefield": "全领域",
+            "status": "关闭"
+        },
+        {
+            "invoicestatus": "已开票",
+            "ischange": "0",
+            "sys_enterpriseid": 4370,
+            "writeoffamount": 271452.60,
+            "enterprisename": "四川青石建设有限公司",
+            "brandname": "",
+            "type": "项目订单",
+            "isreturn": "0",
+            "invoiceamount": 452421.00,
+            "defaultamount": 452421.00,
+            "returnamount": 0.00,
+            "rowindex": 6,
+            "erpbillno": "ASO1-23070057",
+            "sonum": "SO-202307100005",
+            "amount": 452421.00,
+            "projectname": "颍上自来水厂(二期)10标段 电气动阀门",
+            "salename": "刘伟",
+            "sa_orderid": 49819,
+            "goodsstatus": "未备货",
+            "writeoffstatus": "部分核销",
+            "qty": 5.0000,
+            "submitdate": "2023-07-10 10:02:53",
+            "remarks": "增加加长杆备注",
+            "checkdate": "2023-07-10 10:16:01",
+            "tradefield": "全领域",
+            "status": "关闭"
+        },
+        {
+            "invoicestatus": "已开票",
+            "ischange": "1",
+            "sys_enterpriseid": 4370,
+            "writeoffamount": 1098748.80,
+            "enterprisename": "四川青石建设有限公司",
+            "brandname": "",
+            "type": "项目订单",
+            "isreturn": "0",
+            "invoiceamount": 1831248.00,
+            "defaultamount": 1831248.00,
+            "returnamount": 0.00,
+            "rowindex": 7,
+            "erpbillno": "ASO1-23050220",
+            "sonum": "SO-202305230052",
+            "amount": 1831248.00,
+            "projectname": "颍上自来水厂(二期)10标段 电气动阀门",
+            "salename": "刘伟",
+            "sa_orderid": 48009,
+            "goodsstatus": "未备货",
+            "writeoffstatus": "部分核销",
+            "qty": 85.0000,
+            "submitdate": "2023-05-25 11:28:04",
+            "remarks": "",
+            "checkdate": "2023-05-26 10:43:12",
+            "tradefield": "全领域",
+            "status": "关闭"
+        }
+      ],
+    },
+  })
+  // 构造“最近线索表格”示例数据
+  const buildRecentClues = () => ({
+    content: '为你查询到最近的线索:',
+    button: ['详情'],
+    table: {
+      columns: [
+        { title: '城市', dataIndex: 'city',width: 150, ellipsis: false },
+        { title: '项目名称', dataIndex: 'projectName',width: 200, ellipsis: false },
+        { title: '投资估算(万元)', dataIndex: 'investmentEstimate',width: 150, ellipsis: false },
+        { title: '招标内容', dataIndex: 'tenderContent',width: 300, ellipsis: false },
+        { title: '发布时间', dataIndex: 'publishDate',width: 150, ellipsis: false },
+        { title: '来源', dataIndex: 'source',width: 150, ellipsis: false },
+      ],
+      dataSource: [
+        { key: '1', city: '北京市怀柔区', projectName: '怀柔地表水厂建设工程', investmentEstimate: 8000, tenderContent: '怀柔地表水厂建设工程的初步设计(含设计概算)、施工图设计、工程施工、设备采购', publishDate: '2025.10.25', source: '公共资源中心' },
+        { key: '2', city: '浙江省嘉兴市', projectName: '嘉兴联合污水处理厂二期改造工程施工02标', investmentEstimate: 17923.09, tenderContent: '1)联合污水厂厂内:主要涉及污水泵房、雨水泵房、初沉池、二沉池、细格栅及沉砂池、浓缩池、排海泵房、', publishDate: '2025.11.7', source: '公共资源中心' },
+        { key: '3', city: '贵州省贵阳市', projectName: '朱家河污水处理厂设备升级更新项目(一标段)设备采购及安装', investmentEstimate: 6000, tenderContent: '', publishDate: '2025.11.7', source: '公共资源中心' },
+      ],
+    },
+  })
+  // 跟进对象
+  const buildFollowUpObject = () => ({ 
+    content: `<p style="line-height:25px;margin:0;">跟进对象?</p>`,
+    table: {
+      columns: [
+        { title: '姓名', dataIndex: 'name',width: 150, ellipsis: false },
+        { title: '联系方式', dataIndex: 'contact',width: 200, ellipsis: false },
+        { title: '微信', dataIndex: 'wechat',width: 150, ellipsis: false },
+        { title: '标签', dataIndex: 'tags',width: 300, ellipsis: false },
+        { title: '邮箱', dataIndex: 'email',width: 150, ellipsis: false },
+        { title: '部门', dataIndex: 'source',width: 150, ellipsis: false },
+      ],
+      dataSource: [
+        { key: '1', name: '陈金贵', contact: '13801921384', wechat: '--', tags: '支持者', email: '--', source: '销售部' },
+        { key: '2', name: '袁永详', contact: '13816957336', wechat: '--', tags: '关键决策人', email: '--', source: '总经办' },
+      ],
+    },
+  })
+
+  // 回款订单(逾期收款明细)
+  const buildOverduePayments = () => ({
+    content: '为你查询到逾期收款明细:',
+    table: {
+      columns: [
+        { title: '逾期说明', dataIndex: 'overdueexplanation', width: 360, ellipsis: false },
+        { title: '业务员', dataIndex: 'name', width: 120, ellipsis: true },
+        { title: '部门', dataIndex: 'depname', width: 120, ellipsis: true },
+        { title: '订单号', dataIndex: 'sonum', width: 180, ellipsis: true },
+        { title: '项目名称', dataIndex: 'projectname', width: 240, ellipsis: true },
+        { title: '客户名称', dataIndex: 'enterprisename', width: 220, ellipsis: true },
+        { title: '行号', dataIndex: 'rowno', width: 80, ellipsis: true },
+        { title: '商品名称', dataIndex: 'itemname', width: 180, ellipsis: true },
+        { title: '商品编码', dataIndex: 'itemno', width: 160, ellipsis: true },
+        { title: '订单数量', dataIndex: 'qty', width: 100, ellipsis: true },
+        { title: '订单金额(元)', dataIndex: 'amount', width: 140, ellipsis: true },
+        { title: '逾期金额(元)', dataIndex: 'overdueamount', width: 160, ellipsis: true },
+        { title: '审核时间', dataIndex: 'checkdate', width: 180, ellipsis: true },
+        
+      ],
+      dataSource: [
+        {
+          key: 'SO-202403190003-328412',
+          rowno: 20,
+          projectname: '庆元县人民医院迁建工程',
+          amount: 19550.00,
+          sonum: 'SO-202403190003',
+          itemname: 'BRVB喷管止回阀',
+          sys_enterpriseid: 2664,
+          itemno: '28131890009',
+          enterprisename: '杭州祺源实业有限公司',
+          overdueamount: 187.96,
+          spec: 'DN200/PN16',
+          sa_orderitemsid: 328412,
+          sa_orderid: 58106,
+          hrid: 480,
+          qty: 10.0,
+          name: '吴金星',
+          overdueexplanation: '已出货 533 天,依照合同收款条件,应于 2024-05-30 收款,现已逾期 532 天',
+          model: 'BRVB-0200C',
+          depname: '华东区',
+          rowindex: 1,
+          checkdate: '2024-03-19 14:14:36'
+        },
+        {
+            "rowno": 2,
+            "projectname": "庆元县人民医院迁建工程",
+            "amount": 3876.00,
+            "sonum": "SO-202403220027",
+            "itemname": "BAGV丝口型黄铜闸阀",
+            "sys_enterpriseid": 2664,
+            "itemno": "22111050009",
+            "enterprisename": "杭州祺源实业有限公司",
+            "overdueamount": 32.190000000000,
+            "spec": "DN32/PN16",
+            "sa_orderitemsid": 331888,
+            "sa_orderid": 58360,
+            "hrid": 480,
+            "qty": 57.0000,
+            "name": "吴金星",
+            "overdueexplanation": "已出货 533 天,依照合同收款条件,应于 2024-05-30 收款,现已逾期 532 天",
+            "model": "BAGV-0032C",
+            "depname": "华东区",
+            "rowindex": 2,
+            "checkdate": "2024-03-22 16:52:23"
+        },
+        {
+            "rowno": 4,
+            "projectname": "庆元县人民医院迁建工程",
+            "amount": 66538.00,
+            "sonum": "SO-202403220027",
+            "itemname": "BAGV丝口型黄铜闸阀",
+            "sys_enterpriseid": 2664,
+            "itemno": "22111030010",
+            "enterprisename": "杭州祺源实业有限公司",
+            "overdueamount": 28.850000000000,
+            "spec": "DN20/PN16",
+            "sa_orderitemsid": 331891,
+            "sa_orderid": 58360,
+            "hrid": 480,
+            "qty": 2060.0000,
+            "name": "吴金星",
+            "overdueexplanation": "已出货 533 天,依照合同收款条件,应于 2024-05-30 收款,现已逾期 532 天",
+            "model": "BAGV-0020C",
+            "depname": "华东区",
+            "rowindex": 3,
+            "checkdate": "2024-03-22 16:52:23"
+        },
+        {
+            "rowno": 1,
+            "projectname": "宁波市水务环境集团2024年调流调压阀采购项目",
+            "amount": 311820.00,
+            "sonum": "SO-202408130028",
+            "itemname": "RCEX活塞阀",
+            "sys_enterpriseid": 7655,
+            "itemno": "28141290096",
+            "enterprisename": "宁波市水务环境集团股份有限公司鄞州分公司",
+            "overdueamount": 311820.000000000000,
+            "spec": "DN800/PN10",
+            "sa_orderitemsid": 400665,
+            "sa_orderid": 64211,
+            "hrid": 480,
+            "qty": 1.0000,
+            "name": "吴金星",
+            "overdueexplanation": "已出货 380 天,依照合同收款条件,应于 2024-11-06 收款,现已逾期 372 天",
+            "model": "RCEX-0800B",
+            "depname": "华东区",
+            "rowindex": 4,
+            "checkdate": "2024-08-16 14:08:34"
+        },
+      ],
+    },
+  })
+  // 关键词匹配规则
+  const matchers = [
+    {
+      test: /最近|近\d+天|近(一|二|三|四|五|六|七|八|九|十)天|线索表|线索表格|查询.*线索|线索.*查询/.test(q),
+      build: buildRecentClues,
+    },
+    {
+      test: /最近|近\d+天|近(一|二|三|四|五|六|七|八|九|十)天|订单表|订单表格|查询.*订单|订单.*查询/.test(q),
+      build: buildRecentOrders,
+    },
+    {
+      test: /订单统计|统计订单|订单.*状态.*统计/.test(q),
+      build: () => ({ content: '建议设定时间区间并按订单状态分组统计,以获取数量与金额的分布。' }),
+    },
+    {
+      test: /导出报表|导出.*订单|订单.*导出/.test(q),
+      build: () => ({ content: '完成筛选后使用导出功能,可选择导出字段与顺序,导出结果与当前视图一致。' }),
+    },
+    {
+      test: /字段说明|字段含义|表格字段/.test(q),
+      build: () => ({ content: '例如“accountno”为账户编号,“amount”为订单金额;字段会统一格式化以便阅读。' }),
+    },
+    // 逾期收款
+    {
+      test: /逾期|欠款|应收|回款|收款.*逾期/.test(q),
+      build: buildOverduePayments,
+    },
+    {
+      // 查询长宁188项目
+      test: /查询.*长宁|188.*查询/.test(q),
+      build: () => ({
+        content: `
+        <p style="line-height:25px;margin:0;">项目信息:</p>
+        <p style="line-height:25px;margin:0;">项目名称:长宁188项目</p>
+        <p style="line-height:25px;margin:0;">项目编号:HY-202511070001</p>
+        <p style="line-height:25px;margin:0;">报备进度:未报备</p>
+        <p style="line-height:25px;margin:0;">项目规模:2312万吨/天</p>
+        <div style="display: flex;flex-direction: row;gap: 8px;">
+        <div type="default" shape="round" class="cust-btn">报备</div>
+        <div type="default" shape="round" class="cust-btn">跟进</div>
+        <div type="default" shape="round" class="cust-btn">阶段</div></div>`})
+    },
+    // 报备
+    {
+      test: /^报备$/.test(q),
+      build: () => ({ content: `
+        <p style="line-height:25px;margin:0;">项目信息:</p>
+        <p style="line-height:25px;margin:0;">项目名称:长宁188项目</p>
+        <p style="line-height:25px;margin:0;">项目编号:HY-202511070001</p>
+        <p style="line-height:25px;margin:0;">报备进度:已报备</p>
+        <p style="line-height:25px;margin:0;">项目规模:2312万吨/天</p>
+      ` }),
+    },
+    // 跟进
+    {
+      test: /^跟进$/.test(q),
+      build: () => ({ content: `
+        <p style="line-height:25px;margin:0;">跟进类型?①现场交流;②网络交流;③电话拜访</p>
+      ` }),
+    },
+    // 现场交流
+    {
+      test: /^现场交流$/.test(q),
+      build:buildFollowUpObject,
+    },
+    // 袁永详
+    { 
+      test: /^袁永详$/.test(q),
+      build: () => ({ content: `
+        <p style="line-height:25px;margin:0;">跟进目的?</p>
+      ` }),
+    },
+    // 项目推进
+    {
+      test: /^项目推进$/.test(q),
+      build: () => ({ content: `
+        <p style="line-height:25px;margin:0;">跟进过程?</p>
+      `}),
+    }, 
+    // 安装已中标,是一个公寓型酒店的给水泵房改造,项目符合合资档次。安装公司现在在比价阶段(KITZ/沃茨)
+    {
+      test: /安装.*KITZ|沃茨.*安装|给水泵房.*改造|公寓.*酒店.*安装|比价.*KITZ|比价.*沃茨/.test(q),
+      build: () => ({ content: `
+        <p style="line-height:25px;margin:0;">跟进结果?</p>
+      `}),
+    }, 
+    // 材质跟着管道走,大概率会选用不锈钢。配合安装先做选型报价。提供相关产品图册。
+    {
+      test: /比价.*KITZ|比价.*沃茨|材质.*管道|不锈钢.*选型|选型.*产品图册/.test(q),
+      build: () => ({ content: `
+        <p style="line-height:25px;margin:0;">下次跟进计划?</p>
+      `}),
+    }, 
+    // 跟进报价进展
+    {
+      test: /报价.*进展|进展.*报价|进展/.test(q),
+      build: () => ({ content: `
+        <div style="background:#fff;padding:10px;border-radius:8px;">
+          <p style="line-height:25px;margin:0;">您填写的跟进记录如下:</p>
+          <p style="line-height:25px;margin:0;">跟进类型:现场交流</p>
+          <p style="line-height:25px;margin:0;">跟进对象:袁永详</p>
+          <p style="line-height:25px;margin:0;">目的:项目情况</p>
+          <p style="line-height:25px;margin:0;">跟进过程:安装已中标,是一个公寓型酒店的给水泵房改造,项目符合合资档次。安装公司现在在比价阶段(KITZ/沃茨)。</p>
+          <p style="line-height:25px;margin:0;">结果:材质跟着管道走,大概率会选用不锈钢。配合安装先做选型报价。提供相关产品图册。</p>
+          <p style="line-height:25px;margin:0;">下次跟进计划:跟进报价进展。</p>
+        </div>
+      `}),
+    }, 
+    // 查订单
+    {
+      test: /^查订单$/.test(q),
+      build: () => ({ content: `
+        <p style="line-height:25px;margin:0;">请给出项目名称或客户名称</p>
+      `}),
+    }, 
+    {
+      test: /^四川青石$/.test(q),
+      build: buildRecentOrders
+    }, 
+    // 查吴金星逾期回款订单
+    {
+      test: /吴金星.*逾期|回款.*回款/.test(q),
+      build: buildOverduePayments
+    }, 
+  ]
+
+  const matched = matchers.find(m => m.test)
+
+  return new Promise((resolve) => {
+    setTimeout(() => {
+      resolve({
+        code: 1,
+        msg: 'ok',
+        data: {
+          answer: matched ? matched.build() : simulateAIReply(question),
+        },
+      })
+    }, 500)
+  })
+}
+
+// 简单时间格式化:HH:mm:ss
+export function formatTime(date = new Date()) {
+  const pad = (n) => (n < 10 ? '0' + n : '' + n)
+  return `${pad(date.getHours())}:${pad(date.getMinutes())}:${pad(date.getSeconds())}`
+}
+
+// 演示场景:点击即可载入对应对话内容
+export const demoScenarios = [
+  {
+    name: '订单统计',
+    messages: [
+      { role: 'ai', content: '我可以帮你统计订单的状态与金额分布。', time: formatTime() },
+      { role: 'user', content: '统计一下最近30天的订单按状态数量。', time: formatTime() },
+      { role: 'ai', content: '好的,建议先设定时间区间为最近30天,并按“新建/提交/审核/关闭”等状态进行聚合统计。', time: formatTime() },
+    ],
+  },
+  {
+    name: '报表导出',
+    messages: [
+      { role: 'user', content: '如何导出当前筛选结果的报表?', time: formatTime() },
+      { role: 'ai', content: '先完成筛选条件设置,再点击导出即可,导出会保持和当前视图一致。', time: formatTime() },
+      { role: 'ai', content: '如需Excel格式,可选择包含字段与顺序,避免超大数据导致打开缓慢。', time: formatTime() },
+    ],
+  },
+  {
+    name: '字段说明',
+    messages: [
+      { role: 'user', content: '请解释一下表格中的关键字段含义。', time: formatTime() },
+      { role: 'ai', content: '例如“accountno”为账户编号,“amount”为订单金额;部分字段会按统一格式化展示以便阅读。', time: formatTime() },
+    ],
+  },
+  {
+    name: '最近订单(表格)',
+    messages: [
+      { role: 'user', content: '请查询最近的订单,并输出表格。', time: formatTime() },
+      { role: 'ai', content: '为你查询到最近的订单:', time: formatTime() },
+      {
+        role: 'ai',
+        content: '如下表所示:',
+        time: formatTime(),
+        table: {
+          columns: [
+            { title: '订单号', dataIndex: 'orderNo' },
+            { title: '客户', dataIndex: 'customer' },
+            { title: '金额(元)', dataIndex: 'amount' },
+            { title: '状态', dataIndex: 'status' },
+            { title: '下单时间', dataIndex: 'date' },
+          ],
+          dataSource: [
+            { key: '1', orderNo: 'SO-20241101-001', customer: '张三', amount: 1299, status: '已发货', date: '2024-11-01 10:12' },
+            { key: '2', orderNo: 'SO-20241101-002', customer: '李四', amount: 288, status: '待发货', date: '2024-11-01 11:05' },
+            { key: '3', orderNo: 'SO-20241102-003', customer: '王五', amount: 5600, status: '已完成', date: '2024-11-02 09:48' },
+            { key: '4', orderNo: 'SO-20241102-004', customer: '赵六', amount: 75, status: '已取消', date: '2024-11-02 14:21' },
+          ],
+        },
+      },
+    ],
+  },
+]

+ 17 - 0
src/components/AIDialog/icons/fs.svg

@@ -0,0 +1,17 @@
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="24" height="24" viewBox="0 0 24 24">
+  <defs>
+    <linearGradient id="linear-gradient" x1="0.5" x2="0.5" y2="1" gradientUnits="objectBoundingBox">
+      <stop offset="0" stop-color="#3774f6"/>
+      <stop offset="1" stop-color="#8d8dff"/>
+    </linearGradient>
+    <clipPath id="clip-path">
+      <rect id="矩形_186" data-name="矩形 186" width="12" height="12" transform="translate(597.722 738.722)" fill="#fff" stroke="#707070" stroke-width="1"/>
+    </clipPath>
+  </defs>
+  <g id="组_5615" data-name="组 5615" transform="translate(-593 -734)">
+    <circle id="椭圆_19" data-name="椭圆 19" cx="12" cy="12" r="12" transform="translate(593 734)" fill="url(#linear-gradient)"/>
+    <g id="蒙版组_28" data-name="蒙版组 28" transform="translate(1.278 1.278)" clip-path="url(#clip-path)">
+      <path id="icon" d="M13.32,7.046,9.232,2.959a.817.817,0,0,0-1.156,0L3.99,7.046A.817.817,0,0,0,5.145,8.2L7.837,5.51v7.836a.817.817,0,0,0,1.635,0V5.51L12.164,8.2A.817.817,0,1,0,13.32,7.046Z" transform="translate(595.067 736.28)" fill="#fff"/>
+    </g>
+  </g>
+</svg>

+ 18 - 0
src/components/AIDialog/icons/fw.svg

@@ -0,0 +1,18 @@
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="24" height="24" viewBox="0 0 24 24">
+  <defs>
+    <linearGradient id="linear-gradient" x1="0.5" x2="0.5" y2="1" gradientUnits="objectBoundingBox">
+      <stop offset="0" stop-color="#3774f6"/>
+      <stop offset="0.551" stop-color="#6682fb"/>
+      <stop offset="1" stop-color="#8d8dff"/>
+    </linearGradient>
+    <clipPath id="clip-path">
+      <rect id="矩形_185" data-name="矩形 185" width="12" height="12" transform="translate(604 326)" fill="#fff" stroke="#707070" stroke-width="1"/>
+    </clipPath>
+  </defs>
+  <g id="组_5612" data-name="组 5612" transform="translate(-598 -320)">
+    <rect id="矩形_156" data-name="矩形 156" width="24" height="24" rx="12" transform="translate(598 320)" fill="url(#linear-gradient)"/>
+    <g id="蒙版组_27" data-name="蒙版组 27" clip-path="url(#clip-path)">
+      <path id="icon" d="M10.8,9.2A1.2,1.2,0,0,1,9.6,8V6.4a1.19,1.19,0,0,1,.8-1.119V5.2a4,4,0,1,0-8,0v.081A1.19,1.19,0,0,1,3.2,6.4V8A1.2,1.2,0,0,1,.8,8V6.4a1.19,1.19,0,0,1,.8-1.119V5.2a4.8,4.8,0,1,1,9.6,0v.081A1.19,1.19,0,0,1,12,6.4V8A1.2,1.2,0,0,1,10.8,9.2ZM7.6,12.4H6a.4.4,0,0,1-.4-.4v-.8a.4.4,0,0,1,.4-.4H7.6a.4.4,0,0,1,.4.4v.366A2.55,2.55,0,0,0,10.4,9.2h.8A3.418,3.418,0,0,1,7.6,12.4Z" transform="translate(603.6 325.6)" fill="#fff"/>
+    </g>
+  </g>
+</svg>

+ 9 - 0
src/components/AIDialog/icons/grxx.svg

@@ -0,0 +1,9 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
+  <g id="组_5593" data-name="组 5593" transform="translate(-1248 -14)">
+    <rect id="矩形_161" data-name="矩形 161" width="16" height="16" rx="8" transform="translate(1248 14)" fill="#3774f6"/>
+    <g id="User" transform="translate(1250.169 16.169)">
+      <rect id="矩形_163" data-name="矩形 163" width="12" height="12" transform="translate(-0.169 -0.169)" fill="rgba(255,255,255,0.88)" opacity="0"/>
+      <path id="路径_171" data-name="路径 171" d="M8.473,9.065H7.789A.09.09,0,0,1,7.7,8.976a3.418,3.418,0,0,0-6.832,0,.09.09,0,0,1-.091.089H.091a.09.09,0,0,1-.066-.028A.09.09,0,0,1,0,8.972,4.223,4.223,0,0,1,.336,7.4a4.281,4.281,0,0,1,.918-1.362,4.227,4.227,0,0,1,1.36-.918l.009,0h0a2.825,2.825,0,1,1,3.308,0h.013A4.284,4.284,0,0,1,8.563,8.97a.092.092,0,0,1-.026.066.09.09,0,0,1-.064.029ZM4.282.866a1.96,1.96,0,1,0,1.385.574A1.96,1.96,0,0,0,4.282.866Z" transform="translate(1.549 1.298)" fill="rgba(255,255,255,0.88)"/>
+    </g>
+  </g>
+</svg>

+ 17 - 0
src/components/AIDialog/icons/jl.svg

@@ -0,0 +1,17 @@
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="24" height="24" viewBox="0 0 24 24">
+  <defs>
+    <linearGradient id="linear-gradient" x1="0.5" x2="0.5" y2="1" gradientUnits="objectBoundingBox">
+      <stop offset="0" stop-color="#3774f6"/>
+      <stop offset="1" stop-color="#8d8dff"/>
+    </linearGradient>
+    <clipPath id="clip-path">
+      <rect id="矩形_184" data-name="矩形 184" width="12" height="12" transform="translate(604 263)" fill="#fff" stroke="#707070" stroke-width="1"/>
+    </clipPath>
+  </defs>
+  <g id="组_5611" data-name="组 5611" transform="translate(-598 -257)">
+    <rect id="矩形_155" data-name="矩形 155" width="24" height="24" rx="12" transform="translate(598 257)" fill="url(#linear-gradient)"/>
+    <g id="蒙版组_26" data-name="蒙版组 26" transform="translate(0 -1)" clip-path="url(#clip-path)">
+      <path id="icon" d="M1.345,11.292H4.5V6.23l-.862-.6L1.345,7.575Zm3.894,0h3.15V6.26L6.867,7.54,5.239,6.655ZM9.133,5.664v5.628h3.15V5.7l-1.345-1.77Zm-7.267.5L3.579,4.733,6.852,6.726,10.734,3.07a.421.421,0,0,0,.037-.043l.654.661L12.478.726,9.457,1.7l.723.731c-.01.007-.02.014-.029.022L6.741,5.664,3.5,3.691,1.321,5.515a.425.425,0,1,0,.545.652Zm10.347,5.709H1.327a.425.425,0,0,0,0,.85H12.212a.425.425,0,0,0,0-.85Z" transform="translate(603.23 262.274)" fill="#fff"/>
+    </g>
+  </g>
+</svg>

+ 55 - 0
src/components/AIDialog/icons/jqr.svg

@@ -0,0 +1,55 @@
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="32" height="32" viewBox="0 0 32 32">
+  <defs>
+    <linearGradient id="linear-gradient" x1="0.5" x2="0.5" y2="1" gradientUnits="objectBoundingBox">
+      <stop offset="0" stop-color="#8db4ff"/>
+      <stop offset="1" stop-color="#25f6e1"/>
+    </linearGradient>
+    <linearGradient id="linear-gradient-2" x1="2.537" y1="1" x2="2.456" y2="-1.439" gradientUnits="objectBoundingBox">
+      <stop offset="0" stop-color="#00fffe"/>
+      <stop offset="1" stop-color="#3774f6"/>
+    </linearGradient>
+    <linearGradient id="linear-gradient-3" x1="0.5" x2="0.5" y2="1" gradientUnits="objectBoundingBox">
+      <stop offset="0" stop-color="#8d8dff"/>
+      <stop offset="1" stop-color="#3774f6"/>
+    </linearGradient>
+    <linearGradient id="linear-gradient-4" x1="0.5" x2="0.5" y2="1" gradientUnits="objectBoundingBox">
+      <stop offset="0" stop-color="#83f4e7"/>
+      <stop offset="1" stop-color="#d5e8fc"/>
+    </linearGradient>
+    <filter id="椭圆_15">
+      <feOffset dy="1" input="SourceAlpha"/>
+      <feGaussianBlur stdDeviation="1.5" result="blur"/>
+      <feFlood flood-opacity="0.161" result="color"/>
+      <feComposite operator="out" in="SourceGraphic" in2="blur"/>
+      <feComposite operator="in" in="color"/>
+      <feComposite operator="in" in2="SourceGraphic"/>
+    </filter>
+    <filter id="椭圆_16">
+      <feOffset dy="1" input="SourceAlpha"/>
+      <feGaussianBlur stdDeviation="1.5" result="blur-2"/>
+      <feFlood flood-opacity="0.161" result="color-2"/>
+      <feComposite operator="out" in="SourceGraphic" in2="blur-2"/>
+      <feComposite operator="in" in="color-2"/>
+      <feComposite operator="in" in2="SourceGraphic"/>
+    </filter>
+  </defs>
+  <g id="组_5647" data-name="组 5647" transform="translate(-594 -6)">
+    <rect id="矩形_188" data-name="矩形 188" width="32" height="7.346" rx="2" transform="translate(594 21.304)" fill="url(#linear-gradient)"/>
+    <path id="联合_7" data-name="联合 7" d="M-762-1108.035v-7.346h1.883v-1.313a1.648,1.648,0,0,1-1.255-1.636A1.621,1.621,0,0,1-759.8-1120a1.621,1.621,0,0,1,1.569,1.67,1.648,1.648,0,0,1-1.255,1.636v1.313h1.883v7.346Z" transform="translate(1369.804 1126)" fill="url(#linear-gradient-2)"/>
+    <path id="联合_5" data-name="联合 5" d="M16,6.623c7.45,0,13.49,5.681,13.49,12.689S23.45,32,16,32,2.51,26.319,2.51,19.311,8.55,6.623,16,6.623Z" transform="translate(594 6)" fill="url(#linear-gradient-3)"/>
+    <path id="路径_177" data-name="路径 177" d="M3.137,0H8.778l1.359,1.1L11.469,0h6.1a3.243,3.243,0,0,1,3.137,3.339V6.678c0,1.844-3.137,3.339-3.137,3.339s-2.057,1.083-7.3,1.055c-5.013-.014-7.133-1.055-7.133-1.055S0,8.522,0,6.678V3.339A3.243,3.243,0,0,1,3.137,0Z" transform="translate(599.953 20.636)" fill="#3774f6"/>
+    <path id="路径_176" data-name="路径 176" d="M3.137,0H8.778l1.359,1.1L11.469,0h6.1a3.243,3.243,0,0,1,3.137,3.339V6.678c0,1.844-3.137,3.339-3.137,3.339s-2.057,1.083-7.3,1.055c-5.013-.014-7.133-1.055-7.133-1.055S0,8.522,0,6.678V3.339A3.243,3.243,0,0,1,3.137,0Z" transform="translate(599.953 19.969)" opacity="0.5" fill="url(#linear-gradient-4)"/>
+    <g data-type="innerShadowGroup">
+      <ellipse id="椭圆_15-2" data-name="椭圆 15" cx="2" cy="2.667" rx="2" ry="2.667" transform="translate(604.182 23.333)" fill="#0fffff"/>
+      <g transform="matrix(1, 0, 0, 1, 594, 6)" filter="url(#椭圆_15)">
+        <ellipse id="椭圆_15-3" data-name="椭圆 15" cx="2" cy="2.667" rx="2" ry="2.667" transform="translate(10.18 17.33)" fill="#fff"/>
+      </g>
+    </g>
+    <g data-type="innerShadowGroup">
+      <ellipse id="椭圆_16-2" data-name="椭圆 16" cx="2" cy="2.667" rx="2" ry="2.667" transform="translate(613.091 23.333)" fill="#0fffff"/>
+      <g transform="matrix(1, 0, 0, 1, 594, 6)" filter="url(#椭圆_16)">
+        <ellipse id="椭圆_16-3" data-name="椭圆 16" cx="2" cy="2.667" rx="2" ry="2.667" transform="translate(19.09 17.33)" fill="#fff"/>
+      </g>
+    </g>
+  </g>
+</svg>

+ 4 - 0
src/components/AIDialog/icons/lsjl.svg

@@ -0,0 +1,4 @@
+<svg id="Time" xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
+  <rect id="矩形_165" data-name="矩形 165" width="16" height="16" fill="rgba(51,51,51,0.88)" opacity="0"/>
+  <path id="路径_173" data-name="路径 173" d="M0,7a7,7,0,1,1,7,7A7,7,0,0,1,0,7ZM1.187,7A5.813,5.813,0,1,0,7,1.187,5.813,5.813,0,0,0,1.187,7ZM9.136,9.789,6.552,7.9A.123.123,0,0,1,6.5,7.8V3.5a.126.126,0,0,1,.125-.125h.751A.125.125,0,0,1,7.5,3.5V7.367L9.73,8.978a.125.125,0,0,1,.028.175l-.447.609a.125.125,0,0,1-.1.051A.127.127,0,0,1,9.136,9.789Z" transform="translate(1 1)" fill="rgba(51,51,51,0.88)"/>
+</svg>

+ 6 - 0
src/components/AIDialog/icons/qp.svg

@@ -0,0 +1,6 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
+  <g id="组_5646" data-name="组 5646" transform="translate(-1176 -14)">
+    <rect id="矩形_166" data-name="矩形 166" width="16" height="16" transform="translate(1176 14)" fill="none"/>
+    <path id="icon" d="M8.45,5.125H6.15V4.1h4.1V8.2H9.226V5.8L6.1,8.92a1.024,1.024,0,0,1,.046.306v4.1h7.176V1.025H1.025V8.2h4.1a1.05,1.05,0,0,1,.224.024l3.1-3.1ZM1.025,0h12.3a1.025,1.025,0,0,1,1.025,1.025v12.3a1.025,1.025,0,0,1-1.025,1.025H1.025A1.025,1.025,0,0,1,0,13.326V1.025A1.025,1.025,0,0,1,1.025,0Zm0,9.226v4.1h4.1v-4.1h-4.1Z" transform="translate(1176.824 14.824)" fill="rgba(51,51,51,0.88)"/>
+  </g>
+</svg>

+ 12 - 0
src/components/AIDialog/icons/sc.svg

@@ -0,0 +1,12 @@
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="24" height="24" viewBox="0 0 24 24">
+  <defs>
+    <linearGradient id="linear-gradient" x1="0.5" x2="0.5" y2="1" gradientUnits="objectBoundingBox">
+      <stop offset="0" stop-color="#3774f6"/>
+      <stop offset="1" stop-color="#8d8dff"/>
+    </linearGradient>
+  </defs>
+  <g id="组_5607" data-name="组 5607" transform="translate(-602 -72)">
+    <rect id="矩形_152" data-name="矩形 152" width="24" height="24" rx="12" transform="translate(602 72)" fill="url(#linear-gradient)"/>
+    <path id="联合_6" data-name="联合 6" d="M11.628,12.7,10.4,11.438V11.4A2.866,2.866,0,0,1,8.127,12,3.243,3.243,0,0,1,5.487,8.33,3.193,3.193,0,0,1,9.042,5.572a3.243,3.243,0,0,1,2.641,3.666,3.154,3.154,0,0,1-.881,1.816l1.232,1.263A.283.283,0,0,1,12,12.7a.261.261,0,0,1-.373,0ZM6,8.4a2.708,2.708,0,0,0,2.234,3.073,2.671,2.671,0,0,0,2.979-2.305A2.708,2.708,0,0,0,8.974,6.1,2.616,2.616,0,0,0,8.6,6.069,2.665,2.665,0,0,0,6,8.4Zm-.742,2.793H.332A.33.33,0,0,1,0,10.867V7.384a.33.33,0,0,1,.332-.327H4.85a4.264,4.264,0,0,0-.252.775H.665v2.677h4.2a4.2,4.2,0,0,0,.386.683h0ZM.332,6.617A.323.323,0,0,1,0,6.306v-2.3A.322.322,0,0,1,.332,3.7H4.978a.323.323,0,0,1,.332.312V6.255c-.081.112-.158.228-.228.346a.363.363,0,0,1-.1.016Zm5.7-1.124V.487a.488.488,0,0,1,.209-.4A.456.456,0,0,1,6.5,0h3.882a.468.468,0,0,1,.436.3.5.5,0,0,1,.036.186V5.351a3.943,3.943,0,0,0-4.822.143h0ZM.336,3.207A.337.337,0,0,1,0,2.865V.343A.346.346,0,0,1,.1.1.322.322,0,0,1,.334,0H4.982a.337.337,0,0,1,.332.342V2.864a.339.339,0,0,1-.333.343Zm.332-.685H4.65V.685H.668Z" transform="translate(607.952 78.61)" fill="#fff"/>
+  </g>
+</svg>

+ 4 - 0
src/components/AIDialog/icons/sz.svg

@@ -0,0 +1,4 @@
+<svg id="Setting" xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
+  <rect id="矩形_164" data-name="矩形 164" width="16" height="16" fill="rgba(51,51,51,0.88)" opacity="0"/>
+  <path id="路径_172" data-name="路径 172" d="M6.627,14a7.012,7.012,0,0,1-1.243-.112l-.041-.007a.5.5,0,0,1-.4-.4L4.7,12.146a5.434,5.434,0,0,1-1.546-.9L1.87,11.7a.5.5,0,0,1-.549-.149l-.028-.033A6.966,6.966,0,0,1,.043,9.366L.03,9.326a.5.5,0,0,1,.145-.55l1.036-.885a5.56,5.56,0,0,1,0-1.784L.175,5.223a.505.505,0,0,1-.145-.55l.014-.041A6.98,6.98,0,0,1,1.289,2.478l.028-.033A.5.5,0,0,1,1.866,2.3l1.28.454a5.5,5.5,0,0,1,1.546-.9L4.939.519a.5.5,0,0,1,.4-.4L5.384.11a7.07,7.07,0,0,1,2.485,0l.042.008a.5.5,0,0,1,.4.4l.245,1.328a5.506,5.506,0,0,1,1.558.9L11.388,2.3a.5.5,0,0,1,.548.148l.028.033A6.919,6.919,0,0,1,13.21,4.636l.014.041a.5.5,0,0,1-.146.55L12.055,6.1a5.563,5.563,0,0,1,0,1.806l1.023.875a.5.5,0,0,1,.146.547l-.014.04a6.96,6.96,0,0,1-1.246,2.155l-.028.033a.5.5,0,0,1-.549.149l-1.271-.452a5.468,5.468,0,0,1-1.558.9l-.245,1.328a.5.5,0,0,1-.4.4l-.042.007A6.961,6.961,0,0,1,6.627,14ZM3.37,9.977h0l.49.4a4.381,4.381,0,0,0,1.23.723l.59.227.28,1.518a5.854,5.854,0,0,0,1.328,0l.28-1.516.6-.223A4.391,4.391,0,0,0,9.4,10.387l.491-.4,1.45.514a5.862,5.862,0,0,0,.666-1.15l-1.167-1,.1-.626a4.4,4.4,0,0,0,0-1.441l-.1-.624,1.167-1a5.951,5.951,0,0,0-.665-1.15L9.9,4.024l-.491-.4a4.39,4.39,0,0,0-1.238-.715l-.6-.223-.28-1.52a5.854,5.854,0,0,0-1.328,0l-.28,1.519-.592.223a4.358,4.358,0,0,0-1.229.714l-.49.4-1.46-.519a5.813,5.813,0,0,0-.665,1.15L2.425,5.666l-.1.625A4.354,4.354,0,0,0,2.265,7a4.547,4.547,0,0,0,.058.711l.1.625L1.246,9.347A5.867,5.867,0,0,0,1.911,10.5L3.37,9.978ZM6.628,9.6a2.75,2.75,0,1,1,2.75-2.75A2.75,2.75,0,0,1,6.628,9.6Zm0-4.5a1.751,1.751,0,1,0,1.238.513A1.751,1.751,0,0,0,6.628,5.1Z" transform="translate(1.372 0.998)" fill="rgba(51,51,51,0.88)"/>
+</svg>

+ 17 - 0
src/components/AIDialog/icons/tb.svg

@@ -0,0 +1,17 @@
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="24" height="24" viewBox="0 0 24 24">
+  <defs>
+    <linearGradient id="linear-gradient" x1="0.5" x2="0.5" y2="1" gradientUnits="objectBoundingBox">
+      <stop offset="0" stop-color="#3774f6"/>
+      <stop offset="1" stop-color="#8d8dff"/>
+    </linearGradient>
+    <clipPath id="clip-path">
+      <rect id="矩形_183" data-name="矩形 183" width="12" height="12" transform="translate(604 200)" fill="#fff" stroke="#707070" stroke-width="1"/>
+    </clipPath>
+  </defs>
+  <g id="组_5610" data-name="组 5610" transform="translate(-598 -194)">
+    <rect id="矩形_154" data-name="矩形 154" width="24" height="24" rx="12" transform="translate(598 194)" fill="url(#linear-gradient)"/>
+    <g id="蒙版组_25" data-name="蒙版组 25" clip-path="url(#clip-path)">
+      <path id="icon" d="M8.291,12.6a.43.43,0,0,1,.436.436v.273h.327a.43.43,0,0,1,.436.436A.517.517,0,0,1,9,14.182H3.164a.436.436,0,1,1,0-.873h.273v-.273a.43.43,0,0,1,.436-.436H8.291Zm.055-7.8L10.8,7.255l-.873.873,1.418,1.418a.619.619,0,0,1,.436.164l2.782,2.836a.526.526,0,0,1,0,.764l-.764.764a.527.527,0,0,1-.764,0l-2.782-2.836a.5.5,0,0,1-.109-.545L8.782,9.273l-.873.927.055.055c.055.109.109.164.109.273v.109a.389.389,0,0,1-.164.327l-.491.491a.527.527,0,0,1-.764,0L4.036,8.836c-.218-.109-.218-.491,0-.709l.491-.491a.527.527,0,0,1,.764,0l.109.109L8.345,4.8ZM9.491,3.436l2.618,2.618a.471.471,0,0,1,.164.327v.055a.417.417,0,0,1-.109.273l-.055.055-.491.491c-.055.055-.055.055-.109.055a.572.572,0,0,1-.655-.055L8.236,4.636a.527.527,0,0,1,0-.764l.491-.436a.527.527,0,0,1,.764,0Z" transform="translate(601.273 197.245)" fill="#fff"/>
+    </g>
+  </g>
+</svg>

+ 9 - 0
src/components/AIDialog/icons/xf.svg

@@ -0,0 +1,9 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
+  <g id="组_5595" data-name="组 5595" transform="translate(-1140 -14)">
+    <rect id="矩形_158" data-name="矩形 158" width="16" height="16" transform="translate(1140 14)" fill="none"/>
+    <g id="组_5594" data-name="组 5594" transform="translate(1012.693 -113.307)">
+      <path id="路径_174" data-name="路径 174" d="M140.886,128a1.728,1.728,0,0,1,1.728,1.728v11.158a1.728,1.728,0,0,1-1.728,1.728H129.728A1.728,1.728,0,0,1,128,140.886V129.728A1.728,1.728,0,0,1,129.728,128Zm0,1.225H129.728a.5.5,0,0,0-.5.5v11.158a.5.5,0,0,0,.5.5h11.158a.5.5,0,0,0,.5-.5V129.728A.5.5,0,0,0,140.886,129.225Z" transform="translate(0 0)" fill="rgba(51,51,51,0.88)"/>
+      <path id="路径_175" data-name="路径 175" d="M636.773,128a.612.612,0,0,1,.613.613V142a.613.613,0,0,1-1.225,0V128.613A.612.612,0,0,1,636.773,128Z" transform="translate(-498.49 0)" fill="rgba(51,51,51,0.88)"/>
+    </g>
+  </g>
+</svg>

+ 17 - 0
src/components/AIDialog/icons/yw.svg

@@ -0,0 +1,17 @@
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="24" height="24" viewBox="0 0 24 24">
+  <defs>
+    <linearGradient id="linear-gradient" x1="0.5" x2="0.5" y2="1" gradientUnits="objectBoundingBox">
+      <stop offset="0" stop-color="#3774f6"/>
+      <stop offset="1" stop-color="#8d8dff"/>
+    </linearGradient>
+    <clipPath id="clip-path">
+      <rect id="矩形_182" data-name="矩形 182" width="12" height="12" transform="translate(604 137)" fill="#fff" stroke="#707070" stroke-width="1"/>
+    </clipPath>
+  </defs>
+  <g id="组_5608" data-name="组 5608" transform="translate(-598 -131)">
+    <rect id="矩形_153" data-name="矩形 153" width="24" height="24" rx="12" transform="translate(598 131)" fill="url(#linear-gradient)"/>
+    <g id="蒙版组_24" data-name="蒙版组 24" clip-path="url(#clip-path)">
+      <path id="icon" d="M10.4,8.034V8.7a.6.6,0,1,1-1.2.116.553.553,0,0,1,0-.116V8.034H4.553V8.7a.6.6,0,1,1-1.2.116.553.553,0,0,1,0-.116V8.034H.877v3.141a1.419,1.419,0,0,0,1.35,1.488h9.3a1.418,1.418,0,0,0,1.35-1.488V8.034ZM3.953,6.464a.62.62,0,0,1,.6.641.1.1,0,0,1,0,.02H9.2a.681.681,0,0,1,.6-.661.62.62,0,0,1,.6.641.1.1,0,0,1,0,.02h2.474V4.647a1.419,1.419,0,0,0-1.35-1.488H9.953V2.579A1.419,1.419,0,0,0,8.6,1.091H5.153A1.418,1.418,0,0,0,3.8,2.579V3.24H2.227A1.42,1.42,0,0,0,.877,4.729v2.48c.825,0,1.65-.083,2.474-.083a.683.683,0,0,1,.6-.661ZM5.129,2H8.6a.541.541,0,0,1,.527.555.146.146,0,0,1,0,.024v.661h-4.5V2.581A.539.539,0,0,1,5.129,2Z" transform="translate(603.123 136.123)" fill="#fff"/>
+    </g>
+  </g>
+</svg>

+ 6 - 0
src/components/AIDialog/icons/yy.svg

@@ -0,0 +1,6 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
+  <g id="组_5645" data-name="组 5645" transform="translate(-1176 -749)">
+    <rect id="矩形_146" data-name="矩形 146" width="16" height="16" transform="translate(1176 749)" fill="none"/>
+    <path id="icon" d="M9.591,14.792v1.926a.551.551,0,0,1-1.1,0V14.792A6.242,6.242,0,0,1,2.8,8.575V8.208a.551.551,0,1,1,1.1,0v.367a5.139,5.139,0,1,0,10.279,0V8.208a.551.551,0,1,1,1.1,0v.367A6.242,6.242,0,0,1,9.591,14.792ZM5.37,5.269a3.671,3.671,0,0,1,7.342,0V8.577a3.671,3.671,0,0,1-7.342,0V5.269Zm1.1,0V8.577a2.57,2.57,0,0,0,5.139,0V5.269a2.57,2.57,0,0,0-5.139,0Z" transform="translate(1174.793 747.693)"/>
+  </g>
+</svg>

+ 402 - 0
src/components/AIDialog/index.vue

@@ -0,0 +1,402 @@
+<template>
+  <div class="ai-dialog-container">
+    <!-- 悬浮按钮:随时唤起 AI 对话(Element-UI) -->
+    <a
+      type="primary"
+      class="ai-dialog-button"
+      @click="togglePanel"
+    >
+      <img src="./icons/jqr.svg" />
+    </a>
+
+    <!-- 悬浮对话框:固定在右下角,可关闭 -->
+    <transition name="fade">
+      <div v-if="showPanel" class="ai-dialog-panel">
+        <div class="ai-dialog-header">
+          <h3 style="margin: 0;display: flex;align-items: center;gap: 8px;">
+            <img src="./icons/jqr.svg" style="width: 30px; height: 30px;" />
+            班尼戈CRM-AI
+          </h3>
+          <div class="header-icons" style="display:flex;gap:20px;align-items:center;">
+            <img src="./icons/lsjl.svg" />
+            <img src="./icons/xf.svg" />
+            <img src="./icons/qp.svg" />
+            <img src="./icons/sz.svg" />
+            <img src="./icons/grxx.svg" />
+          </div>
+        </div>
+        <div class="ai-dialog-content">
+          <div class="ai-dialog-aside">
+            <div>
+              <img src="./icons/sc.svg" />
+              <p>市场</p>
+            </div>
+            <div>
+              <img src="./icons/yw.svg" />
+              <p>业务</p>
+            </div>
+            <div>
+              <img src="./icons/tb.svg" />
+              <p>投标</p>
+            </div>
+            <div>
+              <img src="./icons/jl.svg" />
+              <p>教练</p>
+            </div>
+            <div>
+              <img src="./icons/fw.svg" />
+              <p>服务</p>
+            </div>
+          </div>
+          <el-card :body-style="{ padding: '12px' }" :style="{ height: '100%', borderRadius:'0', boxShadow:'none' }" shadow="never">
+            <div class="message-area" ref="messageArea">
+              <div v-if="messages.length === 0" class="welcome-msg">
+                <div>
+                  <img src="./icons/jqr.svg" style="width: 40px; height: 40px;margin-bottom:10px;" />
+                  <h3>你好!我是你的<span style="color: #108ee9;">AI助手小班</span></h3>
+                </div>
+              </div>
+              <div v-else v-for="(msg, idx) in messages" :key="idx" :class="['msg-item', msg.role]">
+                <img v-if="msg.role === 'ai'" src="./icons/jqr.svg" style="width: 24px; height: 24px;" />
+                <img v-else src="./icons/grxx.svg" style="width: 24px; height: 24px;" />
+                <div :class="['bubble', msg.role === 'ai' ? 'bubble-ai' : 'bubble-user']">
+                  <template v-if="msg.pending">
+                    <span style="display:flex;align-items:center;gap:8px;">
+                      <i class="el-icon-loading"></i>
+                      正在思考...
+                    </span>
+                  </template>
+                  <div v-else-if="msg.content" v-html="msg.content"></div>
+                  <el-table
+                    v-if="msg.table"
+                    :data="msg.table.dataSource"
+                    size="mini"
+                    border
+                    style="background-color: #fff;border-radius:0;width:600px"
+                  >
+                    <el-table-column
+                      v-for="(col, cIdx) in (msg.table.columns || [])"
+                      :key="cIdx"
+                      :prop="col.dataIndex || col.key"
+                      :label="col.title"
+                      :width="col.width"
+                      :show-overflow-tooltip="true"
+                    />
+                  </el-table>
+                  <div style="margin-top: 10px;" v-if="msg.button">
+                    <el-button
+                      v-for="btn in msg.button"
+                      :key="btn"
+                      type="default"
+                      size="small"
+                      round
+                      style="background: linear-gradient( 180deg, #3774F6 0%, #8D8DFF 100%);border-radius: 50px;color:#fff;"
+                    >{{ btn }}</el-button>
+                  </div>
+                </div>
+              </div>
+            </div>
+
+            <!-- 预设问题(可点击) -->
+            <div class="preset">
+              <div style="display:flex;flex-wrap:wrap;gap:8px;">
+                <span class="preset-item" v-for="p in presets" :key="p" @click="usePreset(p)"  style="cursor: pointer">{{ p }}</span>
+              </div>
+            </div>
+
+            <!-- 输入区 -->
+            <div class="input-area">
+              <el-input
+                type="textarea"
+                v-model="inputValue"
+                :rows="5"
+                placeholder="搜索、提问或上传图片、附件"
+                @keydown.native="onKeydown"
+              />
+              <div class="actions" style="display:flex;align-items:center;gap:8px;">
+                <img src="./icons/yy.svg" @click="send" style="width: 20px; height: 20px;cursor:pointer;" />
+                <el-divider direction="vertical" />
+                <img src="./icons/fs.svg" @click="send" style="width: 25px; height: 25px;cursor:pointer;" />
+              </div>
+            </div>
+          </el-card>
+        </div>
+      </div>
+    </transition>
+  </div>
+</template>
+
+<script>
+import { presets as presetData, sampleMessages, simulateAIReply, formatTime, demoScenarios, mockRequested } from './data.js'
+
+export default {
+  name: 'AIDialog',
+  data () {
+    return {
+      showPanel: false,
+      presets: presetData,
+      scenarios: demoScenarios,
+      messages: sampleMessages.slice(),
+      inputValue: '',
+      sending: false
+    }
+  },
+  methods: {
+    togglePanel () {
+      this.showPanel = !this.showPanel
+    },
+    usePreset (p) {
+      this.inputValue = p
+    },
+    onKeydown (e) {
+      if (e.key === 'Enter' && !e.shiftKey) {
+        e.preventDefault()
+        this.send()
+      }
+    },
+    clearMessages () {
+      this.messages = []
+    },
+    getCustomDelay (content) {
+      const len = (content || '').length
+      if (/表格|报表|统计|分析|线索|收款明细|订单/.test(content)) return 2800
+      if (len <= 20) return 1800
+      if (len <= 100) return 1200
+      return 1500
+    },
+    async send () {
+      const content = (this.inputValue || '').trim()
+      if (!content) return
+      // 推入用户消息
+      this.messages.push({ role: 'user', content, time: formatTime(new Date()) })
+      this.$nextTick(() => {
+        this.scrollToBottom()
+      })
+      this.inputValue = ''
+      this.sending = true
+
+      const delayMs = this.getCustomDelay(content)
+      const pendingMsg = { role: 'ai', pending: true, time: formatTime(new Date()), delayMs }
+      const pendingIndex = this.messages.length
+      this.messages.push(pendingMsg)
+      this.$nextTick(() => {
+        this.scrollToBottom()
+      })
+
+      try {
+        const [res] = await Promise.all([
+          mockRequested(content),
+          new Promise(resolve => setTimeout(resolve, delayMs))
+        ])
+        const aiAns = (res && res.data && (res.data.answer || res.data)) || simulateAIReply(content)
+        if (aiAns && typeof aiAns === 'object') {
+          if (aiAns.content) {
+            pendingMsg.pending = false
+            pendingMsg.content = String(aiAns.content)
+          } else {
+            pendingMsg.pending = false
+            pendingMsg.content = '收到你的请求,正在处理。'
+          }
+          this.$set(this.messages, pendingIndex, { ...pendingMsg })
+          this.$nextTick(() => {
+            this.scrollToBottom()
+          })
+          if (aiAns.table) {
+            this.messages.push({ role: 'ai', content: aiAns.content ? '' : '如下表所示:', table: aiAns.table, button: aiAns.button, time: formatTime(new Date()) })
+            this.$nextTick(() => {
+              this.scrollToBottom()
+            })
+          }
+        } else {
+          pendingMsg.pending = false
+          pendingMsg.content = String(aiAns)
+          this.$set(this.messages, pendingIndex, { ...pendingMsg })
+          this.$nextTick(() => {
+            this.scrollToBottom()
+          })
+        }
+      } catch (error) {
+        const failContent = '请求失败,已为你生成模拟回复:\n' + simulateAIReply(content)
+        this.$set(this.messages, pendingIndex, { ...pendingMsg, pending: false, content: failContent })
+        this.$nextTick(() => {
+          this.scrollToBottom()
+        })
+      } finally {
+        this.sending = false
+      }
+    },
+    loadScenario (s) {
+      if (!s || !s.messages) return
+      this.messages = s.messages.map(m => ({ ...m }))
+      this.$nextTick(() => {
+        this.scrollToBottom()
+      })
+    },
+    resetToSample () {
+      this.messages = sampleMessages.slice()
+      this.$nextTick(() => {
+        this.scrollToBottom()
+      })
+    },
+    scrollToBottom () {
+      const wrap = this.$refs && this.$refs.messageArea
+      if (wrap && wrap.scrollHeight != null) {
+        wrap.scrollTop = wrap.scrollHeight
+      }
+    }
+  },
+  mounted () {
+    // 组件初始化时可扩展:拉取推荐问法等
+    this.$nextTick(() => {
+      this.scrollToBottom()
+    })
+  }
+}
+</script>
+
+<style>
+.ai-dialog-panel {
+  font-size:12px;
+  position: fixed;
+  right: 24px;
+  bottom: 54px;
+  width: 780px;
+  height: 90vh;
+  z-index: 999999;
+  background: #F0F4FA;
+  border-radius: 8px;
+  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
+  overflow: hidden;
+}
+.message-area {
+  height: 60vh;
+  overflow-y: auto;
+  padding-right: 6px;
+  margin-bottom: 8px;
+}
+.preset {
+  margin-bottom: 18px;
+}
+.demo {
+  margin-bottom: 8px;
+}
+.input-area {
+  position:relative;
+  display: flex;
+  flex-direction: column;
+  gap: 8px;
+}
+.actions {
+  position: absolute;
+  bottom: 10px;
+  right: 10px;
+  text-align: right;
+}
+.msg-item {
+  display: flex;
+  gap: 8px;
+  margin: 8px 0;
+}
+.msg-item.user {
+  flex-direction: row-reverse;
+}
+.bubble {
+  background: #EEF3F9;
+  padding: 8px 10px;
+  border-radius: 8px;
+  
+}
+.bubble-ai{
+  position: relative;
+  border-radius: 10px 10px 10px 0px;
+}
+.msg-item.user .bubble-user {
+  color: #fff !important; 
+  background: linear-gradient( 90deg, #3774F6 0%, #0051FD 100%);
+  border-radius: 10px 10px 0px 10px;
+}
+.meta {
+  margin-top: 4px;
+  display: flex;
+  gap: 8px;
+  align-items: center;
+}
+.bubble .el-table {
+  background: transparent;
+}
+.fade-enter-active,
+.fade-leave-active { transition: opacity .2s ease; }
+.fade-enter-from,
+.fade-leave-to { opacity: 0; }
+
+.ai-dialog-header{
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+  padding: 12px 16px;
+}
+.ai-dialog-header img{
+  cursor: pointer;
+  width: 15px;
+  height: 15px;
+}
+.ai-dialog-content{
+  display: flex;
+  height:94%;
+}
+.ai-dialog-aside{
+  display: flex;
+  flex-direction: column;
+  padding: 20px 16px 12px 16px;
+}
+.ai-dialog-aside p{
+  font-size: 12px;
+  margin-bottom:10px
+}
+.welcome-msg{
+  text-align: center;
+  height:100%;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+}
+.preset-item{
+  display:block;
+  height: 30px;
+  line-height: 30px;
+  text-align: center;
+  padding: 0 10px;
+  background: #F0F4FA;
+  border-radius: 50px 50px 50px 50px;
+  border: 1px solid #DDDDDD;
+}
+.preset-item:hover{
+  background-color: #e6f7ff;
+}
+.cust-btn{
+  width: 61px;
+  height: 25px;
+  background: linear-gradient(180deg, #3774F6 0%, #8D8DFF 100%);
+  border-radius: 50px 50px 50px 50px;
+  text-align: center;
+  line-height: 25px;
+  color: #fff;
+  margin-top:10px;
+  cursor: pointer;
+}
+.ai-dialog-button{
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  position: fixed;
+  right: 24px;
+  bottom: 124px;
+  border-radius: 50%;
+  z-index: 99999;
+  cursor: pointer;
+}
+.ai-dialog-button img{
+  width: 50px;
+  filter: drop-shadow(0 3px 8px rgba(5, 5, 17, 1));
+}
+</style>

+ 3 - 1
src/components/newLayout/index.vue

@@ -51,6 +51,7 @@
         }}</el-button>
       </span>
     </el-dialog>
+    <AIDialog></AIDialog>
   </div>
 </template>
 
@@ -60,7 +61,7 @@ import asideTemp from "./modules/aside.vue";
 import menuTemp from "./modules/menu.vue";
 import navTemp from "./modules/navRight.vue";
 import socketMessage from "@/components/socketMessage/index.vue";
-
+import AIDialog from "@/components/AIDialog/index.vue";
 import { mapGetters } from "vuex";
 
 export default {
@@ -70,6 +71,7 @@ export default {
     menuTemp,
     navTemp,
     socketMessage,
+    AIDialog
   },
   computed: {
     ...mapGetters({