feat(product): 实现产品需求管理模块(后端 + 前端)
后端:Product Module(CRUD)、Requirement Module(CRUD + 状态机流转)、PrismaService 前端:产品列表页、产品详情页(含需求池 Tab)、Zustand Store、API 封装 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
66
apps/web/stores/useRequirementStore.ts
Normal file
66
apps/web/stores/useRequirementStore.ts
Normal file
@@ -0,0 +1,66 @@
|
||||
'use client';
|
||||
|
||||
import { create } from 'zustand';
|
||||
import { Requirement, RequirementStatus } from '@ftb/shared';
|
||||
import { api } from '@/lib/api';
|
||||
|
||||
interface RequirementWithCreator extends Requirement {
|
||||
creator?: { id: string; name: string };
|
||||
}
|
||||
|
||||
interface RequirementState {
|
||||
requirements: RequirementWithCreator[];
|
||||
loading: boolean;
|
||||
error: string | null;
|
||||
statusFilter: RequirementStatus | null;
|
||||
fetchRequirements: (productId: string, status?: RequirementStatus) => Promise<void>;
|
||||
createRequirement: (productId: string, data: { title: string; description?: string; priority?: number; creatorId: string }) => Promise<void>;
|
||||
updateRequirement: (productId: string, id: string, data: { title?: string; description?: string; priority?: number }) => Promise<void>;
|
||||
updateStatus: (productId: string, id: string, status: RequirementStatus) => Promise<void>;
|
||||
deleteRequirement: (productId: string, id: string) => Promise<void>;
|
||||
setStatusFilter: (status: RequirementStatus | null) => void;
|
||||
}
|
||||
|
||||
export const useRequirementStore = create<RequirementState>((set, get) => ({
|
||||
requirements: [],
|
||||
loading: false,
|
||||
error: null,
|
||||
statusFilter: null,
|
||||
|
||||
fetchRequirements: async (productId, status) => {
|
||||
set({ loading: true, error: null });
|
||||
try {
|
||||
const query = status ? `?status=${status}` : '';
|
||||
const requirements = await api.get<RequirementWithCreator[]>(
|
||||
`/products/${productId}/requirements${query}`,
|
||||
);
|
||||
set({ requirements, loading: false });
|
||||
} catch (e: any) {
|
||||
set({ error: e.message, loading: false });
|
||||
}
|
||||
},
|
||||
|
||||
createRequirement: async (productId, data) => {
|
||||
await api.post(`/products/${productId}/requirements`, data);
|
||||
await get().fetchRequirements(productId, get().statusFilter || undefined);
|
||||
},
|
||||
|
||||
updateRequirement: async (productId, id, data) => {
|
||||
await api.patch(`/products/${productId}/requirements/${id}`, data);
|
||||
await get().fetchRequirements(productId, get().statusFilter || undefined);
|
||||
},
|
||||
|
||||
updateStatus: async (productId, id, status) => {
|
||||
await api.patch(`/products/${productId}/requirements/${id}/status`, { status });
|
||||
await get().fetchRequirements(productId, get().statusFilter || undefined);
|
||||
},
|
||||
|
||||
deleteRequirement: async (productId, id) => {
|
||||
await api.delete(`/products/${productId}/requirements/${id}`);
|
||||
set({ requirements: get().requirements.filter((r) => r.id !== id) });
|
||||
},
|
||||
|
||||
setStatusFilter: (status) => {
|
||||
set({ statusFilter: status });
|
||||
},
|
||||
}));
|
||||
Reference in New Issue
Block a user