| @@ -32,6 +32,7 @@ interface SemiFGProductionAnalysisReportProps { | |||
| loading: boolean; | |||
| setLoading: (loading: boolean) => void; | |||
| reportTitle?: string; | |||
| onExportSuccess?: (format: "pdf" | "excel") => void; | |||
| } | |||
| export default function SemiFGProductionAnalysisReport({ | |||
| @@ -40,6 +41,7 @@ export default function SemiFGProductionAnalysisReport({ | |||
| loading, | |||
| setLoading, | |||
| reportTitle = '成品/半成品生產分析報告', | |||
| onExportSuccess, | |||
| }: SemiFGProductionAnalysisReportProps) { | |||
| const [showConfirmDialog, setShowConfirmDialog] = useState(false); | |||
| const [selectedItemCodesInfo, setSelectedItemCodesInfo] = useState<ItemCodeWithCategory[]>([]); | |||
| @@ -101,6 +103,7 @@ export default function SemiFGProductionAnalysisReport({ | |||
| } else { | |||
| await generateSemiFGProductionAnalysisReport(criteria, reportTitle); | |||
| } | |||
| onExportSuccess?.(format); | |||
| setShowConfirmDialog(false); | |||
| } catch (error) { | |||
| console.error('Failed to generate report:', error); | |||
| @@ -27,6 +27,11 @@ import { | |||
| fetchSemiFGItemCodesWithCategory | |||
| } from './semiFGProductionAnalysisApi'; | |||
| import { generateGrnReportExcel } from './grnReportApi'; | |||
| import { | |||
| FEATURE_USAGE, | |||
| FEATURE_USAGE_ACTION, | |||
| logFeatureUsage, | |||
| } from '@/lib/featureUsageLog'; | |||
| interface ItemCodeWithName { | |||
| code: string; | |||
| @@ -138,6 +143,10 @@ export default function ReportPage() { | |||
| setDynamicOptions({}); | |||
| }, [selectedReportId]); | |||
| useEffect(() => { | |||
| logFeatureUsage(FEATURE_USAGE.REPORT_MANAGEMENT, FEATURE_USAGE_ACTION.PAGE_VIEW); | |||
| }, []); | |||
| const validateRequiredFields = () => { | |||
| if (!currentReport) return true; | |||
| @@ -220,6 +229,13 @@ export default function ReportPage() { | |||
| link.remove(); | |||
| window.URL.revokeObjectURL(downloadUrl); | |||
| } | |||
| if (currentReport) { | |||
| logFeatureUsage( | |||
| FEATURE_USAGE.REPORT_MANAGEMENT, | |||
| FEATURE_USAGE_ACTION.DOWNLOAD, | |||
| `${currentReport.id}:excel`, | |||
| ); | |||
| } | |||
| setShowConfirmDialog(false); | |||
| } catch (error) { | |||
| console.error("Failed to generate Excel report:", error); | |||
| @@ -265,6 +281,12 @@ export default function ReportPage() { | |||
| link.click(); | |||
| link.remove(); | |||
| window.URL.revokeObjectURL(downloadUrl); | |||
| logFeatureUsage( | |||
| FEATURE_USAGE.REPORT_MANAGEMENT, | |||
| FEATURE_USAGE_ACTION.DOWNLOAD, | |||
| `${currentReport.id}:pdf`, | |||
| ); | |||
| setShowConfirmDialog(false); | |||
| } catch (error) { | |||
| @@ -503,6 +525,13 @@ export default function ReportPage() { | |||
| loading={loading} | |||
| setLoading={setLoading} | |||
| reportTitle={currentReport.title} | |||
| onExportSuccess={(format) => { | |||
| logFeatureUsage( | |||
| FEATURE_USAGE.REPORT_MANAGEMENT, | |||
| FEATURE_USAGE_ACTION.DOWNLOAD, | |||
| `${currentReport.id}:${format}`, | |||
| ); | |||
| }} | |||
| /> | |||
| ) : currentReport.id === 'rep-013' || currentReport.id === 'rep-009' || currentReport.id === 'rep-012' || currentReport.id === 'rep-004' || currentReport.id === 'rep-007' || currentReport.id === 'rep-008' || currentReport.id === 'rep-011' ? ( | |||
| <> | |||
| @@ -45,6 +45,11 @@ import TruckRoutingSummaryTab, { TruckRoutingSummaryFilters } from "./TruckRouti | |||
| import { clientAuthFetch } from "@/app/utils/clientAuthFetch"; | |||
| import { NEXT_PUBLIC_API_URL } from "@/config/api"; | |||
| import { fetchTruckRoutingSummaryPrecheck } from "@/app/(main)/report/truckRoutingSummaryApi"; | |||
| import { | |||
| FEATURE_USAGE, | |||
| FEATURE_USAGE_ACTION, | |||
| logFeatureUsage, | |||
| } from "@/lib/featureUsageLog"; | |||
| interface Props { | |||
| // pickOrders: PickOrderResult[]; | |||
| @@ -350,6 +355,11 @@ const [selectedPrinterForDraft, setSelectedPrinterForDraft] = useState<PrinterCo | |||
| const errorText = await response.text(); | |||
| throw new Error(`HTTP ${response.status}: ${errorText}`); | |||
| } | |||
| logFeatureUsage( | |||
| FEATURE_USAGE.TRUCK_ROUTING_SUMMARY, | |||
| FEATURE_USAGE_ACTION.PRINT, | |||
| `direct:${storeId}:${truckLanceCode}:${date}`, | |||
| ); | |||
| Swal.fire({ | |||
| position: "bottom-end", | |||
| icon: "success", | |||
| @@ -382,6 +392,12 @@ const [selectedPrinterForDraft, setSelectedPrinterForDraft] = useState<PrinterCo | |||
| fetchReleasedOrderCount(); | |||
| }, [fetchReleasedOrderCount]); | |||
| useEffect(() => { | |||
| if (tabIndex === 5) { | |||
| logFeatureUsage(FEATURE_USAGE.TRUCK_ROUTING_SUMMARY, FEATURE_USAGE_ACTION.PAGE_VIEW); | |||
| } | |||
| }, [tabIndex]); | |||
| useEffect(() => { | |||
| const onAssigned = () => { | |||
| localStorage.removeItem('hideCompletedUntilNext'); | |||
| @@ -11,6 +11,11 @@ import { | |||
| fetchTruckRoutingSummaryPrecheck, | |||
| ReportOption, | |||
| } from "@/app/(main)/report/truckRoutingSummaryApi"; | |||
| import { | |||
| FEATURE_USAGE, | |||
| FEATURE_USAGE_ACTION, | |||
| logFeatureUsage, | |||
| } from "@/lib/featureUsageLog"; | |||
| export type TruckRoutingSummaryFilters = { | |||
| storeId: string; | |||
| @@ -94,6 +99,11 @@ const TruckRoutingSummaryTab: React.FC<Props> = ({ onFiltersChange }) => { | |||
| link.click(); | |||
| link.remove(); | |||
| window.URL.revokeObjectURL(downloadUrl); | |||
| logFeatureUsage( | |||
| FEATURE_USAGE.TRUCK_ROUTING_SUMMARY, | |||
| FEATURE_USAGE_ACTION.DOWNLOAD, | |||
| `pdf:${storeId}:${truckLanceCode}:${date}`, | |||
| ); | |||
| } catch (error) { | |||
| console.error("Failed to download Truck Routing Summary", error); | |||
| alert("下載送貨路線摘要失敗,請稍後再試。"); | |||
| @@ -111,5 +111,15 @@ | |||
| "Show Supplier Code": "Show Supplier Code", | |||
| "Show Purchase Order Codes": "Show Purchase Order Codes", | |||
| "x/y orders received": "x/y orders received", | |||
| "Goods Receipt Status New": "Goods Receipt Status" | |||
| "Goods Receipt Status New": "Goods Receipt Status", | |||
| "Usage statistics": "Usage statistics", | |||
| "Usage stats description": "Report management and truck routing summary: page views, downloads, and direct prints.", | |||
| "Usage stats report section": "Report management (報告管理)", | |||
| "Usage stats truck routing section": "Truck routing summary (送貨路線摘要)", | |||
| "Usage stats user": "User", | |||
| "Usage stats page views": "Page views", | |||
| "Usage stats downloads": "Downloads", | |||
| "Usage stats prints": "Direct prints", | |||
| "Usage stats refresh": "Refresh", | |||
| "Usage stats load error": "Could not load usage statistics." | |||
| } | |||
| @@ -119,5 +119,15 @@ | |||
| "Auto-refresh every 5 minutes": "每5分鐘自動刷新", | |||
| "Auto-refresh every 10 minutes": "每10分鐘自動刷新", | |||
| "Auto-refresh every 15 minutes": "每15分鐘自動刷新", | |||
| "Auto-refresh every 1 minute": "每1分鐘自動刷新" | |||
| "Auto-refresh every 1 minute": "每1分鐘自動刷新", | |||
| "Usage statistics": "報告管理與送貨路線摘要使用統計", | |||
| "Usage stats description": "報告管理與送貨路線摘要:進入頁面次數、下載與直接列印次數。", | |||
| "Usage stats report section": "報告管理", | |||
| "Usage stats truck routing section": "送貨路線摘要", | |||
| "Usage stats user": "使用者", | |||
| "Usage stats page views": "進入頁面次數", | |||
| "Usage stats downloads": "下載次數", | |||
| "Usage stats prints": "直接列印次數", | |||
| "Usage stats refresh": "重新整理", | |||
| "Usage stats load error": "無法載入使用統計。" | |||
| } | |||