diff --git a/app/components/item/DeleteModal.vue b/app/components/item/DeleteModal.vue new file mode 100644 index 0000000..5fcd2fc --- /dev/null +++ b/app/components/item/DeleteModal.vue @@ -0,0 +1,53 @@ + + + + + diff --git a/app/components/item/AddModal.vue b/app/components/item/EditModal.vue similarity index 100% rename from app/components/item/AddModal.vue rename to app/components/item/EditModal.vue diff --git a/app/composables/items.ts b/app/composables/items.ts index d39c68b..e822d9f 100644 --- a/app/composables/items.ts +++ b/app/composables/items.ts @@ -1,6 +1,5 @@ import { useLocalStorage, createSharedComposable } from "@vueuse/core"; -// 类型定义 export type Item = { id: number; name: string; @@ -12,9 +11,10 @@ export type Item = { }; const _useItems = () => { - const items = useLocalStorage("item-database", [], { + const stored = useLocalStorage("item-database", [], { serializer: { read: (v) => { + if (!v) return []; const parsed = JSON.parse(v); return parsed.map((item: any) => ({ ...item, @@ -26,34 +26,37 @@ const _useItems = () => { }, }); + // 直接使用 stored(Ref)。模板会自动解包,其他逻辑也简单。 + const items = stored; // Ref + + // 统计项使用 items.value const stats = { - totalItems: computed(() => items.value.length), + totalItems: computed(() => (items.value ?? []).length), addedThisMonth: computed(() => { const now = new Date(); const thisMonth = now.getMonth(); const thisYear = now.getFullYear(); - - let count = 0; - for (const item of items.value) { - const date = item.createdAt; - if (date.getMonth() === thisMonth && date.getFullYear() === thisYear) { - count++; - } - } - return count; + return (items.value ?? []).filter( + (item) => + item.createdAt.getMonth() === thisMonth && + item.createdAt.getFullYear() === thisYear + ).length; }), latestId: computed( - () => (items.value[items.value.length - 1]?.id ?? 0) + 1 + () => (items.value?.[items.value.length - 1]?.id ?? 0) + 1 ), }; const isNameAvailable = (name: string) => - !items.value.some((item) => item.name === name); + !(items.value ?? []).some((item) => item.name === name); - const addItem = (item: Item) => items.value.push(item); + const addItem = (item: Item) => { + items.value = [...(items.value ?? []), item]; // <-- 替换数组引用 + }; - const removeItem = (id: number) => - (items.value = items.value.filter((i) => i.id !== id)); + const removeItem = (id: number) => { + items.value = (items.value ?? []).filter((i) => i.id !== id); // <-- 替换数组引用 + }; return { items, stats, isNameAvailable, addItem, removeItem }; }; diff --git a/app/layouts/default.vue b/app/layouts/default.vue index 5366a0a..3ab660b 100644 --- a/app/layouts/default.vue +++ b/app/layouts/default.vue @@ -36,7 +36,7 @@ const items = computed(() => [ { label: "物品管理", to: "/", - icon: "marketeq:home-alt-3", + icon: "marketeq:box", }, { label: "导出配置", diff --git a/app/pages/index.vue b/app/pages/index.vue index 9190023..260538f 100644 --- a/app/pages/index.vue +++ b/app/pages/index.vue @@ -1,10 +1,10 @@ + + @@ -104,15 +109,23 @@