R31-1 R31-4: 收口详情页工作台化与 E2E 契约

这个提交包含在:
2026-03-24 08:58:36 +08:00
父节点 994d98e74c
当前提交 279be83931
共修改 17 个文件,包含 906 行新增和 455 行删除
+11 -4
查看文件
@@ -12,6 +12,7 @@ import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from ".
import { toast } from "sonner";
import { isApiError } from "../api/types";
import { mapApiErrorMessage } from "../api/errorMessages";
import { TEST_IDS } from "../lib/testIds";
function errorMessage(error: unknown, fallback: string) {
if (isApiError(error)) {
@@ -140,7 +141,7 @@ export function TodosPage() {
</TableRow>
) : todoItems.length ? (
todoItems.map((item) => (
<TableRow key={item.id}>
<TableRow data-testid={TEST_IDS.todo.row} key={item.id}>
<TableCell>
<div className="font-medium text-zinc-900">{item.title}</div>
<div className="text-xs text-zinc-500">{item.description ?? "-"}</div>
@@ -151,7 +152,13 @@ export function TodosPage() {
<TableCell>{item.status}</TableCell>
<TableCell>
<div className="flex gap-2">
<Button size="sm" type="button" disabled={completeMutation.isPending || item.status === "done"} onClick={() => completeMutation.mutate(item.id)}>
<Button
data-testid={TEST_IDS.todo.complete}
size="sm"
type="button"
disabled={completeMutation.isPending || item.status === "done"}
onClick={() => completeMutation.mutate(item.id)}
>
完成
</Button>
<Button size="sm" variant="secondary" type="button" disabled={cancelMutation.isPending || item.status === "cancelled"} onClick={() => cancelMutation.mutate(item.id)}>
@@ -177,7 +184,7 @@ export function TodosPage() {
<SectionPanel title="新增待办" description="建议把周报计划、项目跟进或临时事项都拆成清晰动作。">
<div className="space-y-4">
<div className="space-y-2">
<Input placeholder="待办标题" value={title} onChange={(event) => setTitle(event.target.value)} />
<Input data-testid={TEST_IDS.todo.createTitle} placeholder="待办标题" value={title} onChange={(event) => setTitle(event.target.value)} />
</div>
<div className="space-y-2">
<Input placeholder="补充说明(可选)" value={description} onChange={(event) => setDescription(event.target.value)} />
@@ -192,7 +199,7 @@ export function TodosPage() {
))}
</select>
</div>
<Button type="button" onClick={() => createMutation.mutate()} disabled={createMutation.isPending || !title.trim()}>
<Button data-testid={TEST_IDS.todo.createSubmit} type="button" onClick={() => createMutation.mutate()} disabled={createMutation.isPending || !title.trim()}>
{createMutation.isPending ? "新建中..." : "新建待办"}
</Button>
</div>