Files
star-erp/resources/js/Pages/PurchaseOrder/Show.tsx
sky121113 a8091276b8 feat: 優化採購單操作紀錄與統一刪除確認 UI
- 優化採購單更新與刪除的活動紀錄邏輯 (PurchaseOrderController)
  - 整合更新異動為單一紀錄,包含品項差異
  - 刪除時記錄當下品項快照
- 統一採購單刪除確認介面,使用 AlertDialog 取代原生 confirm (PurchaseOrderActions)
- Refactor: 將 ActivityDetailDialog 移至 Components/ActivityLog 並優化樣式與大數據顯示
- 調整 UI 文字:將「總金額」統一為「小計」
- 其他模型與 Controller 的活動紀錄支援更新
2026-01-19 15:32:41 +08:00

170 lines
9.7 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 { ArrowLeft, ShoppingCart } from "lucide-react";
import { Button } from "@/Components/ui/button";
import AuthenticatedLayout from "@/Layouts/AuthenticatedLayout";
import { Head, Link } from "@inertiajs/react";
import { StatusProgressBar } from "@/Components/PurchaseOrder/StatusProgressBar";
import PurchaseOrderStatusBadge from "@/Components/PurchaseOrder/PurchaseOrderStatusBadge";
import CopyButton from "@/Components/shared/CopyButton";
import { PurchaseOrderItemsTable } from "@/Components/PurchaseOrder/PurchaseOrderItemsTable";
import type { PurchaseOrder } from "@/types/purchase-order";
import { formatCurrency, formatDateTime } from "@/utils/format";
import { getShowBreadcrumbs } from "@/utils/breadcrumb";
interface Props {
order: PurchaseOrder;
}
export default function ViewPurchaseOrderPage({ order }: Props) {
return (
<AuthenticatedLayout breadcrumbs={getShowBreadcrumbs("purchaseOrders", `詳情 (#${order.poNumber})`)}>
<Head title={`採購單詳情 - ${order.poNumber}`} />
<div className="container mx-auto p-6 max-w-7xl">
{/* Header */}
<div className="mb-6">
<Link href="/purchase-orders">
<Button
variant="outline"
className="gap-2 button-outlined-primary mb-6"
>
<ArrowLeft className="h-4 w-4" />
</Button>
</Link>
<div className="flex items-center justify-between mb-6">
<div>
<h1 className="text-2xl font-bold text-grey-0 flex items-center gap-2">
<ShoppingCart className="h-6 w-6 text-primary-main" />
</h1>
<p className="text-gray-500 mt-1">{order.poNumber}</p>
</div>
<div className="flex items-center gap-3">
<Link href={`/purchase-orders/${order.id}/edit`}>
<Button variant="outline" className="button-outlined-primary">
</Button>
</Link>
<PurchaseOrderStatusBadge status={order.status} />
</div>
</div>
</div>
{/* 狀態流程條 */}
<div className="mb-8">
<StatusProgressBar currentStatus={order.status} />
</div>
<div className="space-y-8">
{/* 基本資訊與品項 */}
<div className="space-y-8">
{/* 基本資訊卡片 */}
<div className="bg-white rounded-lg border shadow-sm p-6">
<h2 className="text-lg font-bold text-gray-900 mb-6"></h2>
<div className="grid grid-cols-1 md:grid-cols-2 gap-x-8 gap-y-6">
<div>
<span className="text-sm text-gray-500 block mb-1"></span>
<div className="flex items-center gap-1.5">
<span className="font-mono font-medium text-gray-900">{order.poNumber}</span>
<CopyButton text={order.poNumber} label="複製單號" />
</div>
</div>
<div>
<span className="text-sm text-gray-500 block mb-1"></span>
<span className="font-medium text-gray-900">{order.supplierName}</span>
</div>
<div>
<span className="text-sm text-gray-500 block mb-1"> ()</span>
<span className="font-medium text-gray-900">
{order.warehouse_name} ({order.createdBy})
</span>
</div>
<div>
<span className="text-sm text-gray-500 block mb-1"></span>
<span className="font-medium text-gray-900">{formatDateTime(order.createdAt)}</span>
</div>
<div>
<span className="text-sm text-gray-500 block mb-1"></span>
<span className="font-medium text-gray-900">{order.expectedDate || "-"}</span>
</div>
</div>
{order.remark && (
<div className="mt-8 pt-6 border-t border-gray-100">
<span className="text-sm text-gray-500 block mb-2"></span>
<p className="text-sm text-gray-700 bg-gray-50 p-4 rounded-lg leading-relaxed">
{order.remark}
</p>
</div>
)}
</div>
{/* 發票資訊卡片 */}
{(order.invoiceNumber || order.invoiceDate || (order.invoiceAmount !== null && order.invoiceAmount !== undefined)) && (
<div className="bg-white rounded-lg border shadow-sm p-6">
<h2 className="text-lg font-bold text-gray-900 mb-6"></h2>
<div className="grid grid-cols-1 md:grid-cols-3 gap-x-8 gap-y-6">
{order.invoiceNumber && (
<div>
<span className="text-sm text-gray-500 block mb-1"></span>
<div className="flex items-center gap-1.5">
<span className="font-mono font-medium text-gray-900">{order.invoiceNumber}</span>
<CopyButton text={order.invoiceNumber} label="複製發票號碼" />
</div>
</div>
)}
{order.invoiceDate && (
<div>
<span className="text-sm text-gray-500 block mb-1"></span>
<span className="font-medium text-gray-900">{order.invoiceDate}</span>
</div>
)}
{order.invoiceAmount !== null && order.invoiceAmount !== undefined && (
<div>
<span className="text-sm text-gray-500 block mb-1"></span>
<span className="font-medium text-gray-900">{formatCurrency(order.invoiceAmount)}</span>
</div>
)}
</div>
</div>
)}
{/* 採購項目卡片 */}
<div className="bg-white rounded-lg border shadow-sm overflow-hidden">
<div className="p-6 border-b border-gray-100">
<h2 className="text-lg font-bold text-gray-900"></h2>
</div>
<div className="p-6">
<PurchaseOrderItemsTable
items={order.items}
isReadOnly={true}
/>
<div className="mt-4 flex flex-col items-end gap-2 border-t pt-4">
<div className="flex items-center gap-8 text-gray-600">
<span className="font-medium"></span>
<span>{formatCurrency(order.totalAmount)}</span>
</div>
<div className="flex items-center gap-8 text-gray-600">
<span className="font-medium"></span>
<span>{formatCurrency(order.tax_amount || 0)}</span>
</div>
<div className="flex items-center gap-8 pt-2 mt-2 border-t border-gray-100">
<span className="font-bold text-lg"></span>
<span className="text-xl font-bold text-primary">
{formatCurrency(order.grand_total || (order.totalAmount + (order.tax_amount || 0)))}
</span>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</AuthenticatedLayout>
);
}