浏览代码

Add stock lot on-hand report (rep-021) to report management.

Register filters, inventory category, Excel download lock, and no-data dialog. Includes extra inbound-trace (rep-004) location/PP-PF filters already staged.

Co-authored-by: Cursor <[email protected]>
fix負數倉
CANCERYS\kw093 2 周前
父节点
当前提交
aee380e28f
共有 6 个文件被更改,包括 327 次插入19 次删除
  1. +2
    -0
      src/app/(main)/report/ReportSelectionDashboard.tsx
  2. +108
    -14
      src/app/(main)/report/page.tsx
  3. +2
    -2
      src/app/(main)/report/reportCategories.ts
  4. +119
    -1
      src/config/reportConfig.ts
  5. +48
    -1
      src/i18n/en/report.json
  6. +48
    -1
      src/i18n/zh/report.json

+ 2
- 0
src/app/(main)/report/ReportSelectionDashboard.tsx 查看文件

@@ -25,6 +25,7 @@ const REPORT_ICON_MAP: Record<string, SvgIconComponent> = {
"rep-011": Inventory2OutlinedIcon, "rep-011": Inventory2OutlinedIcon,
"rep-007": MonetizationOnOutlinedIcon, "rep-007": MonetizationOnOutlinedIcon,
"rep-012": LayersOutlinedIcon, "rep-012": LayersOutlinedIcon,
"rep-021": Inventory2OutlinedIcon,
"rep-010": SearchOutlinedIcon, "rep-010": SearchOutlinedIcon,
"rep-004": LocalShippingOutlinedIcon, "rep-004": LocalShippingOutlinedIcon,
"rep-014": LocalShippingOutlinedIcon, "rep-014": LocalShippingOutlinedIcon,
@@ -170,6 +171,7 @@ function CategoryColumn({
); );
} }


/** FP-MTMS Version Checklist | Functions Ref. No. 69 | v1.0.0 | 2026-08-31 */
export default function ReportSelectionDashboard({ export default function ReportSelectionDashboard({
selectedReportId, selectedReportId,
onSelectReport, onSelectReport,


+ 108
- 14
src/app/(main)/report/page.tsx 查看文件

@@ -1,6 +1,6 @@
"use client"; "use client";


import React, { useState, useMemo, useEffect } from 'react';
import React, { useState, useMemo, useEffect, useRef } from 'react';
import { useSession } from "next-auth/react"; import { useSession } from "next-auth/react";
import { SessionWithTokens } from "@/config/authConfig"; import { SessionWithTokens } from "@/config/authConfig";
import { AUTH } from "@/authorities"; import { AUTH } from "@/authorities";
@@ -18,8 +18,13 @@ import {
Autocomplete, Autocomplete,
Checkbox, Checkbox,
FormControlLabel, FormControlLabel,
Dialog,
DialogTitle,
DialogContent,
DialogActions,
} from '@mui/material'; } from '@mui/material';
import DownloadIcon from '@mui/icons-material/Download'; import DownloadIcon from '@mui/icons-material/Download';
import InfoOutlinedIcon from '@mui/icons-material/InfoOutlined';
import { REPORTS } from '@/config/reportConfig'; import { REPORTS } from '@/config/reportConfig';
import { NEXT_PUBLIC_API_URL } from '@/config/api'; import { NEXT_PUBLIC_API_URL } from '@/config/api';
import { clientAuthFetch } from '@/app/utils/clientAuthFetch'; import { clientAuthFetch } from '@/app/utils/clientAuthFetch';
@@ -46,6 +51,7 @@ interface ItemCodeWithName {


/** FP-MTMS Version Checklist | Functions Ref. No. 39 | v1.0.0 | 2026-08-03 */ /** FP-MTMS Version Checklist | Functions Ref. No. 39 | v1.0.0 | 2026-08-03 */
/** FP-MTMS Version Checklist | Functions Ref. No. 60 | v1.0.1 | 2026-08-11 */ /** FP-MTMS Version Checklist | Functions Ref. No. 60 | v1.0.1 | 2026-08-11 */
/** FP-MTMS Version Checklist | Functions Ref. No. 69 | v1.0.0 | 2026-08-31 */
export default function ReportPage() { export default function ReportPage() {
const { data: session } = useSession() as { data: SessionWithTokens | null }; const { data: session } = useSession() as { data: SessionWithTokens | null };
const { t, reportTitle, fieldLabel, optionLabel } = useReportLabels(); const { t, reportTitle, fieldLabel, optionLabel } = useReportLabels();
@@ -55,8 +61,10 @@ export default function ReportPage() {
const [selectedReportId, setSelectedReportId] = useState<string>(''); const [selectedReportId, setSelectedReportId] = useState<string>('');
const [criteria, setCriteria] = useState<Record<string, string>>({}); const [criteria, setCriteria] = useState<Record<string, string>>({});
const [loading, setLoading] = useState(false); const [loading, setLoading] = useState(false);
const excelInFlightRef = useRef(false);
const [dynamicOptions, setDynamicOptions] = useState<Record<string, { label: string; value: string }[]>>({}); const [dynamicOptions, setDynamicOptions] = useState<Record<string, { label: string; value: string }[]>>({});
const [showConfirmDialog, setShowConfirmDialog] = useState(false); const [showConfirmDialog, setShowConfirmDialog] = useState(false);
const [showNoDataDialog, setShowNoDataDialog] = useState(false);
// Find the configuration for the currently selected report // Find the configuration for the currently selected report
const rep012RoundIds = useMemo(() => { const rep012RoundIds = useMemo(() => {
@@ -76,13 +84,27 @@ export default function ReportPage() {
const handleSelectReport = (reportId: string) => { const handleSelectReport = (reportId: string) => {
if (reportId === selectedReportId) return; if (reportId === selectedReportId) return;
setSelectedReportId(reportId); setSelectedReportId(reportId);
// rep-010: default QC item scope to all (show label, not empty select)
setCriteria(reportId === 'rep-010' ? { qcType: 'all', qcItemScope: 'all' } : {});
if (reportId === 'rep-010') {
setCriteria({ qcType: 'all', qcItemScope: 'all' });
} else if (reportId === 'rep-004') {
setCriteria({ storeId: 'All', poPrefix: 'All' });
} else if (reportId === 'rep-021') {
setCriteria({ storeId: 'All', stockTakeSectionDescription: 'All', lotOrigin: 'All' });
} else {
setCriteria({});
}
}; };


const handleFieldChange = (name: string, value: string | string[]) => { const handleFieldChange = (name: string, value: string | string[]) => {
const stringValue = Array.isArray(value) ? value.join(',') : value; const stringValue = Array.isArray(value) ? value.join(',') : value;
setCriteria((prev) => ({ ...prev, [name]: stringValue }));
setCriteria((prev) => {
const next = { ...prev, [name]: stringValue };
if (currentReport?.id === 'rep-021' && name === 'warehouse') {
const m = stringValue.trim().match(/^w(\d)/i);
if (m) next.storeId = `${m[1]}F`;
}
return next;
});
// If this is stockCategory and there's a field that depends on it, fetch dynamic options // If this is stockCategory and there's a field that depends on it, fetch dynamic options
if (name === 'stockCategory' && currentReport) { if (name === 'stockCategory' && currentReport) {
@@ -139,8 +161,27 @@ export default function ReportPage() {
if (!response.ok) throw new Error(`HTTP error! status: ${response.status}`); if (!response.ok) throw new Error(`HTTP error! status: ${response.status}`);


const data = await response.json(); const data = await response.json();
const options = Array.isArray(data)
? data.map((item: any) => ({ label: item.label || item.name || item.code || String(item), value: item.value || item.code || String(item) }))
const options = Array.isArray(data)
? field.name === 'stockTakeSectionDescription'
? (() => {
const seen = new Set<string>();
const mapped: { label: string; value: string }[] = [{ label: '全部', value: 'All' }];
data.forEach((item: { stockTakeSectionDescription?: string; stockTakeSection?: string }) => {
const desc = (item.stockTakeSectionDescription || '').trim();
if (!desc || seen.has(desc)) return;
seen.add(desc);
const section = (item.stockTakeSection || '').trim();
mapped.push({
label: section ? `${desc} (${section})` : desc,
value: desc,
});
});
return mapped;
})()
: data.map((item: any) => ({
label: item.label || item.name || item.code || String(item),
value: item.value || item.code || String(item),
}))
: []; : [];
setDynamicOptions((prev) => ({ ...prev, [field.name]: options })); setDynamicOptions((prev) => ({ ...prev, [field.name]: options }));
@@ -303,6 +344,8 @@ export default function ReportPage() {


const executeExcelReport = async () => { const executeExcelReport = async () => {
if (!currentReport) return; if (!currentReport) return;
if (excelInFlightRef.current) return;
excelInFlightRef.current = true;
setLoading(true); setLoading(true);
try { try {
if (currentReport.id === 'rep-014') { if (currentReport.id === 'rep-014') {
@@ -342,6 +385,10 @@ export default function ReportPage() {
}); });


if (response.status === 401 || response.status === 403) return; if (response.status === 401 || response.status === 403) return;
if (response.status === 204) {
setShowNoDataDialog(true);
return;
}
if (!response.ok) { if (!response.ok) {
const errorText = await response.text(); const errorText = await response.text();
console.error("Response error:", errorText); console.error("Response error:", errorText);
@@ -378,6 +425,7 @@ export default function ReportPage() {
alert(t('generateError')); alert(t('generateError'));
} finally { } finally {
setLoading(false); setLoading(false);
excelInFlightRef.current = false;
} }
}; };


@@ -386,7 +434,7 @@ export default function ReportPage() {


setLoading(true); setLoading(true);
try { try {
const queryParams =
let queryParams =
currentReport.id === 'rep-012' currentReport.id === 'rep-012'
? buildRep012QueryString() ? buildRep012QueryString()
: currentReport.id === 'rep-010' : currentReport.id === 'rep-010'
@@ -439,6 +487,7 @@ export default function ReportPage() {
}; };


return ( return (
<>
<Box sx={{ p: 4, maxWidth: 1280, margin: '0 auto' }}> <Box sx={{ p: 4, maxWidth: 1280, margin: '0 auto' }}>
<Typography variant="h4" gutterBottom fontWeight="bold"> <Typography variant="h4" gutterBottom fontWeight="bold">
{t('title')} {t('title')}
@@ -460,12 +509,13 @@ export default function ReportPage() {
<Grid container spacing={3}> <Grid container spacing={3}>
{currentReport.fields.map((field) => { {currentReport.fields.map((field) => {
const translatedLabel = fieldLabel(currentReport.id, field); const translatedLabel = fieldLabel(currentReport.id, field);
const options = field.dynamicOptions
? (dynamicOptions[field.name] || [])
: (field.options || []).map((opt) => ({
...opt,
label: optionLabel(currentReport.id, field.name, opt),
}));
const rawOptions = field.dynamicOptions
? (dynamicOptions[field.name] || field.options || [])
: (field.options || []);
const options = rawOptions.map((opt) => ({
...opt,
label: optionLabel(currentReport.id, field.name, opt),
}));
const currentValue = criteria[field.name] || ''; const currentValue = criteria[field.name] || '';
const valueForSelect = field.multiple const valueForSelect = field.multiple
? (currentValue ? currentValue.split(',').map(v => v.trim()).filter(v => v) : []) ? (currentValue ? currentValue.split(',').map(v => v.trim()).filter(v => v) : [])
@@ -602,7 +652,7 @@ export default function ReportPage() {
label={translatedLabel} label={translatedLabel}
type={field.type} type={field.type}
placeholder={field.placeholder} placeholder={field.placeholder}
disabled={disabledByCheckedCheckbox || disabledRep012Status}
disabled={disabledByCheckedCheckbox || disabledRep012Status || !!field.disabled}
InputLabelProps={field.type === 'date' ? { shrink: true } : {}} InputLabelProps={field.type === 'date' ? { shrink: true } : {}}
inputProps={ inputProps={
field.type === 'date' && field.minDate === 'today' field.type === 'date' && field.minDate === 'today'
@@ -778,5 +828,49 @@ export default function ReportPage() {
</Card> </Card>
)} )}
</Box> </Box>
<Dialog
open={showNoDataDialog}
onClose={() => setShowNoDataDialog(false)}
maxWidth="sm"
fullWidth
PaperProps={{
sx: {
borderRadius: 3,
px: 1,
},
}}
>
<DialogTitle sx={{ display: 'flex', alignItems: 'center', gap: 1.5, pt: 3, px: 4, pb: 1.5 }}>
<Box
sx={{
width: 36,
height: 36,
borderRadius: '50%',
bgcolor: 'warning.light',
color: 'warning.dark',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
flexShrink: 0,
}}
>
<InfoOutlinedIcon fontSize="small" />
</Box>
<Typography component="span" variant="h6" fontWeight="bold">
{t('noDataFoundTitle')}
</Typography>
</DialogTitle>
<DialogContent sx={{ px: 4, pt: 0.5 }}>
<Typography color="text.secondary" sx={{ pl: 6.5 }}>
{t('noDataFoundHint')}
</Typography>
</DialogContent>
<DialogActions sx={{ justifyContent: 'center', px: 4, pb: 3, pt: 2 }}>
<Button variant="contained" onClick={() => setShowNoDataDialog(false)} autoFocus sx={{ minWidth: 96 }}>
{t('ok')}
</Button>
</DialogActions>
</Dialog>
</>
); );
} }

+ 2
- 2
src/app/(main)/report/reportCategories.ts 查看文件

@@ -9,7 +9,7 @@ export interface ReportCategoryConfig {
reportIds: string[]; reportIds: string[];
} }


/** Display order and grouping for the report management dashboard. */
/** FP-MTMS Version Checklist | Functions Ref. No. 69 | v1.0.0 | 2026-08-31 */
export const REPORT_CATEGORIES: ReportCategoryConfig[] = [ export const REPORT_CATEGORIES: ReportCategoryConfig[] = [
{ {
id: "inventory", id: "inventory",
@@ -17,7 +17,7 @@ export const REPORT_CATEGORIES: ReportCategoryConfig[] = [
headerBg: "#b8e0b8", headerBg: "#b8e0b8",
bodyBg: "#eef8ee", bodyBg: "#eef8ee",
accent: "#2e7d32", accent: "#2e7d32",
reportIds: ["rep-011", "rep-007", "rep-012", "rep-010"],
reportIds: ["rep-011", "rep-007", "rep-012", "rep-021", "rep-010"],
}, },
{ {
id: "inbound-outbound", id: "inbound-outbound",


+ 119
- 1
src/config/reportConfig.ts 查看文件

@@ -19,6 +19,8 @@ export interface ReportField {
disablesFieldsWhenChecked?: string[]; disablesFieldsWhenChecked?: string[];
/** For date fields: restrict picker so value cannot be before today */ /** For date fields: restrict picker so value cannot be before today */
minDate?: 'today'; minDate?: 'today';
/** Disable the input (e.g. date locked to today) */
disabled?: boolean;
} }


export type ReportResponseType = 'pdf' | 'excel'; export type ReportResponseType = 'pdf' | 'excel';
@@ -32,6 +34,7 @@ export interface ReportDefinition {
fields: ReportField[]; fields: ReportField[];
} }


/** FP-MTMS Version Checklist | Functions Ref. No. 69 | v1.0.0 | 2026-08-31 */
export const REPORTS: ReportDefinition[] = [ export const REPORTS: ReportDefinition[] = [
//{ //{
// id: "rep-001", // id: "rep-001",
@@ -81,10 +84,37 @@ export const REPORTS: ReportDefinition[] = [
title: "入倉追蹤報告", title: "入倉追蹤報告",
apiEndpoint: `${NEXT_PUBLIC_API_URL}/report/print-stock-in-traceability`, apiEndpoint: `${NEXT_PUBLIC_API_URL}/report/print-stock-in-traceability`,
fields: [ fields: [
{ label: "入倉日期:由 Last In Date Start", name: "lastInDateStart", type: "date", required: false }, { label: "入倉日期:由 Last In Date Start", name: "lastInDateStart", type: "date", required: false },
{ label: "入倉日期:至 Last In Date End", name: "lastInDateEnd", type: "date", required: false }, { label: "入倉日期:至 Last In Date End", name: "lastInDateEnd", type: "date", required: false },
{ label: "貨品編號 Item Code", name: "itemCode", type: "text", required: false}, { label: "貨品編號 Item Code", name: "itemCode", type: "text", required: false},
{
label: "樓層 Store ID",
name: "storeId",
type: "select",
required: false,
options: [
{ label: "全部", value: "All" },
{ label: "1F", value: "1F" },
{ label: "2F", value: "2F" },
{ label: "3F", value: "3F" },
{ label: "4F", value: "4F" },
],
},
{ label: "倉庫 Warehouse", name: "warehouse", type: "text", required: false, placeholder: "e.g. W201" },
{ label: "區域 Area", name: "area", type: "text", required: false, placeholder: "e.g. #A" },
{ label: "儲位 Slot", name: "slot", type: "text", required: false, placeholder: "e.g. 01" },
{ label: "批號 Lot No", name: "lotNo", type: "text", required: false, placeholder: "e.g. LT-202608" },
{
label: "PP/PF 分類",
name: "poPrefix",
type: "select",
required: false,
options: [
{ label: "全部", value: "All" },
{ label: "PP", value: "PP" },
{ label: "PF", value: "PF" },
],
},
] ]
}, },
{ {
@@ -169,6 +199,80 @@ export const REPORTS: ReportDefinition[] = [
}, },
] ]
}, },
/* Hidden for now: 庫存批次結餘報告 (rep-019)
{
id: "rep-019",
title: "庫存批次結餘報告",
apiEndpoint: `${NEXT_PUBLIC_API_URL}/report/print-stock-lot-balance`,
responseType: "excel",
fields: [
{ label: "庫存日期 Stock Date(僅今天)", name: "stockDate", type: "date", required: true, disabled: true },
{ label: "貨品編號 Item Code", name: "itemCode", type: "text", required: false },
{ label: "倉位 Warehouse Code", name: "warehouseCode", type: "text", required: false, placeholder: "e.g. W200 or 2F-W200-#A-00" },
{
label: "樓層 Store ID",
name: "storeId",
type: "select",
required: false,
options: [
{ label: "全部", value: "All" },
{ label: "1F", value: "1F" },
{ label: "2F", value: "2F" },
{ label: "3F", value: "3F" },
{ label: "4F", value: "4F" },
],
},
{ label: "批號 Lot No", name: "lotNo", type: "text", required: false, placeholder: "e.g. LT-202608" },
],
},
*/
{
id: "rep-021",
title: "庫存批次現況報告",
apiEndpoint: `${NEXT_PUBLIC_API_URL}/report/print-stock-lot-onhand`,
responseType: "excel",
fields: [
{ label: "貨品編號 Item Code", name: "itemCode", type: "text", required: false },
{
label: "樓層 Store ID",
name: "storeId",
type: "select",
required: false,
options: [
{ label: "全部", value: "All" },
{ label: "1F", value: "1F" },
{ label: "2F", value: "2F" },
{ label: "3F", value: "3F" },
{ label: "4F", value: "4F" },
],
},
{ label: "倉庫 Warehouse", name: "warehouse", type: "text", required: false, placeholder: "e.g. W201" },
{ label: "區域 Area", name: "area", type: "text", required: false, placeholder: "e.g. #A" },
{ label: "儲位 Slot", name: "slot", type: "text", required: false, placeholder: "e.g. 02" },
{
label: "盤點區域說明 Stock Take Section",
name: "stockTakeSectionDescription",
type: "select",
required: false,
dynamicOptions: true,
dynamicOptionsEndpoint: `${NEXT_PUBLIC_API_URL}/warehouse/stockTakeSections`,
options: [{ label: "全部", value: "All" }],
},
{ label: "批號 Lot No", name: "lotNo", type: "text", required: false, placeholder: "e.g. LT-202608" },
{
label: "來源 Lot Origin",
name: "lotOrigin",
type: "select",
required: false,
options: [
{ label: "全部", value: "All" },
{ label: "PP", value: "PP" },
{ label: "PF", value: "PF" },
{ label: "其他", value: "other" },
],
},
],
},
{ id: "rep-011", { id: "rep-011",
title: "庫存明細報告", title: "庫存明細報告",
apiEndpoint: `${NEXT_PUBLIC_API_URL}/report/print-stock-ledger`, apiEndpoint: `${NEXT_PUBLIC_API_URL}/report/print-stock-ledger`,
@@ -178,6 +282,19 @@ export const REPORTS: ReportDefinition[] = [
{ label: "貨品編號 Item Code", name: "itemCode", type: "text", required: false}, { label: "貨品編號 Item Code", name: "itemCode", type: "text", required: false},
] ]
}, },
/* Hidden for now: 庫存流水帳報告 (rep-020)
{
id: "rep-020",
title: "庫存流水帳報告",
apiEndpoint: `${NEXT_PUBLIC_API_URL}/report/print-stock-lot-ledger`,
responseType: "excel",
fields: [
{ label: "期間起 Period From(永遠該月1日)", name: "lastInDateStart", type: "date", required: true },
{ label: "期間迄 Period To", name: "lastInDateEnd", type: "date", required: true },
{ label: "貨品編號 Item Code", name: "itemCode", type: "text", required: false },
],
},
*/
/* /*
{ {
id: "rep-007", id: "rep-007",
@@ -236,6 +353,7 @@ export const REPORTS: ReportDefinition[] = [
] ]
}, },



{ id: "rep-010", { id: "rep-010",
/** FP-MTMS Version Checklist | Functions Ref. No. 64 | v1.0.0 | 2026-08-11 */ /** FP-MTMS Version Checklist | Functions Ref. No. 64 | v1.0.0 | 2026-08-11 */
title: "庫存品質檢測報告", title: "庫存品質檢測報告",


+ 48
- 1
src/i18n/en/report.json 查看文件

@@ -11,6 +11,10 @@
"generatingExcel": "Generating Excel...", "generatingExcel": "Generating Excel...",
"generatingReport": "Generating report...", "generatingReport": "Generating report...",
"generateError": "An error occurred while generating the report. Please try again.", "generateError": "An error occurred while generating the report. Please try again.",
"noDataFound": "No data found",
"noDataFoundTitle": "No Data Found / 查無資料",
"noDataFoundHint": "No inventory records match your search. Please try adjusting the filters.",
"ok": "OK",
"missingRequired": "Missing required fields:\n- {{fields}}", "missingRequired": "Missing required fields:\n- {{fields}}",
"dateNotBeforeToday": "Date cannot be before today:\n- {{fields}}", "dateNotBeforeToday": "Date cannot be before today:\n- {{fields}}",
"selectOrEnterItemCode": "Select or enter item code", "selectOrEnterItemCode": "Select or enter item code",
@@ -43,7 +47,23 @@
"fields": { "fields": {
"lastInDateStart": "Last In Date Start", "lastInDateStart": "Last In Date Start",
"lastInDateEnd": "Last In Date End", "lastInDateEnd": "Last In Date End",
"itemCode": "Item Code"
"itemCode": "Item Code",
"storeId": "Floor",
"warehouse": "Warehouse",
"area": "Area",
"slot": "Slot",
"lotNo": "Lot No",
"poPrefix": "PP/PF"
},
"options": {
"storeId": {
"All": "All"
},
"poPrefix": {
"All": "All",
"PP": "PP",
"PF": "PF"
}
} }
}, },
"rep-008": { "rep-008": {
@@ -213,6 +233,33 @@
"All": "All" "All": "All"
} }
} }
},
"rep-021": {
"title": "Stock Lot On-hand Report",
"fields": {
"itemCode": "Item Code",
"storeId": "Floor",
"warehouse": "Warehouse",
"area": "Area",
"slot": "Slot",
"stockTakeSectionDescription": "Stock Take Section",
"lotNo": "Lot No",
"lotOrigin": "Lot Origin"
},
"options": {
"storeId": {
"All": "All"
},
"stockTakeSectionDescription": {
"All": "All"
},
"lotOrigin": {
"All": "All",
"PP": "PP",
"PF": "PF",
"other": "Other"
}
}
} }
}, },
"excel": { "excel": {


+ 48
- 1
src/i18n/zh/report.json 查看文件

@@ -11,6 +11,10 @@
"generatingExcel": "生成 Excel...", "generatingExcel": "生成 Excel...",
"generatingReport": "生成報告...", "generatingReport": "生成報告...",
"generateError": "產生報告時發生錯誤,請再試一次。", "generateError": "產生報告時發生錯誤,請再試一次。",
"noDataFound": "查無資料",
"noDataFoundTitle": "查無資料",
"noDataFoundHint": "找不到符合您搜尋條件的庫存資料,請嘗試調整篩選條件。",
"ok": "確定",
"missingRequired": "缺少必填條件:\n- {{fields}}", "missingRequired": "缺少必填條件:\n- {{fields}}",
"dateNotBeforeToday": "日期不可早於今天:\n- {{fields}}", "dateNotBeforeToday": "日期不可早於今天:\n- {{fields}}",
"selectOrEnterItemCode": "選擇或輸入物料編號", "selectOrEnterItemCode": "選擇或輸入物料編號",
@@ -43,7 +47,23 @@
"fields": { "fields": {
"lastInDateStart": "入倉日期:由 Last In Date Start", "lastInDateStart": "入倉日期:由 Last In Date Start",
"lastInDateEnd": "入倉日期:至 Last In Date End", "lastInDateEnd": "入倉日期:至 Last In Date End",
"itemCode": "貨品編號 Item Code"
"itemCode": "貨品編號 Item Code",
"storeId": "樓層 Store ID",
"warehouse": "倉庫 Warehouse",
"area": "區域 Area",
"slot": "儲位 Slot",
"lotNo": "批號 Lot No",
"poPrefix": "PP/PF 分類"
},
"options": {
"storeId": {
"All": "全部"
},
"poPrefix": {
"All": "全部",
"PP": "PP",
"PF": "PF"
}
} }
}, },
"rep-008": { "rep-008": {
@@ -213,6 +233,33 @@
"All": "全部" "All": "全部"
} }
} }
},
"rep-021": {
"title": "庫存批次現況報告",
"fields": {
"itemCode": "貨品編號 Item Code",
"storeId": "樓層 Store ID",
"warehouse": "倉庫 Warehouse",
"area": "區域 Area",
"slot": "儲位 Slot",
"stockTakeSectionDescription": "盤點區域說明 Stock Take Section",
"lotNo": "批號 Lot No",
"lotOrigin": "來源 Lot Origin"
},
"options": {
"storeId": {
"All": "全部"
},
"stockTakeSectionDescription": {
"All": "全部"
},
"lotOrigin": {
"All": "全部",
"PP": "PP",
"PF": "PF",
"other": "其他"
}
}
} }
}, },
"excel": { "excel": {


正在加载...
取消
保存