增加AI通过上云码添加仪表的功能
This commit is contained in:
parent
e806d61ede
commit
53994476c4
@ -1,28 +1,47 @@
|
|||||||
// ai.js
|
// scripts/ai.js
|
||||||
import { COMMANDS } from './commands.js';
|
import { COMMANDS } from './commands.js';
|
||||||
|
|
||||||
export async function translateToCommand(userInput) {
|
export async function translateToCommand(userInput) {
|
||||||
const availableKeys = COMMANDS.map(c => c.key).join(', ');
|
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) => {
|
return new Promise((resolve) => {
|
||||||
// 1. 监听结果
|
|
||||||
const handler = (event) => {
|
const handler = (event) => {
|
||||||
const response = event.detail;
|
const response = event.detail;
|
||||||
window.removeEventListener("AI_RESULT", handler);
|
window.removeEventListener("AI_RESULT", handler);
|
||||||
|
|
||||||
if (response.success) {
|
if (response && response.success && response.data) {
|
||||||
const content = response.data.choices[0].message.content.trim();
|
try {
|
||||||
console.log("📥 AI 识别结果:", content);
|
if (response.data.choices && response.data.choices.length > 0) {
|
||||||
resolve(content === "UNKNOWN" ? null : content);
|
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 {
|
} else {
|
||||||
console.error("AI 失败:", response.error);
|
|
||||||
resolve(null);
|
resolve(null);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
window.addEventListener("AI_RESULT", handler);
|
window.addEventListener("AI_RESULT", handler);
|
||||||
|
|
||||||
// 2. 触发请求
|
|
||||||
window.dispatchEvent(new CustomEvent("DO_AI_REQUEST", {
|
window.dispatchEvent(new CustomEvent("DO_AI_REQUEST", {
|
||||||
detail: { userInput, systemPrompt }
|
detail: { userInput, systemPrompt }
|
||||||
}));
|
}));
|
||||||
|
|||||||
@ -39,51 +39,82 @@ export const COMMANDS = [
|
|||||||
{ key: "数据下云", menu: "数据下云", route: "/系统管理/数据下云" },
|
{ 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) {
|
export function expandParentMenu(span) {
|
||||||
const subMenu = span.closest(".el-sub-menu");
|
const subMenu = span.closest(".el-sub-menu");
|
||||||
if (subMenu) {
|
if (subMenu && !subMenu.classList.contains("is-opened")) {
|
||||||
const title = subMenu.querySelector(".el-sub-menu__title");
|
const title = subMenu.querySelector(".el-sub-menu__title");
|
||||||
if (title && !subMenu.classList.contains("is-opened")) {
|
if (title) title.click();
|
||||||
title.click();
|
|
||||||
console.log("📂 已展开父菜单");
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export function goToRoute(route) {
|
export function handleCommand(aiResult) {
|
||||||
// 兼容 Hash 路由和普通路由,根据实际项目情况
|
if (!aiResult) return;
|
||||||
window.location.hash = route;
|
console.log("🚀 处理自动化指令:", aiResult);
|
||||||
console.log("✅ 已跳转到路由:", route);
|
|
||||||
}
|
// 解析格式:"指令 参数" (例如 "添加设备 20260114")
|
||||||
|
const [key, arg] = aiResult.split(" ");
|
||||||
export function handleCommand(keyOrText) {
|
|
||||||
console.log("🚀 执行指令逻辑:", keyOrText);
|
const command = COMMANDS.find(c => c.key === key) ||
|
||||||
|
COMMANDS.find(c => key.includes(c.key));
|
||||||
// 尝试精确匹配 (AI返回的Key) 或 模糊匹配 (用户输入的Text)
|
|
||||||
const command = COMMANDS.find(c => c.key === keyOrText) ||
|
if (command) {
|
||||||
COMMANDS.find(c => keyOrText.includes(c.key));
|
// 第一步:查找菜单并跳转
|
||||||
|
const allSpans = Array.from(document.querySelectorAll("span"));
|
||||||
if (!command) {
|
let span = allSpans.find(el => el.innerText.trim() === command.menu);
|
||||||
console.warn("无法执行,未找到对应菜单动作:", keyOrText);
|
|
||||||
return;
|
if (span) {
|
||||||
}
|
expandParentMenu(span);
|
||||||
|
span.click();
|
||||||
// 查找菜单 DOM 元素 (根据你原有的逻辑)
|
window.location.hash = command.route;
|
||||||
const allSpans = Array.from(document.querySelectorAll("span"));
|
|
||||||
|
// 第二步:如果有编号参数,启动后续填充流程
|
||||||
// 优先全匹配,防止"报表"匹配到"高级报表"
|
if (arg) {
|
||||||
let span = allSpans.find(el => el.innerText.trim() === command.menu);
|
console.log(`⏳ 页面跳转中,准备填充参数: ${arg}`);
|
||||||
|
autoFillAndSubmit(arg);
|
||||||
if (span) {
|
}
|
||||||
expandParentMenu(span);
|
}
|
||||||
// 模拟点击触发 Vue/React 的路由跳转,或者直接改 Hash
|
} else {
|
||||||
// 如果页面需要点击才能触发加载,建议 span.click()
|
console.warn("未匹配到标准指令:", key);
|
||||||
// 如果只是纯 hash 跳转,goToRoute 即可
|
}
|
||||||
|
|
||||||
// 建议先点击,确保侧边栏高亮
|
|
||||||
span.click();
|
|
||||||
goToRoute(command.route);
|
|
||||||
} else {
|
|
||||||
console.error(`❌ 未找到菜单元素: ${command.menu}`);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user