Selaa lähdekoodia

update stock take record

MergeProblem1
CANCERYS\kw093 18 tuntia sitten
vanhempi
commit
aae9839da9
6 muutettua tiedostoa jossa 132 lisäystä ja 52 poistoa
  1. +6
    -0
      src/app/api/stockTake/actions.ts
  2. +40
    -11
      src/components/StockTakeManagement/ApproverStockTakeAll.tsx
  3. +37
    -14
      src/components/StockTakeManagement/PickerReStockTake.tsx
  4. +41
    -16
      src/components/StockTakeManagement/PickerStockTake.tsx
  5. +6
    -11
      src/components/StockTakeManagement/StockTakeTab.tsx
  6. +2
    -0
      src/i18n/zh/inventory.json

+ 6
- 0
src/app/api/stockTake/actions.ts Näytä tiedosto

@@ -199,6 +199,12 @@ export const getApproverStockTakeRecords = async () => {
);
return stockTakeRecords;
}
export const getLatestApproverStockTakeHeader = async () => {
return serverFetchJson<AllPickedStockTakeListReponse>(
`${BASE_API_URL}/stockTakeRecord/LatestApproverStockTakeHeader`,
{ method: "GET" }
);
}
export const createStockTakeForSections = async () => {
const createStockTakeForSections = await serverFetchJson<Map<string, string>>(
`${BASE_API_URL}/stockTake/createForSections`,


+ 40
- 11
src/components/StockTakeManagement/ApproverStockTakeAll.tsx Näytä tiedosto

@@ -64,7 +64,7 @@ const ApproverStockTakeAll: React.FC<ApproverStockTakeAllProps> = ({
const [batchSaving, setBatchSaving] = useState(false);
const [updatingStatus, setUpdatingStatus] = useState(false);
const [page, setPage] = useState(0);
const [pageSize, setPageSize] = useState<number | string>("all");
const [pageSize, setPageSize] = useState<number | string>(50);
const [total, setTotal] = useState(0);

const currentUserId = session?.id ? parseInt(session.id) : undefined;
@@ -337,7 +337,19 @@ const ApproverStockTakeAll: React.FC<ApproverStockTakeAllProps> = ({
},
[t, onSnackbar]
);

const blockNonIntegerKeys = (e: React.KeyboardEvent<HTMLInputElement>) => {
// 禁止小数点、逗号、科学计数、正负号
if ([".", ",", "e", "E", "+", "-"].includes(e.key)) {
e.preventDefault();
}
};
const sanitizeIntegerInput = (value: string) => {
// 只保留数字
return value.replace(/[^\d]/g, "");
};
const isIntegerString = (value: string) => /^\d+$/.test(value);
const handleBatchSubmitAll = useCallback(async () => {
if (mode === "approved") return;
if (!selectedSession || !currentUserId) {
@@ -431,9 +443,16 @@ const ApproverStockTakeAll: React.FC<ApproverStockTakeAllProps> = ({
size="small"
type="number"
value={variancePercentTolerance}
onChange={(e) => setVariancePercentTolerance(e.target.value)}
onKeyDown={blockNonIntegerKeys}
onChange={(e) => {
const clean = sanitizeIntegerInput(e.target.value);
setVariancePercentTolerance(clean);
}}
label={t("Variance %")}
sx={{ width: 100 }}
inputProps={{ min: 0, max: 100, step: 0.1 }}
/>
{mode === "pending" && (
@@ -564,7 +583,9 @@ const ApproverStockTakeAll: React.FC<ApproverStockTakeAllProps> = ({
<Radio
size="small"
checked={selection === "first"}
disabled={mode === "approved"}
onChange={() =>

setQtySelection({
...qtySelection,
[detail.id]: "first",
@@ -592,6 +613,7 @@ const ApproverStockTakeAll: React.FC<ApproverStockTakeAllProps> = ({
<Radio
size="small"
checked={selection === "second"}
disabled={mode === "approved"}
onChange={() =>
setQtySelection({
...qtySelection,
@@ -620,6 +642,7 @@ const ApproverStockTakeAll: React.FC<ApproverStockTakeAllProps> = ({
<Radio
size="small"
checked={selection === "approver"}
disabled={mode === "approved"}
onChange={() =>
setQtySelection({
...qtySelection,
@@ -634,12 +657,14 @@ const ApproverStockTakeAll: React.FC<ApproverStockTakeAllProps> = ({
size="small"
type="number"
value={approverQty[detail.id] || ""}
onChange={(e) =>
onKeyDown={blockNonIntegerKeys}
onChange={(e) => {
const clean = sanitizeIntegerInput(e.target.value);
setApproverQty({
...approverQty,
[detail.id]: e.target.value,
})
}
[detail.id]: clean,
});
}}
sx={{
width: 130,
minWidth: 130,
@@ -650,18 +675,21 @@ const ApproverStockTakeAll: React.FC<ApproverStockTakeAllProps> = ({
}}
placeholder={t("Stock Take Qty")}
disabled={selection !== "approver"}
inputProps={{ inputMode: "numeric", pattern: "[0-9]*" }}
/>

<TextField
size="small"
type="number"
value={approverBadQty[detail.id] || ""}
onChange={(e) =>
onKeyDown={blockNonIntegerKeys}
onChange={(e) => {
const clean = sanitizeIntegerInput(e.target.value);
setApproverBadQty({
...approverBadQty,
[detail.id]: e.target.value,
})
}
[detail.id]: clean,
});
}}
sx={{
width: 130,
minWidth: 130,
@@ -672,6 +700,7 @@ const ApproverStockTakeAll: React.FC<ApproverStockTakeAllProps> = ({
}}
placeholder={t("Bad Qty")}
disabled={selection !== "approver"}
inputProps={{ inputMode: "numeric", pattern: "[0-9]*" }}
/>
<Typography variant="body2">
={" "}


+ 37
- 14
src/components/StockTakeManagement/PickerReStockTake.tsx Näytä tiedosto

@@ -70,7 +70,17 @@ const PickerReStockTake: React.FC<PickerReStockTakeProps> = ({
const handleChangePage = useCallback((event: unknown, newPage: number) => {
setPage(newPage);
}, []);
const blockNonIntegerKeys = (e: React.KeyboardEvent<HTMLInputElement>) => {
// 禁止小数点、逗号、科学计数、正负号
if ([".", ",", "e", "E", "+", "-"].includes(e.key)) {
e.preventDefault();
}
};
const sanitizeIntegerInput = (value: string) => {
// 只保留数字
return value.replace(/[^\d]/g, "");
};
const isIntegerString = (value: string) => /^\d+$/.test(value);
const handleChangeRowsPerPage = useCallback((event: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>) => {
const newSize = parseInt(event.target.value, 10);
if (newSize === -1) {
@@ -437,9 +447,11 @@ const PickerReStockTake: React.FC<PickerReStockTakeProps> = ({
size="small"
type="number"
value={inputs.firstQty}
inputProps={{ min: 0, step: "any" }}
inputProps={{ inputMode: "numeric", pattern: "[0-9]*" }}
onKeyDown={blockNonIntegerKeys}
onChange={(e) => {
const val = e.target.value;
const clean = sanitizeIntegerInput(e.target.value);
const val = clean;
if (val.includes("-")) return;
setRecordInputs(prev => ({
...prev,
@@ -460,9 +472,11 @@ const PickerReStockTake: React.FC<PickerReStockTakeProps> = ({
size="small"
type="number"
value={inputs.firstBadQty}
inputProps={{ min: 0, step: "any" }}
inputProps={{ inputMode: "numeric", pattern: "[0-9]*" }}
onKeyDown={blockNonIntegerKeys}
onChange={(e) => {
const val = e.target.value;
const clean = sanitizeIntegerInput(e.target.value);
const val = clean;
if (val.includes("-")) return;
setRecordInputs(prev => ({
...prev,
@@ -500,13 +514,15 @@ const PickerReStockTake: React.FC<PickerReStockTakeProps> = ({
size="small"
type="number"
value={inputs.secondQty}
inputProps={{ min: 0, step: "any" }}
inputProps={{ inputMode: "numeric", pattern: "[0-9]*" }}
onKeyDown={blockNonIntegerKeys}
onChange={(e) => {
const val = e.target.value;
const clean = sanitizeIntegerInput(e.target.value);
const val = clean;
if (val.includes("-")) return;
setRecordInputs(prev => ({
...prev,
[detail.id]: { ...(prev[detail.id] ?? defaultInputs), secondQty: val }
[detail.id]: { ...(prev[detail.id] ?? defaultInputs), secondQty: clean }
}));
}}
sx={{
@@ -523,13 +539,15 @@ const PickerReStockTake: React.FC<PickerReStockTakeProps> = ({
size="small"
type="number"
value={inputs.secondBadQty}
inputProps={{ min: 0, step: "any" }}
inputProps={{ inputMode: "numeric", pattern: "[0-9]*" }}
onKeyDown={blockNonIntegerKeys}
onChange={(e) => {
const val = e.target.value;
const clean = sanitizeIntegerInput(e.target.value);
const val = clean;
if (val.includes("-")) return;
setRecordInputs(prev => ({
...prev,
[detail.id]: { ...(prev[detail.id] ?? defaultInputs), secondBadQty: val }
[detail.id]: { ...(prev[detail.id] ?? defaultInputs), secondBadQty: clean }
}));
}}
sx={{
@@ -581,10 +599,15 @@ const PickerReStockTake: React.FC<PickerReStockTakeProps> = ({
<TextField
size="small"
value={inputs.remark}
onChange={(e) => setRecordInputs(prev => ({
onKeyDown={blockNonIntegerKeys}
inputProps={{ inputMode: "text", pattern: "[0-9]*" }}
onChange={(e) => {
const clean = sanitizeIntegerInput(e.target.value);
setRecordInputs(prev => ({
...prev,
[detail.id]: { ...(prev[detail.id] ?? defaultInputs), remark: e.target.value }
}))}
[detail.id]: { ...(prev[detail.id] ?? defaultInputs), remark: clean }
}));
}}
sx={{ width: 150 }}
/>
</>


+ 41
- 16
src/components/StockTakeManagement/PickerStockTake.tsx Näytä tiedosto

@@ -394,7 +394,19 @@ const PickerStockTake: React.FC<PickerStockTakeProps> = ({
window.removeEventListener("keydown", handleKeyPress);
};
}, []);

const blockNonIntegerKeys = (e: React.KeyboardEvent<HTMLInputElement>) => {
// 禁止小数点、逗号、科学计数、正负号
if ([".", ",", "e", "E", "+", "-"].includes(e.key)) {
e.preventDefault();
}
};
const sanitizeIntegerInput = (value: string) => {
// 只保留数字
return value.replace(/[^\d]/g, "");
};
const isIntegerString = (value: string) => /^\d+$/.test(value);
const isSubmitDisabled = useCallback((detail: InventoryLotDetailResponse): boolean => {
if (selectedSession?.status?.toLowerCase() === "completed") {
return true;
@@ -580,9 +592,11 @@ const PickerStockTake: React.FC<PickerStockTakeProps> = ({
size="small"
type="number"
value={recordInputs[detail.id]?.firstQty || ""}
inputProps={{ min: 0, step: "any" }}
inputProps={{ inputMode: "numeric", pattern: "[0-9]*" }}
onKeyDown={blockNonIntegerKeys}
onChange={(e) => {
const val = e.target.value;
const clean = sanitizeIntegerInput(e.target.value);
const val = clean;
if (val.includes("-")) return;
setRecordInputs(prev => ({ ...prev, [detail.id]: { ...prev[detail.id], firstQty: val } }));
}}
@@ -604,9 +618,11 @@ const PickerStockTake: React.FC<PickerStockTakeProps> = ({
size="small"
type="number"
value={recordInputs[detail.id]?.firstBadQty || ""}
inputProps={{ min: 0, step: "any" }}
inputProps={{ inputMode: "numeric", pattern: "[0-9]*" }}
onKeyDown={blockNonIntegerKeys}
onChange={(e) => {
const val = e.target.value;
const clean = sanitizeIntegerInput(e.target.value);
const val = clean;
if (val.includes("-")) return;
setRecordInputs(prev => ({ ...prev, [detail.id]: { ...prev[detail.id], firstBadQty: val } }));
}}
@@ -656,9 +672,11 @@ const PickerStockTake: React.FC<PickerStockTakeProps> = ({
size="small"
type="number"
value={recordInputs[detail.id]?.secondQty || ""}
inputProps={{ min: 0, step: "any" }}
inputProps={{ inputMode: "numeric", pattern: "[0-9]*" }}
onKeyDown={blockNonIntegerKeys}
onChange={(e) => {
const val = e.target.value;
const clean = sanitizeIntegerInput(e.target.value);
const val = clean;
if (val.includes("-")) return;
setRecordInputs(prev => ({ ...prev, [detail.id]: { ...prev[detail.id], secondQty: val } }));
}}
@@ -676,9 +694,11 @@ const PickerStockTake: React.FC<PickerStockTakeProps> = ({
size="small"
type="number"
value={recordInputs[detail.id]?.secondBadQty || ""}
inputProps={{ min: 0, step: "any" }}
inputProps={{ inputMode: "numeric", pattern: "[0-9]*" }}
onKeyDown={blockNonIntegerKeys}
onChange={(e) => {
const val = e.target.value;
const clean = sanitizeIntegerInput(e.target.value);
const val = clean;
if (val.includes("-")) return;
setRecordInputs(prev => ({ ...prev, [detail.id]: { ...prev[detail.id], secondBadQty: val } }));
}}
@@ -751,13 +771,18 @@ const PickerStockTake: React.FC<PickerStockTakeProps> = ({
<TextField
size="small"
value={recordInputs[detail.id]?.remark || ""}
onChange={(e) => setRecordInputs(prev => ({
...prev,
[detail.id]: {
...(prev[detail.id] ?? { firstQty: "", secondQty: "", firstBadQty: "", secondBadQty: "", remark: "" }),
remark: e.target.value
}
}))}
onKeyDown={blockNonIntegerKeys}
inputProps={{ inputMode: "text", pattern: "[0-9]*" }}
onChange={(e) => {
const clean = sanitizeIntegerInput(e.target.value);
setRecordInputs(prev => ({
...prev,
[detail.id]: {
...(prev[detail.id] ?? { firstQty: "", secondQty: "", firstBadQty: "", secondBadQty: "", remark: "" }),
remark: clean
}
}));
}}
sx={{ width: 150 }}
/>
</>


+ 6
- 11
src/components/StockTakeManagement/StockTakeTab.tsx Näytä tiedosto

@@ -3,7 +3,7 @@
import { Box, Tab, Tabs, Snackbar, Alert, CircularProgress, Typography } from "@mui/material";
import { useState, useCallback, useEffect } from "react";
import { useTranslation } from "react-i18next";
import { AllPickedStockTakeListReponse, getApproverStockTakeRecords } from "@/app/api/stockTake/actions";
import { AllPickedStockTakeListReponse, getLatestApproverStockTakeHeader } from "@/app/api/stockTake/actions";
import PickerCardList from "./PickerCardList";
import PickerStockTake from "./PickerStockTake";
import PickerReStockTake from "./PickerReStockTake";
@@ -54,12 +54,11 @@ const StockTakeTab: React.FC = () => {
}, []);

useEffect(() => {
if (tabValue !== 1) return;
if (tabValue !== 1 && tabValue !== 2) return;
setApproverLoading(true);
getApproverStockTakeRecords()
.then((records) => {
const list = Array.isArray(records) ? records : [];
setApproverSession(list[0] ?? null);
getLatestApproverStockTakeHeader()
.then((header) => {
setApproverSession(header ?? null);
})
.catch((e) => {
console.error(e);
@@ -150,11 +149,7 @@ const StockTakeTab: React.FC = () => {
)}
{tabValue === 2 && (
<Box>
{approverLoading ? (
<Box sx={{ display: "flex", justifyContent: "center", p: 3 }}>
<CircularProgress />
</Box>
) : approverSession ? (
{approverSession ? (
<ApproverStockTakeAll
selectedSession={approverSession}
mode="approved"


+ 2
- 0
src/i18n/zh/inventory.json Näytä tiedosto

@@ -6,6 +6,8 @@
"Status": "來貨狀態",
"Qty": "盤點數量",
"UoM": "單位",
"Approver Pending": "審核待處理",
"Approver Approved": "審核通過",
"mat": "物料",
"variance": "差異",
"Plan Start Date": "計劃開始日期",


Ladataan…
Peruuta
Tallenna