import { useState } from 'react'; import AuthenticatedLayout from '@/Layouts/AuthenticatedLayout'; import { Head, router } from '@inertiajs/react'; import { PageProps } from '@/types/global'; import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow, } from "@/Components/ui/table"; import { Badge } from "@/Components/ui/badge"; import Pagination from '@/Components/shared/Pagination'; import { SearchableSelect } from "@/Components/ui/searchable-select"; import { FileText, Eye, ArrowUpDown, ArrowUp, ArrowDown } from 'lucide-react'; import { Button } from '@/Components/ui/button'; import ActivityDetailDialog from './ActivityDetailDialog'; interface Activity { id: number; description: string; subject_type: string; event: string; causer: string; created_at: string; properties: any; } interface PaginationLinks { url: string | null; label: string; active: boolean; } interface Props extends PageProps { activities: { data: Activity[]; links: PaginationLinks[]; current_page: number; last_page: number; total: number; from: number; }; filters: { per_page?: string; sort_by?: string; sort_order?: 'asc' | 'desc'; }; } export default function ActivityLogIndex({ activities, filters }: Props) { const [perPage, setPerPage] = useState(filters.per_page || "10"); const [selectedActivity, setSelectedActivity] = useState(null); const [detailOpen, setDetailOpen] = useState(false); const getEventBadgeClass = (event: string) => { switch (event) { case 'created': return 'bg-green-50 text-green-700 border-green-200 hover:bg-green-100'; case 'updated': return 'bg-blue-50 text-blue-700 border-blue-200 hover:bg-blue-100'; case 'deleted': return 'bg-red-50 text-red-700 border-red-200 hover:bg-red-100'; default: return 'bg-gray-50 text-gray-700 border-gray-200 hover:bg-gray-100'; } }; const getEventLabel = (event: string) => { switch (event) { case 'created': return '新增'; case 'updated': return '更新'; case 'deleted': return '刪除'; default: return event; } }; const getDescription = (activity: Activity) => { const props = activity.properties || {}; const attrs = props.attributes || {}; const old = props.old || {}; // Try to find a name in attributes or old values // Priority: specific name fields > generic name > code > ID const nameParams = ['product_name', 'warehouse_name', 'category_name', 'base_unit_name', 'name', 'code', 'title']; let subjectName = ''; // Special handling for Inventory: show "Warehouse - Product" if (attrs.warehouse_name && attrs.product_name) { subjectName = `${attrs.warehouse_name} - ${attrs.product_name}`; } else if (old.warehouse_name && old.product_name) { subjectName = `${old.warehouse_name} - ${old.product_name}`; } else { // Default fallback for (const param of nameParams) { if (attrs[param]) { subjectName = attrs[param]; break; } if (old[param]) { subjectName = old[param]; break; } } } // If no name found, try ID but format it nicely if possible, or just don't show it if it's redundant with subject_type if (!subjectName && (attrs.id || old.id)) { subjectName = `#${attrs.id || old.id}`; } // Combine parts: [Causer] [Action] [Name] [Subject] // Example: Admin 新增 可樂 商品 // Example: Admin 更新 台北倉 - 可樂 庫存 return ( {activity.causer} {getEventLabel(activity.event)} {subjectName && ( {subjectName} )} {activity.subject_type} {/* Display reason/source if available (e.g., from Replenishment) */} {(attrs._reason || old._reason) && ( (來自 {attrs._reason || old._reason}) )} ); }; const handleViewDetail = (activity: Activity) => { setSelectedActivity(activity); setDetailOpen(true); }; const handlePerPageChange = (value: string) => { setPerPage(value); router.get( route('activity-logs.index'), { ...filters, per_page: value }, { preserveState: false, replace: true, preserveScroll: true } ); }; const handleSort = (field: string) => { let newSortBy: string | undefined = field; let newSortOrder: 'asc' | 'desc' | undefined = 'asc'; if (filters.sort_by === field) { if (filters.sort_order === 'asc') { newSortOrder = 'desc'; } else { newSortBy = undefined; newSortOrder = undefined; } } router.get( route('activity-logs.index'), { ...filters, sort_by: newSortBy, sort_order: newSortOrder }, { preserveState: true, replace: true } ); }; const SortIcon = ({ field }: { field: string }) => { if (filters.sort_by !== field) { return ; } if (filters.sort_order === "asc") { return ; } return ; }; return (

操作紀錄

檢視系統內的所有操作活動,包含新增、修改與刪除紀錄

# 操作人員 描述 動作 對象 操作 {activities.data.length > 0 ? ( activities.data.map((activity, index) => ( {activities.from + index} {activity.created_at} {activity.causer} {getDescription(activity)} {getEventLabel(activity.event)} {activity.subject_type} )) ) : ( 尚無操作紀錄 )}
每頁顯示
); }