120 lines
4.1 KiB
TypeScript
120 lines
4.1 KiB
TypeScript
'use client';
|
|
import { create } from 'zustand';
|
|
import type { Bug, BugStatus, BugLog } from '@/lib/bug';
|
|
import { generateBugNo } from '@/lib/bug';
|
|
import { applyBugTransition } from '@/lib/bug-workflow';
|
|
import { loadServerData, saveServerData } from '@/lib/server-data';
|
|
import {
|
|
makeBugCreatedActivity,
|
|
makeBugStatusActivity,
|
|
makeBugTransferredActivity,
|
|
} from '@/lib/work-activity-factory';
|
|
import { useWorkActivityStore } from './useWorkActivityStore';
|
|
|
|
function saveStored(items: Bug[]) {
|
|
saveServerData('bugs', items).catch(() => {});
|
|
}
|
|
|
|
async function loadStored(): Promise<Bug[] | null> {
|
|
try {
|
|
return await loadServerData<Bug[]>('bugs');
|
|
} catch {}
|
|
return null;
|
|
}
|
|
|
|
function makeLog(action: BugLog['action'], operator: string, from?: string, to?: string, remark?: string): BugLog {
|
|
return { id: `log-${Date.now()}-${Math.random().toString(36).slice(2, 6)}`, action, fromValue: from, toValue: to, operator, remark, createdAt: new Date().toISOString() };
|
|
}
|
|
|
|
interface BugState {
|
|
bugs: Bug[];
|
|
fetchBugs: () => Promise<void>;
|
|
createBug: (data: Omit<Bug, 'id' | 'bugNo' | 'createdAt' | 'updatedAt' | 'status' | 'logs'>, operator: string) => Bug;
|
|
updateBug: (id: string, data: Partial<Bug>) => void;
|
|
deleteBug: (id: string) => void;
|
|
changeStatus: (id: string, to: BugStatus, operator: string, extra?: { resolution?: string }) => { ok: boolean; message?: string };
|
|
transferBug: (id: string, newAssigneeId: string, operator: string, remark?: string) => { ok: boolean; message?: string };
|
|
getByTestCase: (caseId: string) => Bug[];
|
|
getByVersion: (versionId: string) => Bug[];
|
|
getByAssignee: (assigneeId: string) => Bug[];
|
|
}
|
|
|
|
export const useBugStore = create<BugState>((set, get) => ({
|
|
bugs: [],
|
|
|
|
fetchBugs: async () => {
|
|
const cached = await loadStored();
|
|
if (cached) set({ bugs: cached });
|
|
},
|
|
|
|
createBug: (data, operator) => {
|
|
const list = get().bugs;
|
|
const now = new Date().toISOString();
|
|
const log = makeLog('create', operator);
|
|
const bug: Bug = {
|
|
...data,
|
|
id: `bug-${Date.now()}`,
|
|
bugNo: generateBugNo(list),
|
|
status: 'open',
|
|
logs: [log],
|
|
createdAt: now,
|
|
updatedAt: now,
|
|
};
|
|
const updated = [...list, bug];
|
|
set({ bugs: updated });
|
|
saveStored(updated);
|
|
useWorkActivityStore.getState().addActivity(makeBugCreatedActivity(bug, operator));
|
|
return bug;
|
|
},
|
|
|
|
updateBug: (id, data) => {
|
|
const updated = get().bugs.map((b) =>
|
|
b.id === id ? { ...b, ...data, updatedAt: new Date().toISOString() } : b,
|
|
);
|
|
set({ bugs: updated });
|
|
saveStored(updated);
|
|
},
|
|
|
|
deleteBug: (id) => {
|
|
const updated = get().bugs.filter((b) => b.id !== id);
|
|
set({ bugs: updated });
|
|
saveStored(updated);
|
|
},
|
|
|
|
changeStatus: (id, to, operator, extra) => {
|
|
const bug = get().bugs.find((b) => b.id === id);
|
|
if (!bug) return { ok: false, message: 'Bug不存在' };
|
|
const result = applyBugTransition(bug, to, operator, {
|
|
now: new Date(),
|
|
resolution: extra?.resolution,
|
|
});
|
|
if (!result.ok || !result.patch) return { ok: false, message: result.message };
|
|
get().updateBug(id, result.patch);
|
|
const activity = makeBugStatusActivity(bug, bug.status, to, operator);
|
|
if (activity) useWorkActivityStore.getState().addActivity(activity);
|
|
return { ok: true };
|
|
},
|
|
|
|
transferBug: (id, newAssigneeId, operator, remark) => {
|
|
const bug = get().bugs.find((b) => b.id === id);
|
|
if (!bug) return { ok: false, message: 'Bug不存在' };
|
|
if (bug.assigneeId === newAssigneeId) return { ok: false, message: '已是当前负责人' };
|
|
const log = makeLog('transfer', operator, bug.assigneeId, newAssigneeId, remark);
|
|
get().updateBug(id, { assigneeId: newAssigneeId, logs: [...(bug.logs || []), log] });
|
|
useWorkActivityStore.getState().addActivity(makeBugTransferredActivity(bug, operator, newAssigneeId));
|
|
return { ok: true };
|
|
},
|
|
|
|
getByTestCase: (caseId) => {
|
|
return get().bugs.filter((b) => b.testCaseId === caseId);
|
|
},
|
|
|
|
getByVersion: (versionId) => {
|
|
return get().bugs.filter((b) => b.versionId === versionId);
|
|
},
|
|
|
|
getByAssignee: (assigneeId) => {
|
|
return get().bugs.filter((b) => b.assigneeId === assigneeId);
|
|
},
|
|
}));
|