ソースを参照

udpate bom search for WIP/FG

production
CANCERYS\kw093 5時間前
コミット
16d2fd7941
1個のファイルの変更49行の追加35行の削除
  1. +49
    -35
      src/components/ImportBom/ImportBomDetailTab.tsx

+ 49
- 35
src/components/ImportBom/ImportBomDetailTab.tsx ファイルの表示

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

import React, { useEffect, useState } from "react";
import React, { useEffect, useRef, useState } from "react";
import {
Box,
Stack,
@@ -32,7 +32,6 @@ import {
type EquipmentMasterRow,
type ProcessMasterRow,
} from "@/app/api/bom/client";
import type { SelectChangeEvent } from "@mui/material/Select";
import { useTranslation } from "react-i18next";
import SearchBox, { Criterion } from "../SearchBox";
import { useMemo, useCallback } from "react";
@@ -70,6 +69,7 @@ const ImportBomDetailTab: React.FC = () => {
const [loadingDetail, setLoadingDetail] = useState(false);
const [filteredBoms, setFilteredBoms] = useState<BomCombo[]>([])
const [currentBom, setCurrentBom] = useState<BomCombo | null>(null);
const loadDetailInFlightRef = useRef(false);

type EditMaterialRow = {
key: string;
@@ -195,15 +195,34 @@ const ImportBomDetailTab: React.FC = () => {
[t],
);
useEffect(() => {
setFilteredBoms(bomList); // 初始顯示全部
setFilteredBoms([]);
}, [bomList]);
const loadBomDetail = useCallback(
async (id: number) => {
if (!id || loadDetailInFlightRef.current) return;
loadDetailInFlightRef.current = true;
setSelectedBomId(id);
setCurrentBom(bomList.find((b) => b.id === id) ?? null);
setDetail(null);
setLoadingDetail(true);
try {
const d = await fetchBomDetailClient(id);
setDetail(d);
} finally {
setLoadingDetail(false);
loadDetailInFlightRef.current = false;
}
},
[bomList],
);

const handleSearchBom = useCallback(
(inputs: Record<BomSearchKey | `${BomSearchKey}To`, string>) => {
const code = (inputs.code ?? "").trim().toLowerCase();
const name = (inputs.name ?? "").trim().toLowerCase();
const result = bomList.filter((b) => {
const label = b.label.toLowerCase();
const label = String(b.label ?? "").toLowerCase();
const okCode = !code || label.includes(code);
const okName = !name || label.includes(name);
return okCode && okName;
@@ -213,16 +232,14 @@ const ImportBomDetailTab: React.FC = () => {
// 如果只找到一個,直接載入明細
if (result.length === 1) {
const only = result[0];
setSelectedBomId(only.id);
void loadBomDetail(result[0].id);
} else {
setSelectedBomId("");
setCurrentBom(null);
setDetail(null);
setLoadingDetail(true);
fetchBomDetailClient(only.id)
.then((d) => setDetail(d))
.finally(() => setLoadingDetail(false));
}
},
[bomList],
[bomList, loadBomDetail],
);
const renderAllergic = (v?: number) => {
if (v === 0) return "有";
@@ -270,20 +287,6 @@ const ImportBomDetailTab: React.FC = () => {
setDetail(null);
}, [bomList]);
*/
const handleChangeBom = async (event: SelectChangeEvent<number>) => {
const id = Number(event.target.value);
setSelectedBomId(id);
setDetail(null);
if (!id) return;
setLoadingDetail(true);
try {
const d = await fetchBomDetailClient(id);
setDetail(d);
} finally {
setLoadingDetail(false);
}
};

const genKey = () => Math.random().toString(36).slice(2);

const startEdit = useCallback(async () => {
@@ -555,16 +558,27 @@ const ImportBomDetailTab: React.FC = () => {
//onReset={handleResetBom}
/>
{currentBom && (
<Paper variant="outlined" sx={{ p: 1.5 }}>
<Typography variant="subtitle2">
CODE / NAME
</Typography>
<Typography variant="body2">
{currentBom.label} ({t("Output Quantity")} {currentBom.outputQty} {currentBom.outputQtyUom})
</Typography>
</Paper>
)}

{filteredBoms.length > 1 && (
<Paper variant="outlined" sx={{ p: 1.5 }}>
<Typography variant="subtitle2" sx={{ mb: 1 }}>
找到多筆 BOM,請選擇一筆載入明細
</Typography>
<Stack direction="row" spacing={1} flexWrap="wrap">
{filteredBoms.map((b) => (
<Button
key={b.id}
size="small"
variant={selectedBomId === b.id ? "contained" : "outlined"}
disabled={loadingDetail}
onClick={() => void loadBomDetail(b.id)}
>
{String(b.label ?? b.id)} ({renderType(b.description)})
</Button>
))}
</Stack>
</Paper>
)}
{loadingDetail && (
<Typography variant="body2" color="text.secondary">
{t("Loading BOM Detail...")}


読み込み中…
キャンセル
保存