From 9d0c116ce3da9fd6d1debb59a82423d9118d8be4 Mon Sep 17 00:00:00 2001 From: Wang Defa <1+wangdefa@noreply.gitea.bcde.io> Date: Thu, 9 Jul 2026 19:05:28 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BB=93=E5=BA=93=E8=87=AA=E5=8C=85=E5=90=AB?= =?UTF-8?q?=E5=8C=96=EF=BC=9ACI/=E6=96=87=E6=A1=A3/=E8=A7=84=E8=8C=83?= =?UTF-8?q?=E5=85=A5=E5=BA=93=EF=BC=8C=E5=8D=87=E7=BA=A7=20echarts?= =?UTF-8?q?=EF=BC=8C=E5=A1=AB=E5=85=B3=E4=BA=8E=E9=A1=B5=E9=93=BE=E6=8E=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitea/workflows/ci.yml | 24 + .gitea/workflows/release.yml | 34 + .github/workflows/ci.yml | 23 + .github/workflows/release.yml | 40 + .trellis/.version | 1 + .trellis/spec/frontend/api-and-state.md | 5 + .../spec/frontend/component-guidelines.md | 59 ++ .trellis/spec/frontend/directory-structure.md | 36 + .trellis/spec/frontend/hook-guidelines.md | 51 ++ .trellis/spec/frontend/index.md | 44 ++ .trellis/spec/frontend/quality-guidelines.md | 51 ++ .trellis/spec/frontend/state-management.md | 51 ++ .../spec/frontend/styling-design-tokens.md | 111 +++ .trellis/spec/frontend/type-safety.md | 51 ++ .trellis/spec/frontend/typescript-vue.md | 16 + .../spec/guides/code-reuse-thinking-guide.md | 223 ++++++ .../spec/guides/cross-layer-thinking-guide.md | 327 ++++++++ .trellis/spec/guides/design-workflow.md | 27 + .trellis/spec/guides/index.md | 97 +++ .trellis/workflow.md | 708 ++++++++++++++++++ .vscode/extensions.json | 8 + .vscode/settings.json | 33 + AGENTS.md | 54 ++ CHANGELOG.md | 13 + CLAUDE.md | 54 ++ LICENSE | 21 + README.md | 37 + package-lock.json | 63 +- package.json | 4 +- src/api/mock.ts | 36 +- src/components/settings/AboutTab.vue | 4 +- 31 files changed, 2235 insertions(+), 71 deletions(-) create mode 100644 .gitea/workflows/ci.yml create mode 100644 .gitea/workflows/release.yml create mode 100644 .github/workflows/ci.yml create mode 100644 .github/workflows/release.yml create mode 100644 .trellis/.version create mode 100644 .trellis/spec/frontend/api-and-state.md create mode 100644 .trellis/spec/frontend/component-guidelines.md create mode 100644 .trellis/spec/frontend/directory-structure.md create mode 100644 .trellis/spec/frontend/hook-guidelines.md create mode 100644 .trellis/spec/frontend/index.md create mode 100644 .trellis/spec/frontend/quality-guidelines.md create mode 100644 .trellis/spec/frontend/state-management.md create mode 100644 .trellis/spec/frontend/styling-design-tokens.md create mode 100644 .trellis/spec/frontend/type-safety.md create mode 100644 .trellis/spec/frontend/typescript-vue.md create mode 100644 .trellis/spec/guides/code-reuse-thinking-guide.md create mode 100644 .trellis/spec/guides/cross-layer-thinking-guide.md create mode 100644 .trellis/spec/guides/design-workflow.md create mode 100644 .trellis/spec/guides/index.md create mode 100644 .trellis/workflow.md create mode 100644 .vscode/extensions.json create mode 100644 .vscode/settings.json create mode 100644 AGENTS.md create mode 100644 CHANGELOG.md create mode 100644 CLAUDE.md create mode 100644 LICENSE create mode 100644 README.md diff --git a/.gitea/workflows/ci.yml b/.gitea/workflows/ci.yml new file mode 100644 index 0000000..cfac5cd --- /dev/null +++ b/.gitea/workflows/ci.yml @@ -0,0 +1,24 @@ +name: CI + +# 仅分支推送触发:tag 推送交给 release.yml;solo 开发不走 PR,去掉 pull_request 避免同一提交双跑 +on: + push: + branches: ["**"] + +jobs: + test: + runs-on: ubuntu-latest-amd64 + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: + node-version: "24" + cache: npm + - name: 安装依赖 + run: npm ci + - name: ESLint(检查模式) + run: npx eslint . + - name: 类型检查 + run: npm run typecheck + - name: 构建 + run: npm run build diff --git a/.gitea/workflows/release.yml b/.gitea/workflows/release.yml new file mode 100644 index 0000000..d24b483 --- /dev/null +++ b/.gitea/workflows/release.yml @@ -0,0 +1,34 @@ +name: Release + +on: + push: + tags: ["v*"] + +jobs: + release: + runs-on: ubuntu-latest-amd64 + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: + node-version: "24" + cache: npm + + - name: 构建并打包 dist.zip + run: | + npm ci + npm run build + cd dist && zip -qr ../dist.zip . && cd .. + + - name: 提取 CHANGELOG 版本段作为 Release 描述 + run: | + TAG="${{ gitea.ref_name }}" + awk -v ver="${TAG#v}" '$0 ~ "^## \\[" ver "\\]" {flag=1; next} /^## \[/ && flag {exit} flag {print}' CHANGELOG.md > release-notes.md + [ -s release-notes.md ] || echo "Release ${TAG}" > release-notes.md + + - name: 创建 Release 并上传 dist.zip(重跑幂等,同名附件自动替换) + uses: https://gitea.com/actions/gitea-release-action@v1 + with: + token: ${{ secrets.BUILD_TOKEN }} + body_path: release-notes.md + files: dist.zip diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..1d26a91 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,23 @@ +name: CI + +on: + push: + pull_request: + +jobs: + test: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: + node-version: "24" + cache: npm + - name: 安装依赖 + run: npm ci + - name: ESLint(检查模式) + run: npx eslint . + - name: 类型检查 + run: npm run typecheck + - name: 构建 + run: npm run build diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..63de34f --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,40 @@ +name: Release + +on: + push: + tags: ["v*"] + +permissions: + contents: write + +jobs: + release: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: + node-version: "24" + cache: npm + + - name: 构建并打包 dist.zip + run: | + npm ci + npm run build + cd dist && zip -qr ../dist.zip . && cd .. + ls -lh dist.zip + + - name: 提取 CHANGELOG 版本段作为 Release 描述 + env: + TAG: ${{ github.ref_name }} + run: | + VERSION="${TAG#v}" + awk -v ver="$VERSION" '$0 ~ "^## \\[" ver "\\]" {flag=1; next} /^## \[/ && flag {exit} flag {print}' CHANGELOG.md > release-notes.md + [ -s release-notes.md ] || echo "Release ${TAG}" > release-notes.md + + - name: 创建 Release 并上传 dist.zip + uses: softprops/action-gh-release@v3 + with: + token: ${{ github.token }} + body_path: release-notes.md + files: dist.zip diff --git a/.trellis/.version b/.trellis/.version new file mode 100644 index 0000000..e0ea44c --- /dev/null +++ b/.trellis/.version @@ -0,0 +1 @@ +0.6.5 \ No newline at end of file diff --git a/.trellis/spec/frontend/api-and-state.md b/.trellis/spec/frontend/api-and-state.md new file mode 100644 index 0000000..50a090d --- /dev/null +++ b/.trellis/spec/frontend/api-and-state.md @@ -0,0 +1,5 @@ +# API 层与状态管理规范 + +- 所有请求经统一 request 封装(`src/api/request`):注入 JWT、401 统一跳登录、错误统一提示;组件内不直接 `fetch`/裸 axios。 +- 跨页面共享状态才进 Pinia;页面内状态用 `ref`/`computed` 就地管理,不把一切塞 store。 +- 请求函数返回类型化数据(`Promise`),错误向上抛由封装层兜底,不在每个调用点重复 try/catch。 diff --git a/.trellis/spec/frontend/component-guidelines.md b/.trellis/spec/frontend/component-guidelines.md new file mode 100644 index 0000000..6836c3f --- /dev/null +++ b/.trellis/spec/frontend/component-guidelines.md @@ -0,0 +1,59 @@ +# Component Guidelines + +> How components are built in this project. + +--- + +## Overview + + + +(To be filled by the team) + +--- + +## Component Structure + + + +(To be filled by the team) + +--- + +## Props Conventions + + + +(To be filled by the team) + +--- + +## Styling Patterns + + + +(To be filled by the team) + +--- + +## Accessibility + + + +(To be filled by the team) + +--- + +## Common Mistakes + + + +(To be filled by the team) diff --git a/.trellis/spec/frontend/directory-structure.md b/.trellis/spec/frontend/directory-structure.md new file mode 100644 index 0000000..4d90360 --- /dev/null +++ b/.trellis/spec/frontend/directory-structure.md @@ -0,0 +1,36 @@ +# 前端目录结构 + +> Vue 3 前端工程的目录职责与命名约定。 + +## 目录职责 + +```text +oci-portal-dash/ +├── package.json 脚本 dev / build / typecheck / lint / format +├── vite.config.ts @ 别名指向 src/;dev 代理 /api → localhost:8080 +├── .env.development VITE_MOCK=1,开发默认走内置 mock 数据 +├── index.html +└── src/ + ├── main.ts 应用入口,挂 Pinia 与 router + ├── App.vue NConfigProvider 注入 Naive 主题 + ├── assets/ main.css:Tailwind @theme 设计 token(浅色)+ html.dark 暗色变量覆盖与全局基础样式 + ├── theme/ tokens.ts(JS 侧 token 唯一来源,含 darkTokens 暗色板)、naive.ts(亮暗两套 themeOverrides 同一工厂生成) + ├── types/ api.ts:与 docs/API接口文档.md 一一对应的 DTO 类型 + ├── api/ request 封装(JWT 注入、401 跳登录、错误 hint 拼接)+ 按资源分模块;VITE_MOCK=1 时返回 mock.ts 数据 + ├── stores/ Pinia:auth(令牌持久化)、app(侧栏收缩、暗色主题:默认跟随系统 + localStorage 记忆,驱动 html.dark 与 Naive darkTheme)、scope(全局作用域:租户/区域/区间,localStorage 按租户记忆) + ├── router/ 路由与登录守卫 + ├── composables/ useAsync(异步状态)、useFormat(时间/字节/OCID 格式化)、useRegionAlias(区域友好名)、useTransientPoll(过渡态自动轮询:实例电源 / 挂载操作后每 5 秒刷新至稳态) + ├── components/ StatusBadge、OcidText、CostChart 等复用组件;表单基座 FormModal / FormField(hint 问号 tooltip + error / feedback 下置提示)/ FormSection(分组标题)/ FilePicker(含 compact 单行态)/ AppInputNumber(数字框统一封装:右侧垂直上下箭头步进);tenant/ 下为租户详情各 tab 与失联占位 DeadPlaceholder(失联时整体替换 tab 内容),storage/ 下为引导卷编辑 / 挂载弹窗,task/ 下含 CronEditor 可视化编辑器与任务表单(tab 分类型),instance/ 下含 InstanceSpecForm(实例规格表单,创建实例弹窗与抢机任务共用),logs/ 下为日志页各 tab 面板(SystemLogPanel 系统日志、LogEventPanel 回传日志) + ├── layouts/ AppLayout(顶栏 + 内容区,顶栏右侧为全局作用域租户 / 区域选择器)、SidebarNav(分组导航、收缩态) + └── views/ 页面:登录、总览、租户列表/详情、实例列表/详情、网络、VCN 详情、引导卷列表(编辑 / 挂载 / 删除以弹窗内联完成,无单独详情页)、任务、日志(tab 结构:「系统日志」操作留痕,预留回传日志)、设置(tab 结构:「通知」通知管理 + Telegram 配置,「任务」抢机熔断阈值)等 +``` + +## 全局作用域约定 + +租户 / 区域在顶栏右上角全局选择,区间在各资源列表页内选择,三者经 scope store 全站共享——实例 / 网络 / 引导卷页跟随同一作用域查询单租户数据,切页无需重选;选择按租户记忆在 localStorage,未开启多区域 / 多区间支持的租户对应选择器禁用锁定默认值。租户导入 / 修改 / 删除 / 测活、订阅新区域成功后经 `scope.refreshConfigs()` 即时刷新全局选择器,无需刷新页面。 + +## 命名约定 + +- `src/` 下按职责分层:`views/`(页面)、`components/`(复用组件)、`composables/`、`api/`(接口封装)、`stores/`(Pinia)、`types/`、`assets/`。 +- 组件文件 PascalCase(`TaskLogDrawer.vue`),composable/工具文件 camelCase,路由路径 kebab-case。 +- `api/` 模块按后端资源划分(`instances.ts`、`tasks.ts`…),函数名与接口语义对应,不散调 axios。 diff --git a/.trellis/spec/frontend/hook-guidelines.md b/.trellis/spec/frontend/hook-guidelines.md new file mode 100644 index 0000000..60c6bb6 --- /dev/null +++ b/.trellis/spec/frontend/hook-guidelines.md @@ -0,0 +1,51 @@ +# Hook Guidelines + +> How hooks are used in this project. + +--- + +## Overview + + + +(To be filled by the team) + +--- + +## Custom Hook Patterns + + + +(To be filled by the team) + +--- + +## Data Fetching + + + +(To be filled by the team) + +--- + +## Naming Conventions + + + +(To be filled by the team) + +--- + +## Common Mistakes + + + +(To be filled by the team) diff --git a/.trellis/spec/frontend/index.md b/.trellis/spec/frontend/index.md new file mode 100644 index 0000000..93ed69c --- /dev/null +++ b/.trellis/spec/frontend/index.md @@ -0,0 +1,44 @@ +# Frontend Development Guidelines(oci-portal-dash 前端规范) + +> Vue 3 前端(`oci-portal-dash/`)编码规范入口。 + +--- + +## 技术栈约束 + +Vue 3 + Vite + TypeScript + Naive UI + Tailwind CSS v4 + ECharts + Pinia。Naive UI 承担组件视觉(`themeOverrides`),Tailwind 只承载设计 token 与布局工具类。 + +--- + +## Guidelines Index + +| Guide | 内容 | +|-------|------| +| [Directory Structure](./directory-structure.md) | src 分层、文件命名与全局作用域约定 | +| [TypeScript & Vue](./typescript-vue.md) | TS 严格模式与组件写法 | +| [Styling & Design Tokens](./styling-design-tokens.md) | Anthropic 风设计 token、字体与反模式清单 | +| [API & State](./api-and-state.md) | 请求封装与 Pinia 使用边界 | + +--- + +## Pre-Development Checklist + +写代码前确认: + +- [ ] 读过 [Directory Structure](./directory-structure.md),文件放对层(views / components / composables / api / stores / types) +- [ ] 涉及颜色、圆角、间距时先看 [Styling & Design Tokens](./styling-design-tokens.md),禁止硬编码 hex +- [ ] 新增请求走 `api/` 统一封装,DTO 类型进 `types/`(与 `docs/API接口文档.md` 一一对应) +- [ ] 出 UI 设计稿前读 `../guides/design-workflow.md` + +## Quality Check + +提交前必过: + +```bash +npm run lint # ESLint(flat config,含 eslint-plugin-vue recommended)+ Prettier +npm run typecheck # vue-tsc --noEmit +npm run build # 类型检查 + 产物构建 +``` + +- 提交信息沿用项目规范(中文、≤50 字),不采用 Conventional Commits。 +- 依赖变更后 `package.json` 与 lockfile 一起提交;不提交 `node_modules`、构建产物。 diff --git a/.trellis/spec/frontend/quality-guidelines.md b/.trellis/spec/frontend/quality-guidelines.md new file mode 100644 index 0000000..05a1411 --- /dev/null +++ b/.trellis/spec/frontend/quality-guidelines.md @@ -0,0 +1,51 @@ +# Quality Guidelines + +> Code quality standards for frontend development. + +--- + +## Overview + + + +(To be filled by the team) + +--- + +## Forbidden Patterns + + + +(To be filled by the team) + +--- + +## Required Patterns + + + +(To be filled by the team) + +--- + +## Testing Requirements + + + +(To be filled by the team) + +--- + +## Code Review Checklist + + + +(To be filled by the team) diff --git a/.trellis/spec/frontend/state-management.md b/.trellis/spec/frontend/state-management.md new file mode 100644 index 0000000..b4fc966 --- /dev/null +++ b/.trellis/spec/frontend/state-management.md @@ -0,0 +1,51 @@ +# State Management + +> How state is managed in this project. + +--- + +## Overview + + + +(To be filled by the team) + +--- + +## State Categories + + + +(To be filled by the team) + +--- + +## When to Use Global State + + + +(To be filled by the team) + +--- + +## Server State + + + +(To be filled by the team) + +--- + +## Common Mistakes + + + +(To be filled by the team) diff --git a/.trellis/spec/frontend/styling-design-tokens.md b/.trellis/spec/frontend/styling-design-tokens.md new file mode 100644 index 0000000..48c49cc --- /dev/null +++ b/.trellis/spec/frontend/styling-design-tokens.md @@ -0,0 +1,111 @@ +# 样式与设计 Token 规范 + +> Anthropic 风(warm editorial)设计体系:色板、字体、圆角与反模式清单。代码事实源:`src/theme/tokens.ts`(JS 侧唯一来源)与 `src/assets/main.css`(Tailwind `@theme`)。 + +## 基本规则 + +- 设计 token(色板、圆角、字体、间距)唯一来源是全局 CSS 变量(Tailwind `@theme`),Naive UI `themeOverrides` 从同一份取值;组件内禁止散落硬编码 hex。 +- Tailwind 工具类只用于布局、间距、排版;组件视觉(按钮/输入/表格)交给组件库主题,不用工具类二次描皮。 +- 间距遵循 4px 网格;圆角、阴影、配色遵守下方 token 与反模式清单。 + +## 风格特征 + +- **暖纸色底**:不用纯白,用象牙色 `#FAF9F5` 做主背景,靠 1px 细边框(hairline)和一层灰度差分层,几乎不用投影。 +- **单一强调色**:赤陶橙(terracotta)只出现在主按钮、激活态、品牌标记上,页面 95% 面积是黑白灰米。 +- **小圆角、扁平**:圆角 4–6px 量级;无渐变、无玻璃拟态、无 3D 浮雕、无大面积色块光晕。 +- **排版即装饰**:层级靠字号/字重/留白拉开;图标用细线性风格(lucide/tabler),不用 emoji 和彩色立体图标。 +- **克制的动效**:过渡 150–250ms、只做透明度/位移,无弹跳和视差。 + +## 官方色值(Anthropic 官方 brand-guidelines) + +主色: + +| Token | 色值 | 用途 | +| --- | --- | --- | +| Dark | `#141413` | 主文本、深色背景 | +| Light | `#FAF9F5` | 浅色背景、深底上的文本 | +| Mid Gray | `#B0AEA5` | 次要元素、占位、禁用 | +| Light Gray | `#E8E6DC` | 细微背景、分隔线、边框 | + +强调色: + +| Token | 色值 | 用途 | +| --- | --- | --- | +| Orange | `#D97757` | 主强调(按钮、激活、链接 hover) | +| Blue | `#6A9BCC` | 次强调(信息、链接) | +| Green | `#788C5D` | 三级强调(成功) | + +品牌橙近似变体(社区考证):`#C15F3C`(Crail,更深)与 `#CC785C`(Book Cloth),可用作橙色的 hover/active 深档。 + +## 管理面板适配 token + +官方色板缺管理面板必需的语义色,按同色温补齐: + +| 语义 | 建议值 | 说明 | +| --- | --- | --- | +| 背景主 | `#FAF9F5` | 页面底 | +| 背景面 | `#F0EEE6` | 侧栏、区块底(Light 与 Light Gray 之间) | +| 卡片 | `#FFFFFF` | 白卡浮在暖底上,配 1px `#E8E6DC` 边框 | +| 文本主/次 | `#141413` / `#6B6A63` | 次级文本由 Dark 与 Mid Gray 插值 | +| 主强调 | `#D97757`,hover `#C15F3C` | | +| 成功 / 信息 | `#788C5D` / `#6A9BCC` | 官方绿 / 蓝 | +| 警告 | `#B8860B` 一档的暖赭 | 与暖色调和谐,避免高饱和黄 | +| 危险 | `#BF4D43` 一档的砖红 | 避免纯红 `#FF0000` 系 | +| 暗色模式 | 底 `#141413`、面 `#1F1E1D`、边框 `#33322E` | 文本反转用 Light | +| 圆角 | 按钮/输入 4px,卡片 6px,最大不超过 8px | 拒绝大圆角 | +| 阴影 | 无或 `0 1px 2px rgba(20,20,19,.05)` | 分层靠边框 | + +## 字体 + +- 官方品牌字体 **Styrene**(无衬线)+ **Tiempos**(衬线)为商业授权,不可直接使用;官方开源替代:标题 **Poppins**、正文 **Lora**。 +- 本项目:UI 与数据全用无衬线(`Inter` 或 `Poppins`,中文回退 `PingFang SC` / `Noto Sans SC`);OCID、IP、日志等用等宽(`JetBrains Mono` / `ui-monospace`);衬线(Lora)只做登录页/大标题的编辑风点缀,可选。 + +## 反模式清单(设计稿与代码评审逐条对照) + +大圆角(>8px 的按钮/卡片)、任何渐变(含品牌色渐变文字)、玻璃拟态/毛玻璃、霓虹光晕、彩色大投影、emoji 当图标、深紫深蓝"AI 感"配色、满屏色块卡片、弹跳动效。 + +## Common Mistake: NModal 宽度不能用 Tailwind class + +**Symptom**:`` 弹窗实际渲染为全宽。 + +**Cause**:naive-ui 的样式为运行时注入(CSSinJS,`