feat(export): implement export page for bidding items
Introduces a new export page for creating and managing bidding lists. Key features include: selecting items from a master list, adding them to a bidding list, editing start price/remarks, batch price updates, and drag-and-drop reordering. The final list can be previewed and exported as a CSV. This change adds the `useBiddingItems` composable and the `sortablejs` dependency. Also refactors `imageUrl` to be a non-nullable string for type consistency.
This commit is contained in:
79
app/components/export/EditModal.vue
Normal file
79
app/components/export/EditModal.vue
Normal file
@@ -0,0 +1,79 @@
|
||||
<template>
|
||||
<UModal v-model:open="open" title="编辑标品">
|
||||
<template #body>
|
||||
<UForm
|
||||
@submit="onSubmit"
|
||||
:state="biddingItemEditState"
|
||||
:schema="biddingItemEditSchema"
|
||||
>
|
||||
<UFormField label="起拍价" name="startPrice">
|
||||
<UInput
|
||||
v-model.number="biddingItemEditState.startPrice"
|
||||
type="number"
|
||||
/>
|
||||
</UFormField>
|
||||
|
||||
<UFormField label="备注" name="remarks">
|
||||
<UTextarea v-model="biddingItemEditState.remarks" />
|
||||
</UFormField>
|
||||
|
||||
<UButton type="submit" label="保存" color="primary" class="mt-4" />
|
||||
</UForm>
|
||||
</template>
|
||||
</UModal>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import type { FormSubmitEvent } from "@nuxt/ui";
|
||||
import * as z from "zod";
|
||||
|
||||
const biddingItemEditForm = ref();
|
||||
const currentId = ref<number>(0);
|
||||
const open = ref<boolean>(false);
|
||||
|
||||
const toast = useToast();
|
||||
|
||||
const { biddingItems, editBiddingItem } = useBiddingItems();
|
||||
|
||||
const biddingItemEditSchema = z.object({
|
||||
startPrice: z.number().min(0, "起拍价不能少于 RM 0").default(0),
|
||||
remarks: z.string().optional(),
|
||||
});
|
||||
|
||||
type BiddingItemEditSchema = z.output<typeof biddingItemEditSchema>;
|
||||
|
||||
const biddingItemEditState = reactive<BiddingItem & BiddingItemEditSchema>({
|
||||
id: 0,
|
||||
name: "",
|
||||
imageUrl: "",
|
||||
startPrice: 0,
|
||||
remarks: "",
|
||||
});
|
||||
|
||||
const openModal = (biddingItem: BiddingItem) => {
|
||||
Object.assign(biddingItemEditState, biddingItem); // 👈 一次性复制所有字段
|
||||
currentId.value = biddingItem.id;
|
||||
open.value = true;
|
||||
};
|
||||
|
||||
const onSubmit = async (event: FormSubmitEvent<BiddingItemEditSchema>) => {
|
||||
const updatedItem: BiddingItem = {
|
||||
...biddingItemEditState, // 👈 这里直接复用已有字段
|
||||
startPrice: event.data.startPrice,
|
||||
remarks: event.data.remarks ?? "",
|
||||
};
|
||||
|
||||
editBiddingItem(updatedItem);
|
||||
toast.add({
|
||||
title: "已保存修改",
|
||||
description: `${updatedItem.name} 的信息已更新`,
|
||||
color: "success",
|
||||
});
|
||||
|
||||
open.value = false;
|
||||
};
|
||||
|
||||
defineExpose({ openModal });
|
||||
</script>
|
||||
|
||||
<style></style>
|
||||
@@ -100,7 +100,7 @@ const { utils, isNameAvailable, addItem, editItem, items } = useItemsStore();
|
||||
const baseSchema = z.object({
|
||||
brand: z.string().optional(),
|
||||
name: z.string().min(1, "名称不能为空"),
|
||||
imageUrl: z.string().nullable().optional(),
|
||||
imageUrl: z.string().optional(),
|
||||
description: z.string().nullable().optional(),
|
||||
tags: z.string().nullable().optional(),
|
||||
});
|
||||
@@ -121,7 +121,7 @@ type ItemSchema = z.output<typeof baseSchema>;
|
||||
const itemState = reactive<ItemSchema>({
|
||||
brand: undefined,
|
||||
name: "",
|
||||
imageUrl: null,
|
||||
imageUrl: "",
|
||||
description: null,
|
||||
tags: null,
|
||||
});
|
||||
@@ -134,7 +134,7 @@ const openModal = (item?: Item) => {
|
||||
currentId.value = item.id;
|
||||
itemState.brand = item.brand;
|
||||
itemState.name = item.name;
|
||||
itemState.imageUrl = item.imageUrl ?? null;
|
||||
itemState.imageUrl = item.imageUrl;
|
||||
itemState.description = item.description ?? null;
|
||||
itemState.tags = item.tags?.join(", ") ?? null;
|
||||
} else {
|
||||
@@ -143,7 +143,7 @@ const openModal = (item?: Item) => {
|
||||
itemState.brand = undefined;
|
||||
currentId.value = null;
|
||||
itemState.name = "";
|
||||
itemState.imageUrl = null;
|
||||
itemState.imageUrl = "";
|
||||
itemState.description = null;
|
||||
itemState.tags = null;
|
||||
}
|
||||
|
||||
50
app/composables/biddingItems.ts
Normal file
50
app/composables/biddingItems.ts
Normal file
@@ -0,0 +1,50 @@
|
||||
import { createSharedComposable } from "@vueuse/core";
|
||||
|
||||
export type BiddingItem = {
|
||||
id: number;
|
||||
name: string;
|
||||
startPrice: number;
|
||||
remarks: string;
|
||||
imageUrl?: string;
|
||||
};
|
||||
|
||||
const _useBiddingItems = () => {
|
||||
const biddingItems = ref<BiddingItem[]>([]);
|
||||
|
||||
const biddingItemsLatestId = computed(() => {
|
||||
const arr = biddingItems.value ?? [];
|
||||
if (arr.length === 0) return 1;
|
||||
return Math.max(...arr.map((i) => i.id)) + 1;
|
||||
});
|
||||
|
||||
const addBiddingItem = (item: Item, startPrice: number) => {
|
||||
biddingItems.value.push({
|
||||
id: biddingItemsLatestId.value,
|
||||
name: `${item.brand} ${item.name}`,
|
||||
startPrice: startPrice,
|
||||
remarks: "",
|
||||
imageUrl: item.imageUrl,
|
||||
});
|
||||
};
|
||||
|
||||
const removeBiddingItem = (id: number) => {
|
||||
biddingItems.value = (biddingItems.value ?? []).filter((i) => i.id !== id);
|
||||
};
|
||||
|
||||
const editBiddingItem = (biddingItem: BiddingItem) => {
|
||||
const idx = (biddingItems.value ?? []).findIndex(
|
||||
(i) => i.id === biddingItem.id
|
||||
);
|
||||
if (idx === -1) return;
|
||||
const updatedBiddingItems = [...(biddingItems.value ?? [])];
|
||||
updatedBiddingItems[idx] = {
|
||||
...updatedBiddingItems[idx],
|
||||
...biddingItem,
|
||||
};
|
||||
biddingItems.value = updatedBiddingItems;
|
||||
};
|
||||
|
||||
return { biddingItems, addBiddingItem, removeBiddingItem, editBiddingItem };
|
||||
};
|
||||
|
||||
export const useBiddingItems = createSharedComposable(_useBiddingItems);
|
||||
@@ -4,7 +4,7 @@ export type Item = {
|
||||
id: number;
|
||||
brand?: string;
|
||||
name: string;
|
||||
imageUrl?: string | null;
|
||||
imageUrl?: string;
|
||||
description?: string | null;
|
||||
tags?: string[] | null;
|
||||
createdAt?: Date;
|
||||
|
||||
@@ -1,13 +1,349 @@
|
||||
<template>
|
||||
<div>
|
||||
|
||||
<main class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-8">
|
||||
<div class="space-y-4">
|
||||
<div class="flex gap-4">
|
||||
<!-- 物品列表 -->
|
||||
<div class="w-1/2 min-w-[600px] overflow-x-auto">
|
||||
<h2 class="text-2xl font-medium">物品列表</h2>
|
||||
<div class="flex flex-col flex-1 w-full">
|
||||
<div
|
||||
class="flex justify-between items-center gap-2 overflow-x-auto px-4 py-3.5 border-b border-accented"
|
||||
>
|
||||
<div class="space-x-2">
|
||||
<UInput
|
||||
v-model="globalFilter"
|
||||
class="max-w-sm"
|
||||
placeholder="Search..."
|
||||
icon="lucide:search"
|
||||
/>
|
||||
<UInputNumber
|
||||
v-model="startPriceInput"
|
||||
:min="0"
|
||||
increment-icon="lucide:banknote-arrow-up"
|
||||
decrement-icon="lucide:banknote-arrow-down"
|
||||
class="max-w-sm"
|
||||
placeholder="Starting price"
|
||||
icon="lucide:banknote"
|
||||
:format-options="{
|
||||
style: 'currency',
|
||||
currency: 'MYR',
|
||||
currencyDisplay: 'narrowSymbol',
|
||||
currencySign: 'accounting',
|
||||
}"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<UTable
|
||||
sticky
|
||||
v-model:global-filter="globalFilter"
|
||||
:data="itemsList"
|
||||
:columns="itemColumns"
|
||||
class="max-h-[640px]"
|
||||
v-model:row-selection="itemListRowSelection"
|
||||
@select="onitemListSelect"
|
||||
>
|
||||
<template #name-cell="{ row }">
|
||||
<div class="flex items-center gap-3 select-none">
|
||||
<UAvatar
|
||||
:src="row.original.imageUrl"
|
||||
size="lg"
|
||||
:alt="row.original.name"
|
||||
/>
|
||||
<div>
|
||||
<p class="font-medium text-highlighted">
|
||||
<strong>{{ row.original.brand }}</strong>
|
||||
{{ row.original.name }}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</UTable>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 竞标清单 -->
|
||||
<div class="w-1/2 min-w-[600px] overflow-x-auto">
|
||||
<h2 class="text-2xl font-medium">竞标清单</h2>
|
||||
<div class="flex flex-col flex-1 w-full">
|
||||
<div
|
||||
class="flex justify-between items-center gap-2 overflow-x-auto px-4 py-3.5 border-b border-accented"
|
||||
>
|
||||
<div class="flex items-center gap-2">
|
||||
<UInputNumber
|
||||
v-model="batchStartPriceInput"
|
||||
:min="0"
|
||||
increment-icon="lucide:banknote-arrow-up"
|
||||
decrement-icon="lucide:banknote-arrow-down"
|
||||
class="max-w-sm"
|
||||
placeholder="Starting price"
|
||||
icon="lucide:banknote"
|
||||
:format-options="{
|
||||
style: 'currency',
|
||||
currency: 'MYR',
|
||||
currencyDisplay: 'narrowSymbol',
|
||||
currencySign: 'accounting',
|
||||
}"
|
||||
/>
|
||||
<UButton
|
||||
icon="lucide:check"
|
||||
:disabled="!isSomeBiddingItemSelected"
|
||||
@click="applyStartPriceButtonClicked"
|
||||
>应用到选中</UButton
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
<UTable
|
||||
ref="biddingItemsTableRef"
|
||||
sticky
|
||||
:data="biddingItemList"
|
||||
:columns="biddingItemColumns"
|
||||
class="max-h-[640px] no-wrap-header"
|
||||
:ui="{
|
||||
tbody: 'bidding-item-table-tbody',
|
||||
}"
|
||||
v-model:column-pinning="biddingItemColumnPinning"
|
||||
>
|
||||
<template #select-cell="{ row }">
|
||||
<UCheckbox
|
||||
:model-value="row.getIsSelected()"
|
||||
@update:model-value="(value: boolean | 'indeterminate') => row.toggleSelected(!!value)"
|
||||
aria-label="Select row"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<template #name-cell="{ row }">
|
||||
<div class="flex items-center gap-3">
|
||||
<UAvatar
|
||||
:src="row.original.imageUrl"
|
||||
size="lg"
|
||||
:alt="row.original.name"
|
||||
/>
|
||||
<div>
|
||||
<p class="font-medium text-highlighted">
|
||||
{{ row.original.name }}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<template #startPrice-cell="{ row }">
|
||||
<div class="">
|
||||
{{ formatCurrency(row.original.startPrice) }}
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<template #button-cell="{ row }">
|
||||
<div class="space-x-2">
|
||||
<UButton
|
||||
icon="lucide:pencil-line"
|
||||
@click="editItemButtonClicked(row.original)"
|
||||
/>
|
||||
<UButton
|
||||
icon="lucide:trash-2"
|
||||
color="error"
|
||||
variant="outline"
|
||||
@click="deleteItemButtonClicked(row.original.id)"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
</UTable>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 导出预览 -->
|
||||
<div class="space-y-2">
|
||||
<h2 class="text-2xl font-medium">导出预览</h2>
|
||||
<div class="bg-gray-200 p-6 rounded-md">
|
||||
<pre>{{ exportCsv }}</pre>
|
||||
</div>
|
||||
<div class="flex gap-2">
|
||||
<UButton
|
||||
class="flex-1 justify-center"
|
||||
icon="lucide:file-output"
|
||||
@click="downloadCsv"
|
||||
>导出 CSV</UButton
|
||||
>
|
||||
<UButton class="flex-1 justify-center" icon="lucide:download"
|
||||
>下载图片集</UButton
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<ExportEditModal ref="biddingItemEditModal" />
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import type { TableColumn, TableRow } from "@nuxt/ui";
|
||||
import type { Table, Row } from "@tanstack/table-core";
|
||||
import { useSortable } from "@vueuse/integrations/useSortable";
|
||||
|
||||
const UCheckbox = resolveComponent("UCheckbox");
|
||||
|
||||
const { items } = useItemsStore();
|
||||
const itemsList = computed(() => items.value ?? []);
|
||||
|
||||
const { biddingItems, addBiddingItem, removeBiddingItem } = useBiddingItems();
|
||||
const biddingItemList = biddingItems
|
||||
|
||||
const biddingItemEditModal = ref<any>(null);
|
||||
|
||||
const formatCurrency = (value: number) => {
|
||||
return new Intl.NumberFormat("en-MY", {
|
||||
style: "currency",
|
||||
currency: "MYR",
|
||||
minimumFractionDigits: 2,
|
||||
currencyDisplay: "narrowSymbol",
|
||||
}).format(value);
|
||||
};
|
||||
|
||||
// Left Table (Item List)
|
||||
const globalFilter = ref<string>("");
|
||||
const startPriceInput = ref<number>(0);
|
||||
|
||||
const itemListRowSelection = ref<Record<string, boolean>>({});
|
||||
|
||||
function onitemListSelect(row: TableRow<Item>, e?: Event) {
|
||||
/* If you decide to also select the column you can do this */
|
||||
// row.toggleSelected(!row.getIsSelected());
|
||||
addBiddingItem(row.original, startPriceInput.value);
|
||||
}
|
||||
|
||||
const itemColumns: TableColumn<Item>[] = [
|
||||
{
|
||||
accessorKey: "id",
|
||||
header: "#",
|
||||
cell: ({ row }) => `#${row.getValue("id")}`,
|
||||
},
|
||||
{
|
||||
accessorKey: "name",
|
||||
header: "标品名称",
|
||||
},
|
||||
// 新增一个 brand 列 —— 让它参与全局搜索,但不实际渲染内容(brand 已在 name-cell 中显示)
|
||||
{
|
||||
accessorKey: "brand",
|
||||
header: "", // 留空,避免影响布局
|
||||
// 明确允许全局过滤(通常是默认 true,但写上更明确)
|
||||
enableGlobalFilter: true,
|
||||
// 不在表格中重复显示 brand(因为你在 name-cell 已经显示了)
|
||||
cell: () => null,
|
||||
},
|
||||
];
|
||||
// Right Table (Bidding Item List)
|
||||
const biddingItemsTable = useTemplateRef<{
|
||||
tableRef: HTMLTableElement;
|
||||
tableApi: Table<BiddingItem>;
|
||||
}>("biddingItemsTableRef");
|
||||
const batchStartPriceInput = ref<number>(0);
|
||||
|
||||
const isSomeBiddingItemSelected = computed<boolean>(
|
||||
() =>
|
||||
(biddingItemsTable.value?.tableApi.getIsSomeRowsSelected() ||
|
||||
biddingItemsTable.value?.tableApi.getIsAllRowsSelected()) ??
|
||||
false
|
||||
);
|
||||
|
||||
const biddingItemColumns: TableColumn<BiddingItem>[] = [
|
||||
{
|
||||
id: "select",
|
||||
header: ({ table }) =>
|
||||
h(UCheckbox, {
|
||||
modelValue: table.getIsSomePageRowsSelected()
|
||||
? "indeterminate"
|
||||
: table.getIsAllPageRowsSelected(),
|
||||
"onUpdate:modelValue": (value: boolean | "indeterminate") =>
|
||||
table.toggleAllPageRowsSelected(!!value),
|
||||
ariaLabel: "Select all",
|
||||
}),
|
||||
},
|
||||
{
|
||||
accessorKey: "id",
|
||||
header: "#",
|
||||
cell: ({ row }) => `${row.index + 1}`, // 动态行号,从 1 开始
|
||||
},
|
||||
{
|
||||
accessorKey: "name",
|
||||
header: "标品名称",
|
||||
},
|
||||
{
|
||||
accessorKey: "startPrice",
|
||||
header: "起拍价",
|
||||
},
|
||||
{
|
||||
accessorKey: "remarks",
|
||||
header: "备注",
|
||||
},
|
||||
{
|
||||
id: "button",
|
||||
header: "",
|
||||
},
|
||||
];
|
||||
const biddingItemColumnPinning = ref({
|
||||
left: [],
|
||||
right: ["button"],
|
||||
});
|
||||
|
||||
useSortable(".bidding-item-table-tbody", biddingItemList, {
|
||||
animation: 150,
|
||||
});
|
||||
|
||||
const applyStartPriceButtonClicked = () => {
|
||||
const selectedBiddingItems: Row<BiddingItem>[] =
|
||||
biddingItemsTable.value?.tableApi.getFilteredSelectedRowModel().rows ?? [];
|
||||
selectedBiddingItems.forEach((r) => {
|
||||
r.original.startPrice = batchStartPriceInput.value;
|
||||
});
|
||||
|
||||
biddingItemsTable.value?.tableApi.resetRowSelection();
|
||||
};
|
||||
|
||||
const editItemButtonClicked = (biddingItem: BiddingItem) => {
|
||||
biddingItemEditModal.value?.openModal(biddingItem);
|
||||
};
|
||||
|
||||
const deleteItemButtonClicked = (id: number) => {
|
||||
removeBiddingItem(id);
|
||||
};
|
||||
|
||||
function toUnderscore(name: string) {
|
||||
return name.trim().toLowerCase().replace(/\s+/g, "_");
|
||||
}
|
||||
|
||||
// Export Preview
|
||||
const exportCsv = computed<string>(() => {
|
||||
return [
|
||||
...biddingItems.value.map(
|
||||
(biddingItem) =>
|
||||
`${biddingItem.name},${biddingItem.startPrice},${
|
||||
biddingItem.remarks
|
||||
},${toUnderscore(biddingItem.name)}`
|
||||
),
|
||||
].join("\n");
|
||||
});
|
||||
|
||||
const downloadCsv = () => {
|
||||
const blob = new Blob([exportCsv.value], { type: "text/csv;charset=utf-8;" });
|
||||
const url = URL.createObjectURL(blob);
|
||||
const a = document.createElement("a");
|
||||
a.href = url;
|
||||
a.download = `物品清单-${new Date().toISOString().split("T")[0]}.csv`;
|
||||
document.body.appendChild(a);
|
||||
a.click();
|
||||
document.body.removeChild(a);
|
||||
URL.revokeObjectURL(url);
|
||||
};
|
||||
</script>
|
||||
|
||||
<style>
|
||||
|
||||
</style>
|
||||
/* 阻止表头换行 */
|
||||
.no-wrap-header thead th {
|
||||
white-space: nowrap !important;
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
"dependencies": {
|
||||
"@nuxt/ui": "4.0.1",
|
||||
"nuxt": "^4.1.3",
|
||||
"sortablejs": "^1.15.6",
|
||||
"typescript": "^5.9.3",
|
||||
"vue": "^3.5.22",
|
||||
"vue-router": "^4.5.1"
|
||||
|
||||
17
pnpm-lock.yaml
generated
17
pnpm-lock.yaml
generated
@@ -10,10 +10,13 @@ importers:
|
||||
dependencies:
|
||||
'@nuxt/ui':
|
||||
specifier: 4.0.1
|
||||
version: 4.0.1(@babel/parser@7.28.4)(db0@0.3.4)(embla-carousel@8.6.0)(ioredis@5.8.1)(magicast@0.3.5)(typescript@5.9.3)(vite@7.1.9(jiti@2.6.1)(lightningcss@1.30.1)(terser@5.44.0)(yaml@2.8.1))(vue-router@4.5.1(vue@3.5.22(typescript@5.9.3)))(vue@3.5.22(typescript@5.9.3))(zod@4.1.12)
|
||||
version: 4.0.1(@babel/parser@7.28.4)(db0@0.3.4)(embla-carousel@8.6.0)(ioredis@5.8.1)(magicast@0.3.5)(sortablejs@1.15.6)(typescript@5.9.3)(vite@7.1.9(jiti@2.6.1)(lightningcss@1.30.1)(terser@5.44.0)(yaml@2.8.1))(vue-router@4.5.1(vue@3.5.22(typescript@5.9.3)))(vue@3.5.22(typescript@5.9.3))(zod@4.1.12)
|
||||
nuxt:
|
||||
specifier: ^4.1.3
|
||||
version: 4.1.3(@parcel/watcher@2.5.1)(@vue/compiler-sfc@3.5.22)(db0@0.3.4)(ioredis@5.8.1)(lightningcss@1.30.1)(magicast@0.3.5)(rollup@4.52.4)(terser@5.44.0)(typescript@5.9.3)(vite@7.1.9(jiti@2.6.1)(lightningcss@1.30.1)(terser@5.44.0)(yaml@2.8.1))(yaml@2.8.1)
|
||||
sortablejs:
|
||||
specifier: ^1.15.6
|
||||
version: 1.15.6
|
||||
typescript:
|
||||
specifier: ^5.9.3
|
||||
version: 5.9.3
|
||||
@@ -3152,6 +3155,9 @@ packages:
|
||||
smob@1.5.0:
|
||||
resolution: {integrity: sha512-g6T+p7QO8npa+/hNx9ohv1E5pVCmWrVCUzUXJyLdMmftX6ER0oiWY/w9knEonLpnOp6b6FenKnMfR8gqwWdwig==}
|
||||
|
||||
sortablejs@1.15.6:
|
||||
resolution: {integrity: sha512-aNfiuwMEpfBM/CN6LY0ibyhxPfPbyFeBTYJKCvzkJ2GkUpazIt3H+QIPAMHwqQ7tMKaHz1Qj+rJJCqljnf4p3A==}
|
||||
|
||||
source-map-js@1.2.1:
|
||||
resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
@@ -4439,7 +4445,7 @@ snapshots:
|
||||
transitivePeerDependencies:
|
||||
- magicast
|
||||
|
||||
'@nuxt/ui@4.0.1(@babel/parser@7.28.4)(db0@0.3.4)(embla-carousel@8.6.0)(ioredis@5.8.1)(magicast@0.3.5)(typescript@5.9.3)(vite@7.1.9(jiti@2.6.1)(lightningcss@1.30.1)(terser@5.44.0)(yaml@2.8.1))(vue-router@4.5.1(vue@3.5.22(typescript@5.9.3)))(vue@3.5.22(typescript@5.9.3))(zod@4.1.12)':
|
||||
'@nuxt/ui@4.0.1(@babel/parser@7.28.4)(db0@0.3.4)(embla-carousel@8.6.0)(ioredis@5.8.1)(magicast@0.3.5)(sortablejs@1.15.6)(typescript@5.9.3)(vite@7.1.9(jiti@2.6.1)(lightningcss@1.30.1)(terser@5.44.0)(yaml@2.8.1))(vue-router@4.5.1(vue@3.5.22(typescript@5.9.3)))(vue@3.5.22(typescript@5.9.3))(zod@4.1.12)':
|
||||
dependencies:
|
||||
'@ai-sdk/vue': 2.0.68(vue@3.5.22(typescript@5.9.3))(zod@4.1.12)
|
||||
'@iconify/vue': 5.0.0(vue@3.5.22(typescript@5.9.3))
|
||||
@@ -4456,7 +4462,7 @@ snapshots:
|
||||
'@tanstack/vue-table': 8.21.3(vue@3.5.22(typescript@5.9.3))
|
||||
'@unhead/vue': 2.0.19(vue@3.5.22(typescript@5.9.3))
|
||||
'@vueuse/core': 13.9.0(vue@3.5.22(typescript@5.9.3))
|
||||
'@vueuse/integrations': 13.9.0(fuse.js@7.1.0)(vue@3.5.22(typescript@5.9.3))
|
||||
'@vueuse/integrations': 13.9.0(fuse.js@7.1.0)(sortablejs@1.15.6)(vue@3.5.22(typescript@5.9.3))
|
||||
colortranslator: 5.0.0
|
||||
consola: 3.4.2
|
||||
defu: 6.1.4
|
||||
@@ -5292,13 +5298,14 @@ snapshots:
|
||||
'@vueuse/shared': 13.9.0(vue@3.5.22(typescript@5.9.3))
|
||||
vue: 3.5.22(typescript@5.9.3)
|
||||
|
||||
'@vueuse/integrations@13.9.0(fuse.js@7.1.0)(vue@3.5.22(typescript@5.9.3))':
|
||||
'@vueuse/integrations@13.9.0(fuse.js@7.1.0)(sortablejs@1.15.6)(vue@3.5.22(typescript@5.9.3))':
|
||||
dependencies:
|
||||
'@vueuse/core': 13.9.0(vue@3.5.22(typescript@5.9.3))
|
||||
'@vueuse/shared': 13.9.0(vue@3.5.22(typescript@5.9.3))
|
||||
vue: 3.5.22(typescript@5.9.3)
|
||||
optionalDependencies:
|
||||
fuse.js: 7.1.0
|
||||
sortablejs: 1.15.6
|
||||
|
||||
'@vueuse/metadata@10.11.1': {}
|
||||
|
||||
@@ -7237,6 +7244,8 @@ snapshots:
|
||||
|
||||
smob@1.5.0: {}
|
||||
|
||||
sortablejs@1.15.6: {}
|
||||
|
||||
source-map-js@1.2.1: {}
|
||||
|
||||
source-map-support@0.5.21:
|
||||
|
||||
Reference in New Issue
Block a user