feat(平台): 补齐服务端持久化和AI拆解契约
This commit is contained in:
@@ -3,6 +3,7 @@
|
||||
import { create } from 'zustand';
|
||||
import type { Requirement, RequirementStatus, Effort, DictItem, SourceType, SourceTarget } from '@/lib/requirement';
|
||||
import type { Priority } from '@/lib/derive';
|
||||
import { loadServerData, saveServerData } from '@/lib/server-data';
|
||||
|
||||
interface RequirementState {
|
||||
requirements: Requirement[];
|
||||
@@ -10,7 +11,7 @@ interface RequirementState {
|
||||
types: DictItem[];
|
||||
platforms: DictItem[];
|
||||
loading: boolean;
|
||||
fetchRequirements: () => void;
|
||||
fetchRequirements: () => Promise<void>;
|
||||
createRequirement: (data: Omit<Requirement, 'id' | 'code' | 'createdAt'>) => void;
|
||||
updateRequirement: (id: string, data: Partial<Requirement>) => void;
|
||||
deleteRequirement: (id: string) => void;
|
||||
@@ -50,33 +51,17 @@ const PRESET_PLATFORMS: DictItem[] = [
|
||||
|
||||
// --- Mock requirements ---
|
||||
|
||||
const MOCK_REQUIREMENTS: Requirement[] = [
|
||||
{ id: 'req-1', code: 'REQ-001', title: '值班排班自动生成', description: '根据员工可用时间自动排班,支持轮换规则', productId: 'mock-1', projectId: 'p3', status: 'pending_review', priority: 'P1', effort: 'L', sourceType: 'internal', sourceTarget: '运营部', platforms: ['platform-1'], typeId: 'type-1', creator: '张三', createdAt: '2024-06-01' },
|
||||
{ id: 'req-2', code: 'REQ-002', title: '值班交接确认', description: '交接班时双方确认签到,记录交接内容', productId: 'mock-1', projectId: 'p3', status: 'pending_review', priority: 'P1', effort: 'M', sourceType: 'internal', sourceTarget: '门店经理', platforms: ['platform-1'], typeId: 'type-1', creator: '张三', createdAt: '2024-06-01' },
|
||||
{ id: 'req-3', code: 'REQ-003', title: '值班异常提醒', description: '迟到、缺勤自动推送提醒给店长', productId: 'mock-1', projectId: 'p3', status: 'pending_review', priority: 'P0', effort: 'M', sourceType: 'customer', sourceTarget: '连锁品牌A', platforms: ['platform-1', 'platform-2'], typeId: 'type-1', creator: '李四', createdAt: '2024-06-02' },
|
||||
{ id: 'req-4', code: 'REQ-004', title: '值班日历视图', description: '以日历形式展示当月值班安排', productId: 'mock-1', projectId: 'p3', status: 'pending_review', priority: 'P2', effort: 'L', sourceType: 'internal', sourceTarget: '产品部', platforms: ['platform-1'], typeId: 'type-2', creator: '张三', createdAt: '2024-06-03' },
|
||||
{ id: 'req-5', code: 'REQ-005', title: '值班换班申请', description: '员工可发起换班申请,经理审批', productId: 'mock-1', projectId: 'p3', status: 'pending_review', priority: 'P2', effort: 'M', sourceType: 'customer', sourceTarget: '连锁品牌B', platforms: ['platform-1'], typeId: 'type-1', creator: '李四', createdAt: '2024-06-03' },
|
||||
{ id: 'req-6', code: 'REQ-006', title: '值班统计报表', description: '按月/周统计各员工值班时长、缺勤次数', productId: 'mock-1', projectId: 'p3', status: 'pending_review', priority: 'P2', effort: 'L', sourceType: 'internal', sourceTarget: '运营部', platforms: ['platform-1'], typeId: 'type-3', creator: '张三', createdAt: '2024-06-04' },
|
||||
{ id: 'req-7', code: 'REQ-007', title: '多门店值班管理', description: '区域经理可查看管辖所有门店值班情况', productId: 'mock-1', projectId: 'p3', status: 'pending_review', priority: 'P1', effort: 'XL', sourceType: 'management', sourceTarget: '区域总监', platforms: ['platform-1', 'platform-3'], typeId: 'type-1', creator: '张三', createdAt: '2024-06-05' },
|
||||
{ id: 'req-8', code: 'REQ-008', title: '值班备注功能', description: '排班时可添加备注(如特殊事项提醒)', productId: 'mock-1', projectId: 'p3', status: 'pending_review', priority: 'P3', effort: 'S', sourceType: 'internal', sourceTarget: '产品部', platforms: ['platform-1'], typeId: 'type-2', creator: '李四', createdAt: '2024-06-05' },
|
||||
{ id: 'req-9', code: 'REQ-009', title: '法定节假日排班规则', description: '节假日自动应用特殊排班规则(加班费标记)', productId: 'mock-1', projectId: 'p3', status: 'pending_review', priority: 'P1', effort: 'M', sourceType: 'operation', sourceTarget: '合规部', platforms: ['platform-1'], typeId: 'type-1', creator: '张三', createdAt: '2024-06-06' },
|
||||
{ id: 'req-10', code: 'REQ-010', title: '值班模板管理', description: '创建值班模板供快速复用(如早中晚三班)', productId: 'mock-1', projectId: 'p3', status: 'pending_review', priority: 'P2', effort: 'M', sourceType: 'internal', sourceTarget: '产品部', platforms: ['platform-1'], typeId: 'type-1', creator: '张三', createdAt: '2024-06-06' },
|
||||
];
|
||||
const MOCK_REQUIREMENTS: Requirement[] = [];
|
||||
|
||||
// --- localStorage helpers ---
|
||||
// --- Server persistence helpers ---
|
||||
|
||||
const STORAGE_KEY = 'ftb_requirements_v3';
|
||||
|
||||
function saveLocal(state: { requirements: Requirement[]; sourceTargets: SourceTarget[]; types: DictItem[]; platforms: DictItem[] }) {
|
||||
try {
|
||||
localStorage.setItem(STORAGE_KEY, JSON.stringify(state));
|
||||
} catch {}
|
||||
function saveStored(state: { requirements: Requirement[]; sourceTargets: SourceTarget[]; types: DictItem[]; platforms: DictItem[] }) {
|
||||
saveServerData('requirements', state).catch(() => {});
|
||||
}
|
||||
|
||||
function loadLocal(): { requirements: Requirement[]; sourceTargets: SourceTarget[]; types: DictItem[]; platforms: DictItem[] } | null {
|
||||
async function loadStored(): Promise<{ requirements: Requirement[]; sourceTargets: SourceTarget[]; types: DictItem[]; platforms: DictItem[] } | null> {
|
||||
try {
|
||||
const raw = localStorage.getItem(STORAGE_KEY);
|
||||
if (raw) return JSON.parse(raw);
|
||||
return await loadServerData<{ requirements: Requirement[]; sourceTargets: SourceTarget[]; types: DictItem[]; platforms: DictItem[] }>('requirements');
|
||||
} catch {}
|
||||
return null;
|
||||
}
|
||||
@@ -91,8 +76,8 @@ export const useRequirementStore = create<RequirementState>((set, get) => {
|
||||
platforms: PRESET_PLATFORMS,
|
||||
loading: false,
|
||||
|
||||
fetchRequirements: () => {
|
||||
const cached = loadLocal();
|
||||
fetchRequirements: async () => {
|
||||
const cached = await loadStored();
|
||||
if (cached) {
|
||||
set({ requirements: cached.requirements, sourceTargets: cached.sourceTargets, types: cached.types, platforms: cached.platforms });
|
||||
}
|
||||
@@ -110,21 +95,21 @@ export const useRequirementStore = create<RequirementState>((set, get) => {
|
||||
};
|
||||
const updated = [...requirements, newReq];
|
||||
set({ requirements: updated });
|
||||
saveLocal({ requirements: updated, sourceTargets, types, platforms });
|
||||
saveStored({ requirements: updated, sourceTargets, types, platforms });
|
||||
},
|
||||
|
||||
updateRequirement: (id, data) => {
|
||||
const { requirements, sourceTargets, types, platforms } = get();
|
||||
const updated = requirements.map((r) => (r.id === id ? { ...r, ...data } : r));
|
||||
set({ requirements: updated });
|
||||
saveLocal({ requirements: updated, sourceTargets, types, platforms });
|
||||
saveStored({ requirements: updated, sourceTargets, types, platforms });
|
||||
},
|
||||
|
||||
deleteRequirement: (id) => {
|
||||
const { requirements, sourceTargets, types, platforms } = get();
|
||||
const updated = requirements.filter((r) => r.id !== id);
|
||||
set({ requirements: updated });
|
||||
saveLocal({ requirements: updated, sourceTargets, types, platforms });
|
||||
saveStored({ requirements: updated, sourceTargets, types, platforms });
|
||||
},
|
||||
|
||||
// --- SourceTarget dict ---
|
||||
@@ -133,21 +118,21 @@ export const useRequirementStore = create<RequirementState>((set, get) => {
|
||||
const item: SourceTarget = { id: `st-${Date.now()}`, name, sourceType, createdAt: new Date().toISOString().slice(0, 10) };
|
||||
const updated = [...sourceTargets, item];
|
||||
set({ sourceTargets: updated });
|
||||
saveLocal({ requirements, sourceTargets: updated, types, platforms });
|
||||
saveStored({ requirements, sourceTargets: updated, types, platforms });
|
||||
},
|
||||
|
||||
updateSourceTarget: (id, name) => {
|
||||
const { requirements, sourceTargets, types, platforms } = get();
|
||||
const updated = sourceTargets.map((s) => (s.id === id ? { ...s, name } : s));
|
||||
set({ sourceTargets: updated });
|
||||
saveLocal({ requirements, sourceTargets: updated, types, platforms });
|
||||
saveStored({ requirements, sourceTargets: updated, types, platforms });
|
||||
},
|
||||
|
||||
deleteSourceTarget: (id) => {
|
||||
const { requirements, sourceTargets, types, platforms } = get();
|
||||
const updated = sourceTargets.filter((s) => s.id !== id);
|
||||
set({ sourceTargets: updated });
|
||||
saveLocal({ requirements, sourceTargets: updated, types, platforms });
|
||||
saveStored({ requirements, sourceTargets: updated, types, platforms });
|
||||
},
|
||||
|
||||
// --- Type dict ---
|
||||
@@ -156,21 +141,21 @@ export const useRequirementStore = create<RequirementState>((set, get) => {
|
||||
const item: DictItem = { id: `type-${Date.now()}`, name, createdAt: new Date().toISOString().slice(0, 10) };
|
||||
const updated = [...types, item];
|
||||
set({ types: updated });
|
||||
saveLocal({ requirements, sourceTargets, types: updated, platforms });
|
||||
saveStored({ requirements, sourceTargets, types: updated, platforms });
|
||||
},
|
||||
|
||||
updateType: (id, name) => {
|
||||
const { requirements, sourceTargets, types, platforms } = get();
|
||||
const updated = types.map((t) => (t.id === id ? { ...t, name } : t));
|
||||
set({ types: updated });
|
||||
saveLocal({ requirements, sourceTargets, types: updated, platforms });
|
||||
saveStored({ requirements, sourceTargets, types: updated, platforms });
|
||||
},
|
||||
|
||||
deleteType: (id) => {
|
||||
const { requirements, sourceTargets, types, platforms } = get();
|
||||
const updated = types.filter((t) => t.id !== id);
|
||||
set({ types: updated });
|
||||
saveLocal({ requirements, sourceTargets, types: updated, platforms });
|
||||
saveStored({ requirements, sourceTargets, types: updated, platforms });
|
||||
},
|
||||
|
||||
// --- Platform dict ---
|
||||
@@ -179,21 +164,21 @@ export const useRequirementStore = create<RequirementState>((set, get) => {
|
||||
const item: DictItem = { id: `platform-${Date.now()}`, name, createdAt: new Date().toISOString().slice(0, 10) };
|
||||
const updated = [...platforms, item];
|
||||
set({ platforms: updated });
|
||||
saveLocal({ requirements, sourceTargets, types, platforms: updated });
|
||||
saveStored({ requirements, sourceTargets, types, platforms: updated });
|
||||
},
|
||||
|
||||
updatePlatform: (id, name) => {
|
||||
const { requirements, sourceTargets, types, platforms } = get();
|
||||
const updated = platforms.map((p) => (p.id === id ? { ...p, name } : p));
|
||||
set({ platforms: updated });
|
||||
saveLocal({ requirements, sourceTargets, types, platforms: updated });
|
||||
saveStored({ requirements, sourceTargets, types, platforms: updated });
|
||||
},
|
||||
|
||||
deletePlatform: (id) => {
|
||||
const { requirements, sourceTargets, types, platforms } = get();
|
||||
const updated = platforms.filter((p) => p.id !== id);
|
||||
set({ platforms: updated });
|
||||
saveLocal({ requirements, sourceTargets, types, platforms: updated });
|
||||
saveStored({ requirements, sourceTargets, types, platforms: updated });
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user