B.E.N.S.O.N 2 недель назад
Родитель
Сommit
85f922d413
6 измененных файлов: 80 добавлений и 2 удалений
  1. +3
    -0
      src/app/(main)/report/SemiFGProductionAnalysisReport.tsx
  2. +29
    -0
      src/app/(main)/report/page.tsx
  3. +16
    -0
      src/components/FinishedGoodSearch/FinishedGoodSearch.tsx
  4. +10
    -0
      src/components/FinishedGoodSearch/TruckRoutingSummaryTab.tsx
  5. +11
    -1
      src/i18n/en/dashboard.json
  6. +11
    -1
      src/i18n/zh/dashboard.json

+ 3
- 0
src/app/(main)/report/SemiFGProductionAnalysisReport.tsx Просмотреть файл

@@ -32,6 +32,7 @@ interface SemiFGProductionAnalysisReportProps {
loading: boolean; loading: boolean;
setLoading: (loading: boolean) => void; setLoading: (loading: boolean) => void;
reportTitle?: string; reportTitle?: string;
onExportSuccess?: (format: "pdf" | "excel") => void;
} }


export default function SemiFGProductionAnalysisReport({ export default function SemiFGProductionAnalysisReport({
@@ -40,6 +41,7 @@ export default function SemiFGProductionAnalysisReport({
loading, loading,
setLoading, setLoading,
reportTitle = '成品/半成品生產分析報告', reportTitle = '成品/半成品生產分析報告',
onExportSuccess,
}: SemiFGProductionAnalysisReportProps) { }: SemiFGProductionAnalysisReportProps) {
const [showConfirmDialog, setShowConfirmDialog] = useState(false); const [showConfirmDialog, setShowConfirmDialog] = useState(false);
const [selectedItemCodesInfo, setSelectedItemCodesInfo] = useState<ItemCodeWithCategory[]>([]); const [selectedItemCodesInfo, setSelectedItemCodesInfo] = useState<ItemCodeWithCategory[]>([]);
@@ -101,6 +103,7 @@ export default function SemiFGProductionAnalysisReport({
} else { } else {
await generateSemiFGProductionAnalysisReport(criteria, reportTitle); await generateSemiFGProductionAnalysisReport(criteria, reportTitle);
} }
onExportSuccess?.(format);
setShowConfirmDialog(false); setShowConfirmDialog(false);
} catch (error) { } catch (error) {
console.error('Failed to generate report:', error); console.error('Failed to generate report:', error);


+ 29
- 0
src/app/(main)/report/page.tsx Просмотреть файл

@@ -27,6 +27,11 @@ import {
fetchSemiFGItemCodesWithCategory fetchSemiFGItemCodesWithCategory
} from './semiFGProductionAnalysisApi'; } from './semiFGProductionAnalysisApi';
import { generateGrnReportExcel } from './grnReportApi'; import { generateGrnReportExcel } from './grnReportApi';
import {
FEATURE_USAGE,
FEATURE_USAGE_ACTION,
logFeatureUsage,
} from '@/lib/featureUsageLog';


interface ItemCodeWithName { interface ItemCodeWithName {
code: string; code: string;
@@ -138,6 +143,10 @@ export default function ReportPage() {
setDynamicOptions({}); setDynamicOptions({});
}, [selectedReportId]); }, [selectedReportId]);


useEffect(() => {
logFeatureUsage(FEATURE_USAGE.REPORT_MANAGEMENT, FEATURE_USAGE_ACTION.PAGE_VIEW);
}, []);

const validateRequiredFields = () => { const validateRequiredFields = () => {
if (!currentReport) return true; if (!currentReport) return true;


@@ -220,6 +229,13 @@ export default function ReportPage() {
link.remove(); link.remove();
window.URL.revokeObjectURL(downloadUrl); window.URL.revokeObjectURL(downloadUrl);
} }
if (currentReport) {
logFeatureUsage(
FEATURE_USAGE.REPORT_MANAGEMENT,
FEATURE_USAGE_ACTION.DOWNLOAD,
`${currentReport.id}:excel`,
);
}
setShowConfirmDialog(false); setShowConfirmDialog(false);
} catch (error) { } catch (error) {
console.error("Failed to generate Excel report:", error); console.error("Failed to generate Excel report:", error);
@@ -265,6 +281,12 @@ export default function ReportPage() {
link.click(); link.click();
link.remove(); link.remove();
window.URL.revokeObjectURL(downloadUrl); window.URL.revokeObjectURL(downloadUrl);

logFeatureUsage(
FEATURE_USAGE.REPORT_MANAGEMENT,
FEATURE_USAGE_ACTION.DOWNLOAD,
`${currentReport.id}:pdf`,
);
setShowConfirmDialog(false); setShowConfirmDialog(false);
} catch (error) { } catch (error) {
@@ -503,6 +525,13 @@ export default function ReportPage() {
loading={loading} loading={loading}
setLoading={setLoading} setLoading={setLoading}
reportTitle={currentReport.title} 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' ? ( ) : 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' ? (
<> <>


+ 16
- 0
src/components/FinishedGoodSearch/FinishedGoodSearch.tsx Просмотреть файл

@@ -45,6 +45,11 @@ import TruckRoutingSummaryTab, { TruckRoutingSummaryFilters } from "./TruckRouti
import { clientAuthFetch } from "@/app/utils/clientAuthFetch"; import { clientAuthFetch } from "@/app/utils/clientAuthFetch";
import { NEXT_PUBLIC_API_URL } from "@/config/api"; import { NEXT_PUBLIC_API_URL } from "@/config/api";
import { fetchTruckRoutingSummaryPrecheck } from "@/app/(main)/report/truckRoutingSummaryApi"; import { fetchTruckRoutingSummaryPrecheck } from "@/app/(main)/report/truckRoutingSummaryApi";
import {
FEATURE_USAGE,
FEATURE_USAGE_ACTION,
logFeatureUsage,
} from "@/lib/featureUsageLog";


interface Props { interface Props {
// pickOrders: PickOrderResult[]; // pickOrders: PickOrderResult[];
@@ -350,6 +355,11 @@ const [selectedPrinterForDraft, setSelectedPrinterForDraft] = useState<PrinterCo
const errorText = await response.text(); const errorText = await response.text();
throw new Error(`HTTP ${response.status}: ${errorText}`); throw new Error(`HTTP ${response.status}: ${errorText}`);
} }
logFeatureUsage(
FEATURE_USAGE.TRUCK_ROUTING_SUMMARY,
FEATURE_USAGE_ACTION.PRINT,
`direct:${storeId}:${truckLanceCode}:${date}`,
);
Swal.fire({ Swal.fire({
position: "bottom-end", position: "bottom-end",
icon: "success", icon: "success",
@@ -382,6 +392,12 @@ const [selectedPrinterForDraft, setSelectedPrinterForDraft] = useState<PrinterCo
fetchReleasedOrderCount(); fetchReleasedOrderCount();
}, [fetchReleasedOrderCount]); }, [fetchReleasedOrderCount]);


useEffect(() => {
if (tabIndex === 5) {
logFeatureUsage(FEATURE_USAGE.TRUCK_ROUTING_SUMMARY, FEATURE_USAGE_ACTION.PAGE_VIEW);
}
}, [tabIndex]);

useEffect(() => { useEffect(() => {
const onAssigned = () => { const onAssigned = () => {
localStorage.removeItem('hideCompletedUntilNext'); localStorage.removeItem('hideCompletedUntilNext');


+ 10
- 0
src/components/FinishedGoodSearch/TruckRoutingSummaryTab.tsx Просмотреть файл

@@ -11,6 +11,11 @@ import {
fetchTruckRoutingSummaryPrecheck, fetchTruckRoutingSummaryPrecheck,
ReportOption, ReportOption,
} from "@/app/(main)/report/truckRoutingSummaryApi"; } from "@/app/(main)/report/truckRoutingSummaryApi";
import {
FEATURE_USAGE,
FEATURE_USAGE_ACTION,
logFeatureUsage,
} from "@/lib/featureUsageLog";


export type TruckRoutingSummaryFilters = { export type TruckRoutingSummaryFilters = {
storeId: string; storeId: string;
@@ -94,6 +99,11 @@ const TruckRoutingSummaryTab: React.FC<Props> = ({ onFiltersChange }) => {
link.click(); link.click();
link.remove(); link.remove();
window.URL.revokeObjectURL(downloadUrl); window.URL.revokeObjectURL(downloadUrl);
logFeatureUsage(
FEATURE_USAGE.TRUCK_ROUTING_SUMMARY,
FEATURE_USAGE_ACTION.DOWNLOAD,
`pdf:${storeId}:${truckLanceCode}:${date}`,
);
} catch (error) { } catch (error) {
console.error("Failed to download Truck Routing Summary", error); console.error("Failed to download Truck Routing Summary", error);
alert("下載送貨路線摘要失敗,請稍後再試。"); alert("下載送貨路線摘要失敗,請稍後再試。");


+ 11
- 1
src/i18n/en/dashboard.json Просмотреть файл

@@ -111,5 +111,15 @@
"Show Supplier Code": "Show Supplier Code", "Show Supplier Code": "Show Supplier Code",
"Show Purchase Order Codes": "Show Purchase Order Codes", "Show Purchase Order Codes": "Show Purchase Order Codes",
"x/y orders received": "x/y orders received", "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."
} }

+ 11
- 1
src/i18n/zh/dashboard.json Просмотреть файл

@@ -119,5 +119,15 @@
"Auto-refresh every 5 minutes": "每5分鐘自動刷新", "Auto-refresh every 5 minutes": "每5分鐘自動刷新",
"Auto-refresh every 10 minutes": "每10分鐘自動刷新", "Auto-refresh every 10 minutes": "每10分鐘自動刷新",
"Auto-refresh every 15 minutes": "每15分鐘自動刷新", "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": "無法載入使用統計。"
} }

Загрузка…
Отмена
Сохранить