feat: enhance PurchaseGroupedTable to display product information and item numbering

This commit is contained in:
Yoga Pangestu 2026-07-19 18:56:56 +07:00
parent 70531b443d
commit 6271bca490

View File

@ -48,15 +48,37 @@ function rowNumber(index: number): number {
return groupedTableRowNumber(props.firstItem, index);
}
interface ProductInfo {
name: string;
unitLabel?: string;
}
function productInfos(items: PurchaseItemDetail[]): ProductInfo[] {
const map = new Map<number, ProductInfo>();
items.forEach((item) => {
const id = item.raw_material_id ?? 0;
if (id && !map.has(id)) {
map.set(id, {
name: item.raw_material_name || 'Bahan Baku Tidak Diketahui',
unitLabel: item.raw_material_unit_label,
});
}
});
return [...map.values()];
}
interface GroupedPurchaseItems {
rawMaterialId: number;
rawMaterialName: string;
unitLabel?: string;
items: PurchaseItemDetail[];
items: (PurchaseItemDetail & { item_number: number })[];
}
function getGroupedItems(items: PurchaseItemDetail[]): GroupedPurchaseItems[] {
const groups: Record<number, GroupedPurchaseItems> = {};
let itemCounter = 0;
items.forEach((item) => {
const rawMaterialId = item.raw_material_id ?? 0;
@ -72,7 +94,8 @@ function getGroupedItems(items: PurchaseItemDetail[]): GroupedPurchaseItems[] {
};
}
groups[rawMaterialId].items.push(item);
itemCounter++;
groups[rawMaterialId].items.push({ ...item, item_number: itemCounter });
});
return Object.values(groups);
@ -102,9 +125,16 @@ function openVerificationDetail(requestId: number | undefined) {
{{ rowNumber(index) }}
</span>
<div class="min-w-0 space-y-2">
<h3 class="font-medium leading-tight">
{{ purchase.supplier?.name }}
<h3 class="font-medium leading-tight flex flex-wrap items-center gap-x-1">
<template v-for="(product, pIdx) in productInfos(purchase.items)" :key="pIdx">
<span>{{ product.name }}</span>
<Badge v-if="product.unitLabel" variant="secondary" class="font-normal">{{ product.unitLabel }}</Badge>
<span v-if="pIdx < productInfos(purchase.items).length - 1" class="text-muted-foreground">,&nbsp;</span>
</template>
</h3>
<p class="text-muted-foreground text-sm">
Supplier: {{ purchase.supplier?.name }}
</p>
<p v-if="purchase.has_pending_request" class="text-sm text-amber-600">
{{ purchase.pending_request_submitted_by_name }} mengajukan {{ purchase.pending_request_action_label?.toLowerCase() }} belanja ini
<button type="button" class="underline-offset-2 hover:underline" @click="openVerificationDetail(purchase.pending_request_id)">lihat</button>
@ -138,6 +168,7 @@ function openVerificationDetail(requestId: number | undefined) {
<Table>
<TableHeader>
<TableRow>
<TableHead class="w-8">#</TableHead>
<TableHead>Varian</TableHead>
<TableHead>Jumlah</TableHead>
<TableHead>Harga Satuan</TableHead>
@ -146,20 +177,15 @@ function openVerificationDetail(requestId: number | undefined) {
</TableHeader>
<TableBody>
<TableRow v-if="!purchase.items.length" :key="`${purchase.id}-empty`">
<TableCell colspan="4" class="text-muted-foreground">
<TableCell colspan="5" class="text-muted-foreground">
Belum ada item
</TableCell>
</TableRow>
<template v-else v-for="group in getGroupedItems(purchase.items)" :key="group.rawMaterialId">
<TableRow class="bg-muted/20 hover:bg-muted/20">
<TableCell colspan="4" class="font-semibold text-foreground">
{{ group.rawMaterialName }}
<Badge v-if="group.unitLabel" variant="secondary" class="ml-2 font-normal">
{{ group.unitLabel }}
</Badge>
</TableCell>
</TableRow>
<TableRow v-for="item in group.items" :key="item.id">
<TableCell class="pl-6 text-center text-muted-foreground tabular-nums">
{{ item.item_number }}
</TableCell>
<TableCell class="pl-6 font-medium">
{{ item.variant }}
</TableCell>