import { useLocalStorage, createSharedComposable } from "@vueuse/core"; export type Item = { id: number; name: string; imageUrl?: string | null; description?: string | null; tags?: string[] | null; createdAt: Date; updatedAt: Date; }; const _useItems = () => { const stored = useLocalStorage("item-database", [], { serializer: { read: (v) => { if (!v) return []; const parsed = JSON.parse(v); return parsed.map((item: any) => ({ ...item, createdAt: new Date(item.createdAt), updatedAt: new Date(item.updatedAt), })); }, write: (v) => JSON.stringify(v), }, }); // 直接使用 stored(Ref)。模板会自动解包,其他逻辑也简单。 const items = stored; // Ref // 统计项使用 items.value const stats = { totalItems: computed(() => (items.value ?? []).length), addedThisMonth: computed(() => { const now = new Date(); const thisMonth = now.getMonth(); const thisYear = now.getFullYear(); return (items.value ?? []).filter( (item) => item.createdAt.getMonth() === thisMonth && item.createdAt.getFullYear() === thisYear ).length; }), latestId: computed(() => { const arr = items.value ?? []; if (arr.length === 0) return 1; return Math.max(...arr.map((i) => i.id)) + 1; }), }; const isNameAvailable = (name: string) => !(items.value ?? []).some((item) => item.name === name); const addItem = (item: Item) => { items.value = [...(items.value ?? []), item]; // <-- 替换数组引用 }; const editItem = (item: Item) => { const index = (items.value ?? []).findIndex((i) => i.id === item.id); if (index === -1) return; // 未找到则直接返回 // 生成一个新的数组(保持响应式) const updatedItems = [...(items.value ?? [])]; updatedItems[index] = { ...updatedItems[index], ...item, updatedAt: new Date(), // 自动更新时间戳 }; items.value = updatedItems; // 替换引用,触发 UI 更新 }; const removeItem = (id: number) => { items.value = (items.value ?? []).filter((i) => i.id !== id); // <-- 替换数组引用 }; return { items, stats, isNameAvailable, addItem, editItem, removeItem }; }; export const useItemsStore = createSharedComposable(_useItems);