fix: 前端统一解析后端 detail 报错,杜绝 [object Object]
各处 catch 里直接 `toast(err?.response?.data?.detail ?? "xx失败")` 有坑: 请求体校验失败(422)时 detail 是数组,React 会把每个对象渲染成 [object Object]。 - utils/errorMessage.ts(新增): extractErrorMessage 统一解析三种形态 —— 字符串 / FastAPI 校验错误数组 / 对象;数组取 msg 并剥掉 Pydantic 的 "Value error, " 前缀、带上字段名、同字段去重后用「;」拼接;解析不出内容 则回落到调用方给的兜底文案。行为与移动端 extractErrorDetail 对齐 - 19 处调用点全部替换:AdminTasksPage(4) / AdminProductsPage(5) / TaskTreeViewer(4) / AdminPrintConfigPage(2) / ScanPage / CreateProductDialog / ImageUploader / authApi - TaskRejectPayload.images 与 taskApi.rejectTask 的注释同步为「选填,支持空数组」 - 新增 components/ui/ImageUploader.tsx(驳回弹窗选图上传组件), RejectModal 同步放开无图拦截:去掉 images 非空校验、提交按钮不再因 无图禁用、标签由必填星号改为「(选填,最多 9 张)」,并移除因此失效的 error 状态 - AdminTasksPage.tsx: 支持大屏下钻的 ?search / ?status / ?stage 预设参数, 新增「售后流转中」状态 Tab(按 lifecycle_phase 判定)与全局重置; ?stage 只在跳入时生效一次,用户手动改条件即解除锁定 - 杂项清理: TaskFlowView 移除透传的 assigneeNames、TaskListCard/MyTasksPage 移除未使用导入、QrScanner 关闭 verbose 日志
This commit is contained in:
@ -1,5 +1,6 @@
|
||||
/** 认证 API — 登录、刷新 Token、获取用户信息 */
|
||||
import type { UserInfo } from "../contexts/AuthContext";
|
||||
import { extractErrorMessage } from "../utils/errorMessage";
|
||||
|
||||
const API_BASE = import.meta.env.VITE_API_BASE_URL;
|
||||
|
||||
@ -23,7 +24,7 @@ export async function login(username: string, password: string): Promise<LoginRe
|
||||
});
|
||||
if (!res.ok) {
|
||||
const err = await res.json().catch(() => ({}));
|
||||
throw new Error((err as any).detail ?? "登录失败");
|
||||
throw new Error(extractErrorMessage(err, "登录失败"));
|
||||
}
|
||||
return res.json();
|
||||
}
|
||||
|
||||
@ -96,14 +96,17 @@ export async function receiveTask(taskId: string): Promise<TaskResponse> {
|
||||
/**
|
||||
* 品质驳回 — → REJECTED,后端自动创建返工任务。
|
||||
* 对应后端 POST /api/v1/tasks/{taskId}/reject
|
||||
*
|
||||
* images 为选填,支持空数组(编号错误、选错工序等场景无需拍照举证)。
|
||||
*/
|
||||
export async function rejectTask(
|
||||
taskId: string,
|
||||
reason: string
|
||||
reason: string,
|
||||
images: string[]
|
||||
): Promise<TaskResponse> {
|
||||
const { data } = await api.post<TaskResponse>(
|
||||
`/tasks/${taskId}/reject`,
|
||||
{ reason } satisfies TaskRejectPayload
|
||||
{ reason, images } satisfies TaskRejectPayload
|
||||
);
|
||||
return data;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user