diff --git a/package.json b/package.json index fcb2958e..b539fc38 100644 --- a/package.json +++ b/package.json @@ -117,7 +117,6 @@ "unplugin-vue-components": "^28.8.0", "vite": "^7.1.12", "vite-plugin-mock-dev-server": "^2.0.2", - "vite-plugin-vue-mcp": "^0.3.2", "vue-eslint-parser": "^10.2.0", "vue-tsc": "^2.2.12" }, diff --git a/src/App.vue b/src/App.vue index 141389ba..c1febe5a 100644 --- a/src/App.vue +++ b/src/App.vue @@ -20,6 +20,7 @@ import { useAppStore, useSettingsStore } from "@/store"; import { defaultSettings } from "@/settings"; import { ThemeMode, ComponentSize } from "@/enums"; import AiAssistant from "@/components/AiAssistant/index.vue"; +import { AuthStorage } from "@/utils/auth"; const appStore = useAppStore(); const settingsStore = useSettingsStore(); @@ -27,7 +28,13 @@ const settingsStore = useSettingsStore(); const locale = computed(() => appStore.locale); const size = computed(() => appStore.size as ComponentSize); const showWatermark = computed(() => settingsStore.showWatermark); -const enableAiAssistant = computed(() => settingsStore.enableAiAssistant); + +// 只有在启用 AI 助手且用户已登录时才显示 +const enableAiAssistant = computed(() => { + const isEnabled = settingsStore.enableAiAssistant; + const isLoggedIn = !!AuthStorage.getAccessToken(); + return isEnabled && isLoggedIn; +}); // 明亮/暗黑主题水印字体颜色适配 const fontColor = computed(() => { diff --git a/src/api/ai/index.ts b/src/api/ai/index.ts index b177543a..faf208d5 100644 --- a/src/api/ai/index.ts +++ b/src/api/ai/index.ts @@ -30,6 +30,8 @@ export interface FunctionCall { * AI 命令解析响应 */ export interface AiCommandResponse { + /** 解析日志ID(用于关联执行记录) */ + parseLogId?: string; /** 是否成功解析 */ success: boolean; /** 解析后的函数调用列表 */ @@ -48,6 +50,10 @@ export interface AiCommandResponse { * AI 命令执行请求 */ export interface AiExecuteRequest { + /** 关联的解析日志ID */ + parseLogId?: string; + /** 原始命令(用于审计) */ + originalCommand?: string; /** 要执行的函数调用 */ functionCall: FunctionCall; /** 确认模式:auto=自动执行, manual=需要用户确认 */ @@ -56,6 +62,8 @@ export interface AiExecuteRequest { userConfirmed?: boolean; /** 幂等性令牌(防止重复执行) */ idempotencyKey?: string; + /** 当前页面路由 */ + currentRoute?: string; } /** @@ -72,14 +80,60 @@ export interface AiExecuteResponse { affectedRows?: number; /** 错误信息 */ error?: string; - /** 审计ID(用于追踪) */ - auditId?: string; + /** 记录ID(用于追踪) */ + recordId?: string; /** 需要用户确认 */ requiresConfirmation?: boolean; /** 确认提示信息 */ confirmationPrompt?: string; } +export interface AiCommandRecordPageQuery extends PageQuery { + keywords?: string; + executeStatus?: string; + parseSuccess?: boolean; + userId?: number; + isDangerous?: boolean; + provider?: string; + model?: string; + functionName?: string; + createTime?: [string, string]; +} + +export interface AiCommandRecordVO { + id: string; + userId: number; + username: string; + originalCommand: string; + provider?: string; + model?: string; + parseSuccess?: boolean; + functionCalls?: string; + explanation?: string; + confidence?: number; + parseErrorMessage?: string; + inputTokens?: number; + outputTokens?: number; + totalTokens?: number; + parseTime?: number; + functionName?: string; + functionArguments?: string; + executeStatus?: string; + executeResult?: string; + executeErrorMessage?: string; + affectedRows?: number; + isDangerous?: boolean; + requiresConfirmation?: boolean; + userConfirmed?: boolean; + executionTime?: number; + ipAddress?: string; + userAgent?: string; + currentRoute?: string; + createTime?: string; + updateTime?: string; + remark?: string; +} + /** * AI 命令 API */ @@ -102,10 +156,10 @@ class AiCommandApi { * 执行已解析的命令 * * @param data 执行请求参数 - * @returns 执行结果 + * @returns 执行结果数据(成功时返回,失败时抛出异常) */ - static executeCommand(data: AiExecuteRequest): Promise { - return request({ + static executeCommand(data: AiExecuteRequest): Promise { + return request({ url: "/api/v1/ai/command/execute", method: "post", data, @@ -113,45 +167,22 @@ class AiCommandApi { } /** - * 获取命令执行历史 - * - * @param params 查询参数 - * @returns 历史记录列表 + * 获取命令记录分页列表 */ - static getCommandHistory(params?: { - page?: number; - size?: number; - startTime?: string; - endTime?: string; - }) { - return request({ - url: "/api/v1/ai/command/history", - method: "get", - params, - }); - } - - /** - * 获取可用的函数列表(用于展示或调试) - * - * @returns 函数列表 - */ - static getAvailableFunctions() { - return request({ - url: "/api/v1/ai/command/functions", + static getCommandRecordPage(queryParams: AiCommandRecordPageQuery) { + return request>({ + url: "/api/v1/ai/command/records", method: "get", + params: queryParams, }); } /** * 撤销命令执行(如果支持) - * - * @param auditId 审计ID - * @returns 撤销结果 */ - static rollbackCommand(auditId: string) { + static rollbackCommand(recordId: string) { return request({ - url: `/api/v1/ai/command/rollback/${auditId}`, + url: `/api/v1/ai/command/rollback/${recordId}`, method: "post", }); } diff --git a/src/components/AiAssistant/index.vue b/src/components/AiAssistant/index.vue index e697232d..4bcb2e65 100644 --- a/src/components/AiAssistant/index.vue +++ b/src/components/AiAssistant/index.vue @@ -35,7 +35,7 @@ v-model="command" type="textarea" :rows="3" - placeholder="试试说:查询姓名为张三用户 或者:跳转到用户管理 按 Ctrl+Enter 快速发送" + placeholder="试试说:修改test用户的姓名为测试人员 或者:跳转到用户管理 按 Ctrl+Enter 快速发送" :disabled="loading" @keydown.ctrl.enter="handleExecute" /> @@ -71,6 +71,19 @@ {{ response.action.query }} +
+ + 跳转至: + {{ response.action.pageName }} + + 并搜索: + {{ response.action.query }} + + + + 执行: + {{ response.action.functionCall.name }} +
执行: @@ -94,21 +107,57 @@ diff --git a/src/views/demo/ai-command.vue b/src/views/demo/ai-command.vue deleted file mode 100644 index 64526114..00000000 --- a/src/views/demo/ai-command.vue +++ /dev/null @@ -1,599 +0,0 @@ - - - - - diff --git a/src/views/system/user/index.vue b/src/views/system/user/index.vue index 6d9e7383..9fbd9ee6 100644 --- a/src/views/system/user/index.vue +++ b/src/views/system/user/index.vue @@ -95,6 +95,7 @@ stripe highlight-current-row class="data-table__content" + row-key="id" @selection-change="handleSelectionChange" > @@ -244,10 +245,13 @@ diff --git a/vite.config.ts b/vite.config.ts index 680589fb..15bca5f8 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -11,10 +11,6 @@ import UnoCSS from "unocss/vite"; import { resolve } from "path"; import { name, version, engines, dependencies, devDependencies } from "./package.json"; -// MCP 插件:为项目开启 MCP Server(仅开发环境) -// 使用前请先安装:pnpm add -D vite-plugin-vue-mcp -import { VueMcp } from "vite-plugin-vue-mcp"; - // 平台的名称、版本、运行所需的 node 版本、依赖、构建时间的类型提示 const __APP_INFO__ = { pkg: { name, version, engines, dependencies, devDependencies }, @@ -59,8 +55,6 @@ export default defineConfig(({ mode }: ConfigEnv): UserConfig => { plugins: [ vue(), ...(env.VITE_MOCK_DEV_SERVER === "true" ? [mockDevServerPlugin()] : []), - // MCP 插件:仅在开发环境启用,用于 AI 工具集成,让 Cursor AI 能够读取应用运行时的 Store 状态,帮助调试和理解代码 - ...(!isProduction ? [VueMcp()] : []), UnoCSS(), // API 自动导入 AutoImport({