优化程序逻辑

This commit is contained in:
Cx330 committed 2026-01-11 17:50:27 +08:00
1 parent be4bbe55df
commit d1f8b403c4
10 files changed
+7 -14

No files matched your search

+30
View File
@@ -0,0 +1,30 @@
// ai.js
import { COMMANDS } from './commands.js';
export async function translateToCommand(userInput) {
const availableKeys = COMMANDS.map(c => c.key).join(', ');
const systemPrompt = `你是一个助手。将输入映射到以下关键词之一:${availableKeys}。只输出关键词,不要其他字。无法匹配则输出 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);
} else {
console.error("AI 失败:", response.error);
resolve(null);
}
};
window.addEventListener("AI_RESULT", handler);
// 2. 触发请求
window.dispatchEvent(new CustomEvent("DO_AI_REQUEST", {
detail: { userInput, systemPrompt }
}));
});
}
+89
View File
@@ -0,0 +1,89 @@
export const COMMANDS = [
{ key: "首页", menu: "首页", route: "/首页" },
{ key: "添加设备", menu: "添加设备", route: "/添加设备/添加设备" },
{ key: "监控中心", menu: "监控中心", route: "/监控中心/监控中心" },
{ key: "摄像头管理", menu: "摄像头管理", route: "/云视频管理/摄像头管理" },
{ key: "云视频监控", menu: "云视频监控", route: "/云视频监控/云视频监控" },
{ key: "GIS监控", menu: "GIS监控", route: "/GIS管理/GIS监控" },
{ key: "我的流量", menu: "我的流量", route: "/资源管理/我的流量" },
{ key: "我的资源", menu: "我的资源", route: "/资源管理/我的资源" },
{ key: "我的订单", menu: "我的订单", route: "/资源管理/我的订单" },
{ key: "仪表积分", menu: "仪表积分", route: "/资源管理/仪表积分" },
{ key: "报警设置", menu: "报警设置", route: "/报警管理/报警设置" },
{ key: "报警通知", menu: "报警通知", route: "/报警管理/报警通知" },
{ key: "报警记录", menu: "报警记录", route: "/报警管理/报警记录" },
{ key: "基础报表", menu: "基础报表", route: "/报表管理/基础报表" },
{ key: "高级报表配置", menu: "高级报表配置", route: "/报表管理/高级报表配置" },
{ key: "高级报表", menu: "高级报表", route: "/报表管理/高级报表" },
{ key: "应用场景", menu: "应用场景", route: "/仪表管理/应用场景" },
{ key: "仪表管理", menu: "仪表管理", route: "/仪表管理/仪表管理" },
{ key: "虚拟仪表", menu: "虚拟仪表", route: "/仪表管理/虚拟仪表" },
{ key: "物位监测", menu: "物位监测", route: "/场景管理/物位监测/物位监测" },
{ key: "物位监测配置", menu: "物位监测配置", route: "/场景管理/物位监测/物位监测配置" },
{ key: "车间看板", menu: "车间看板", route: "/场景管理/车间看板/车间看板" },
{ key: "车间看板配置", menu: "车间看板配置", route: "/场景管理/车间看板/车间看板配置" },
{ key: "能源结算", menu: "能源结算", route: "/场景管理/能源抄表/能源结算" },
{ key: "能源结算配置", menu: "能源结算配置", route: "/场景管理/能源抄表/能源结算配置" },
{ key: "多租户能源结算", menu: "多租户能源结算", route: "/场景管理/多租户结算/多租户能源结算" },
{ key: "租户管理", menu: "租户管理", route: "/场景管理/多租户结算/租户管理" },
{ key: "计价方式管理", menu: "计价方式管理", route: "/场景管理/多租户结算/计价方式管理" },
{ key: "单染缸印染结算", menu: "单染缸印染结算", route: "/场景管理/印染结算/单染缸印染结算" },
{ key: "多染缸印染结算", menu: "多染缸印染结算", route: "/场景管理/印染结算/多染缸印染结算" },
{ key: "染缸能耗一览表", menu: "染缸能耗一览表", route: "/场景管理/印染结算/染缸能耗一览表" },
{ key: "印染结算配置", menu: "印染结算配置", route: "/场景管理/印染结算/印染结算配置" },
{ key: "尘埃粒子车间", menu: "尘埃粒子车间", route: "/场景管理/尘埃粒子/尘埃粒子车间" },
{ key: "洁净度一览表", menu: "洁净度一览表", route: "/场景管理/尘埃粒子/洁净度一览表" },
{ key: "尘埃粒子配置", menu: "尘埃粒子配置", route: "/场景管理/尘埃粒子/尘埃粒子配置" },
{ key: "消息管理", menu: "消息管理", route: "/系统管理/消息管理" },
{ key: "数据服务", menu: "数据服务", route: "/系统管理/数据服务" },
{ key: "数据下云", menu: "数据下云", route: "/系统管理/数据下云" },
];
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("📂 已展开父菜单");
}
}
}
export function goToRoute(route) {
// 兼容 Hash 路由和普通路由,根据实际项目情况
window.location.hash = route;
console.log("✅ 已跳转到路由:", route);
}
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));
if (!command) {
console.warn("无法执行,未找到对应菜单动作:", keyOrText);
return;
}
// 查找菜单 DOM 元素 (根据你原有的逻辑)
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}`);
}
}
+51
View File
@@ -0,0 +1,51 @@
export function createPanel() {
const panelId = "automation-ai-panel";
// 防止重复创建
let panel = document.getElementById(panelId);
if (panel) return getUIRefs(panel);
panel = document.createElement("div");
panel.id = panelId;
panel.style.cssText = `
position: fixed; bottom: 24px; right: 24px; z-index: 2147483647;
background: white; border-radius: 10px;
box-shadow: 0 4px 12px rgba(0,0,0,.2); padding: 12px; width: 260px;
font-size: 14px; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
`;
panel.innerHTML = `
<div style="display:flex;gap:8px;align-items:center;">
<input id="voiceTextInput" type="text" placeholder="输入指令或自然语言..."
style="flex:1;padding:8px;border:1px solid #dcdfe6;border-radius:4px;outline:none;font-size:13px;" />
<button id="voiceBtn" title="按 Alt+V 快捷开启"
style="padding:8px 12px;border:none;border-radius:4px;background:#409eff;color:#fff;cursor:pointer;display:flex;align-items:center;justify-content:center;">
🎤
</button>
</div>
<div id="panelStatus" style="margin-top:8px;color:#999;font-size:12px;display:flex;justify-content:space-between;align-items:center;">
<span id="statusText">准备就绪</span>
<span id="aiLoading" style="display:none;color:#409eff;font-weight:bold;">🤖 思考中...</span>
</div>
`;
document.body.appendChild(panel);
return getUIRefs(panel);
}
function getUIRefs(panel) {
const input = panel.querySelector("#voiceTextInput");
const btn = panel.querySelector("#voiceBtn");
const loading = panel.querySelector("#aiLoading");
const statusText = panel.querySelector("#statusText");
return {
input,
btn,
setLoading: (isLoading) => {
loading.style.display = isLoading ? "inline" : "none";
statusText.style.display = isLoading ? "none" : "inline";
input.disabled = isLoading;
if (!isLoading) input.focus();
}
};
}
+36
View File
@@ -0,0 +1,36 @@
// 语音识别
export function initVoice(panel, handleCommand) {
const SpeechRecognition = window.SpeechRecognition || window.webkitSpeechRecognition;
const supportSpeech = !!SpeechRecognition;
let recognition;
if (supportSpeech) {
recognition = new SpeechRecognition();
recognition.lang = "zh-CN";
recognition.continuous = false;
recognition.interimResults = false;
recognition.onresult = (event) => {
const text = event.results[0][0].transcript.trim();
handleCommand(text);
};
recognition.onerror = (event) => {
console.error("语音识别错误", event.error);
};
panel.querySelector("#voiceBtn").onclick = () => recognition.start();
} else {
panel.querySelector("#voiceBtn").disabled = true;
panel.querySelector("#voiceBtn").innerText = "❌";
}
document.addEventListener("keydown", (e) => {
if (e.altKey && e.key.toLowerCase() === "v" && supportSpeech && recognition) {
recognition.start();
}
});
return supportSpeech;
}