store/resources/js/pages/admin/manage/cuttings/Share.vue
Yoga Pangestu 33afec2513
Some checks failed
linter / quality (push) Waiting to run
tests / ci (8.3) (push) Has been cancelled
tests / ci (8.4) (push) Has been cancelled
tests / ci (8.5) (push) Has been cancelled
feat: enhance Cutting module by adding image upload functionality and improving form handling; update CuttingPosForm and related components to support image management and improve user experience
2026-07-02 23:03:27 +07:00

300 lines
13 KiB
Vue

<script setup lang="ts">
import { computed } from 'vue';
import { Badge } from '@/components/ui/badge';
import {
Table,
TableBody,
TableCell,
TableHead,
TableHeader,
TableRow,
} from '@/components/ui/table';
import { cuttingStatusBadgeVariant } from '@/constants/cutting-status';
import MediaThumbnailCell from '@/components/media/MediaThumbnailCell.vue';
import type { CuttingListItem } from '@/types/cutting';
const props = defineProps<{
cutting: CuttingListItem;
}>();
interface GroupedMaterials {
key: number;
name: string;
unitLabel?: string;
items: typeof props.cutting.materials;
}
interface GroupedResults {
key: number;
name: string;
items: typeof props.cutting.results;
}
const groupedMaterials = computed<GroupedMaterials[]>(() => {
const groups: Record<number, GroupedMaterials> = {};
props.cutting.materials.forEach((item) => {
const key = item.raw_material_id ?? 0;
const name = item.raw_material_name || 'Bahan Baku Tidak Diketahui';
if (!groups[key]) {
groups[key] = {
key,
name,
unitLabel: item.raw_material_unit_label,
items: [],
};
}
groups[key].items.push(item);
});
return Object.values(groups);
});
const groupedResults = computed<GroupedResults[]>(() => {
const groups: Record<number, GroupedResults> = {};
props.cutting.results.forEach((item) => {
const product = item.product_variant?.product;
const key = product?.id ?? 0;
const name = product?.name ?? 'Produk Tidak Diketahui';
if (!groups[key]) {
groups[key] = { key, name, items: [] };
}
groups[key].items.push(item);
});
return Object.values(groups);
});
</script>
<template>
<div class="min-h-screen bg-background">
<div class="mx-auto max-w-3xl px-4 py-8 sm:px-6 lg:px-8">
<!-- Header -->
<div class="mb-8 text-center">
<h1 class="text-2xl font-bold tracking-tight">
Detail Cutting
</h1>
<p class="mt-1 text-muted-foreground">
Rincian data proses cutting
</p>
</div>
<!-- Main Card -->
<div class="overflow-hidden rounded-lg border bg-card shadow-sm">
<!-- Cutting Info Header -->
<div class="border-b bg-muted/30 p-6">
<div class="flex flex-wrap items-center gap-3">
<h2 class="text-xl font-semibold">
Cutting #{{ cutting.id }}
</h2>
<Badge
:variant="cuttingStatusBadgeVariant(cutting.status)"
>
{{ cutting.status_label }}
</Badge>
</div>
<div class="mt-3 space-y-1 text-sm text-muted-foreground">
<p>{{ cutting.created_at_formatted }}</p>
<p>
Oleh
{{
cutting.created_by?.profile?.full_name ??
cutting.created_by?.username
}}
</p>
</div>
<p v-if="cutting.description" class="mt-3 text-sm">
{{ cutting.description }}
</p>
<div
v-if="cutting.images && cutting.images.length > 0"
class="mt-3 flex flex-wrap gap-2"
>
<MediaThumbnailCell
:items="cutting.images"
:max-visible="10"
/>
</div>
</div>
<!-- Summary -->
<div class="border-b p-6">
<h3 class="mb-3 text-sm font-semibold">Ringkasan</h3>
<div class="grid gap-4 sm:grid-cols-2">
<div class="rounded-lg border p-3">
<p class="text-xs text-muted-foreground">
Total Hasil Cutting
</p>
<p class="mt-1 text-lg font-semibold text-primary">
{{ cutting.total_result_pieces ?? 0 }} pcs
</p>
</div>
<div
v-if="
cutting.total_material_usage_summary_formatted
"
class="rounded-lg border p-3"
>
<p class="text-xs text-muted-foreground">
Total Pemakaian Bahan
</p>
<p class="mt-1 text-lg font-semibold text-primary">
{{
cutting.total_material_usage_summary_formatted
}}
</p>
</div>
</div>
</div>
<!-- Materials Section -->
<div v-if="cutting.materials.length" class="border-b p-6">
<h3 class="mb-3 text-sm font-semibold">Bahan Baku</h3>
<div class="overflow-hidden rounded-md border">
<Table>
<TableHeader>
<TableRow>
<TableHead>Varian</TableHead>
<TableHead>Foto</TableHead>
<TableHead class="text-right"
>Pemakaian</TableHead
>
</TableRow>
</TableHeader>
<TableBody>
<template
v-for="group in groupedMaterials"
:key="group.key"
>
<TableRow
class="bg-muted/20 hover:bg-muted/20"
>
<TableCell
colspan="3"
class="font-semibold"
>
{{ group.name }}
<Badge
v-if="group.unitLabel"
variant="secondary"
class="ml-2 font-normal"
>
{{ group.unitLabel }}
</Badge>
</TableCell>
</TableRow>
<TableRow
v-for="material in group.items"
:key="material.id"
>
<TableCell class="pl-6">
{{ material.variant }}
</TableCell>
<TableCell>
<MediaThumbnailCell
:items="material.images ?? []"
:max-visible="1"
/>
</TableCell>
<TableCell
class="text-right tabular-nums"
>
{{
material.material_usage_formatted
}}
</TableCell>
</TableRow>
</template>
</TableBody>
</Table>
</div>
</div>
<!-- Results Section -->
<div v-if="cutting.results.length" class="p-6">
<h3 class="mb-3 text-sm font-semibold">Hasil Produk</h3>
<div class="overflow-hidden rounded-md border">
<Table>
<TableHeader>
<TableRow>
<TableHead>Varian</TableHead>
<TableHead>Foto</TableHead>
<TableHead class="text-right"
>Hasil</TableHead
>
<TableHead class="text-right"
>Sample</TableHead
>
<TableHead class="text-right"
>Diluar Sample</TableHead
>
</TableRow>
</TableHeader>
<TableBody>
<template
v-for="group in groupedResults"
:key="group.key"
>
<TableRow
class="bg-muted/20 hover:bg-muted/20"
>
<TableCell
colspan="5"
class="font-semibold"
>
{{ group.name }}
</TableCell>
</TableRow>
<TableRow
v-for="result in group.items"
:key="result.id"
>
<TableCell class="pl-6">
{{ result.product_variant?.name }}
</TableCell>
<TableCell>
<MediaThumbnailCell
:items="
result.product_variant
?.images ?? []
"
:max-visible="1"
/>
</TableCell>
<TableCell
class="text-right tabular-nums"
>
{{ result.cutting_result }} pcs
</TableCell>
<TableCell
class="text-right tabular-nums"
>
{{ result.sample }} pcs
</TableCell>
<TableCell
class="text-right tabular-nums"
>
{{ result.original_outside_sample }}
pcs
</TableCell>
</TableRow>
</template>
</TableBody>
</Table>
</div>
</div>
</div>
<!-- Footer -->
<div class="mt-6 text-center text-xs text-muted-foreground">
<p>Data ini dibagikan dari sistem DST Collection</p>
</div>
</div>
</div>
</template>