diff --git a/CI/linter/license/.licenserc.yaml b/CI/linter/license/.licenserc.yaml index 0ef0ec505..cb0223db3 100644 --- a/CI/linter/license/.licenserc.yaml +++ b/CI/linter/license/.licenserc.yaml @@ -84,4 +84,5 @@ header: - 'CI/linter/codespell/.codespell.skip' - 'mvnw' - 'mvnw.cmd' + - '**/*.mdc' comment: never diff --git a/data-agent-frontend-nuxt/.cursor/rules/frontend-standards-nuxt4-spa.mdc b/data-agent-frontend-nuxt/.cursor/rules/frontend-standards-nuxt4-spa.mdc new file mode 100644 index 000000000..3c1612e5b --- /dev/null +++ b/data-agent-frontend-nuxt/.cursor/rules/frontend-standards-nuxt4-spa.mdc @@ -0,0 +1,92 @@ +--- +alwaysApply: true +--- +# DataAgent(Nuxt 4 SPA + TypeScript + Vuetify 3)开发法则 + +## 0. 关键上下文(最高优先级) +- 框架:Nuxt 4(Nitro),项目以 **纯 SPA 模式** 运行(`ssr: false`)。 +- 包管理器:只能使用 `pnpm`。 +- 语言:TypeScript(建议严格模式思维),**禁止**引入或使用 `.js` 新文件。 +- UI:Vuetify 3(MDI 图标使用 `mdi-*` 字符串形式,优先 ``)。 +- 请求:服务层统一放在 `app/services/`,并以该仓库现有习惯为准(本项目当前广泛使用 `axios`;如有冲突以现有服务实现风格为准)。 +- HTML 安全:任何 `v-html` 展示都需先经过 `DOMPurify`(或明确来自已处理的安全渲染函数)。 + +## 1. 知识检索协议(在“写代码/改代码”之前必须做) +1. **框架层优先级**:涉及 Nuxt 核心(route、plugin、composable、Nitro 等)优先参考 Nuxt 官方文档与仓库内现有实现模式。 +2. **本地上下文**:修改或新增组件/模块前,先检查目标目录下是否存在自动生成的 `README.md`(技能卡/上下文卡片)。 +3. **查重机制(Exist before Create)**:如果仓库已有类似实现(组件、工具函数、composable、utils),优先复用与小幅改造,而不是复制新代码。 +4. **类型优先**:优先引用现有 `types/` 或同级 `.ts` 定义;避免凭空猜测数据结构。 + +## 2. 编码规范(Coding Standards) +### 2.1 TypeScript 约束 +- 所有变量/参数/返回值尽量显式类型(至少保证关键边界类型安全)。 +- 禁止使用 `any`;需要时使用合理联合类型/泛型/类型守卫(type guards)。 +- 避免“看起来已经判断过”的可空值类型仍被 TS 推断为 `T | undefined`:用局部变量收窄(例如 `const x = arr[0]; if (!x) return; ...`)或非空断言(仅在确认绝对安全时使用)。 + +### 2.2 Vue / Nuxt 写法 +- 使用 ` + + +``` + +**Available components**: Dialog, Tabs, ExpansionPanel, Checkbox, Radio, Popover, Pagination + +**Component examples**: See [component-examples.md](references/component-examples.md) + +## Essential Patterns + +### Selection State +```ts +// Single selection (tabs, theme picker) +const single = createSingle({ mandatory: 'force' }) + +// Multi-selection (tags, filters) +const selection = createSelection({ multiple: true }) + +// Group with "select all" (data tables) +const group = createGroup() +``` + +### Context Sharing +```ts +// Type-safe provide/inject +const [useTheme, provideTheme] = createContext('Theme') +``` + +### Form Validation +```ts +const form = createForm() +form.register({ id: 'email', rules: [required, email] }) +``` + +## Anti-Patterns + +**Don't reinvent these wheels:** + +❌ **Custom selection logic** → Use `createSelection` +❌ **Manual provide/inject** → Use `createContext` +❌ **SSR checks** → Use `IN_BROWSER` constant + +**Detailed anti-patterns**: See [anti-patterns.md](references/anti-patterns.md) + +## Development Tools + +**Generate common patterns:** +```bash +python scripts/scaffold_pattern.py --type selection --output ./composables +``` + +**Check for anti-patterns:** +```bash +python scripts/check_patterns.py ./src +``` + +**Vuetify MCP** for structured API access: +```bash +claude mcp add vuetify-mcp https://mcp.vuetifyjs.com/mcp +``` + +## Resources + +- **Detailed examples**: [references/component-examples.md](references/component-examples.md) +- **Advanced patterns**: [references/advanced-patterns.md](references/advanced-patterns.md) +- **Migration guide**: [references/migration-guide.md](references/migration-guide.md) +- **Full API**: [references/REFERENCE.md](references/REFERENCE.md) +- **Live docs**: https://0.vuetifyjs.com diff --git a/data-agent-frontend-nuxt/.gitignore b/data-agent-frontend-nuxt/.gitignore new file mode 100644 index 000000000..8acbb5f2b --- /dev/null +++ b/data-agent-frontend-nuxt/.gitignore @@ -0,0 +1,30 @@ +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* +lerna-debug.log* + +# OS metadata +.DS_Store +Thumbs.db + +# Node +node_modules/ +dist/ +.npm +.pnpm-store + +# Nuxt +.nuxt/ +.output/ +.env + +# IDE +.vscode/ +.idea/ +*.swp +*.swo +.history/ diff --git a/data-agent-frontend-nuxt/.scripts/ai-gen-cache.json b/data-agent-frontend-nuxt/.scripts/ai-gen-cache.json new file mode 100644 index 000000000..c21035f26 --- /dev/null +++ b/data-agent-frontend-nuxt/.scripts/ai-gen-cache.json @@ -0,0 +1,41 @@ +{ + "app/components/common/KnowledgePageHeader/index.vue": "892b0bedfe0f92e4a5dac6f96d1d2ecd", + "app/components/common/ConfirmDialog/index.vue": "746b505f3a6e42b66f66dd0d54aac8c2", + "app/components/common/Tip/index.vue": "8e9907438fae5af53f895a37d188d418", + "app/components/BaseDrawer/index.vue": "7e25e3aa69f0732a056931c836c46f60", + "app/components/chat/ChatInputArea.vue": "9c2f570e3fc232f96539c2d5945459be", + "app/components/chat/ChatMarkdownReport.vue": "f075e04cb9981b99fab43347778fd099", + "app/components/chat/ChatMessageList.vue": "8e0ef2838b46afe39d839f44b4e3374b", + "app/components/chat/ChatResultSet.vue": "302d9774d3126acd3c1d15ef4b55e87e", + "app/components/chat/ChatSidebar.vue": "549b88d98581e4010aab484fd5c1ba62", + "app/components/chat/ChatStreamingReport.vue": "0a16694c5f597834084b3df4cc5998d7", + "app/components/chat/ChatWelcome.vue": "e2138cbec57e8fdb49f295f67cac3b31", + "app/components/chat/ChatWorkflowTimeline.vue": "ec258ddf99a94649cd05dc14844926da", + "app/layouts/default.vue": "74912a5495c55ca2fcd3c353a0dfda00", + "app/composables/useEchartsRenderer.ts": "fc233e44d3924da1b4e87831b5160eb8", + "app/composables/useCrudPage/index.ts": "ebacb28b00386fd1fc0382508b1c42b3", + "app/composables/useConfirm/index.ts": "94fc195477c8a337de3b52a5c1c9e79a", + "app/services/agentDatasource.ts": "d2cb4e7dd1dbdf1858f03e779b10eec8", + "app/services/agent/index.ts": "fb4e40d36ba443f88083c310d0cb81a5", + "app/services/agentDatasource/index.ts": "eb043af34a64daa8310388e764e646a3", + "app/services/businessKnowledge/index.ts": "dc162a2eb1a8ec45422b6421b9f79bf2", + "app/services/chat/index.ts": "58dc27fbaabba419925b5d85c71c2ee3", + "app/services/agentKnowledge/index.ts": "ee94a8f7bf00fff145a056fc156d9eb0", + "app/services/common/index.ts": "0a0ecffa24057053fcbfa16304c2ae80", + "app/services/datasource/index.ts": "9da08a60104d97d717fcc8983454bc22", + "app/services/graph/index.ts": "a44d446db75ad2fe619b52cc801ea320", + "app/services/logicalRelation/index.ts": "569488d9a30417acc07670a9a2b6af62", + "app/services/fileUpload/index.ts": "87775f4a2ff0a3dec7b2f4fcc786d399", + "app/services/modelConfig/index.ts": "4f4631251e989b8fc447dfec6c491038", + "app/services/presetQuestion/index.ts": "c5e0e91865f07e5ca0e1c217d8eb5833", + "app/services/prompt/index.ts": "d99bf052cf72840173b7721b10ae563a", + "app/services/resultSet/index.ts": "d22b079ebe181f1467b9d6dcf7065a4e", + "app/services/sessionStateManager/index.ts": "391138a13abf3595ec9a1ac7853b1cd8", + "app/services/semanticModel/index.ts": "061729128603a794deff2af607647c3d", + "app/stores/chat.ts": "3eb825918c10e222abf9696e5432e491", + "app/stores/tips/index.ts": "83ca5c54cff3202ca186fa283749527c", + "app/utils/report-html-template.ts": "56e46630d71779186377d93797b8ad79", + "app/utils/markdown/index.ts": "c368471b39983c3a984f80ed4f4a5718", + "app/utils/markdown/markdown-plugin-echarts.ts": "4d700d31bd425f56c64fda7bd9e2bb56", + "app/utils/markdown/markdown-plugin-highlight.ts": "95a407e00cdf058ae35506903d10468c" +} diff --git a/data-agent-frontend-nuxt/README.md b/data-agent-frontend-nuxt/README.md new file mode 100644 index 000000000..5e71f9a12 --- /dev/null +++ b/data-agent-frontend-nuxt/README.md @@ -0,0 +1,97 @@ +# DataAgent Frontend (Nuxt 4) + +本项目是 DataAgent 的前端部分,基于 Nuxt 4 框架构建,采用 TypeScript 开发,UI 库使用 Vuetify 3。 + +## 🛠 技术栈 + +- **框架**: [Nuxt 4](https://nuxt.com.cn/docs/4.x/getting-started/installation/) (基于 Vue 3 Composition API) +- **语言**: TypeScript (严格模式) +- **UI 库**: [Vuetify 3](https://vuetifyjs.com/zh-Hans/getting-started/installation/) +- **图标库**: [Material Design Icons (MDI)](https://pictogrammers.com/library/mdi/) +- **状态管理**: Pinia +- **HTTP 客户端**: Axios +- **包管理器**: pnpm + +## 📂 目录结构规范 + +项目遵循 **Folder-as-Context (目录即上下文)** 模式,实现物理层面的上下文隔离: + +- `app/components/`: UI 组件。公共组件存放于 `common/` 目录下。 +- `app/composables/`: 组合式 API (Hooks)。 +- `app/services/`: 业务服务层,统一封装 API 调用。 +- `app/stores/`: Pinia 状态管理。 +- `app/pages/`: 页面路由。 +- `docs/`: 项目相关文档及 AI 上下文治理说明。 +- `scripts/`: 自动化工具脚本。 + +## 🚀 快速开始 + +### 前置条件 +- Node.js 20.x 或更高版本 +- 已安装 pnpm (`npm install -g pnpm`) + +### 安装依赖 +```bash +pnpm install +``` + +### 启动开发服务器 +```bash +pnpm dev +``` + +### 构建生产版本 +```bash +pnpm build +``` + +## 🤖 AI 上下文治理 (Context Governance) + +本项目引入了自动化的 AI 文档生成体系,确保 AI 能够精确理解代码逻辑: + +- **生成文档**: 运行 `pnpm gen:ctx` 自动提取 JSDoc/TSDoc 并生成模块 `README.md`。 +- **规范**: 开发者需在代码中编写标准的 JSDoc 注释,详情请参考 [docs/CONTEXT_GOVERNANCE.md](./docs/CONTEXT_GOVERNANCE.md)。 + +## 🔄 Git 工作流与 Rebase 规范 + +本项目使用 **Rebase** 模式管理 Git 提交,以保持提交历史的整洁线性。 + +### 详细 Rebase 步骤: + +1. **从基础分支拉取最新代码**: + ```bash + git checkout refactor/fronted-ui + git pull origin refactor/fronted-ui + ``` + +2. **切换回开发分支**: + ```bash + git checkout feature/your-feature-name + ``` + +3. **执行 Rebase**: + ```bash + git rebase refactor/fronted-ui + ``` + *如果出现冲突,请手动解决冲突后执行:* + ```bash + git add . + git rebase --continue + ``` + +4. **推送到远程仓库**: + *由于 Rebase 会改变提交历史,推送时需要使用强制推送 (Force Push):* + ```bash + git push origin feature/your-feature-name --force + ``` + +## 📝 开发规范摘要 + +- **组件命名**: 使用 PascalCase (如 `ModelConfig.vue`)。 +- **插槽语法**: 统一使用 `#slot` 简写,禁止使用 `v-slot:`。 +- **属性顺序**: `class` -> `其他属性` -> `v-if` -> `事件绑定 (@click)`。 +- **严格类型**: 严禁使用 `any`,所有变量和函数必须有明确类型定义。 +- **文档先行**: 修改或新增代码时,必须同步更新 JSDoc 并运行 `pnpm gen:ctx`。 + +--- +*Powered by DataAgent Team* diff --git a/data-agent-frontend-nuxt/app/app.config.ts b/data-agent-frontend-nuxt/app/app.config.ts new file mode 100644 index 000000000..aae7fcc3d --- /dev/null +++ b/data-agent-frontend-nuxt/app/app.config.ts @@ -0,0 +1,17 @@ +/* + * Copyright 2026 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export default defineAppConfig({}); diff --git a/data-agent-frontend-nuxt/app/app.vue b/data-agent-frontend-nuxt/app/app.vue new file mode 100644 index 000000000..29a9720b4 --- /dev/null +++ b/data-agent-frontend-nuxt/app/app.vue @@ -0,0 +1,38 @@ +/* + * Copyright 2026 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + + + diff --git a/data-agent-frontend-nuxt/app/assets/css/main.css b/data-agent-frontend-nuxt/app/assets/css/main.css new file mode 100644 index 000000000..7b897cf37 --- /dev/null +++ b/data-agent-frontend-nuxt/app/assets/css/main.css @@ -0,0 +1,90 @@ +/* + * Copyright 2026 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* 页面淡入淡出且轻微位移 */ +.page-enter-active, +.page-leave-active { + transition: all 0.3s ease; +} + +.page-enter-from { + opacity: 0; + transform: translateY(10px); /* 从下方一点点浮现 */ +} + +.page-leave-to { + opacity: 0; + transform: translateY(-10px); /* 向上方一点点消失 */ +} + +/* ── 公共页面样式 ──────────────────────────────────────────────────────────── */ + +.page-shell { + padding: 32px; +} + +.search-field .v-field__outline { + --v-field-border-color: #e2e8f0; +} + +.custom-label { + font-size: 0.75rem; + font-weight: 600; + color: #64748b; + text-transform: uppercase; + letter-spacing: 0.05em; + margin-bottom: 6px; + display: block; +} + +.breathing-dot { + width: 8px; + height: 8px; + background-color: #10b981; + border-radius: 50%; + margin-right: 6px; + display: inline-block; + animation: breathe 2s infinite ease-in-out; +} + +.breathing-dot-green { + width: 8px; + height: 8px; + background-color: #10b981; + border-radius: 50%; + margin-right: 8px; + display: inline-block; + box-shadow: 0 0 0 rgba(16, 185, 129, 0.4); + animation: breathe 2s infinite ease-in-out; +} + +@keyframes breathe { + 0% { + transform: scale(0.9); + opacity: 0.7; + box-shadow: 0 0 0 0 rgba(16, 185, 129, 0.5); + } + 50% { + transform: scale(1.1); + opacity: 1; + box-shadow: 0 0 0 6px rgba(16, 185, 129, 0); + } + 100% { + transform: scale(0.9); + opacity: 0.7; + box-shadow: 0 0 0 0 rgba(16, 185, 129, 0); + } +} diff --git a/data-agent-frontend-nuxt/app/components/BaseDrawer/README.md b/data-agent-frontend-nuxt/app/components/BaseDrawer/README.md new file mode 100644 index 000000000..59e68c84f --- /dev/null +++ b/data-agent-frontend-nuxt/app/components/BaseDrawer/README.md @@ -0,0 +1,26 @@ +# 组件: BaseDrawer + +## 模块描述 +基础侧边栏布局组件,提供左侧抽屉和右侧内容区的响应式布局 + +## Props +| 属性 | 类型 | 默认值 | 描述 | +| --- | --- | --- | --- | +| drawerWidth | `union` | 260 | 抽屉宽度 (数字或带单位的字符串) | +| modelValue | `boolean` | true | 抽屉是否展开 (支持 v-model) | + +## Slots +| 名称 | 描述 | +| --- | --- | +| drawer | - | +| header | - | +| default | - | + +## Events +| 名称 | 描述 | +| --- | --- | +| update:modelValue | 更新展开状态 | + + +--- +> 🤖 AI 提示: 修改此组件前请阅读上述定义。代码位于 `BaseDrawer/index.vue`。 diff --git a/data-agent-frontend-nuxt/app/components/BaseDrawer/index.vue b/data-agent-frontend-nuxt/app/components/BaseDrawer/index.vue new file mode 100644 index 000000000..c6b870d10 --- /dev/null +++ b/data-agent-frontend-nuxt/app/components/BaseDrawer/index.vue @@ -0,0 +1,126 @@ +/* + * Copyright 2026 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + + + + + diff --git a/data-agent-frontend-nuxt/app/components/README.md b/data-agent-frontend-nuxt/app/components/README.md new file mode 100644 index 000000000..bbdee436b --- /dev/null +++ b/data-agent-frontend-nuxt/app/components/README.md @@ -0,0 +1,10 @@ +# 目录索引: components + +> 🤖 自动生成,请勿手动修改。此文件为 AI 提供模块地图。 + +## 子目录 + +- [BaseDrawer](./BaseDrawer/README.md) +- [chat](./chat/README.md) +- [common](./common/README.md) + diff --git a/data-agent-frontend-nuxt/app/components/chat/ChatInputArea.vue b/data-agent-frontend-nuxt/app/components/chat/ChatInputArea.vue new file mode 100644 index 000000000..c72c5d678 --- /dev/null +++ b/data-agent-frontend-nuxt/app/components/chat/ChatInputArea.vue @@ -0,0 +1,547 @@ +/* + * Copyright 2026 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +