diff --git a/qy-lty-admin/.planning/phases/03-dialog-feedback/03-CONTEXT.md b/qy-lty-admin/.planning/phases/03-dialog-feedback/03-CONTEXT.md index f2b3d07..819f614 100644 --- a/qy-lty-admin/.planning/phases/03-dialog-feedback/03-CONTEXT.md +++ b/qy-lty-admin/.planning/phases/03-dialog-feedback/03-CONTEXT.md @@ -29,9 +29,9 @@ ### 组件抽离 -- **新建**:`components/ai-model/CredentialSlotDialog.tsx` - - 该路径目录 `components/ai-model/` 可能不存在;需 planner 在 read_first 阶段确认(推测目前没有,若没有则 mkdir) - - 沿用 shadcn 组件风格(参考现有 `components/songs/` / `components/outfits/` 等已有业务组件目录的写法) +- **新建**:`components/ai-model/credential-slot-dialog.tsx`(researcher 修正:仓库 9 个现有业务对话框全部 **kebab-case**,如 `add-song-dialog.tsx` / `user-form-dialog.tsx`,本 phase 跟规约) + - 该路径目录 `components/ai-model/` **确认不存在**(researcher 实测 `ls` 退出码 2),需要 mkdir + - 沿用 shadcn 组件风格 + RHF + Zod;1:1 模板首选 `components/users/user-form-dialog.tsx` L1-289(最贴近本 phase 形态:单 dialog + 几个字段 + RHF + Zod + Form wrapper + Loader2 spinner + 提交后关闭) - **修改**:`app/ai-model/page.tsx` - 删除 Phase 2 落地的占位 Dialog(约第 473-485 行的内联 Dialog) - 用 `` 替换 @@ -153,12 +153,35 @@ const onSubmit = async (values: { appId: string; accessToken: string }) => { **Planner 重要:必须按"强制输入"路线落地,不要尝试实现"留空保留旧值"**(除非 plan-checker 一轮里我明确改主意)。 -### Toast 通知 +### Toast 通知(researcher 修正:3 个关键纠偏) -- **Sonner**(项目已用,参考 `components/ui/sonner.tsx` 或 `hooks/use-toast.ts`) -- 成功文案:"凭据槽位已更新" / 描述:"配置已生效" -- 失败文案:title "保存失败" / description: 经 `handleApiError` 映射后的中文消息 -- variant:失败用 `destructive`(如 Sonner 支持) +**纠偏 1 — Sonner Toaster 全局未挂载(关键 pre-existing bug)**: +- `app/layout.tsx` 是 20 行裸 RootLayout,没有 `` +- 现有 9 处 `toast(...)` 调用其实**全是 dead code**(toast 不会显示) +- **本 phase 必须前置一个任务**:在 `app/layout.tsx` `` 末尾挂载 `` from `@/components/ui/sonner` +- 否则 Phase 3 的成功 / 失败反馈完全静默 + +**纠偏 2 — 双 `useToast` 实现都是 Radix Toast,与 Sonner 不通**: +- `hooks/use-toast.ts` + `components/ui/use-toast.ts` 是两份内容相同的 Radix Toast 实现(295 行 dead code) +- 不要走 `useToast` hook +- **直接** `import { toast } from "sonner"` 命令式调用:`toast.success(...)` / `toast.error(...)` + +**纠偏 3 — 双 `handleApiError` 函数**: +- `lib/api/error-handler.ts:38` `(error: unknown): string` ← 用这个 +- `lib/api/index.ts:191` `(error: any): string` ← 同名重复定义,**不要**从 barrel import +- 显式 import:`import { handleApiError } from '@/lib/api/error-handler'` + +**Toast 调用形态**: +```typescript +import { toast } from "sonner" +import { handleApiError } from "@/lib/api/error-handler" + +// 成功 +toast.success("凭据槽位已更新", { description: "配置已生效" }) + +// 失败 +toast.error("保存失败", { description: handleApiError(e) }) +``` ### 错误处理