feat(v2.4): 切换需求池领域主写
This commit is contained in:
@@ -3,6 +3,12 @@
|
||||
import { create } from 'zustand';
|
||||
import type { Requirement, RequirementStatus, Effort, DictItem, SourceType, SourceTarget } from '@/lib/requirement';
|
||||
import type { Priority } from '@/lib/derive';
|
||||
import {
|
||||
createRequirementByProductId,
|
||||
deleteRequirementByProductId,
|
||||
updateRequirementByProductId,
|
||||
updateRequirementStatusByProductId,
|
||||
} from '@/lib/domain-api';
|
||||
import { scheduleSaveWithOptimisticRollback } from '@/lib/optimistic-persistence';
|
||||
import { loadServerData, saveServerData, SERVER_DATA_CACHE_MS } from '@/lib/server-data';
|
||||
|
||||
@@ -16,7 +22,7 @@ interface RequirementState {
|
||||
fetchRequirements: (options?: { force?: boolean }) => Promise<void>;
|
||||
createRequirement: (data: Omit<Requirement, 'id' | 'code' | 'createdAt'>) => void;
|
||||
updateRequirement: (id: string, data: Partial<Requirement>) => void;
|
||||
deleteRequirement: (id: string) => void;
|
||||
deleteRequirement: (id: string, productId?: string) => void;
|
||||
addSourceTarget: (name: string, sourceType: SourceType) => void;
|
||||
updateSourceTarget: (id: string, name: string) => void;
|
||||
deleteSourceTarget: (id: string) => void;
|
||||
@@ -99,7 +105,19 @@ export const useRequirementStore = create<RequirementState>((set, get) => {
|
||||
const updated = [...requirements, newReq];
|
||||
set({ requirements: updated, loaded: true });
|
||||
scheduleSaveWithOptimisticRollback({
|
||||
save: () => saveServerData('requirements', { requirements: updated, sourceTargets, types, platforms }),
|
||||
save: async () => {
|
||||
try {
|
||||
const created = await createRequirementByProductId(newReq.productId, newReq);
|
||||
set({
|
||||
requirements: get().requirements.map((item) => (
|
||||
item.id === newReq.id ? { ...created, creator: newReq.creator || created.creator } : item
|
||||
)),
|
||||
loaded: true,
|
||||
});
|
||||
} catch {
|
||||
await saveRequirementsFallback({ requirements: updated, sourceTargets, types, platforms });
|
||||
}
|
||||
},
|
||||
expected: updated,
|
||||
getCurrent: () => get().requirements,
|
||||
rollback: () => set({ requirements, loaded: true }),
|
||||
@@ -108,22 +126,50 @@ export const useRequirementStore = create<RequirementState>((set, get) => {
|
||||
|
||||
updateRequirement: (id, data) => {
|
||||
const { requirements, sourceTargets, types, platforms } = get();
|
||||
const current = requirements.find((r) => r.id === id);
|
||||
const productId = data.productId ?? current?.productId;
|
||||
const updated = requirements.map((r) => (r.id === id ? { ...r, ...data } : r));
|
||||
set({ requirements: updated, loaded: true });
|
||||
scheduleSaveWithOptimisticRollback({
|
||||
save: () => saveServerData('requirements', { requirements: updated, sourceTargets, types, platforms }),
|
||||
save: async () => {
|
||||
try {
|
||||
if (!productId) throw new Error('missing requirement productId');
|
||||
const domainPatch = { ...data };
|
||||
const status = domainPatch.status;
|
||||
delete domainPatch.status;
|
||||
delete domainPatch.productId;
|
||||
delete domainPatch.productOwner;
|
||||
delete domainPatch.addedToVersionBy;
|
||||
if (hasDomainPatch(domainPatch)) {
|
||||
await updateRequirementByProductId(productId, id, domainPatch);
|
||||
}
|
||||
if (status) {
|
||||
await updateRequirementStatusByProductId(productId, id, status);
|
||||
}
|
||||
} catch {
|
||||
await saveRequirementsFallback({ requirements: updated, sourceTargets, types, platforms });
|
||||
}
|
||||
},
|
||||
expected: updated,
|
||||
getCurrent: () => get().requirements,
|
||||
rollback: () => set({ requirements, loaded: true }),
|
||||
});
|
||||
},
|
||||
|
||||
deleteRequirement: (id) => {
|
||||
deleteRequirement: (id, scopedProductId) => {
|
||||
const { requirements, sourceTargets, types, platforms } = get();
|
||||
const productId = scopedProductId ?? requirements.find((r) => r.id === id)?.productId;
|
||||
const updated = requirements.filter((r) => r.id !== id);
|
||||
set({ requirements: updated, loaded: true });
|
||||
scheduleSaveWithOptimisticRollback({
|
||||
save: () => saveServerData('requirements', { requirements: updated, sourceTargets, types, platforms }),
|
||||
save: async () => {
|
||||
try {
|
||||
if (!productId) throw new Error('missing requirement productId');
|
||||
await deleteRequirementByProductId(productId, id);
|
||||
} catch {
|
||||
await saveRequirementsFallback({ requirements: updated, sourceTargets, types, platforms });
|
||||
}
|
||||
},
|
||||
expected: updated,
|
||||
getCurrent: () => get().requirements,
|
||||
rollback: () => set({ requirements, loaded: true }),
|
||||
@@ -245,3 +291,16 @@ export const useRequirementStore = create<RequirementState>((set, get) => {
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
async function saveRequirementsFallback(data: {
|
||||
requirements: Requirement[];
|
||||
sourceTargets: SourceTarget[];
|
||||
types: DictItem[];
|
||||
platforms: DictItem[];
|
||||
}) {
|
||||
await saveServerData('requirements', data);
|
||||
}
|
||||
|
||||
function hasDomainPatch(data: Partial<Requirement>) {
|
||||
return Object.values(data).some((value) => value !== undefined);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user