diff --git a/scripts/ai.js b/scripts/ai.js index 508dc5d..40e2563 100644 --- a/scripts/ai.js +++ b/scripts/ai.js @@ -1,28 +1,47 @@ -// ai.js +// scripts/ai.js import { COMMANDS } from './commands.js'; export async function translateToCommand(userInput) { const availableKeys = COMMANDS.map(c => c.key).join(', '); - const systemPrompt = `你是一个助手。将输入映射到以下关键词之一:${availableKeys}。只输出关键词,不要其他字。无法匹配则输出 UNKNOWN。`; + + // 优化提示词:增加参数提取规则和别名映射 + const systemPrompt = `你是一个工业自动化系统助手。 +标准指令列表:[${availableKeys}] + +任务规则: +1. 如果用户指令包含设备编号、序列号或验证码(如“20260114”),请按格式输出:“标准指令 参数”。 + 例如:“帮我添加一台编号为20260114的设备” -> 输出 “添加设备 20260114”。 +2. 如果只是单纯跳转,只输出“标准指令”。 +3. “主界面”、“主页”映射为“首页”。 +4. 只输出结果,不要输出任何解释说明或标点。 +5. 无法匹配请输出 UNKNOWN。`; return new Promise((resolve) => { - // 1. 监听结果 const handler = (event) => { const response = event.detail; window.removeEventListener("AI_RESULT", handler); - if (response.success) { - const content = response.data.choices[0].message.content.trim(); - console.log("📥 AI 识别结果:", content); - resolve(content === "UNKNOWN" ? null : content); + if (response && response.success && response.data) { + try { + if (response.data.choices && response.data.choices.length > 0) { + const content = response.data.choices[0].message.content.trim(); + console.log("📥 AI 映射结果:", content); + resolve(content === "UNKNOWN" ? null : content); + } else if (response.data.error || response.data.errors) { + console.error("AI服务报错:", response.data.error || response.data.errors); + resolve(null); + } + } catch (e) { + console.error("解析响应失败:", e); + resolve(null); + } } else { - console.error("AI 失败:", response.error); resolve(null); } }; + window.addEventListener("AI_RESULT", handler); - // 2. 触发请求 window.dispatchEvent(new CustomEvent("DO_AI_REQUEST", { detail: { userInput, systemPrompt } })); diff --git a/scripts/commands.js b/scripts/commands.js index 9a3966c..f852f02 100644 --- a/scripts/commands.js +++ b/scripts/commands.js @@ -39,51 +39,82 @@ export const COMMANDS = [ { key: "数据下云", menu: "数据下云", route: "/系统管理/数据下云" }, ]; +function waitForElement(selector, callback, timeout = 5000) { + const start = Date.now(); + const timer = setInterval(() => { + const el = document.querySelector(selector); + if (el) { + clearInterval(timer); + callback(el); + } else if (Date.now() - start > timeout) { + clearInterval(timer); + console.warn("等待元素超时:", selector); + } + }, 200); +} + +/** + * 自动化填写和点击逻辑 + */ +function autoFillAndSubmit(value) { + // 1. 等待输入框出现 (针对 Element Plus 使用 .el-input__inner) + // 提示:如果有多个框,可改用 'input[placeholder*="上云码"]' 增加精度 + waitForElement('.el-input__inner', (input) => { + console.log("🔍 已定位输入框,开始填充:", value); + + // 填写内容 + input.value = value; + + // 关键:手动触发事件以同步 Vue 的双向绑定 (v-model) + input.dispatchEvent(new Event('input', { bubbles: true })); + input.dispatchEvent(new Event('change', { bubbles: true })); + + // 2. 自动点击“确认”按钮 (通常类名为 el-button--primary) + const submitBtn = document.querySelector('.el-button--primary'); + if (submitBtn) { + setTimeout(() => { + submitBtn.click(); + console.log("✅ 自动化流程已触发提交"); + }, 600); + } + }); +} + export function expandParentMenu(span) { - const subMenu = span.closest(".el-sub-menu"); - if (subMenu) { - const title = subMenu.querySelector(".el-sub-menu__title"); - if (title && !subMenu.classList.contains("is-opened")) { - title.click(); - console.log("📂 已展开父菜单"); + const subMenu = span.closest(".el-sub-menu"); + if (subMenu && !subMenu.classList.contains("is-opened")) { + const title = subMenu.querySelector(".el-sub-menu__title"); + if (title) title.click(); } - } } -export function goToRoute(route) { - // 兼容 Hash 路由和普通路由,根据实际项目情况 - window.location.hash = route; - console.log("✅ 已跳转到路由:", route); -} +export function handleCommand(aiResult) { + if (!aiResult) return; + console.log("🚀 处理自动化指令:", aiResult); -export function handleCommand(keyOrText) { - console.log("🚀 执行指令逻辑:", keyOrText); - - // 尝试精确匹配 (AI返回的Key) 或 模糊匹配 (用户输入的Text) - const command = COMMANDS.find(c => c.key === keyOrText) || - COMMANDS.find(c => keyOrText.includes(c.key)); + // 解析格式:"指令 参数" (例如 "添加设备 20260114") + const [key, arg] = aiResult.split(" "); - if (!command) { - console.warn("无法执行,未找到对应菜单动作:", keyOrText); - return; - } + const command = COMMANDS.find(c => c.key === key) || + COMMANDS.find(c => key.includes(c.key)); - // 查找菜单 DOM 元素 (根据你原有的逻辑) - const allSpans = Array.from(document.querySelectorAll("span")); - - // 优先全匹配,防止"报表"匹配到"高级报表" - let span = allSpans.find(el => el.innerText.trim() === command.menu); + if (command) { + // 第一步:查找菜单并跳转 + const allSpans = Array.from(document.querySelectorAll("span")); + let span = allSpans.find(el => el.innerText.trim() === command.menu); - if (span) { - expandParentMenu(span); - // 模拟点击触发 Vue/React 的路由跳转,或者直接改 Hash - // 如果页面需要点击才能触发加载,建议 span.click() - // 如果只是纯 hash 跳转,goToRoute 即可 - - // 建议先点击,确保侧边栏高亮 - span.click(); - goToRoute(command.route); - } else { - console.error(`❌ 未找到菜单元素: ${command.menu}`); - } + if (span) { + expandParentMenu(span); + span.click(); + window.location.hash = command.route; + + // 第二步:如果有编号参数,启动后续填充流程 + if (arg) { + console.log(`⏳ 页面跳转中,准备填充参数: ${arg}`); + autoFillAndSubmit(arg); + } + } + } else { + console.warn("未匹配到标准指令:", key); + } } \ No newline at end of file