hookehuyr

docs(plan): 记录计划书提交逻辑优化和 API 成功验证经验

This diff is collapsed. Click to expand it.
...@@ -1267,6 +1267,9 @@ ...@@ -1267,6 +1267,9 @@
1267 | 2026-02-09 | `src/components/PlanFormContainer.vue` | 表单提交时数据为空 | 修复 submit() 时序问题,移除立即重置 | ✅ 已解决 | 1267 | 2026-02-09 | `src/components/PlanFormContainer.vue` | 表单提交时数据为空 | 修复 submit() 时序问题,移除立即重置 | ✅ 已解决 |
1268 | 2026-02-09 | `src/components/PlanFormContainer.vue` | 金额显示为 10000 而非 100.00 | 添加 formatAmounts() 格式化显示(分 → 元) | ✅ 已解决 | 1268 | 2026-02-09 | `src/components/PlanFormContainer.vue` | 金额显示为 10000 而非 100.00 | 添加 formatAmounts() 格式化显示(分 → 元) | ✅ 已解决 |
1269 | 2026-02-10 | `src/api/plan.js` | 后端接口已修复,联调成功 | 接口正常工作 | ✅ 已完成 | 1269 | 2026-02-10 | `src/api/plan.js` | 后端接口已修复,联调成功 | 接口正常工作 | ✅ 已完成 |
1270 +| 2026-02-11 | `src/components/PlanFormContainer.vue` | 前端优化成功判断逻辑 | 修改成功判断从 `res.code === 1` 改为同时检查 `res.code === 1` 和 `res.data?.order_id` | ✅ 已完成 |
1271 +| 2026-02-11 | `src/components/PlanFormContainer.vue` | 错误信息路径修正 | 修改错误信息从 `res.data?.message` 改为 `res.data?.msg`,添加降级方案 | ✅ 已完成 |
1272 +| 2026-02-11 | `src/pages/product-detail/index.vue`, `src/pages/search/index.vue`, `src/pages/product-center/index.vue`, `src/pages/index/index.vue` | 统一页面处理逻辑 | 修改所有页面的 `handlePlanSubmit` 函数,实现完整的错误处理和导航 | ✅ 已完成 |
1270 1273
1271 **接口状态**: ✅ 已完成 1274 **接口状态**: ✅ 已完成
1272 1275
......
...@@ -1001,6 +1001,71 @@ export async function fetchProductList(params) { ...@@ -1001,6 +1001,71 @@ export async function fetchProductList(params) {
1001 } 1001 }
1002 ``` 1002 ```
1003 1003
1004 +### ⚠️ 坑: API 成功验证需要检查状态码和必需字段 ⭐ 2026-02-11 新增
1005 +
1006 +**问题描述**:
1007 +
1008 +在计划书提交功能中,最初只检查 `res.code === 1` 来判断 API 调用是否成功,但这种方式不够严格。
1009 +
1010 +**错误代码**:
1011 +```javascript
1012 +// ❌ 只检查状态码
1013 +const res = await addAPI(requestData)
1014 +
1015 +if (res.code === 1) {
1016 + // 可能 res.data 为空或缺少必需字段
1017 + emit('submit', { success: true })
1018 +}
1019 +```
1020 +
1021 +**问题表现**:
1022 +- 即使 API 返回 `{ code: 1, data: null }`,也会判定为成功
1023 +- 缺少关键业务数据(如 `order_id`)时仍视为成功
1024 +- 后续流程可能因缺少必需数据而失败
1025 +
1026 +**正确做法**:
1027 +```javascript
1028 +// ✅ 同时检查状态码和必需字段
1029 +const res = await addAPI(requestData)
1030 +
1031 +// 判断成功:既要 code === 1,也要有 order_id
1032 +const isSuccess = res.code === 1 && res.data?.order_id
1033 +
1034 +if (isSuccess) {
1035 + emit('submit', {
1036 + success: true,
1037 + order_id: res.data.order_id // 确保必需字段存在
1038 + })
1039 +} else {
1040 + // 失败时,从 res.data.msg 或 res.msg 中获取错误信息
1041 + const errorMsg = res.data?.msg || res.msg || '提交失败,请稍后重试'
1042 + emit('submit', { success: false })
1043 +}
1044 +```
1045 +
1046 +**关键原则**:
1047 +1. ✅ **双重验证**:同时检查状态码(`code === 1`)和必需数据字段(如 `order_id`)
1048 +2. ✅ **字段验证**:对于业务关键接口,验证返回数据中是否包含必需字段
1049 +3. ✅ **错误信息路径**:优先从 `res.data.msg` 获取错误信息,其次才是 `res.msg`
1050 +4. ✅ **明确的数据契约**:在 API 文档中明确成功响应必须包含的字段
1051 +
1052 +**适用场景**:
1053 +- ✅ 提交类 API(订单提交、表单提交等)
1054 +- ✅ 创建类 API(创建计划书、创建收藏等)
1055 +- ✅ 任何返回业务数据标识符的接口(如 order_id、bill_id 等)
1056 +
1057 +**相关文件**:
1058 +- `src/components/plan/PlanFormContainer.vue:308-350` (已修复)
1059 +- `src/api/plan.js:27-33` (API 契约文档)
1060 +
1061 +**历史记录**:
1062 +- **第 1 次**:发现计划书提交逻辑只检查 `result.success`(接口未返回此字段)
1063 +- **第 2 次**:用户指出应该检查 `order_id` 字段
1064 +- **第 3 次**:发现错误信息路径应为 `res.data.msg` 而非 `res.data.message`
1065 +- **教训**: ⚠️ **API 成功验证必须检查状态码和必需业务字段**
1066 +
1067 +---
1068 +
1004 ### ❌ 坑: API 调用使用了 `fn()` 包装(重复 2 次) 1069 ### ❌ 坑: API 调用使用了 `fn()` 包装(重复 2 次)
1005 1070
1006 **问题描述**: 1071 **问题描述**:
......
...@@ -116,12 +116,21 @@ export function useFileOperation() { ...@@ -116,12 +116,21 @@ export function useFileOperation() {
116 showCopyButton = !!item.downloadUrl 116 showCopyButton = !!item.downloadUrl
117 } 117 }
118 118
119 - showModal({ 119 + // 构建 showModal 参数
120 + const modalParams = {
120 title: '提示', 121 title: '提示',
121 content: message + suggestion, 122 content: message + suggestion,
122 - confirmText: showCopyButton ? '复制链接' : '我知道了', 123 + confirmText: showCopyButton ? '复制链接' : '我知道了'
123 - cancelText: showCopyButton ? '关闭' : undefined, 124 + }
124 - showCancel: showCopyButton, 125 +
126 + // 只在有下载链接时才显示取消按钮
127 + if (showCopyButton) {
128 + modalParams.cancelText = '关闭'
129 + modalParams.showCancel = true
130 + }
131 +
132 + showModal({
133 + ...modalParams,
125 success: (modalRes) => { 134 success: (modalRes) => {
126 console.log('[文件操作] 用户选择:', modalRes.confirm ? '复制链接' : '关闭') 135 console.log('[文件操作] 用户选择:', modalRes.confirm ? '复制链接' : '关闭')
127 136
......