初始化
This commit is contained in:
@@ -0,0 +1,12 @@
|
||||
---
|
||||
description: 用户要求 git commit、提交代码、写 commit message 或创建提交时,必须先加载 commit-convention skill 并严格遵守
|
||||
alwaysApply: false
|
||||
---
|
||||
|
||||
# Git 提交规范自动激活
|
||||
|
||||
当用户要求**提交代码**、**git commit**、**写提交说明**或执行提交流程时:
|
||||
|
||||
1. 必须先加载 `.cursor/skills/commit-convention/SKILL.md`。
|
||||
2. subject **必须**以 `[Ai]` 或 `[Human]` 开头:Agent 编写的变更用 `[Ai]`,用户手写且仅代提交用 `[Human]`;提交前须结合 diff 与对话上下文判定,并写清业务变更,禁止敷衍 subject。
|
||||
3. 未获用户明确授权不得 commit;不得提交 `.env` 等含密钥文件;默认不 push。
|
||||
@@ -0,0 +1,21 @@
|
||||
---
|
||||
description: 在改动 Vue/hook/service/store/views/components 时,自动加载 frontend-project-standards skill 并按其规范输出
|
||||
globs: src/**/*.vue,src/views/**/*.ts,src/hooks/**/*.ts,src/service/**/*.ts,src/stores/**/*.ts,src/components/**/*.{vue,ts}
|
||||
alwaysApply: false
|
||||
---
|
||||
|
||||
# 前端规范自动激活
|
||||
|
||||
本仓库改动 Vue / hooks / service / store / views / components 范围的代码时:
|
||||
|
||||
1. 必须先加载 `.cursor/skills/frontend-project-standards/SKILL.md`,并严格遵守其中的"强制规则"。
|
||||
2. 命名细则参考 `.cursor/skills/frontend-project-standards/naming-conventions.md`。
|
||||
3. 代码模板参考 `.cursor/skills/frontend-project-standards/reference.md`。
|
||||
4. 用户使用 `@fps:new` / `@fps:refactor` / `@fps:api` / `@fps:fix` / `@fps:review` / `@fps:hook` 时,按 `prompt-templates.md` 对应模板执行。
|
||||
5. 输出必须包含:分层说明、hooks 变更、API 变更与类型、错误覆盖、维护性收益、PR 自检结果。
|
||||
|
||||
不得绕过 `src/utils/request.ts` 直接 axios,不得在 `.vue` / hook 中直接发请求,不得在新增代码中引入宽泛 `any`。
|
||||
|
||||
**禁止过度设计**:默认走最小可行实现,命中 `SKILL.md` 的 `### 0.1) 反过度设计` 任一信号即必须回退方案;任何抽象/拆分动作都需要在输出里说明对应的复用或复杂度信号。
|
||||
|
||||
**完工必须做闭环校验**:按 `SKILL.md` 的 `## 完工闭环校验` 执行,**只校验本次改动文件**,不扫全仓、不修历史问题。最终输出附"闭环校验结果"区块(已校验文件清单 + 5 类校验项 + 未通过项的文件:行号)。Agent 必须对改动文件调用 `ReadLints` 确认 0 新增报错。
|
||||
@@ -0,0 +1,124 @@
|
||||
---
|
||||
name: commit-convention
|
||||
description: 为本仓库生成符合团队规范的 Git 提交信息,并在用户要求提交代码时执行完整提交流程。用于 git commit、提交代码、写 commit message、创建提交、push 前整理提交等场景;须根据变更来源选用 [Ai] 或 [Human] 标记并写清业务变更。
|
||||
---
|
||||
|
||||
# Git 提交规范(Agent 协助提交)
|
||||
|
||||
## 触发条件
|
||||
|
||||
满足任一条件,**必须先加载本 skill**,再执行 `git add` / `git commit`:
|
||||
|
||||
- 用户明确要求:提交、commit、git commit、保存提交、push 前先 commit 等
|
||||
- 用户规则中的「committing-changes-with-git」流程已启动
|
||||
|
||||
**未获用户明确授权时,不得执行 commit。**
|
||||
|
||||
---
|
||||
|
||||
## 提交来源标记(强制)
|
||||
|
||||
所有由 Agent 代为执行的 `git commit`,subject **必须**以 `[Ai]` 或 `[Human]` 开头(二选一,不得省略)。
|
||||
|
||||
```text
|
||||
[Ai] <type>(<scope>): <subject>
|
||||
[Human] <type>(<scope>): <subject>
|
||||
|
||||
<body 可选:业务背景、影响范围、关联 Bug>
|
||||
```
|
||||
|
||||
- `type`:`feat` | `fix` | `refactor` | `style` | `perf` | `chore` | `docs` | `test` | `build` | `ci`
|
||||
- `scope`:模块/页面,如 `benefits`、`mine`、`community`、`player`
|
||||
- 仅当标记为 `[Ai]` 时,可在正文末尾追加 trailer(可选):
|
||||
|
||||
```text
|
||||
Co-Authored-By: Cursor <noreply@cursor.com>
|
||||
```
|
||||
|
||||
### 如何判定用 `[Ai]` 还是 `[Human]`
|
||||
|
||||
在撰写 message **之前**,结合 `git diff` 与**当前对话上下文**判断本次待提交变更的**主要作者**:
|
||||
|
||||
| 标记 | 适用场景 |
|
||||
|------|----------|
|
||||
| **`[Ai]`** | 本次待提交 diff 中的逻辑/样式/配置变更,**主要由当前或近期 Agent 会话编写或修改**;或用户未说明来源且 diff 与对话中 Agent 已完成的实现一致 |
|
||||
| **`[Human]`** | 变更**主要由用户本人编写**(用户仅让 Agent 代写 commit message、执行 add/commit);或用户明确说「人工提交」「我自己改的」「帮我提交一下(我改的)」等 |
|
||||
|
||||
**判定步骤(按序执行):**
|
||||
|
||||
1. 用户是否**明确**要求 `[Human]` / 人工提交?→ 是则用 `[Human]`(除非 diff 明显全是 Agent 刚写的,此时先向用户确认)
|
||||
2. 当前对话里,Agent 是否**为实现用户需求**而修改了待提交文件?→ 是则用 `[Ai]`
|
||||
3. 待提交文件是否**未出现在**本对话的 Agent 编辑记录中,且用户只是要求「提交一下」?→ 用 `[Human]`
|
||||
4. **同一批 staged 变更**中既有 Agent 编写又有用户手写:优先**询问是否拆分**为两次提交;若用户坚持一次提交,以**改动行数/核心逻辑**更多的一方为准,并在 body 中简要说明混合来源
|
||||
5. **无法判断**时:默认 `[Ai]`,并在执行 commit 前**用一句话向用户说明**所选标记及理由;若用户纠正,改用 `[Human]` 后重新 commit(hook 失败则新建 commit,勿 amend 除非符合 user rule)
|
||||
|
||||
**禁止:**
|
||||
|
||||
- 用户明确是人工改动时,仍标 `[Ai]`
|
||||
- 用户未授权时,将 Agent 刚写完的代码标 `[Human]`
|
||||
|
||||
---
|
||||
|
||||
## Subject 质量(强制)
|
||||
|
||||
提交说明必须让人一眼看懂**改了什么业务**或**修了什么问题**。
|
||||
|
||||
### 必须做到
|
||||
|
||||
1. 先并行执行:`git status`、`git diff`(含 staged)、`git log -5 --oneline` 了解风格与变更范围
|
||||
2. **完成上一节来源判定**,选定 `[Ai]` 或 `[Human]`
|
||||
3. subject 用**完整语义**描述,优先中文;可中英混用 scope
|
||||
4. 多文件、多模块时:一条 commit 只包同一业务目标;若混杂无关改动,先询问是否拆分
|
||||
5. body 写:原因、用户可见变化、风险点(如有);混合来源时在 body 注明
|
||||
|
||||
### 严禁(subject 不得仅为或等同于)
|
||||
|
||||
`test`、`修改`、`update`、`fix`、`xxx`、`111`、`wip`、`temp`、`提交`、`save`、纯标点、纯数字、单字
|
||||
|
||||
### 示例
|
||||
|
||||
```text
|
||||
# ✅ Agent 实现的功能
|
||||
[Ai] feat(benefits): 新增七日签到弹窗与连续签到奖励展示
|
||||
[Ai] fix(player): 修复横屏切换后 HLS 首帧黑屏
|
||||
|
||||
# ✅ 用户手写,Agent 仅代提交
|
||||
[Human] style(home): 调整首页 Header 搜索框间距与图标尺寸
|
||||
[Human] fix(lazyImg): 修复弱网下占位图闪烁
|
||||
|
||||
# ❌
|
||||
feat(benefits): 新增签到弹窗 # 缺少来源标记
|
||||
[Ai] fix: 修改
|
||||
修改播放器
|
||||
111
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 提交流程(与 user rule 对齐)
|
||||
|
||||
1. `git status` + `git diff` + `git log`(可并行)
|
||||
2. **判定** `[Ai]` / `[Human]`(见上表)
|
||||
3. 根据 diff **撰写**符合本规范的 message(HEREDOC 传 `-m`)
|
||||
4. 只 `git add` 与本次任务相关的文件
|
||||
5. **不得**提交 `.env`、密钥、凭据类文件;若用户在 staged 中含此类文件,警告并排除
|
||||
6. `git commit` 后 `git status` 确认成功
|
||||
7. hook 失败时:**不要** `commit --amend`,修 message 后**新建 commit**
|
||||
8. **除非用户明确要求,否则不 `git push`**
|
||||
|
||||
---
|
||||
|
||||
## 输出给用户
|
||||
|
||||
提交完成后简要说明:
|
||||
|
||||
- **来源标记**:`[Ai]` 或 `[Human]`,以及一行判定理由
|
||||
- commit hash(若有)
|
||||
- 本次纳入的文件范围
|
||||
- message 摘要(一行)
|
||||
|
||||
---
|
||||
|
||||
## 与本地 Hook / CI 的关系
|
||||
|
||||
本 skill 约束 **Agent 行为**。若仓库后续接入 `husky` + `commitlint` 或 CI,以仓库脚本校验为准;Agent 仍须预先满足 `[Ai]`/`[Human]` 与 subject 质量,避免 hook 拒绝。
|
||||
@@ -0,0 +1,258 @@
|
||||
---
|
||||
name: frontend-project-standards
|
||||
description: 为当前仓库输出可维护的 Vue3 + TypeScript 前端代码规范,覆盖组件分层、hooks 抽离、service 接口封装、错误处理与命名规范。用于新功能开发、页面重构、接口改造、复杂逻辑拆分与可维护性治理场景。
|
||||
---
|
||||
|
||||
# 前端项目规范
|
||||
|
||||
## 适用范围
|
||||
本规范适用于以下所有变更:
|
||||
- `src/views/**`:路由级页面容器及其私有 `components/`、`hooks/`。
|
||||
- `src/components/**`:跨模块复用组件,以及形如 `src/components/<module>/{components,hooks,types.ts,index.vue}` 的"组件即模块"容器(参考 `src/components/HomeHeader/`)。
|
||||
- `src/hooks/**`:全局/通用 composable。
|
||||
- `src/service/**`:接口封装层。
|
||||
- `src/stores/**`:Pinia store。
|
||||
- `src/utils/**`:纯工具函数(无状态、非 Vue 特定)。
|
||||
|
||||
需遵循的项目上下文:
|
||||
- 技术栈:Vue 3 + TypeScript + Vite + Pinia + Vant。
|
||||
- 请求链路:`src/service/*.ts` -> `src/utils/request.ts` -> axios。`request` 实例除标准 `get/post/put/delete` 外还提供 `deletes`(form 形式 DELETE),不要新增同义包装。
|
||||
- 路径别名:从 `src` 导入时统一使用 `@/`。
|
||||
|
||||
## 触发条件
|
||||
满足任一条件,必须先加载并按本规范输出:
|
||||
- 用户消息中出现:前端规范、规范、可维护性、重构、refactor、抽 hook、抽 composable、接口封装、service、错误处理、loading/error/empty、拆分大文件、整改、治理、frontend-project-standards、@fps、/fps。
|
||||
- 改动范围涉及 `*.vue`、`src/hooks/**`、`src/service/**`、`src/components/**`、`src/views/**`、`src/stores/**`,且包含结构、接口、状态、交互或业务逻辑调整。
|
||||
- 用户提供 PRD/Figma/截图要求"按本仓库结构落地"。
|
||||
- PR 自检、code review、规范审查类任务。
|
||||
|
||||
轻量豁免:仅改文案、样式数值、静态资源路径、纯 class 调整时,可只做最小变更并说明“不涉及分层/API/hook 调整”,无需强行套完整交付结构。
|
||||
|
||||
## 快捷指令
|
||||
团队可直接在对话中使用以下短指令触发对应工作流,每条都映射到 `prompt-templates.md` 的具体模板:
|
||||
|
||||
| 指令 | 含义 | 对应模板 |
|
||||
| --- | --- | --- |
|
||||
| `@fps:new <页面/模块>` | 新页面或新模块开发(container + hooks + service 全套分层) | 模板 1 |
|
||||
| `@fps:refactor <文件路径>` | 拆分大文件 / 抽 hook / 行为不变重构 | 模板 2 |
|
||||
| `@fps:api <接口描述> -> <页面>` | 新增接口并接入页面(service typed 方法 + hook + view 三步) | 模板 3 |
|
||||
| `@fps:fix <问题描述>` | 修 bug 同时做最小必要规范化 | 模板 4 |
|
||||
| `@fps:review <文件/diff>` | 仅做规范审查,不大改代码 | 模板 5 |
|
||||
| `@fps:hook <逻辑描述>` | 仅产出单一职责 hook(state/computed/actions) | 模板 1 子集 |
|
||||
|
||||
调用约定:
|
||||
- 任何指令默认带上"输出分层说明 + hooks 变更 + API 变更 + 错误覆盖 + 自检结果"五项交付。
|
||||
- 指令后可追加自由描述,越具体越好(目标文件、行为约束、是否允许重命名等)。
|
||||
- 不带任何指令时,按 `## 触发条件` 自动判定是否启用本规范。
|
||||
- 若某项交付不涉及,简短标注“不涉及”,不要为了满足格式新增无意义文件或抽象。
|
||||
|
||||
## 强制规则(必须遵守)
|
||||
|
||||
### 0) 通用工程准则(最高优先级)
|
||||
- 可维护性 > 短期省事;规则冲突时按 类型安全 > 分层正确性 > 局部简洁性 排序。
|
||||
- **不引入新依赖**:除非用户明确要求,否则不增加 npm/yarn 依赖、不替换现有库(axios/Pinia/Vant 不替换)。
|
||||
- **对齐项目结构**:所有新文件必须落入"适用范围"描述的目录形态,不另起新目录约定。
|
||||
- **优先复用既有逻辑**:动手前先在 `src/hooks`、`src/utils`、`src/service`、`src/stores` 检索可复用项;找到 ≥70% 匹配即扩展或参数化,不重复造轮。
|
||||
- **避免过度设计**:见 `### 0.1)`。
|
||||
- 历史代码受限暂时无法满足规则时,必须明确说明约束并给出分阶段改造计划。
|
||||
|
||||
### 0.1) 反过度设计(硬规则)
|
||||
**默认顺序:先写最小可行实现(MVP),出现下方"复用/复杂度信号"再抽象。**
|
||||
|
||||
判定信号(命中任一即"过度",必须回退到更简方案):
|
||||
- 仅以“未来可能复用”为理由,为只有 1 个调用方的逻辑创建 hook / 工具 / 组件;至少出现 2 处调用、明确跨页面复用价值,或命中本规范的复杂度/职责边界阈值时再抽。
|
||||
- 为只有一种实参的"泛型/策略/工厂"提前预留扩展点(如未被使用的泛型参数、单实现的 strategy map)。
|
||||
- 引入空壳 wrapper:组件 / 函数 / 类除转发外不做事(可直接使用被包装对象)。
|
||||
- 配置爆炸:用 5+ 个布尔/枚举 props 控制一个组件多种形态,应拆为多个组件。
|
||||
- 未使用的导出:新增 export 在本次改动范围内无人调用。
|
||||
- 为不存在的需求设计接口字段、状态分支、loading 子态。
|
||||
- 自造已被现有依赖覆盖的能力(已用 Vant/Pinia/axios 拦截器/`@/utils/request` 时不再造轮)。
|
||||
- 抽象层数 ≥ 3(view -> hook -> hook -> service)且中间层无独立职责。
|
||||
- 单文件代码量小于 80 行却被拆成 3 个文件(除非命名/职责必要)。
|
||||
- 单一页面被拆成大量细碎展示组件,组件之间只是传递原样 props/slot,无法形成清晰职责边界。
|
||||
|
||||
输出要求:
|
||||
- 涉及"是否抽象/拆分/泛化"的决策点,必须显式给一句话理由(命中哪条复用信号或复杂度阈值)。
|
||||
- 找不到理由时,默认走"内联实现 / 单文件 / 字面量参数"的最简路径。
|
||||
- 抽象阈值另见 `### 2) hooks 抽离` 中的硬性拆分触发条件,二者取严。
|
||||
- 页面私有 hook 因复杂副作用或业务域拆分而创建时,不要求跨页面复用;但必须具备独立职责,不能只是移动代码。
|
||||
|
||||
### 1) 组件分层
|
||||
- `src/views/**/index.vue` 作为页面容器,负责路由参数、hooks 组装、子组件编排。
|
||||
- 页面私有组件放在 `src/views/**/components/`。
|
||||
- 跨模块复用组件放在 `src/components/`。
|
||||
- 展示组件禁止直接调接口,避免承载重业务副作用。
|
||||
- 模板相关逻辑留在组件内,复杂业务分支和副作用迁移到 hooks。
|
||||
- 不为了“看起来分层”把一个页面拆成很多小组件。只有满足以下任一条件才拆组件:
|
||||
- 该 UI 区块会复用,或未来已有明确复用场景;
|
||||
- 区块模板/交互复杂,独立后能显著降低容器理解成本;
|
||||
- 区块拥有清晰业务语义边界(如用户面板、订单卡片、筛选栏),而不是纯布局切片。
|
||||
- 仅用于排版、单次使用且逻辑简单的片段,优先留在当前组件内。
|
||||
|
||||
### 2) hooks 抽离
|
||||
- 满足任一条件必须抽离 hook:
|
||||
- 同文件存在多个副作用块(`watch`、`watchEffect`、生命周期);
|
||||
- 一个大 `setup` 中混合了业务状态和 UI 状态;
|
||||
- 逻辑具备跨页面复用价值。
|
||||
- hook 命名统一为 `useXxx.ts`。
|
||||
- 放置规则:
|
||||
- 全局/通用逻辑 -> `src/hooks/`;
|
||||
- 模块专属逻辑 -> `src/views/<module>/hooks/`。
|
||||
- hook 输出保持最小且清晰:`state`、`computed`、`actions`。
|
||||
- 页面私有 hook 的价值来自“隔离副作用/业务域”,不来自文件数量;单纯把几行状态搬出去不算合格抽离。
|
||||
- hook 内必须清理定时器、监听器、订阅等资源。
|
||||
- 大文件硬性拆分触发条件(满足任一即拆):
|
||||
- 非样式代码超过 350 行;
|
||||
- 单文件含 4 个及以上 `watch/watchEffect/生命周期` 块;
|
||||
- 单文件混合 3 个及以上业务域(如分页 + 权限 + 埋点)。
|
||||
- `src/views/**/utils/` 下的重业务文件优先迁移到 `src/views/**/hooks/`,工具函数保持纯函数化。
|
||||
|
||||
### 3) 接口封装
|
||||
- 禁止在 `.vue` 或 hooks 中直接调用 `axios`/`fetch`。
|
||||
- 接口新增或调整统一在 `src/service/*.ts` 中用 class static 方法实现,并保持项目现有风格。
|
||||
- 统一复用 `src/utils/request.ts` 的 `request.get/post/put/delete`。
|
||||
- 新增/修改的接口方法必须有入参和返回值类型(避免新增 `any`)。
|
||||
- URL 路径和参数组装留在 service 层,不放到视图/组件层。
|
||||
- 历史代码若仍有 `any`,本次改动不得继续扩散;应在改动范围内增量替换为明确类型。
|
||||
|
||||
### 4) 错误处理
|
||||
- 网络层与 HTTP 状态码处理继续由 `src/utils/request.ts` 统一兜底。
|
||||
- 业务异步动作仍需本地容错:
|
||||
- `loading` 开关必须成对出现(`finally` 或等价方案);
|
||||
- 失败时必须设置可预期兜底状态(`error`、空态、安全默认值);
|
||||
- 仅在需要用户动作引导时显示用户提示。
|
||||
- 禁止吞错(`catch {}`)以及仅 `console` 不落状态。
|
||||
- 需要继续抛错时,必须保留明确原因与必要上下文。
|
||||
- 异步后会变更 UI 状态的动作,必须覆盖失败分支并防止状态不一致。
|
||||
|
||||
### 5) 类型纪律
|
||||
- view/hook/service 中禁止新增宽泛 `any`。
|
||||
- service 边界优先使用显式 `interface/type`。
|
||||
- 无法确认类型时优先 `unknown`,使用前做类型收窄。
|
||||
- 路由参数标准化要显式处理(例如 `String(route.query.id || '')`)。
|
||||
|
||||
### 6) 命名规范(对齐主流最佳实践)
|
||||
- 目录名统一 `kebab-case`(如 `user-profile`)。
|
||||
- 非组件文件统一 `kebab-case`(如 `media-content.ts`、`use-xxx` 不使用,hook 文件仍保持 `useXxx.ts`)。
|
||||
- Vue 组件文件名使用 `PascalCase.vue`(如 `UserProfileCard.vue`);页面入口保持 `index.vue`。
|
||||
- class、type、interface、enum 名称使用 `PascalCase`。
|
||||
- 变量、函数、方法使用 `camelCase`;常量使用 `UPPER_SNAKE_CASE`。
|
||||
- 布尔变量必须带语义前缀:`is/has/can/should`(如 `isLoading`、`hasPaid`)。
|
||||
- 事件处理函数统一 `handleXxx`;计算属性使用业务语义命名,不使用无意义缩写。
|
||||
- 禁止拼音、无语义缩写、单字符命名(循环计数器 `i/j` 除外)。
|
||||
|
||||
### 7) 历史命名兼容策略(增量治理)
|
||||
- 历史文件允许保留旧命名,不强制一次性全量重命名。
|
||||
- 任何新增文件、新增目录、以及被修改代码中的新增符号,必须遵循最新命名规范。
|
||||
- 若本次改动涉及重命名风险较高区域,可采用“行为不变优先”的分阶段治理:本次先保证增量合规,后续单独提交命名清理任务。
|
||||
- 禁止在新代码中复制旧命名反模式(即使同文件已有旧风格)。
|
||||
|
||||
## 交付输出要求
|
||||
完成编码任务时,输出中必须包含:
|
||||
1. 分层说明:哪些留在 view/container,哪些在 component/hook/service。
|
||||
2. hooks 变更:新增或调整了哪些 hook、各自单一职责是什么。
|
||||
3. 接口变更:新增/修改的 service 方法及其类型定义。
|
||||
4. 错误覆盖:哪些异步路径已补齐失败兜底与状态恢复。
|
||||
5. 维护性收益:如何降低耦合,便于后续功能扩展。
|
||||
6. 自检结果:`reference.md` 中检查项的通过情况。
|
||||
7. **闭环校验结果**:按 `## 完工闭环校验` 给出逐项通过/未通过,未通过需附文件/行号。
|
||||
|
||||
若某项未发生变更,写“不涉及”即可;不要为了输出完整而新增 wrapper、空组件、空 hook 或空 service。
|
||||
|
||||
## 改造工作流
|
||||
按以下顺序执行:
|
||||
1. 识别目标文件中的职责混杂点。
|
||||
2. 必要时拆分为 container + hooks + 展示组件;组件拆分以清晰职责边界为准,不以数量为目标。
|
||||
3. 将直接请求逻辑迁移到 service 层。
|
||||
4. 在 service 边界与 hook 状态处补强类型。
|
||||
5. 补齐 loading/error/empty 等状态保护。
|
||||
6. 执行自检清单并先修复不通过项。
|
||||
7. **执行 `## 完工闭环校验`**,仅针对本次改动文件。
|
||||
8. 最终确认无本规范违规项。
|
||||
|
||||
## 完工闭环校验(仅检查本次改动)
|
||||
**强制收尾步骤**。范围严格限定在"本次新增/修改/重命名"的文件,**不扩到全仓**,不修复历史问题(除非用户明确要求)。
|
||||
|
||||
### 必执行动作(Agent)
|
||||
- 对所有改动文件调用 `ReadLints`(一次性传入改动文件路径数组),确认无新增报错。
|
||||
- 若改动了 `*.vue` 内的 `<script setup lang="ts">` 或新增 `.ts`,须在心中跑一遍 IDE 类型解析:所有 import 路径可达、命名/默认导出对齐、`@/` 别名能正确解析。
|
||||
- 若仓库已配置 `tsc --noEmit` / `vue-tsc`,仅在用户要求时执行;默认依赖 `ReadLints` 增量结果。
|
||||
|
||||
### 校验清单(逐项过)
|
||||
1. **类型与 lint 闭环**
|
||||
- [ ] `ReadLints` 对改动文件返回 0 新增报错;历史已有报错可保留并显式列出。
|
||||
2. **引入与路径闭环**
|
||||
- [ ] 新增/修改的 `import` 路径存在且大小写正确。
|
||||
- [ ] 命名导出 / 默认导出与源文件实际声明一致。
|
||||
- [ ] `@/` 别名指向正确的真实路径。
|
||||
- [ ] 仅类型用途的导入使用 `import type { ... }`。
|
||||
- [ ] 不留未使用的 `import`、ref、computed、props、emits。
|
||||
3. **类型边界闭环**
|
||||
- [ ] service 方法 params/response 类型已声明并被 hook/view 正确消费。
|
||||
- [ ] 无新增宽泛 `any`;`unknown` 已做类型收窄。
|
||||
- [ ] props / emits / defineExpose 类型完整,无隐式 any。
|
||||
- [ ] 全局类型(如 `Types.*`)引用路径与 `src/typings` 实际声明一致。
|
||||
4. **行为闭环**
|
||||
- [ ] 异步动作 loading 开关成对,error/empty 兜底到位。
|
||||
- [ ] hook 内定时器、`watch` 句柄、事件监听、订阅在 `onUnmounted` 释放。
|
||||
- [ ] 模板引用的 ref/computed 都有定义且被使用,无孤儿。
|
||||
5. **范围纪律**
|
||||
- [ ] 改动未扩散到无关文件。
|
||||
- [ ] 历史已有问题未顺手"乱改";如确需顺带修复,单独列在"附带修复"区块。
|
||||
- [ ] 输出区块内显式列出"已校验文件清单"和"未校验/不在范围"的文件。
|
||||
|
||||
### 输出格式(强制)
|
||||
完工时必须附以下区块:
|
||||
|
||||
```markdown
|
||||
### 闭环校验结果
|
||||
**已校验文件**:
|
||||
- src/xxx/yyy.vue
|
||||
- src/xxx/hooks/useZzz.ts
|
||||
- src/service/xxx.ts
|
||||
|
||||
**校验项**
|
||||
- [x] 类型与 lint 闭环(ReadLints 0 新增报错)
|
||||
- [x] 引入与路径闭环
|
||||
- [x] 类型边界闭环
|
||||
- [x] 行为闭环
|
||||
- [x] 范围纪律
|
||||
|
||||
**未通过项**(如有):
|
||||
- <文件:行号> <问题描述> <建议>
|
||||
```
|
||||
|
||||
## 反模式(禁止)
|
||||
- 超大 `setup` 同时处理路由、接口、业务规则、DOM 行为。
|
||||
- 在模板、UI 组件或临时 util 中直接发请求,绕过 service。
|
||||
- 一个 hook 混合多个无关业务域。
|
||||
- 已知结构场景下继续使用宽泛 `any`。
|
||||
- 异步失败分支未做状态回滚或兜底。
|
||||
- 对已超大文件(如 500+ 行)继续堆逻辑而不拆分。
|
||||
- 把埋点逻辑混入通用分页/权限 hook。
|
||||
- **过度设计**:单调用方就抽 hook/util/组件、未被使用的泛型与策略点、空壳 wrapper、5+ 布尔 props 的"全能组件"、未使用的 export、为不存在的需求设计字段或子态、自造已被现有依赖覆盖的能力(违反 `### 0.1)`)。
|
||||
|
||||
## PR 自检清单(必须通过)
|
||||
- [ ] `.vue` 或 hook 文件中无新增直接请求调用。
|
||||
- [ ] 新增/修改 service 方法均具备入参和返回类型。
|
||||
- [ ] 无新增宽泛 `any`。
|
||||
- [ ] 异步动作具备完整 loading/error/fallback 处理。
|
||||
- [ ] 长逻辑已按业务域拆入聚焦 hooks。
|
||||
- [ ] 新增目录/文件/符号命名符合命名规范。
|
||||
- [ ] 历史命名仅保留存量,新增/改动部分全部符合新规范。
|
||||
- [ ] **未触发 `### 0.1)` 任一过度设计信号**;如有抽象/拆分动作,已说明触发的复用或复杂度信号。
|
||||
- [ ] **完工闭环校验已执行且通过**(仅对本次改动文件,`ReadLints` 0 新增报错,import/类型/行为四类闭环全过)。
|
||||
- [ ] 输出内容包含“交付输出要求”中的全部项目。
|
||||
|
||||
## 术语对照(统一用词)
|
||||
- container:页面容器(`src/views/**/index.vue`)。
|
||||
- presentational component:展示组件(偏 UI,无接口副作用)。
|
||||
- hook/composable:可复用业务逻辑单元(`useXxx.ts`)。
|
||||
- service:接口封装层(`src/service/*.ts`)。
|
||||
- request layer:统一请求层(`src/utils/request.ts`)。
|
||||
|
||||
## 参考资料
|
||||
- 代码模板见 [reference.md](reference.md)。
|
||||
- 仓库场景示例见 [examples.md](examples.md)。
|
||||
- 团队提问模板见 [prompt-templates.md](prompt-templates.md)。
|
||||
- 命名规范详表见 [naming-conventions.md](naming-conventions.md)。
|
||||
@@ -0,0 +1,87 @@
|
||||
# 仓库场景示例
|
||||
|
||||
## 示例 A:重构大型视图工具文件
|
||||
|
||||
### 场景
|
||||
`src/views/<module>/utils/` 下某文件同时包含:
|
||||
- 路由参数解析,
|
||||
- 分页加载,
|
||||
- 权限判断,
|
||||
- 事件埋点,
|
||||
- 章节切换。
|
||||
|
||||
### 目标拆分
|
||||
- `index.vue`(容器页):路由绑定 + hooks 组装。
|
||||
- `hooks/useEpisodeList.ts`:列表分页/刷新逻辑。
|
||||
- `hooks/useEpisodeAccess.ts`:权限校验与付费弹窗逻辑。
|
||||
- `hooks/useReadEvents.ts`:阅读进度与埋点上报逻辑。
|
||||
- `service/<module>.ts`:集中承载接口定义与类型边界。
|
||||
|
||||
### 期望结果
|
||||
- 每个 hook 只负责一个业务域。
|
||||
- 容器页仅做编排与组件通信。
|
||||
- 接口调用统一收敛到 service class 方法。
|
||||
- 所有异步动作具备失败兜底状态。
|
||||
|
||||
## 示例 B:新增接口的正确姿势
|
||||
|
||||
### 错误示例
|
||||
- 在 `.vue` 中直接调用 `request.get()`。
|
||||
- 返回值不定义类型,使用点到处强转。
|
||||
|
||||
### 正确示例
|
||||
1. 在 `src/service/<domain>.ts` 中新增方法:
|
||||
- 入参类型明确,
|
||||
- 返回值类型明确,
|
||||
- 不混入视图逻辑。
|
||||
2. hook 调用 service,并映射到本地状态。
|
||||
3. view 仅消费 hook 对外暴露的数据和动作。
|
||||
|
||||
## 示例 C:页面动作的错误处理
|
||||
|
||||
### 必备模式
|
||||
- 异步前先 `loading = true`。
|
||||
- 使用 `try/catch/finally` 包裹异步调用。
|
||||
- `catch` 中设置 `error = true`,并将关键数据恢复到安全默认值。
|
||||
- `finally` 中关闭 loading,避免状态泄漏。
|
||||
|
||||
### 需要避免
|
||||
- `catch (e) { console.log(e) }`,但不修改任何状态。
|
||||
- 仅在成功分支关闭 loading。
|
||||
|
||||
## 示例 D:页面组件拆分克制
|
||||
|
||||
### 应该拆
|
||||
- 用户信息面板、会员卡片、菜单宫格这类具备清晰业务语义的区块。
|
||||
- 交互复杂、模板较长,独立后能明显降低 `index.vue` 理解成本的区块。
|
||||
- 已有复用或确定会复用的 UI/业务组件。
|
||||
|
||||
### 不应该拆
|
||||
- 只有几行 HTML/CSS 的布局容器。
|
||||
- 只接收原样 props 再原样渲染,没有独立语义或交互的小片段。
|
||||
- 为了凑 `components/` 目录,把一个页面按视觉切片拆成大量一次性组件。
|
||||
|
||||
### 期望结果
|
||||
- `index.vue` 负责页面编排,不变成所有状态和副作用的大杂烩。
|
||||
- `components/` 数量服务于职责边界,不以“越多越规范”为目标。
|
||||
- 简单静态片段可以留在页面或父组件内。
|
||||
|
||||
## 示例 E:大文件拆分触发(mediaContentInfo 类场景)
|
||||
|
||||
### 触发条件
|
||||
当类似 `src/views/acgModule/utils/mediaContentInfo.ts` 的文件持续叠加以下逻辑时:
|
||||
- 列表分页逻辑,
|
||||
- 权限与付费闸门逻辑,
|
||||
- 阅读进度与埋点逻辑,
|
||||
- 路由同步逻辑。
|
||||
|
||||
### 推荐拆分方案
|
||||
1. `useMediaEpisodePaging.ts`:分页、刷新、列表合并规则。
|
||||
2. `useMediaEpisodeAccess.ts`:权限校验、付费弹窗状态、购买成功处理。
|
||||
3. `useMediaReadReport.ts`:进度计算与埋点派发。
|
||||
4. 协调文件保持轻量:仅组装 hooks 并对 view 暴露统一 API。
|
||||
|
||||
### 完成标准
|
||||
- 不存在跨多个业务域的“大而全 hook”。
|
||||
- 埋点逻辑不直接修改分页状态。
|
||||
- 权限逻辑不直接承担列表拉取职责。
|
||||
@@ -0,0 +1,87 @@
|
||||
# 命名规范(Vue3 + TypeScript)
|
||||
|
||||
本规范参考 Vue 官方风格与 TypeScript 主流实践,目标是统一可读性、可检索性、可维护性。
|
||||
|
||||
## 0) 历史代码兼容原则
|
||||
|
||||
- 存量代码可暂时保留历史命名,不做一次性全量改名。
|
||||
- 增量从严:新增文件、目录、类型、变量、函数、组件命名必须符合本规范。
|
||||
- 改动旧文件时,至少保证“新增/修改行”不引入旧命名反模式。
|
||||
- 大范围改名需单独评估风险(路由、动态导入、缓存键、埋点字段),建议独立 PR 分批执行。
|
||||
|
||||
## 1) 目录与文件命名
|
||||
|
||||
- 目录名:`kebab-case`
|
||||
- 示例:`src/views/user-center/`
|
||||
- 页面入口文件:`index.vue`
|
||||
- 组件文件:`PascalCase.vue`
|
||||
- 示例:`UserProfileCard.vue`
|
||||
- hooks/composable 文件:`useXxx.ts`
|
||||
- 示例:`useMediaEpisodePaging.ts`
|
||||
- 其他 TS 文件:`kebab-case.ts`
|
||||
- 示例:`media-content-parser.ts`
|
||||
- 样式文件:`kebab-case.scss`
|
||||
|
||||
## 2) 代码符号命名
|
||||
|
||||
- class/type/interface/enum:`PascalCase`
|
||||
- 示例:`UserProfileService`、`MediaListItem`、`ApiError`
|
||||
- 变量/函数/方法:`camelCase`
|
||||
- 示例:`fetchMediaList`、`buildRequestParams`
|
||||
- 常量:`UPPER_SNAKE_CASE`
|
||||
- 示例:`DEFAULT_PAGE_SIZE`
|
||||
- 布尔变量:`is/has/can/should + PascalCase`
|
||||
- 示例:`isLoading`、`hasPermission`
|
||||
- Promise 异步动作:动词开头
|
||||
- 示例:`fetchUserInfo`、`loadEpisodeList`
|
||||
|
||||
## 3) Vue 约定命名
|
||||
|
||||
- 事件处理函数统一 `handleXxx`
|
||||
- 示例:`handleSubmit`、`handleEpisodeChange`
|
||||
- 事件命名(emit)使用 `kebab-case`
|
||||
- 示例:`episode-change`、`submit-success`
|
||||
- props 命名在代码中使用 `camelCase`,模板中可使用 `kebab-case`。
|
||||
- 计算属性命名以业务语义为主,避免 `data1`、`tempVal` 这类占位名。
|
||||
|
||||
## 4) 类型命名细则
|
||||
|
||||
- DTO/接口模型建议加语义后缀:
|
||||
- 入参:`XxxParams`
|
||||
- 返回:`XxxResp` 或 `XxxResponse`
|
||||
- 列表项:`XxxItem`
|
||||
- 错误类型建议统一:`XxxError`
|
||||
- 避免使用 `IUser` 这类 `I` 前缀接口命名。
|
||||
|
||||
## 5) 禁止项
|
||||
|
||||
- 禁止拼音命名(业务专有词且已有共识除外)。
|
||||
- 禁止无语义缩写(如 `tmp`, `obj2`, `aaa`)。
|
||||
- 禁止单字符业务变量命名(循环计数器 `i/j/k` 除外)。
|
||||
- 禁止同一模块混用多种命名风格。
|
||||
|
||||
## 6) 快速示例
|
||||
|
||||
```ts
|
||||
// good
|
||||
const DEFAULT_RETRY_COUNT = 2;
|
||||
|
||||
interface QueryMediaListParams {
|
||||
pageNumber: number;
|
||||
pageSize: number;
|
||||
}
|
||||
|
||||
async function fetchMediaList(params: QueryMediaListParams) {
|
||||
// ...
|
||||
}
|
||||
|
||||
const isListEmpty = computed(() => state.list.length === 0);
|
||||
```
|
||||
|
||||
```ts
|
||||
// bad
|
||||
const retryCountDefault = 2; // 常量未使用 UPPER_SNAKE_CASE
|
||||
interface IQuery {} // 不建议 I 前缀
|
||||
async function getdata(d: any) {} // 命名与类型均不规范
|
||||
const temp = computed(() => state.list.length === 0); // 语义弱
|
||||
```
|
||||
@@ -0,0 +1,83 @@
|
||||
# 提问模板(团队可直接复制)
|
||||
|
||||
以下模板用于稳定触发 `frontend-project-standards`,并确保输出符合本规范的交付结构。
|
||||
|
||||
## 模板 1:新页面开发(标准版)
|
||||
|
||||
```text
|
||||
请按 frontend-project-standards 开发新页面:<页面路径或模块名>。
|
||||
要求:
|
||||
1) 页面按 container + components + hooks + service 分层;
|
||||
2) 接口统一走 src/service/*.ts,禁止在 .vue/hook 里直接 request;
|
||||
3) 补齐 loading/error/empty 状态与错误处理;
|
||||
4) 不新增宽泛 any;
|
||||
5) 命名遵循 naming-conventions.md(历史可保留,新增/改动必须新规范);
|
||||
6) 不要把单一页面过度拆成很多 component,只有复用、复杂交互或清晰业务边界时才拆。
|
||||
|
||||
交付时请输出:
|
||||
- 分层说明
|
||||
- hooks 变更
|
||||
- API 变更与类型
|
||||
- 错误处理覆盖
|
||||
- 维护性收益
|
||||
- 自检结果
|
||||
```
|
||||
|
||||
## 模板 2:重构大文件(如 mediaContentInfo)
|
||||
|
||||
```text
|
||||
请按 frontend-project-standards 重构:<目标文件路径>。
|
||||
当前文件职责混杂,请拆分为多个单一职责 hook,并保持原有行为不回退。
|
||||
要求重点:
|
||||
1) 分离分页、权限/付费、埋点上报、路由同步等业务域;
|
||||
2) 保持 service 层接口边界清晰并补齐类型;
|
||||
3) 异步流程加上失败兜底与状态恢复;
|
||||
4) 组件拆分保持克制,避免把页面按视觉小块切成大量一次性 component;
|
||||
5) 完成后给出迁移说明(旧逻辑 -> 新结构映射)。
|
||||
```
|
||||
|
||||
## 模板 3:新增接口并接入页面
|
||||
|
||||
```text
|
||||
请按 frontend-project-standards 完成接口接入:
|
||||
- 新增接口:<接口描述>
|
||||
- 接入页面:<页面路径>
|
||||
|
||||
要求:
|
||||
1) 在 src/service/<domain>.ts 新增 typed 方法(params/response);
|
||||
2) 页面只通过 hook 使用 service;
|
||||
3) 禁止组件层直接请求;
|
||||
4) 输出本次 API contract(字段说明 + 类型)。
|
||||
```
|
||||
|
||||
## 模板 4:问题修复(带规范化)
|
||||
|
||||
```text
|
||||
请按 frontend-project-standards 修复问题:<问题描述>。
|
||||
除修复 bug 外,还要完成最小必要规范化:
|
||||
1) 抽离与 bug 相关的混杂逻辑到 hook;
|
||||
2) 补齐错误处理分支,避免静默失败;
|
||||
3) 确保不新增 any,不绕过 service;
|
||||
4) 给出回归风险点和验证步骤。
|
||||
```
|
||||
|
||||
## 模板 5:仅做规范审查(不大改代码)
|
||||
|
||||
```text
|
||||
请按 frontend-project-standards 对以下改动做规范审查并给出修正建议:
|
||||
<文件路径或 diff 范围>
|
||||
|
||||
请按严重程度输出:
|
||||
1) 违反分层/hook/API/错误处理规范的问题;
|
||||
2) 每个问题的最小修复方案;
|
||||
3) 可选优化项;
|
||||
4) 最后给出 PR 自检清单通过情况。
|
||||
```
|
||||
|
||||
## 建议补充信息(提高一次成功率)
|
||||
|
||||
- 目标文件路径
|
||||
- 是否允许拆文件/重命名
|
||||
- 行为兼容要求(必须保持 / 可调整)
|
||||
- 优先级(性能、可维护性、上线速度)
|
||||
- 是否需要同时补测试
|
||||
@@ -0,0 +1,148 @@
|
||||
# 参考模板
|
||||
|
||||
## 1) Service 方法模板
|
||||
|
||||
```ts
|
||||
import request from '@/utils/request';
|
||||
|
||||
export interface QueryListParams {
|
||||
pageNumber: number;
|
||||
pageSize: number;
|
||||
mediaId?: string;
|
||||
}
|
||||
|
||||
export interface QueryListResp {
|
||||
list: Array<{
|
||||
id: string;
|
||||
title: string;
|
||||
}>;
|
||||
total: number;
|
||||
}
|
||||
|
||||
export default class ExampleApi {
|
||||
static queryList(params: QueryListParams): Promise<QueryListResp> {
|
||||
return request.get('/example/list', params);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 2) Hook 模板(单一职责)
|
||||
|
||||
```ts
|
||||
import { reactive } from 'vue';
|
||||
import ExampleApi, { QueryListParams } from '@/service/example';
|
||||
|
||||
export function useExampleList(initialParams: QueryListParams) {
|
||||
const state = reactive({
|
||||
loading: false,
|
||||
error: false,
|
||||
list: [] as Array<{ id: string; title: string }>,
|
||||
total: 0,
|
||||
});
|
||||
|
||||
const fetchList = async (params = initialParams) => {
|
||||
state.loading = true;
|
||||
state.error = false;
|
||||
|
||||
try {
|
||||
const res = await ExampleApi.queryList(params);
|
||||
state.list = res.list || [];
|
||||
state.total = Number(res.total || 0);
|
||||
} catch (err) {
|
||||
state.error = true;
|
||||
state.list = [];
|
||||
state.total = 0;
|
||||
} finally {
|
||||
state.loading = false;
|
||||
}
|
||||
};
|
||||
|
||||
return {
|
||||
state,
|
||||
fetchList,
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
## 3) 容器页模板(Container View)
|
||||
|
||||
```vue
|
||||
<script setup lang="ts">
|
||||
import { computed } from 'vue';
|
||||
import { useRoute } from 'vue-router';
|
||||
import { useExampleList } from './hooks/useExampleList';
|
||||
|
||||
const route = useRoute();
|
||||
const mediaId = computed(() => String(route.query.id || ''));
|
||||
|
||||
const { state, fetchList } = useExampleList({
|
||||
pageNumber: 1,
|
||||
pageSize: 30,
|
||||
mediaId: mediaId.value,
|
||||
});
|
||||
|
||||
fetchList();
|
||||
</script>
|
||||
```
|
||||
|
||||
## 4) 错误处理最低检查项
|
||||
|
||||
- 每个异步动作都具备成对的 loading 开关。
|
||||
- 请求失败时会落到确定性兜底状态。
|
||||
- 接口细节与类型由 service 层承载。
|
||||
- UI 层能展示空态/错误态,不允许静默失败。
|
||||
|
||||
## 5) 旧代码 any 的渐进迁移模式
|
||||
|
||||
```ts
|
||||
// 改造前
|
||||
// static getMediaHot(data: any) {
|
||||
// return request.get('/media/hot', data);
|
||||
// }
|
||||
|
||||
// 改造后(增量迁移)
|
||||
export interface GetMediaHotParams {
|
||||
pageNumber: number;
|
||||
pageSize: number;
|
||||
moduleId?: string;
|
||||
}
|
||||
|
||||
export interface GetMediaHotResp {
|
||||
list: Types.Acg.MediaContentListItem[];
|
||||
total: number;
|
||||
}
|
||||
|
||||
static getMediaHot(data: GetMediaHotParams): Promise<GetMediaHotResp> {
|
||||
return request.get('/media/hot', data);
|
||||
}
|
||||
```
|
||||
|
||||
## 6) PR 自检输出模板
|
||||
|
||||
在实现说明中必须附上以下区块(与 `SKILL.md` 保持一致):
|
||||
|
||||
```markdown
|
||||
### 自检结果
|
||||
- [x] view/hook 层没有直接请求调用
|
||||
- [x] service 边界方法具备明确类型
|
||||
- [x] 未新增宽泛 any
|
||||
- [x] 异步失败分支具备兜底状态
|
||||
- [x] 混杂职责已拆分为聚焦 hooks/components
|
||||
```
|
||||
|
||||
## 7) 轻量自动校验命令(可执行)
|
||||
|
||||
在仓库根目录执行以下命令进行快速自检:
|
||||
|
||||
```bash
|
||||
# 1) 优先检查本次改动的 view/hook 文件是否直接调用 request
|
||||
rg "request\\.(get|post|put|delete|deletes)\\(" <changed-view-or-hook-files>
|
||||
|
||||
# 2) 检查本次改动文件是否引入 any(人工结合 diff 判断)
|
||||
rg "\\bany\\b" <changed-files>
|
||||
```
|
||||
|
||||
判定规则:
|
||||
- 命令 1 预期为“无结果”;有结果则说明可能绕过 service。
|
||||
- 命令 2 不要求仓库清零,但本次改动不应新增宽泛 `any`。
|
||||
- 只有在做全仓治理或用户明确要求时,才扩展到 `src/views src/hooks src/service` 全量扫描。
|
||||
@@ -0,0 +1,239 @@
|
||||
---
|
||||
name: ui-requirement-planner
|
||||
description: 将 UI 需求转化为可维护且可落地的 Vue 3 + Vite + TypeScript 实施方案。适用于用户提供产品需求、Figma 链接/节点、截图、现有页面代码或自然语言想法,并希望输出组件分层、页面结构、composable 抽离、Pinia 使用决策、API 合约规划、交互流程、样式建议、边界状态、素材落地(图标/背景识别、下载、目录归档、页面引用)与验收标准。优先给出可执行方案,再生成代码。
|
||||
---
|
||||
|
||||
# UI 需求规划器
|
||||
|
||||
## 概述
|
||||
|
||||
将模糊或分散的 UI 需求整理为可落地的前端实施方案(Vue 3 + Vite + TypeScript)。默认采用“方案优先”输出:先明确页面结构、组件边界、composable、数据流和 API 职责,再给出 Vue 骨架代码。
|
||||
|
||||
默认技术栈与约定:
|
||||
- Vue 3 + Composition API + `<script setup lang="ts">`
|
||||
- Vite
|
||||
- TypeScript(props、emits、API 数据、view model 均需显式类型)
|
||||
- `scoped scss`
|
||||
- `Pinia` 仅在跨路由或远距离组件共享状态时引入
|
||||
- `axios` + 统一请求层 + 统一错误处理
|
||||
|
||||
术语统一:
|
||||
- “素材”默认指 UI 里的图标、背景图、插图、装饰图等静态资源。
|
||||
- “模块目录”默认指 `src/assets/images/png/<module>/`(例如 `mine/newHome`)。
|
||||
|
||||
## 工作流程
|
||||
|
||||
除非用户明确要求更小范围交付,否则按以下顺序执行:
|
||||
|
||||
1. 读取输入并识别来源:
|
||||
- 自然语言需求
|
||||
- PRD / 需求单
|
||||
- 截图 / 线框描述
|
||||
- 现有页面或组件代码
|
||||
- 混合输入
|
||||
2. 将需求归一为简洁的页面目标与主用户路径。
|
||||
3. 按层拆分 UI:
|
||||
- 页面/容器职责
|
||||
- 可复用展示组件
|
||||
- 业务组件
|
||||
- composables
|
||||
- store 使用边界
|
||||
- API / services 分层
|
||||
4. 确定状态模型:
|
||||
- 页面内状态优先使用 `ref` / `reactive`
|
||||
- 展示派生状态使用 `computed`
|
||||
- 仅在共享或跨路由场景引入 `Pinia`
|
||||
5. 定义 API 边界:
|
||||
- service 方法
|
||||
- 请求/响应类型
|
||||
- loading、empty、error、retry、permission 状态
|
||||
6. 若输入包含 Figma/原型:执行素材规划与落地策略。
|
||||
- 识别图标、背景图、插图等素材位
|
||||
- 标记可复用素材与仅页面内使用素材
|
||||
- 生成目录归档与命名方案
|
||||
- 规划页面中的资源引用方式
|
||||
7. 产出结构化实施方案。
|
||||
8. 需要时再补充 Vue 骨架代码或示例文件。
|
||||
|
||||
## Figma 素材处理规则(新增)
|
||||
|
||||
当用户要求“识别 Figma 图标/背景并落地资源”时,必须按以下规则执行:
|
||||
|
||||
1. 识别范围
|
||||
- 至少区分:功能图标、背景图(整页/卡片)、装饰图、头像占位图。
|
||||
- 对同一视觉资源的多处复用,优先抽为同一文件,避免重复导出。
|
||||
|
||||
2. 下载与保存路径
|
||||
- 统一保存到:`src/assets/images/png/<module>/`
|
||||
- `<module>` 与业务页面一致,例如:`mine/newHome`、`home/recommend`
|
||||
- 若资源存在主题态(light/dark)或状态态(default/active/disabled),在文件名中体现。
|
||||
|
||||
3. 命名规范
|
||||
- 文件名使用小写英文 + 连字符,禁止空格与中文文件名。
|
||||
- 推荐模式:`<module>-<semantic>-<state?>.png`
|
||||
- 示例:`mine-home-bg.png`、`mine-home-setting-default.png`、`mine-home-setting-active.png`
|
||||
|
||||
4. 页面引用规范
|
||||
- Vue SFC 模板内静态引用优先使用别名:`@/assets/images/png/...`
|
||||
- TS 里拼装或计算型资源地址使用:`new URL('@/assets/images/png/...', import.meta.url).href`
|
||||
- 必须确保引用与目录结构一致,避免“移动文件后路径失效”。
|
||||
|
||||
5. 无图场景兜底(强制)
|
||||
- 缺少真实素材时必须提供占位图,不可空白。
|
||||
- 占位图尺寸按 UI 设计尺寸;无标注时按容器尺寸。
|
||||
- 方案中需注明占位图来源、尺寸与替换策略(后续替换真实图不改布局)。
|
||||
|
||||
## 输出格式
|
||||
|
||||
除非用户要求更短答复,默认按以下结构输出:
|
||||
|
||||
### 1) 需求摘要
|
||||
- 用 2-4 条概括目标页面/功能
|
||||
- 说明核心用户目标
|
||||
- 说明关键业务约束与待确认项
|
||||
|
||||
### 2) 页面与组件架构
|
||||
- 页面职责
|
||||
- 组件树
|
||||
- 哪些组件保持展示型(dumb/presentational)
|
||||
- 哪些组件承载业务逻辑
|
||||
|
||||
### 3) 状态与数据流
|
||||
- 本地状态
|
||||
- 派生状态
|
||||
- 事件与交互流
|
||||
- 是否需要 `Pinia` 及理由
|
||||
|
||||
### 4) API 与类型规划
|
||||
- 推荐的 `services/api` 拆分方式
|
||||
- 请求方法与用途
|
||||
- 核心类型定义
|
||||
- 是否需要从原始 API 数据映射到 UI 模型
|
||||
|
||||
### 5) 边界与失败状态
|
||||
相关场景下必须覆盖:
|
||||
- loading
|
||||
- empty
|
||||
- error
|
||||
- validation
|
||||
- permission
|
||||
- retry / fallback
|
||||
|
||||
### 6) 实施步骤
|
||||
给出从基础搭建到联调集成的可执行顺序。
|
||||
|
||||
### 7) 验收清单
|
||||
列出开发者/评审可直接核对的验收点。
|
||||
|
||||
### 8) Vue 骨架代码(按需)
|
||||
需要时提供精简骨架:
|
||||
- 页面容器
|
||||
- 子组件 props / emits
|
||||
- composable
|
||||
- store(仅在有充分理由时)
|
||||
- API service
|
||||
- 类型定义
|
||||
|
||||
### 9) 图片与占位图规范(强制)
|
||||
- 若需求未提供真实图片资源(如 banner、封面、头像、商品图等),必须给出占位图方案,禁止留空或“后续补图”而无实现。
|
||||
- 占位图尺寸必须与 UI 设计尺寸一致:优先使用设计稿标注的宽高;若无明确标注,则以对应容器的宽高作为占位尺寸。
|
||||
- 在方案与代码中都要明确占位规则(例如:`<img>` 的 `width/height`、容器比例、`object-fit` 策略)。
|
||||
- 若同一页面包含多种图片位,需分别定义占位图尺寸与样式,不可用一个尺寸通配全部场景。
|
||||
|
||||
### 10) 素材落地清单(Figma/原型场景必填)
|
||||
- 素材识别结果(图标、背景、装饰图分类)
|
||||
- 目标目录:`src/assets/images/png/<module>/`
|
||||
- 文件命名映射(设计稿节点名 -> 最终文件名)
|
||||
- 页面引用点位(组件/页面中的引用位置)
|
||||
- 未交付素材的占位图策略与尺寸
|
||||
|
||||
## 架构规则
|
||||
|
||||
### 组件分层
|
||||
- 路由页聚焦编排,不要在单文件里混放大段模板 + 业务逻辑 + API 调用。
|
||||
- 可复用 UI 放入 `components/`。
|
||||
- 可复用业务逻辑放入 `composables/`。
|
||||
- HTTP 请求逻辑放入 `services/` 或 `services/api/`。
|
||||
- 跨文件共享类型放入 `types/`。
|
||||
- 纯函数工具放入 `utils/`(需无状态且非 Vue 特定)。
|
||||
|
||||
### composable 抽离原则
|
||||
满足任一条件即可考虑抽离:
|
||||
- 逻辑可复用
|
||||
- 页面因异步流程或 watchers 变得难以维护
|
||||
- 表单、列表查询、分页、筛选、权限流程需要独立测试
|
||||
- 页面中 API 编排与 UI 状态迁移耦合过重
|
||||
|
||||
不要为了“挪几行代码”而抽离;抽离应有明确边界价值。
|
||||
|
||||
### Pinia 使用决策
|
||||
默认不使用 store。仅在以下场景推荐 `Pinia`:
|
||||
- 跨页面共享状态
|
||||
- 需要持久化的会话态 UI 状态
|
||||
- 多个远距离组件共同消费同一特性状态
|
||||
- 单页 composable 无法合理承载的缓存或状态协同
|
||||
|
||||
若本地状态足够,需明确说明“不需要 Pinia”。
|
||||
|
||||
### API 设计
|
||||
推荐“统一请求客户端 + 薄 service 模块”:
|
||||
- `services/http/client.ts`:axios 实例与拦截器
|
||||
- `services/api/<feature>.ts`:按业务域组织请求
|
||||
- `types/api.ts` 或 feature 内局部 DTO 类型
|
||||
|
||||
方案中始终要提及:
|
||||
- loading 与取消请求策略(如适用)
|
||||
- 面向用户的错误文案与内部技术错误的区分
|
||||
- 是否需要将后端字段映射为 view model
|
||||
|
||||
### 错误处理
|
||||
必须给出一致的错误处理约定:
|
||||
- 网络与超时失败
|
||||
- 业务错误码/业务失败
|
||||
- 参数校验失败
|
||||
- 乐观更新失败回滚(如适用)
|
||||
- 可安全重试动作的 retry 机制
|
||||
|
||||
避免零散、无模式地到处写 `try/catch`。
|
||||
|
||||
### 样式规范
|
||||
默认使用 `scoped scss`:
|
||||
- 保持布局 token 与重复样式模式一致
|
||||
- 避免样式决策导致无关组件强耦合
|
||||
- 明确指出适合抽离 design token、CSS 变量、共享 mixin 的位置
|
||||
|
||||
### 素材目录与复用边界
|
||||
- 页面私有素材放 `src/assets/images/png/<module>/`,跨页面复用素材可上提到共享目录(如 `src/assets/images/png/common/`)。
|
||||
- 同一个素材在多个页面复用时,不得各自复制一份,优先统一引用共享文件。
|
||||
- 若历史文件命名混乱,方案中应给出“保守兼容 + 渐进收敛”的改造建议。
|
||||
|
||||
## 代码生成规则
|
||||
生成 Vue 代码时:
|
||||
- 使用 `<script setup lang="ts">`
|
||||
- props 与 emits 必须显式类型
|
||||
- 模板保持可读,避免巨型“全塞一页”
|
||||
- 有意义的模板表达式应提升为 `computed`
|
||||
- 小型展示组件中禁止直接写 axios 调用
|
||||
- 无充分理由不得引入 `Pinia`
|
||||
- 后端细节缺失时可用占位 API 方法与类型,并明确假设
|
||||
- 缺少真实图片时,必须提供占位图实现,并按 UI 尺寸设置宽高/比例,确保布局稳定不抖动
|
||||
- 新增素材引用时,必须匹配真实文件路径与命名,不允许“先写引用、后补文件”造成运行时 404
|
||||
|
||||
## 输入不明确时
|
||||
除非缺失信息会阻断有效推进,否则不要卡住:
|
||||
- 明确写出假设
|
||||
- 区分“已确认需求”与“假设项”
|
||||
- 仍需给出可维护的默认架构方案
|
||||
|
||||
## 典型触发场景
|
||||
以下请求应使用本技能:
|
||||
- “把这个后台页面需求拆成 Vue 实现方案”
|
||||
- “根据这张草图规划组件结构和接口”
|
||||
- “把这个 UI 需求整理成前端开发任务和代码骨架”
|
||||
- “这个页面适不适合上 Pinia,接口怎么分层”
|
||||
- “把现有页面按 composables + services 重构出方案”
|
||||
- “识别 Figma 图标和背景,下载到 `src/assets/images/png` 并按模块建目录”
|
||||
- “把设计稿素材落地并在页面正确引用”
|
||||
|
||||
## 参考
|
||||
更详细的输出结构与规划提示词见:`references/planning-template.md`。
|
||||
@@ -0,0 +1,2 @@
|
||||
interface:
|
||||
display_name: "UI Requirement Planner"
|
||||
@@ -0,0 +1,141 @@
|
||||
# 规划模板
|
||||
|
||||
当用户希望获得完整、可执行的前端实施方案时,使用本参考模板。
|
||||
|
||||
## 默认输出模板
|
||||
|
||||
### 需求摘要
|
||||
- 目标:
|
||||
- 核心用户:
|
||||
- 关键操作:
|
||||
- 约束条件:
|
||||
- 假设项:
|
||||
|
||||
### 页面与组件架构
|
||||
- 路由/页面容器职责:
|
||||
- 组件树:
|
||||
- 展示型组件:
|
||||
- 业务组件:
|
||||
- 可复用候选模块:
|
||||
|
||||
### 状态与数据流
|
||||
- 页面本地状态:
|
||||
- 派生状态:
|
||||
- 交互事件:
|
||||
- 异步流程:
|
||||
- 是否需要 Pinia:
|
||||
- 使用或不使用理由:
|
||||
|
||||
### API 与类型规划
|
||||
- Service 模块划分:
|
||||
- 请求方法:
|
||||
- 请求参数:
|
||||
- 响应类型:
|
||||
- ViewModel 映射:
|
||||
- 错误模型:
|
||||
|
||||
### 边界与失败状态
|
||||
- Loading:
|
||||
- Empty:
|
||||
- Error:
|
||||
- Validation:
|
||||
- Permission:
|
||||
- Retry/Fallback:
|
||||
|
||||
### 图片与占位图规范(强制)
|
||||
- 是否提供真实图片资源:
|
||||
- 若未提供,采用的占位图方案:
|
||||
- 占位图尺寸(按 UI 设计尺寸或容器尺寸):
|
||||
- 容器比例与 `object-fit` 策略:
|
||||
- 多图片位是否分别定义尺寸与样式:
|
||||
|
||||
### 实施步骤
|
||||
1.
|
||||
2.
|
||||
3.
|
||||
4.
|
||||
|
||||
### 验收清单
|
||||
- [ ] 组件边界清晰,职责拆分明确
|
||||
- [ ] 展示组件内无直接 API 调用
|
||||
- [ ] 仅在必要时使用 Pinia,且理由明确
|
||||
- [ ] Loading / Empty / Error 等状态已覆盖
|
||||
- [ ] 类型定义完整且显式
|
||||
- [ ] `scoped scss` 职责边界清楚
|
||||
- [ ] 缺图场景有占位图且尺寸符合 UI 设计
|
||||
|
||||
### 骨架目录建议
|
||||
```text
|
||||
src/
|
||||
pages/
|
||||
components/
|
||||
composables/
|
||||
services/
|
||||
http/
|
||||
api/
|
||||
types/
|
||||
utils/
|
||||
```
|
||||
|
||||
## 输入到输出示例
|
||||
|
||||
### 示例 1
|
||||
输入: “做一个用户列表页,支持搜索、筛选、分页、详情抽屉。”
|
||||
|
||||
重点关注:
|
||||
- 表格容器、工具栏、详情抽屉的职责分离
|
||||
- 查询条件状态是否抽离为 composable
|
||||
- 详情抽屉是否需要独立拉取逻辑
|
||||
- loading、empty、retry 状态设计
|
||||
|
||||
### 示例 2
|
||||
输入: “把这个原型图转成 Vue 页面实现方案。”
|
||||
|
||||
重点关注:
|
||||
- 视觉区域如何映射到组件树
|
||||
- 通用 UI 基础组件与一次性业务组件的边界
|
||||
- 占位 API 与类型化 DTO 假设
|
||||
- 明确的响应式与溢出行为
|
||||
- 若原型未提供真实图片,给出按 UI 尺寸的占位图方案
|
||||
|
||||
### 示例 3(Figma 素材落地)
|
||||
输入: “识别 Figma 图标和背景,下载保存到 `src/assets/images/png`,按模块建目录并正确引用到页面。”
|
||||
|
||||
重点关注:
|
||||
- 图标、背景图、装饰图的分类与复用判断
|
||||
- 素材目录是否按模块归档
|
||||
- 文件名是否语义化、可维护
|
||||
- 页面模板和 TS 里的引用方式是否正确
|
||||
- 缺失素材时是否有按 UI 尺寸的占位图兜底
|
||||
|
||||
可直接复用的输出片段:
|
||||
|
||||
````markdown
|
||||
### 素材落地清单
|
||||
- 模块:`mine/newHome`
|
||||
- 目标目录:`src/assets/images/png/mine/newHome/`
|
||||
- 素材映射:
|
||||
- `icon_message` -> `mine-home-icon-message.png`
|
||||
- `icon_setting` -> `mine-home-icon-setting.png`
|
||||
- `bg_header` -> `mine-home-bg-header.png`
|
||||
|
||||
### 目录结构
|
||||
```text
|
||||
src/assets/images/png/mine/newHome/
|
||||
mine-home-icon-message.png
|
||||
mine-home-icon-setting.png
|
||||
mine-home-bg-header.png
|
||||
mine-home-banner-placeholder.png
|
||||
```
|
||||
|
||||
### 页面引用建议
|
||||
- 模板静态引用:
|
||||
- `<img src="@/assets/images/png/mine/newHome/mine-home-icon-message.png" alt="message" />`
|
||||
- TS 计算型引用:
|
||||
- `new URL('@/assets/images/png/mine/newHome/mine-home-bg-header.png', import.meta.url).href`
|
||||
|
||||
### 占位图策略
|
||||
- 当 `bg_header` 未交付时,使用 `mine-home-banner-placeholder.png`
|
||||
- 占位图尺寸:`343 x 84`(按 UI 标注);若无标注则取容器尺寸
|
||||
- `object-fit: cover`,确保替换真实图前后布局不抖动
|
||||
````
|
||||
Reference in New Issue
Block a user