Files
bid-setup.tootaio.com/app/composables/items.ts
xiaomai 1d2ce32ab9 feat(item): implement item editing functionality
This commit introduces the capability to edit existing items. The `ItemEditModal` has been refactored to support both creation and editing modes.

- The modal UI (title, buttons) and submission logic now adapt based on whether an item is being added or edited.
- A new `editItem` function is added to the `useItemsStore` to handle the update logic.
- Form validation for the item name is enhanced to correctly check for uniqueness during edits.
- The table's row action menu now opens the modal in edit mode, pre-populating the form.
- The `latestId` generation logic is improved for robustness.
- Additionally, this commit adds row selection checkboxes to the items table.
2025-10-14 13:40:49 +08:00

82 lines
2.4 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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[]>("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),
},
});
// 直接使用 storedRef<Item[]>)。模板会自动解包,其他逻辑也简单。
const items = stored; // Ref<Item[]>
// 统计项使用 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);