feat: enhance PurchaseGroupedTable to display product information and item numbering
This commit is contained in:
parent
70531b443d
commit
6271bca490
@ -48,15 +48,37 @@ function rowNumber(index: number): number {
|
|||||||
return groupedTableRowNumber(props.firstItem, index);
|
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 {
|
interface GroupedPurchaseItems {
|
||||||
rawMaterialId: number;
|
rawMaterialId: number;
|
||||||
rawMaterialName: string;
|
rawMaterialName: string;
|
||||||
unitLabel?: string;
|
unitLabel?: string;
|
||||||
items: PurchaseItemDetail[];
|
items: (PurchaseItemDetail & { item_number: number })[];
|
||||||
}
|
}
|
||||||
|
|
||||||
function getGroupedItems(items: PurchaseItemDetail[]): GroupedPurchaseItems[] {
|
function getGroupedItems(items: PurchaseItemDetail[]): GroupedPurchaseItems[] {
|
||||||
const groups: Record<number, GroupedPurchaseItems> = {};
|
const groups: Record<number, GroupedPurchaseItems> = {};
|
||||||
|
let itemCounter = 0;
|
||||||
|
|
||||||
items.forEach((item) => {
|
items.forEach((item) => {
|
||||||
const rawMaterialId = item.raw_material_id ?? 0;
|
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);
|
return Object.values(groups);
|
||||||
@ -102,9 +125,16 @@ function openVerificationDetail(requestId: number | undefined) {
|
|||||||
{{ rowNumber(index) }}
|
{{ rowNumber(index) }}
|
||||||
</span>
|
</span>
|
||||||
<div class="min-w-0 space-y-2">
|
<div class="min-w-0 space-y-2">
|
||||||
<h3 class="font-medium leading-tight">
|
<h3 class="font-medium leading-tight flex flex-wrap items-center gap-x-1">
|
||||||
{{ purchase.supplier?.name }}
|
<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">, </span>
|
||||||
|
</template>
|
||||||
</h3>
|
</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">
|
<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 —
|
{{ 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>
|
<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>
|
<Table>
|
||||||
<TableHeader>
|
<TableHeader>
|
||||||
<TableRow>
|
<TableRow>
|
||||||
|
<TableHead class="w-8">#</TableHead>
|
||||||
<TableHead>Varian</TableHead>
|
<TableHead>Varian</TableHead>
|
||||||
<TableHead>Jumlah</TableHead>
|
<TableHead>Jumlah</TableHead>
|
||||||
<TableHead>Harga Satuan</TableHead>
|
<TableHead>Harga Satuan</TableHead>
|
||||||
@ -146,20 +177,15 @@ function openVerificationDetail(requestId: number | undefined) {
|
|||||||
</TableHeader>
|
</TableHeader>
|
||||||
<TableBody>
|
<TableBody>
|
||||||
<TableRow v-if="!purchase.items.length" :key="`${purchase.id}-empty`">
|
<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
|
Belum ada item
|
||||||
</TableCell>
|
</TableCell>
|
||||||
</TableRow>
|
</TableRow>
|
||||||
<template v-else v-for="group in getGroupedItems(purchase.items)" :key="group.rawMaterialId">
|
<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">
|
<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">
|
<TableCell class="pl-6 font-medium">
|
||||||
{{ item.variant }}
|
{{ item.variant }}
|
||||||
</TableCell>
|
</TableCell>
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user