diff --git a/docs/开发任务包/F1-登录与个人页.md b/docs/开发任务包/F1-登录与个人页.md new file mode 100644 index 0000000..eff2c00 --- /dev/null +++ b/docs/开发任务包/F1-登录与个人页.md @@ -0,0 +1,30 @@ +# F1 · 登录页与个人页 + +> 分支:`task/f1-fe` | worktree:`G:\meida-app-f1` | 只改:`app/entry/src/main/ets/pages/LoginPage.ets`、`pages/ProfilePage.ets`(填桩)、`ets/components/f1/`(可自建) +> 先读《README-FE批次.md》(协作规程 + ArkTS 铁律 + API 速查),严格遵守。 + +## 目标 + +登录闭环与个人中心:dev-token 登录页(含 baseUrl 设置)+ 个人页(用户信息、配额卡片、登出)。 + +## LoginPage 要求 + +1. 品牌区("美搭"标题 + 一句 slogan)+ 设备标识输入框(默认值随机生成一次并 @State 记住,可改)+「进入美搭」按钮 +2. **服务器地址设置**:折叠区("高级设置")显示当前 `AuthStore.getBaseUrl()`,可编辑保存(`setBaseUrl`)——真机连开发机靠它 +3. 登录流程:按钮 loading 态 → `AuthStore.loginByDevToken(deviceKey)` → 成功 `router.replaceUrl({url:'pages/HomePage'})`;失败 catch ApiError 展示 message+hint(错误横幅/对话框) +4. 已登录态进入本页时 aboutToAppear 直接跳 HomePage + +## ProfilePage 要求 + +1. 顶部:用户 ID(`AuthStore.getUserId()`,脱敏显示前 6 后 4)、登出按钮(确认弹窗 → `AuthStore.logout()` → 回 LoginPage) +2. **配额卡片**:并行拉 `agent_chat`、`tryon`、`report_basic` 三个 `GET /api/v1/quota`(具名 interface 对齐速查结构;`reset_at` 显示"明日恢复"或日期,null=终身/月度文案区分) +3. 进度条展示 `used/(limit_value+bonus_granted)`,剩余数大字 +4. 「最近流水」:`GET /api/v1/quota/ledger?limit=10` 列表(tx_type 中文映射:consume=消耗/refund=退还/system_grant=奖励;status 颜色区分) +5. 下拉刷新(Refresh 组件)可加分但非必须 + +## 验收 + +1. 构建门禁 `BUILD SUCCESSFUL`(见规程 §1 命令) +2. 无 ArkTS 铁律违规(规程 §3 逐条自查) +3. 请求全部走 `ApiClient`/`AuthStore`(不直接碰 http) +4. 单次提交,信息:`feat(app): login page with dev-token flow and profile with quota cards(F1)` + 正文中文说明 + 偏差说明 diff --git a/docs/开发任务包/F2-应用壳与首页.md b/docs/开发任务包/F2-应用壳与首页.md new file mode 100644 index 0000000..770b3f7 --- /dev/null +++ b/docs/开发任务包/F2-应用壳与首页.md @@ -0,0 +1,32 @@ +# F2 · 应用壳(Tabs)与首页 + +> 分支:`task/f2-fe` | worktree:`G:\meida-app-f2` | 只改:`app/entry/src/main/ets/pages/HomePage.ets`(填桩)、`ets/components/f2/`(自建) +> 先读《README-FE批次.md》,严格遵守。**禁止 import 其它页面文件**(规程铁律 2)。 + +## 目标 + +应用主壳:底部 Tabs(首页/报告/AI/我的)+ 首页内容 + 两个通用组件。 + +## HomePage 要求 + +1. `@Entry @Component struct HomePage` + 底部 `Tabs`(TabContent × 4,barMode 固定四项、图标用 SymbolGlyph 或简单 Text、中文标签) +2. **Tab1 首页**(本页实现): + - 问候区("你好,美搭" + 日期) + - 功能入口卡 ×2:「生成我的形象报告」「AI 穿搭顾问」——点击 `router.pushUrl({url:'pages/ReportCreatePage'})` / `'pages/ChatPage'`(路径跳转,不 import) + - 「今日额度」小卡:`GET /api/v1/quota?quota_key=agent_chat` 显示"AI 对话剩余 N 次"(失败静默显示占位"—",不打扰首页) +3. **Tab2 报告 / Tab4 我的**:占位内容 + 居中按钮跳 `pages/ReportCreatePage` / `pages/ProfilePage`(真页面是独立路由页;后续迭代再决定嵌组件还是跳页,本批先跳页) +4. **Tab3 AI**:占位说明 + 跳 `pages/ChatPage` 按钮 + - 备选方案:若你能在**不 import ChatPage 文件**的前提下用 `builder` 占位则更好;做不到就跳页,别破铁律 +5. 返回键处理:Tab 页内再按返回应退出应用(onBackPress 返回 false 走默认)——不加复杂逻辑,注释说明即可 + +## 通用组件(`ets/components/f2/`) + +1. `LoadingView`:居中 LoadingProgress + 可选文案;props 用 `@Prop` +2. `ErrorView`:错误图标/文案 + `message` + `hint` + 「重试」按钮回调(`onRetry?: () => void`)——**这是 NFR-UX-02「失败态有原因+下一步指引」的落地组件**,其它任务后续会移用(目录带 f2 前缀,移动由协调者做) + +## 验收 + +1. 构建门禁 `BUILD SUCCESSFUL` +2. 四 Tab 可切换、三个跳转按钮路径正确(跳转目标页面是桩也没关系) +3. ArkTS 铁律自查零违规;请求只走 ApiClient +4. 单次提交:`feat(app): app shell tabs with home entries and common loading/error views(F2)` diff --git a/docs/开发任务包/F3-报告流.md b/docs/开发任务包/F3-报告流.md new file mode 100644 index 0000000..e6cef94 --- /dev/null +++ b/docs/开发任务包/F3-报告流.md @@ -0,0 +1,31 @@ +# F3 · 报告流(提交 → 轮询 → 32 维结果展示) + +> 分支:`task/f3-fe` | worktree:`G:\meida-app-f3` | 只改:`pages/ReportCreatePage.ets`、`pages/ReportResultPage.ets`(填桩)、`ets/components/f3/`(自建) +> 先读《README-FE批次.md》,严格遵守(diagnosis 结构见其 §4,**恒 32 项、skipped 显式**)。 + +## ReportCreatePage(问卷 + 模拟照片 + 提交轮询) + +1. **问卷表单**(必填项做前端校验):性别(单选 女/男/不便告知)、身高 cm(TextInput 数字)、体重 kg、生日(DatePicker)、核心诉求(多选:显高/显瘦/显白/显气质/遮肉/修饰肩颈,至少 1 项)、心理风格(9 型单选:戏剧/睿智/自然/古典/优雅/浪漫/前卫/少女/少年) +2. **照片(模拟)**:TextInput 填 `photo_object_key`,输入框上方显式灰字说明"V1 骨架:COS 直传未接入,此处模拟对象键"(键格式提示 `report_photo/...jpg`;留空时自动生成 `report_photo/{userId}/{随机}.jpg`) +3. 提交:组装 `questionnaire` Record(键名对齐:`gender,height_cm,weight_kg,birthday,core_goals[],psych_style`)+ `photo_object_key` + `request_key`(随机 hex)→ `POST /api/v1/reports` + - 40920(本期已生成)→ 对话框提示并给「查看我的报告」按钮跳结果页(携带最近 reportId——无则提示稍后在任务中心看) + - 成功 → 进入**轮询态**:`GET /api/v1/tasks/{task_id}` 每 3s 一次(`setInterval` 或递归 setTimeout,页面销毁清理),进度条 + stage_text 展示;SUCCEEDED → `router.replaceUrl` 结果页(params 带 reportId);FAILED → ErrorView + 重试(重新提交同 request_key 即幂等重放,注释说明) +4. 轮询期间允许返回(清定时器) + +## ReportResultPage(结果展示) + +1. `GET /api/v1/reports/{id}`(reportId 从 `router.getParams()` 取) +2. **文案区**:`result.copy.summary` + sections 渲染(title + paragraphs);`result.validation.degraded === true` 时顶部黄条提示"本报告由规则引擎直接生成"(透明化降级) +3. **32 维诊断区**(核心):`result.diagnosis.dimensions` + - 按 `basic_coverage` 分组思路简化为:**已分析**(status=ok)与**未覆盖**(skipped,灰色 + evidence 作为原因文案)两组 + - 每维卡片:name_cn + value(数组 join '、')+ 来源标签(中文映射:questionnaire=你填写/vision=照片分析/rule=规则推导/derived=推导/kb=知识库)+ 置信度(百分比);confidence < 0.7 加"仅供参考"小标(NFR-UX-05) + - rule_hits 非空时折叠显示"依据规则 N 条" +4. 顶部状态:version、status、completed_at;「重新生成」按钮 → `POST /api/v1/reports/{id}/regenerate` → 成功后拿新 task_id 回到轮询态(同页复用轮询逻辑或跳回 Create 页携带参数——选实现简单者,注释说明) +5. 加载态 LoadingView / 失败态 ErrorView(含重试) + +## 验收 + +1. 构建门禁 `BUILD SUCCESSFUL` +2. 32 维渲染对空值/skipped/数组 value/低置信度四种形态都有处理(本地构造假数据自查 UI 分支,不依赖后端也能看——用临时默认 @State 假数据再删,提交里不留假数据) +3. 轮询有清理、40920/FAILED/降级三条异常路径有 UI +4. 单次提交:`feat(app): report flow with polling and 32-dimension result view(F3)` diff --git a/docs/开发任务包/F4-AI对话页.md b/docs/开发任务包/F4-AI对话页.md new file mode 100644 index 0000000..4faac46 --- /dev/null +++ b/docs/开发任务包/F4-AI对话页.md @@ -0,0 +1,23 @@ +# F4 · AI 穿搭对话页 + +> 分支:`task/f4-fe` | worktree:`G:\meida-app-f4` | 只改:`pages/ChatPage.ets`(填桩)、`ets/components/f4/`(自建) +> 先读《README-FE批次.md》,严格遵守(chat 响应结构见其 §4)。 + +## ChatPage 要求 + +1. **消息列表**:`@State messages: ChatMsg[]`(本地内存态,V1 不做会话持久化——后端 ag_conversation 属后续任务,注释说明);List + ForEach 渲染,气泡样式区分用户/AI(左右对齐 + 配色) +2. `ChatMsg` 具名 interface:`{role: 'user'|'ai', text: string, meta?: string}`(meta 存"模型 · 耗时"小字) +3. **发送流程**:底部输入框(TextInput,回车/按钮发送)→ push 用户消息 → AI 侧显示"正在思考…"占位气泡 → `POST /api/v1/agent/chat` `{message}` → 成功替换为 reply,meta 拼接 `{model} · {latency_ms}ms`,并在顶部薄条更新 `quota_remaining`("今日剩余 N 次") +4. **失败态**(只 catch ApiError): + - 40301(额度用尽):AI 气泡位显示 e.message(后端文案无价格字样)+ e.hint 次行小字;输入框保留可重试 + - 60003(今日服务上限)/ 其它:同样气泡位展示 message+hint;"正在思考…"占位必须撤掉 +5. 发送中禁用输入框防连点;空消息不发送 +6. 顶部栏:标题"AI 穿搭顾问" + 返回(router.back) +7. 首次进入自动插入一条 AI 欢迎语(本地静态文案,不调接口):"你好,我是你的穿搭顾问,可以问我面试怎么穿、约会怎么搭~" + +## 验收 + +1. 构建门禁 `BUILD SUCCESSFUL` +2. 发送/思考/成功/四种失败展示(40301、60003、网络错)路径齐全;思考占位在失败时一定被撤掉 +3. ArkTS 铁律零违规;只走 ApiClient;无第三方依赖 +4. 单次提交:`feat(app): AI chat page with quota hint and error states(F4)` diff --git a/docs/开发任务包/README-FE批次.md b/docs/开发任务包/README-FE批次.md new file mode 100644 index 0000000..2552bbe --- /dev/null +++ b/docs/开发任务包/README-FE批次.md @@ -0,0 +1,52 @@ +# FE 批次·多 Agent 协作规程(第五批 F1~F4) + +> 版本:v1.3 | 2026-08-15 | 适用:**鸿蒙 FE 批次(F1~F4)**——仓库是 Windows 侧 `G:\meida`(本仓库),工程在 `app/`。后端仓库的规程(v1.2)仍适用其后端任务,不适用本批。 +> **每个 agent 开工前必须先读本文件,再读自己的任务文档。** + +## 1. 环境操作手册(纯 Windows,无 WSL) + +| 任务 | worktree | 分支 | +| --- | --- | --- | +| F1 | `G:\meida-app-f1` | `task/f1-fe` | +| F2 | `G:\meida-app-f2` | `task/f2-fe` | +| F3 | `G:\meida-app-f3` | `task/f3-fe` | +| F4 | `G:\meida-app-f4` | `task/f4-fe` | + +- 读写文件:Read/Write/Edit 工具直接用 Windows 路径(如 `G:\meida-app-f1\app\entry\src\main\ets\pages\...`) +- **构建门禁(唯一验收命令)**: + ``` + cd G:/meida-app-f1/app && export DEVECO_SDK_HOME="C:/Program Files/Huawei/DevEco Studio/sdk" && "C:/Program Files/Huawei/DevEco Studio/tools/node/node.exe" "C:/Program Files/Huawei/DevEco Studio/tools/hvigor/bin/hvigorw.js" --mode module -p module=entry@default assembleHap --analyze=false --daemon=false + ``` + (把 f1 换成你的编号;`BUILD SUCCESSFUL` = 通过。未签名 WARN 正常忽略。) + +## 2. 冲突隔离铁律 + +1. **只改自己任务文档允许的文件**。`app/entry/src/main/ets/core/**`、`module.json5`、`main_pages.json`、`app/README.md`、`oh-package*.json5`、`hvigor*` 全部禁改(core 已就绪,路由已全注册)。 +2. **页面间跳转一律 `router.pushUrl({ url: 'pages/XxxPage' })`**,**禁止 import 其它页面文件**——七个页面都已注册,按路径跳不需要 import,这是本批零冲突的根本。 +3. 组件复用:在自己页面文件内声明 `@Component`;确实通用的放 `ets/components/<你的任务名>/`(如 `components/f2/`),**目录名带任务前缀**。 +4. 不引任何第三方 ohpm 包;不动 resources(字符串/颜色硬编码,i18n 后置)。 +5. 提交:构建绿后**单次提交**(信息格式见任务文档),禁止 push、禁止切分支。 + +## 3. ArkTS 严格模式铁律(协调者实测踩坑,违反必炸编译) + +1. **泛型调用必须显式类型参数**:`ApiClient.post(...)`、`ApiClient.get(...)`——裸 `post(...)` 直接报 `arkts-no-inferred-generic-params` +2. **请求体用具型 Record 字面量**:`const req: Record = { 'k': v }`——不允许 interface→Record 强转(无索引签名)、不允许内联对象类型 `{a:string}(...)` 做泛型参数 +3. **wire 响应类型用具名 interface**(文件内声明,字段名对齐后端 JSON),`resp.result as ApiEnvelope` 之后再 `data` 层转具体类型 +4. **throw 只抛 ApiError**:catch 里 `if (e instanceof ApiError) throw e`,未知异常包 `new ApiError(50000, '请求失败,请检查网络', '请稍后重试')` +5. **对象字面量必须有具名声明的对应类型**(Record/接口/class 皆可,裸字面量赋 var 会报错);async 逻辑放**具名方法**而不是复杂箭头链(泛型推断限制) +6. UI 惯例:`@Entry @Component struct XxxPage`、`@State` 状态、`aboutToAppear` 里 async 初始化(用 `.then` 或 fire-and-forget + `@State` 驱动刷新)、异常只 catch `ApiError` 展示 `e.message + e.hint` + +## 4. 后端 API 速查(baseUrl 默认 `http://127.0.0.1:8000`,信封 `{code,message,data,hint}`) + +- 登录:`POST /api/v1/auth/dev-token` `{device_key}` → `{access_token,refresh_token,expires_in,refresh_expires_in,user_id}`(AuthStore 已封装) +- 配额:`GET /api/v1/quota?quota_key=agent_chat|tryon|...` → `{quota_key,used,limit_value,bonus_granted,remaining,reset_at}` +- 流水:`GET /api/v1/quota/ledger?limit=20` → `[{tx_id,delta,tx_type,status,quota_key,balance_after,created_at}]` +- 对话:`POST /api/v1/agent/chat` `{message}` → `{reply,provider,model,prompt_id,prompt_version,call_id,usage{tokens_in,tokens_out,tokens_cached,latency_ms,cost_cents},quota_remaining}` +- 任务:`GET /api/v1/tasks/{id}` → `{task_id,status,progress,stage_text,...}`(status: PENDING/RUNNING/SUCCEEDED/FAILED) +- 报告:`POST /api/v1/reports` `{questionnaire:{...},photo_object_key,request_key?}` → `{report_id,task_id,status,version}`;`GET /api/v1/reports/{id}` → `{report_id,status,version,result{vision,diagnosis,copy,validation},created_at,completed_at}`;`POST /api/v1/reports/{id}/regenerate` `{request_key?}` +- diagnosis 结构:`{dimensions:[{number,key,name_cn,value,confidence,source,evidence,rule_hits,status}](恒 32 项), coverage:{basic_full,total}}`;copy:`{summary,sections:[{title,paragraphs[]}],model,...}`;validation:`{passed,degraded?,checks{pejorative,absolute,consistency}}` +- 常见错误码:40100 未登录 / 40301 额度用尽(文案已无价格字样)/ 40920 本期报告已生成 / 60003 AI 服务今日上限 / 50003 配置异常 + +## 5. 运行验证说明(agent 不做) + +构建绿即可提交;真机/模拟器运行由用户在 DevEco Studio 里做(连本机后端:模拟器 127.0.0.1 直连,真机改登录页 baseUrl 为开发机局域网 IP)。