Kaynağa Gözat

[Feat] DO Workbench -> Carton Qty now can search lane and shop + download btn for specified filters

do_workbench_fix
Harry Groves 1 gün önce
ebeveyn
işleme
4665592671
8 değiştirilmiş dosya ile 905 ekleme ve 175 silme
  1. +0
    -2
      src/app/api/doworkbench/actions.ts
  2. +0
    -2
      src/app/api/pickOrder/actions.ts
  3. +768
    -139
      src/components/FinishedGoodSearch/FinishedGoodCartonDashboardTab.tsx
  4. +59
    -32
      src/components/charts/SafeApexCharts.tsx
  5. +21
    -0
      src/i18n/en/doWorkbench.json
  6. +18
    -0
      src/i18n/en/pickOrder.json
  7. +21
    -0
      src/i18n/zh/doWorkbench.json
  8. +18
    -0
      src/i18n/zh/pickOrder.json

+ 0
- 2
src/app/api/doworkbench/actions.ts Dosyayı Görüntüle

@@ -216,7 +216,6 @@ export async function fetchWorkbenchStoreLaneSummary(
return serverFetchJson<StoreLaneSummary>(url, {
method: "GET",
cache: "no-store",
next: { revalidate: 0 },
});
}

@@ -235,7 +234,6 @@ export async function fetchWorkbenchEtraLaneSummary(
const data = await serverFetchJson<WorkbenchEtraShopLaneGroup[]>(url, {
method: "GET",
cache: "no-store",
next: { revalidate: 0 },
});
return Array.isArray(data) ? data : [];
}


+ 0
- 2
src/app/api/pickOrder/actions.ts Dosyayı Görüntüle

@@ -632,7 +632,6 @@ export async function fetchStoreLaneSummary(storeId: string, requiredDate?: stri
const response = await serverFetchJson<StoreLaneSummary>(url, {
method: "GET",
cache: "no-store",
next: { revalidate: 0 },
});
console.timeEnd(label);
return response;
@@ -856,7 +855,6 @@ export const fetchFGPickOrdersByUserIdWorkbench = async (userId: number) => {
method: "GET",
// Must be fresh: determines whether shell shows Floor/Lane panel or Detail.
cache: "no-store",
next: { revalidate: 0 },
},
);
};


+ 768
- 139
src/components/FinishedGoodSearch/FinishedGoodCartonDashboardTab.tsx
Dosya farkı çok büyük olduğundan ihmal edildi
Dosyayı Görüntüle


+ 59
- 32
src/components/charts/SafeApexCharts.tsx Dosyayı Görüntüle

@@ -150,6 +150,34 @@ function buildApexConfig(

const EMPTY_MESSAGE = "暫無圖表資料(後端無法連線或此區間無資料)。";

/** Apex mutates `options` in place (circular refs). Never throw during render. */
function safeStringify(value: unknown): string {
const seen = new WeakSet<object>();
try {
return JSON.stringify(value, (_key, nested) => {
if (typeof nested === "function") return undefined;
if (typeof nested === "object" && nested !== null) {
if (seen.has(nested)) return undefined;
seen.add(nested);
}
return nested;
});
} catch {
return "";
}
}

function destroyChart(chartRef: { current: { destroy: () => void } | null }) {
const current = chartRef.current;
chartRef.current = null;
if (!current) return;
try {
current.destroy();
} catch {
/* ignore */
}
}

export default function SafeApexCharts(props: SafeApexChartsProps) {
const { type, series, options, height, width, chartRevision, allowZeroSeries = false, ...rest } = props;
const containerRef = useRef<HTMLDivElement>(null);
@@ -162,18 +190,11 @@ export default function SafeApexCharts(props: SafeApexChartsProps) {
sanitized = alignSeriesToCategoryCount(sanitized, cats.length);
}

if (shouldShowPlaceholder(type, options, sanitized, allowZeroSeries)) {
return (
<Typography color="text.secondary" sx={{ py: 3 }}>
{EMPTY_MESSAGE}
</Typography>
);
}

let chartOptions = options;
let renderSeries: ApexChartProps["series"] = sanitized;
let showPlaceholder = shouldShowPlaceholder(type, options, sanitized, allowZeroSeries);

if (isRadialChart(type) && isNumberArray(sanitized)) {
if (!showPlaceholder && isRadialChart(type) && isNumberArray(sanitized)) {
const prev = Array.isArray(options?.labels) ? (options!.labels as unknown[]) : [];
const pairs = sanitized.map((v, i) => {
const n = Number.isFinite(v) ? v : 0;
@@ -183,20 +204,31 @@ export default function SafeApexCharts(props: SafeApexChartsProps) {
});
const nonzero = pairs.filter((p) => p.v > 0);
if (nonzero.length === 0) {
return (
<Typography color="text.secondary" sx={{ py: 3 }}>
{EMPTY_MESSAGE}
</Typography>
);
showPlaceholder = true;
} else {
renderSeries = nonzero.map((p) => p.v);
chartOptions = { ...options, labels: nonzero.map((p) => p.label) };
}
renderSeries = nonzero.map((p) => p.v);
chartOptions = { ...options, labels: nonzero.map((p) => p.label) };
}

const chartType = String(type ?? "line");
const configSnapshot = `${String(chartRevision ?? "")}|${chartType}|${JSON.stringify(renderSeries ?? null)}|${JSON.stringify(chartOptions ?? {})}|${String(height ?? "")}|${String(width ?? "")}`;
const configSnapshot = [
String(chartRevision ?? ""),
chartType,
String(showPlaceholder),
safeStringify(renderSeries ?? null),
safeStringify(cats ?? null),
safeStringify(chartOptions?.labels ?? null),
String(height ?? ""),
String(width ?? ""),
].join("|");

useEffect(() => {
if (showPlaceholder) {
destroyChart(chartRef);
return;
}

const el = containerRef.current;
if (!el) return;

@@ -219,12 +251,7 @@ export default function SafeApexCharts(props: SafeApexChartsProps) {

if (disposed || containerRef.current !== el) {
if (chartRef.current === instance) {
try {
instance.destroy();
} catch {
/* ignore */
}
chartRef.current = null;
destroyChart(chartRef);
}
return;
}
@@ -236,21 +263,21 @@ export default function SafeApexCharts(props: SafeApexChartsProps) {

return () => {
disposed = true;
const c = chartRef.current;
chartRef.current = null;
if (c) {
try {
c.destroy();
} catch {
/* ignore */
}
}
destroyChart(chartRef);
};
}, [configSnapshot]);

const minH = typeof height === "number" ? height : typeof height === "string" ? height : 240;
const dom = rest as { className?: string; id?: string; style?: CSSProperties; sx?: object };

if (showPlaceholder) {
return (
<Typography color="text.secondary" sx={{ py: 3 }}>
{EMPTY_MESSAGE}
</Typography>
);
}

return (
<Box
ref={containerRef}


+ 21
- 0
src/i18n/en/doWorkbench.json Dosyayı Görüntüle

@@ -60,7 +60,28 @@
"Truck Routing Summary (Workbench)": "Truck Routing Summary (Workbench)",
"2/F or 4/F": "2/F or 4/F",
"Lane": "Lane",
"Shop Code": "Shop group",
"All lanes": "All lanes",
"All shops": "All shop groups",
"Cartons by lane": "Cartons by lane",
"Cartons by shop": "Cartons by shop",
"Cartons by shop group": "Cartons by shop group",
"Cartons by floor": "Cartons by floor",
"Share": "Share",
"Click a row to filter": "Click a row to filter",
"Click a bar to filter": "Click a bar to filter",
"Reset filters": "Reset filters",
"Cartons": "Cartons",
"Date": "Date",
"Download Excel": "Download Excel",
"Download this view Excel": "Download Excel (Selected)",
"Download period Excel": "Download Excel (All)",
"Download this view Excel hint": "Excel of the current floor, lane, shop, and date, plus the chart breakdown.",
"Download period Excel hint": "Excel with last 7 days, this month, and this year. Not limited to the current view.",
"Filtered": "Filtered",
"Breakdown": "Breakdown",
"All floors": "All floors",
"FG carton qty filtered title": "FG carton qty (filtered) - {{floor}} - {{lane}} - {{shop}} - {{date}}",
"Generating...": "Generating...",
"Download report (PDF)": "Download report (PDF)",
"Unpicked orders confirm download": "This lane still has {{count}} unpicked order(s).\nPrint / download the truck routing summary anyway?",


+ 18
- 0
src/i18n/en/pickOrder.json Dosyayı Görüntüle

@@ -624,9 +624,27 @@
"FG carton qty this year title": "FG carton qty (this year) - {{floor}} - {{period}}",
"Exporting...": "Exporting...",
"Download Excel": "Download Excel",
"Download this view Excel": "Download Excel (Selected)",
"Download period Excel": "Download Excel (All)",
"Download this view Excel hint": "Excel of the current floor, lane, shop, and date, plus the chart breakdown.",
"Download period Excel hint": "Excel with last 7 days, this month, and this year. Not limited to the current view.",
"Filtered": "Filtered",
"Breakdown": "Breakdown",
"FG carton qty filtered title": "FG carton qty (filtered) - {{floor}} - {{lane}} - {{shop}} - {{date}}",
"Truck Routing Summary (Workbench)": "Truck Routing Summary (Workbench)",
"2/F or 4/F": "2/F or 4/F",
"Lane": "Lane",
"Shop Code": "Shop group",
"All lanes": "All lanes",
"All shops": "All shop groups",
"Cartons by lane": "Cartons by lane",
"Cartons by shop": "Cartons by shop",
"Cartons by shop group": "Cartons by shop group",
"Cartons by floor": "Cartons by floor",
"Share": "Share",
"Click a row to filter": "Click a row to filter",
"Click a bar to filter": "Click a bar to filter",
"Reset filters": "Reset filters",
"Generating...": "Generating...",
"Download report (PDF)": "Download report (PDF)",
"Unpicked orders confirm download": "This lane still has {{count}} unpicked order(s).\nPrint / download the truck routing summary anyway?",


+ 21
- 0
src/i18n/zh/doWorkbench.json Dosyayı Görüntüle

@@ -55,7 +55,28 @@
"Truck Routing Summary (Workbench)": "送貨路線摘要 (Workbench)",
"2/F or 4/F": "2/F 或 4/F",
"Lane": "車線",
"Shop Code": "店鋪組別",
"All lanes": "全部車線",
"All shops": "全部店鋪組別",
"Cartons by lane": "按車線統計箱數",
"Cartons by shop": "按店鋪編號統計箱數",
"Cartons by shop group": "按店鋪組別統計箱數",
"Cartons by floor": "按樓層統計箱數",
"Share": "佔比",
"Click a row to filter": "點選列以篩選",
"Click a bar to filter": "點選長條以篩選",
"Reset filters": "重設篩選",
"Cartons": "箱數",
"Date": "日期",
"Download Excel": "下載 Excel",
"Download this view Excel": "下載 Excel(已選)",
"Download period Excel": "下載 Excel(全部)",
"Download this view Excel hint": "匯出目前樓層、車線、店鋪組別、日期的箱數,以及圖表分項。",
"Download period Excel hint": "匯出近7天、本月、本年的箱數,不限目前篩選畫面。",
"Filtered": "篩選",
"Breakdown": "分項",
"All floors": "全部樓層",
"FG carton qty filtered title": "成品出倉出箱數量(篩選)- {{floor}} - {{lane}} - {{shop}} - {{date}}",
"Generating...": "生成中...",
"Download report (PDF)": "下載報告 (PDF)",
"Unpicked orders confirm download": "此車線仍有 {{count}} 張訂單未執拾。\n是否仍要列印 / 下載送貨路線摘要?",


+ 18
- 0
src/i18n/zh/pickOrder.json Dosyayı Görüntüle

@@ -636,9 +636,27 @@
"FG carton qty this year title": "成品出倉出箱數量(本年)- {{floor}} - {{period}}",
"Exporting...": "匯出中...",
"Download Excel": "下載 Excel",
"Download this view Excel": "下載 Excel(已選)",
"Download period Excel": "下載 Excel(全部)",
"Download this view Excel hint": "匯出目前樓層、車線、店鋪組別、日期的箱數,以及圖表分項。",
"Download period Excel hint": "匯出近7天、本月、本年的箱數,不限目前篩選畫面。",
"Filtered": "篩選",
"Breakdown": "分項",
"FG carton qty filtered title": "成品出倉出箱數量(篩選)- {{floor}} - {{lane}} - {{shop}} - {{date}}",
"Truck Routing Summary (Workbench)": "送貨路線摘要 (Workbench)",
"2/F or 4/F": "2/F 或 4/F",
"Lane": "車線",
"Shop Code": "店鋪組別",
"All lanes": "全部車線",
"All shops": "全部店鋪組別",
"Cartons by lane": "按車線統計箱數",
"Cartons by shop": "按店鋪編號統計箱數",
"Cartons by shop group": "按店鋪組別統計箱數",
"Cartons by floor": "按樓層統計箱數",
"Share": "佔比",
"Click a row to filter": "點選列以篩選",
"Click a bar to filter": "點選長條以篩選",
"Reset filters": "重設篩選",
"Generating...": "生成中...",
"Download report (PDF)": "下載報告 (PDF)",
"Unpicked orders confirm download": "此車線仍有 {{count}} 張訂單未執拾。\n是否仍要列印 / 下載送貨路線摘要?",


Yükleniyor…
İptal
Kaydet