From 8790c4ec987d9986abffd68081f7f25c07bb8978 Mon Sep 17 00:00:00 2001 From: "B.E.N.S.O.N" Date: Mon, 12 Jan 2026 11:43:01 +0800 Subject: [PATCH] Supporting Function: Equipment Handle Update --- .../EquipmentSearch/EquipmentSearch.tsx | 144 +++++++++++++++--- 1 file changed, 124 insertions(+), 20 deletions(-) diff --git a/src/components/EquipmentSearch/EquipmentSearch.tsx b/src/components/EquipmentSearch/EquipmentSearch.tsx index c850014..82c4dd1 100644 --- a/src/components/EquipmentSearch/EquipmentSearch.tsx +++ b/src/components/EquipmentSearch/EquipmentSearch.tsx @@ -30,6 +30,7 @@ import DialogContentText from "@mui/material/DialogContentText"; import DialogActions from "@mui/material/DialogActions"; import TextField from "@mui/material/TextField"; import Autocomplete from "@mui/material/Autocomplete"; +import InputAdornment from "@mui/material/InputAdornment"; type Props = { equipments: EquipmentResult[]; @@ -71,6 +72,8 @@ const EquipmentSearch: React.FC = ({ equipments, tabIndex = 0 }) => { const [selectedDescription, setSelectedDescription] = useState(""); const [selectedName, setSelectedName] = useState(""); const [selectedEquipmentCode, setSelectedEquipmentCode] = useState(""); + const [equipmentCodePrefix, setEquipmentCodePrefix] = useState(""); + const [equipmentCodeNumber, setEquipmentCodeNumber] = useState(""); const [isExistingCombination, setIsExistingCombination] = useState(false); const [loadingEquipments, setLoadingEquipments] = useState(false); const [saving, setSaving] = useState(false); @@ -237,6 +240,8 @@ const EquipmentSearch: React.FC = ({ equipments, tabIndex = 0 }) => { setSelectedDescription(""); setSelectedName(""); setSelectedEquipmentCode(""); + setEquipmentCodePrefix(""); + setEquipmentCodeNumber(""); setIsExistingCombination(false); }, []); @@ -315,12 +320,76 @@ const EquipmentSearch: React.FC = ({ equipments, tabIndex = 0 }) => { } else { setIsExistingCombination(false); setSelectedEquipmentCode(""); + setEquipmentCodePrefix(""); + setEquipmentCodeNumber(""); } }; checkAndGenerateEquipmentCode(); }, [selectedDescription, selectedName, equipmentList]); + useEffect(() => { + const generateNumberForPrefix = async () => { + if (isExistingCombination || !equipmentCodePrefix) { + return; + } + + if (equipmentCodePrefix.length !== 3 || !/^[A-Z]{3}$/.test(equipmentCodePrefix)) { + setEquipmentCodeNumber(""); + setSelectedEquipmentCode(equipmentCodePrefix); + return; + } + + try { + const response = await axiosInstance.get<{ + records: EquipmentResult[]; + total: number; + }>(`${NEXT_PUBLIC_API_URL}/EquipmentDetail/getRecordByPage`, { + params: { + pageNum: 1, + pageSize: 1000, + }, + }); + + let maxNumber = 0; + let maxPaddingLength = 2; + + if (response.data.records && response.data.records.length > 0) { + const matchingCodes = response.data.records + .map((detail) => { + if (!detail.equipmentCode) return null; + const match = detail.equipmentCode.match(new RegExp(`^${equipmentCodePrefix}(\\d+)$`)); + if (match) { + const numberStr = match[1]; + return { + number: parseInt(numberStr, 10), + paddingLength: numberStr.length + }; + } + return null; + }) + .filter((item): item is { number: number; paddingLength: number } => item !== null); + + if (matchingCodes.length > 0) { + maxNumber = Math.max(...matchingCodes.map(c => c.number)); + maxPaddingLength = Math.max(...matchingCodes.map(c => c.paddingLength)); + } + } + + const nextNumber = maxNumber + 1; + const numberStr = String(nextNumber).padStart(maxPaddingLength, '0'); + setEquipmentCodeNumber(numberStr); + setSelectedEquipmentCode(`${equipmentCodePrefix}${numberStr}`); + } catch (error) { + console.error("Error generating equipment code number:", error); + setEquipmentCodeNumber(""); + setSelectedEquipmentCode(equipmentCodePrefix); + } + }; + + generateNumberForPrefix(); + }, [equipmentCodePrefix, isExistingCombination]); + const handleToggleExpand = useCallback( (id: string | number, code: string) => { setExpandedRows(prev => { @@ -546,9 +615,15 @@ const EquipmentSearch: React.FC = ({ equipments, tabIndex = 0 }) => { return; } - if (!isExistingCombination && !selectedEquipmentCode) { - alert("請輸入設備編號"); - return; + if (!isExistingCombination) { + if (equipmentCodePrefix.length !== 3 || !/^[A-Z]{3}$/.test(equipmentCodePrefix)) { + alert("請輸入3個大寫英文字母作為設備編號前綴"); + return; + } + if (!equipmentCodeNumber) { + alert("設備編號生成中,請稍候"); + return; + } } setSaving(true); @@ -623,13 +698,17 @@ const EquipmentSearch: React.FC = ({ equipments, tabIndex = 0 }) => { newEquipmentCode = `LSS${String(1).padStart(2, '0')}`; } } else { - newEquipmentCode = selectedEquipmentCode; + if (isExistingCombination) { + newEquipmentCode = selectedEquipmentCode; + } else { + newEquipmentCode = `${equipmentCodePrefix}${equipmentCodeNumber}`; + } } } else { if (isExistingCombination) { newEquipmentCode = `LSS${String(1).padStart(2, '0')}`; } else { - newEquipmentCode = selectedEquipmentCode; + newEquipmentCode = `${equipmentCodePrefix}${equipmentCodeNumber}`; } } @@ -666,7 +745,7 @@ const EquipmentSearch: React.FC = ({ equipments, tabIndex = 0 }) => { } finally { setSaving(false); } - }, [selectedName, selectedDescription, selectedEquipmentCode, isExistingCombination, equipmentList, refetchData, filterObj, handleAddDialogClose, tabIndex, equipmentDetailsMap, fetchEquipmentDetailsByEquipmentId]); + }, [selectedName, selectedDescription, selectedEquipmentCode, equipmentCodePrefix, equipmentCodeNumber, isExistingCombination, equipmentList, refetchData, filterObj, handleAddDialogClose, tabIndex, equipmentDetailsMap, fetchEquipmentDetailsByEquipmentId]); const renderExpandedRow = useCallback((item: EquipmentResult): React.ReactNode => { if (tabIndex !== 0) { @@ -899,20 +978,45 @@ const EquipmentSearch: React.FC = ({ equipments, tabIndex = 0 }) => { /> )} /> - { - if (!isExistingCombination) { - setSelectedEquipmentCode(e.target.value); - } - }} - disabled={isExistingCombination || loadingEquipments || saving} - placeholder={isExistingCombination ? "自動生成" : "輸入設備編號"} - sx={{ mt: 2 }} - required={!isExistingCombination} - /> + + { + if (!isExistingCombination) { + const input = e.target.value.toUpperCase().replace(/[^A-Z]/g, '').slice(0, 3); + setEquipmentCodePrefix(input); + } + }} + disabled={isExistingCombination || loadingEquipments || saving} + placeholder={isExistingCombination ? "自動生成" : "輸入3個大寫英文字母"} + required={!isExistingCombination} + InputProps={{ + endAdornment: !isExistingCombination && equipmentCodeNumber ? ( + + + {equipmentCodeNumber} + + + ) : null, + }} + helperText={!isExistingCombination && equipmentCodePrefix.length > 0 && equipmentCodePrefix.length !== 3 + ? "必須輸入3個大寫英文字母" + : !isExistingCombination && equipmentCodePrefix.length === 3 && !/^[A-Z]{3}$/.test(equipmentCodePrefix) + ? "必須是大寫英文字母" + : ""} + error={!isExistingCombination && equipmentCodePrefix.length > 0 && (equipmentCodePrefix.length !== 3 || !/^[A-Z]{3}$/.test(equipmentCodePrefix))} + /> +