'use client'; import { create } from 'zustand'; import type { TestCase, TestCaseStatus } from '@/lib/test-case'; import { generateCaseNo, normalizeTestCases } from '@/lib/test-case'; import { applyTestCaseTransition, normalizeTestCaseOnCreate } from '@/lib/test-case-workflow'; import { createEntityId, dedupeEntityIds } from '@/lib/entity-id'; import { loadServerData, saveServerData } from '@/lib/server-data'; function saveStored(items: TestCase[]) { saveServerData('test-cases', items).catch(() => {}); } async function loadStored(): Promise { try { return await loadServerData('test-cases'); } catch {} return null; } interface TestCaseState { testCases: TestCase[]; fetchTestCases: () => Promise; createTestCase: (data: Omit) => TestCase; updateTestCase: (id: string, data: Partial) => void; deleteTestCase: (id: string) => void; changeStatus: (id: string, to: TestCaseStatus, extra?: { failReason?: string; blockReason?: string }) => { ok: boolean; message?: string }; getByRequirement: (reqId: string) => TestCase[]; getByVersion: (versionId: string) => TestCase[]; getByAssignee: (assigneeId: string) => TestCase[]; } export const useTestCaseStore = create((set, get) => ({ testCases: [], fetchTestCases: async () => { const cached = await loadStored(); if (cached) { const result = dedupeEntityIds(normalizeTestCases(cached), 'tc'); if (result.changed) saveStored(result.items); set({ testCases: result.items }); } }, createTestCase: (data) => { const list = get().testCases; const now = new Date().toISOString(); const tc: TestCase = normalizeTestCaseOnCreate({ ...data, id: createEntityId('tc'), caseNo: generateCaseNo(list), status: 'pending', estimateHours: data.estimateHours ?? 0.5, createdAt: now, updatedAt: now, } as TestCase); const updated = [...list, tc]; set({ testCases: updated }); saveStored(updated); return tc; }, updateTestCase: (id, data) => { const updated = get().testCases.map((c) => c.id === id ? { ...c, ...data, aiDraft: false, updatedAt: new Date().toISOString() } : c, ); set({ testCases: updated }); saveStored(updated); }, deleteTestCase: (id) => { const updated = get().testCases.filter((c) => c.id !== id); set({ testCases: updated }); saveStored(updated); }, changeStatus: (id, to, extra) => { const tc = get().testCases.find((c) => c.id === id); if (!tc) return { ok: false, message: '用例不存在' }; const result = applyTestCaseTransition(tc, to, { now: new Date(), failReason: extra?.failReason, blockReason: extra?.blockReason, }); if (!result.ok || !result.patch) return { ok: false, message: result.message }; get().updateTestCase(id, result.patch); return { ok: true }; }, getByRequirement: (reqId) => { return get().testCases.filter((c) => c.requirementId === reqId); }, getByVersion: (versionId) => { return get().testCases.filter((c) => c.versionId === versionId); }, getByAssignee: (assigneeId) => { return get().testCases.filter((c) => c.assigneeId === assigneeId); }, }));