Files
star-erp/resources/js/Pages/Inventory/Traceability/Index.tsx

155 lines
8.3 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 React, { useState } from 'react';
import { Head, router } from '@inertiajs/react';
import AuthenticatedLayout from '@/Layouts/AuthenticatedLayout';
import { PageProps } from '@/types/global';
import { Card, CardContent, CardHeader, CardTitle } from '@/Components/ui/card';
import { Button } from '@/Components/ui/button';
import { Input } from '@/Components/ui/input';
import { Label } from '@/Components/ui/label';
import { TrendingUp, Search, RotateCcw } from 'lucide-react';
import { RadioGroup, RadioGroupItem } from '@/Components/ui/radio-group';
import { cn } from '@/lib/utils';
import TreeView, { TraceabilityNode } from './Components/TreeView';
import { TraceabilitySummary } from './Components/TraceabilitySummary';
import { Can } from '@/Components/Permission/Can';
interface Props extends PageProps {
search: {
batch_number: string | null;
direction: 'backward' | 'forward';
};
result: TraceabilityNode | null;
}
export default function TraceabilityIndex({ search, result }: Props) {
const [batchNumber, setBatchNumber] = useState(search.batch_number || '');
const [direction, setDirection] = useState<'backward' | 'forward'>(search.direction || 'backward');
const [isSearching, setIsSearching] = useState(false);
const handleSearch = (e: React.FormEvent) => {
e.preventDefault();
if (!batchNumber.trim()) return;
setIsSearching(true);
router.get(
route('inventory.traceability.index'),
{ batch_number: batchNumber.trim(), direction },
{
preserveState: true,
preserveScroll: true,
onFinish: () => setIsSearching(false)
}
);
};
return (
<AuthenticatedLayout
breadcrumbs={[
{ label: '報表管理', href: '#' },
{ label: '批號溯源', href: route('inventory.traceability.index'), isPage: true },
]}
>
<Head title="批號溯源 - Star ERP" />
<div className="container mx-auto p-6 max-w-7xl">
<div className="mb-6">
<div className="mb-4">
<h1 className="text-2xl font-bold text-grey-0 flex items-center gap-2">
<TrendingUp className="h-6 w-6 text-primary-main" />
</h1>
<p className="text-gray-500 mt-1">
</p>
</div>
</div>
<Can permission="inventory.traceability.view">
<Card className="mb-6 bg-white shadow-sm border-gray-200">
<CardHeader className="pb-3 border-b border-gray-100 bg-gray-50/50">
<CardTitle className="text-lg flex items-center gap-2 text-gray-800">
<Search className="h-5 w-5 text-primary-main" />
</CardTitle>
</CardHeader>
<CardContent className="pt-6">
<form onSubmit={handleSearch} className="flex flex-col md:flex-row gap-6 items-start md:items-end">
<div className="flex-1 w-full space-y-1.5">
<Label htmlFor="batchNumber" className="text-sm font-medium text-grey-1"></Label>
<Input
id="batchNumber"
type="text"
placeholder="請輸入欲查詢的批號 (例如PROD-TW-20240101-01)"
value={batchNumber}
onChange={(e) => setBatchNumber(e.target.value)}
className="max-w-md w-full"
/>
</div>
<div className="space-y-3">
<Label className="text-gray-700 font-medium"></Label>
<RadioGroup
value={direction}
onValueChange={(val: 'backward' | 'forward') => setDirection(val)}
className="flex space-x-6"
>
<div
className={cn(
"flex items-center space-x-2 px-4 py-2 rounded-lg border cursor-pointer transition-colors",
direction === 'backward' ? "bg-primary-lightest border-primary-light" : "bg-gray-50 border-gray-200 hover:bg-gray-100"
)}
>
<RadioGroupItem value="backward" id="backward" />
<Label htmlFor="backward" className="cursor-pointer flex items-center gap-1.5 font-medium">
<RotateCcw className="h-4 w-4 text-primary-main" />
( )
</Label>
</div>
<div
className={cn(
"flex items-center space-x-2 px-4 py-2 rounded-lg border cursor-pointer transition-colors",
direction === 'forward' ? "bg-primary-lightest border-primary-light" : "bg-gray-50 border-gray-200 hover:bg-gray-100"
)}
>
<RadioGroupItem value="forward" id="forward" />
<Label htmlFor="forward" className="cursor-pointer flex items-center gap-1.5 font-medium">
<TrendingUp className="h-4 w-4 text-primary-main" />
( )
</Label>
</div>
</RadioGroup>
</div>
<Button
type="submit"
disabled={isSearching || !batchNumber.trim()}
className="button-filled-primary min-w-[120px]"
>
{isSearching ? '查詢中...' : '開始查詢'}
</Button>
</form>
</CardContent>
</Card>
{search.batch_number && (
<div className="bg-white rounded-xl border border-gray-200 shadow-sm overflow-hidden p-6 md:p-8">
{result ? (
<>
<TraceabilitySummary data={result} direction={search.direction || 'backward'} />
<TreeView data={result} />
</>
) : (
<div className="py-16 flex flex-col items-center justify-center text-gray-500">
<Search className="h-12 w-12 text-gray-300 mb-4" />
<h3 className="text-lg font-medium text-gray-900 mb-1"></h3>
<p>{search.batch_number}</p>
</div>
)}
</div>
)}
</Can>
</div>
</AuthenticatedLayout>
);
}