|
- "use client";
- import React, { useState, useEffect, useCallback, useMemo } from "react";
- import {
- Box,
- Paper,
- Typography,
- Table,
- TableBody,
- TableCell,
- TableHead,
- TableRow,
- TextField,
- Select,
- MenuItem,
- Button,
- IconButton,
- CircularProgress,
- } from "@mui/material";
- import AddIcon from "@mui/icons-material/Add";
- import DeleteIcon from "@mui/icons-material/Delete";
- import { useTranslation } from "react-i18next";
- import {
- getBagInfo,
- createJoBagConsumption,
- GetBagInfoResponse,
- CreateJoBagConsumptionRequest,
- } from "@/app/api/bag/action";
- import { fetchProductProcessLineDetail } from "@/app/api/jo/actions";
-
- export interface BagConsumptionRow {
- bagId: number;
- bagLotLineId: number;
- consumedQty: number;
- scrapQty: number;
- }
-
- interface BagConsumptionFormProps {
- jobOrderId: number;
- lineId: number;
- bomDescription?: string;
- isLastLine: boolean;
- onRefresh?: () => void;
- }
-
- const BagConsumptionForm: React.FC<BagConsumptionFormProps> = ({
- jobOrderId,
- lineId,
- bomDescription,
- isLastLine,
- onRefresh,
- }) => {
- const { t } = useTranslation(["common", "jo"]);
- const [bagList, setBagList] = useState<GetBagInfoResponse[]>([]);
- const [bagConsumptionRows, setBagConsumptionRows] = useState<BagConsumptionRow[]>([
- { bagId: 0, bagLotLineId: 0, consumedQty: 0, scrapQty: 0 },
- ]);
- const [isLoadingBags, setIsLoadingBags] = useState(false);
- const [isSubmitting, setIsSubmitting] = useState(false);
-
- // 判断是否显示表单
- const shouldShow = useMemo(() => {
- return bomDescription === "FG" && isLastLine;
- }, [bomDescription, isLastLine]);
-
- // 加载 Bag 列表
- useEffect(() => {
- if (shouldShow) {
- setIsLoadingBags(true);
- getBagInfo()
- .then((bags) => {
- setBagList(bags);
- console.log("✅ Bag list loaded:", bags);
- })
- .catch((error) => {
- console.error("❌ Error loading bag list:", error);
- })
- .finally(() => {
- setIsLoadingBags(false);
- });
- }
- }, [shouldShow]);
-
- // 添加 Bag 行
- const handleAddBagRow = useCallback(() => {
- setBagConsumptionRows((prev) => [
- ...prev,
- { bagId: 0, bagLotLineId: 0, consumedQty: 0, scrapQty: 0 },
- ]);
- }, []);
-
- // 删除 Bag 行
- const handleDeleteBagRow = useCallback((index: number) => {
- setBagConsumptionRows((prev) => prev.filter((_, i) => i !== index));
- }, []);
-
- // 更新 Bag 行数据
- const handleBagRowChange = useCallback(
- (index: number, field: keyof BagConsumptionRow, value: any) => {
- setBagConsumptionRows((prev) =>
- prev.map((row, i) => (i === index ? { ...row, [field]: value } : row))
- );
- },
- []
- );
-
- // 当选择 bag 时,自动填充 bagLotLineId
- const handleBagSelect = useCallback(
- (index: number, bagLotLineId: number) => {
- const selectedBag = bagList.find((b) => b.id === bagLotLineId);
- if (selectedBag) {
- handleBagRowChange(index, "bagId", selectedBag.bagId);
- handleBagRowChange(index, "bagLotLineId", selectedBag.id);
- }
- },
- [bagList, handleBagRowChange]
- );
-
- // 提交 Bag Consumption
- const handleSubmitBagConsumption = useCallback(async () => {
- if (!jobOrderId || !lineId) {
- alert(t("Missing job order ID or line ID"));
- return;
- }
-
- try {
- setIsSubmitting(true);
-
- // 过滤掉未选择 bag 的行
- const validRows = bagConsumptionRows.filter(
- (row) => row.bagId > 0 && row.bagLotLineId > 0
- );
-
- if (validRows.length === 0) {
- alert(t("Please select at least one bag"));
- return;
- }
-
- // 提交每个 bag consumption
- const promises = validRows.map((row) => {
- const selectedBag = bagList.find((b) => b.id === row.bagLotLineId);
- const request: CreateJoBagConsumptionRequest = {
- bagId: row.bagId,
- bagLotLineId: row.bagLotLineId,
- jobId: jobOrderId,
- //startQty: selectedBag?.balanceQty || 0,
- consumedQty: row.consumedQty,
- scrapQty: row.scrapQty,
- };
- return createJoBagConsumption(request);
- });
-
- await Promise.all(promises);
- console.log("✅ Bag consumption submitted successfully");
-
- // 清空表单
- setBagConsumptionRows([
- { bagId: 0, bagLotLineId: 0, consumedQty: 0, scrapQty: 0 },
- ]);
-
- // 刷新 line detail
- if (onRefresh) {
- onRefresh();
- } else {
- const detail = await fetchProductProcessLineDetail(lineId);
- console.log("✅ Line detail refreshed:", detail);
- }
- } catch (error: any) {
- console.error("❌ Error submitting bag consumption:", error);
-
- // ✅ 显示更详细的错误信息
- const errorMessage = error?.message ||
- error?.response?.data?.message ||
- t("Failed to submit bag consumption. Please try again.");
- alert(errorMessage);
- } finally {
- setIsSubmitting(false);
- }
- }, [bagConsumptionRows, bagList, jobOrderId, lineId, onRefresh, t]);
-
- // 如果不满足显示条件,不渲染
- if (!shouldShow) {
- return null;
- }
-
- return (
- <Box sx={{ mt: 3 }}>
- <Paper sx={{ p: 3, bgcolor: "info.50" }}>
- <Typography variant="h6" gutterBottom>
- {t("Bag Consumption")}
- </Typography>
-
- {isLoadingBags ? (
- <Box sx={{ display: "flex", justifyContent: "center", p: 3 }}>
- <CircularProgress />
- </Box>
- ) : (
- <>
- <Table size="small" sx={{ mt: 2 }}>
- <TableHead>
- <TableRow>
- <TableCell width="40%">{t("Bag")}</TableCell>
- <TableCell width="25%" align="right">
- {t("Consumed Qty")}
- </TableCell>
- <TableCell width="25%" align="right">
- {t("Scrap Qty")}
- </TableCell>
- <TableCell width="10%" align="center">
- {t("Action")}
- </TableCell>
- </TableRow>
- </TableHead>
- <TableBody>
- {bagConsumptionRows.map((row, index) => (
- <TableRow key={index}>
- <TableCell>
- <Select
- fullWidth
- size="small"
- value={row.bagLotLineId || 0} // ✅ 改为使用 bagLotLineId
- onChange={(e) =>
- handleBagSelect(index, Number(e.target.value))
- }
- displayEmpty
- >
- <MenuItem value={0}>
- <em>{t("Select Bag")}</em>
- </MenuItem>
- {bagList.map((bag) => (
- <MenuItem key={bag.id} value={bag.id}> {/* ✅ 改为使用 bag.id (bagLotLineId) */}
- {bag.bagName} ({bag.code}) - {t("Balance")}:{" "}
- {bag.balanceQty}
- </MenuItem>
- ))}
- </Select>
- </TableCell>
- <TableCell align="right">
- <TextField
- type="number"
- size="small"
- fullWidth
- value={row.consumedQty}
- onChange={(e) =>
- handleBagRowChange(
- index,
- "consumedQty",
- Number(e.target.value) || 0
- )
- }
- inputProps={{ min: 0 }}
- />
- </TableCell>
- <TableCell align="right">
- <TextField
- type="number"
- size="small"
- fullWidth
- value={row.scrapQty}
- onChange={(e) =>
- handleBagRowChange(
- index,
- "scrapQty",
- Number(e.target.value) || 0
- )
- }
- inputProps={{ min: 0 }}
- />
- </TableCell>
- <TableCell align="center">
- {bagConsumptionRows.length > 1 && (
- <IconButton
- size="small"
- color="error"
- onClick={() => handleDeleteBagRow(index)}
- >
- <DeleteIcon />
- </IconButton>
- )}
- </TableCell>
- </TableRow>
- ))}
- </TableBody>
- </Table>
-
- <Box sx={{ mt: 2, display: "flex", gap: 2 }}>
- <Button
- variant="outlined"
- startIcon={<AddIcon />}
- onClick={handleAddBagRow}
- >
- {t("Select Another Bag Lot")}
- </Button>
- <Button
- variant="contained"
- color="primary"
- onClick={handleSubmitBagConsumption}
- disabled={isSubmitting}
- >
- {isSubmitting ? t("Submitting...") : t("Submit Bag Consumption")}
- </Button>
- </Box>
- </>
- )}
- </Paper>
- </Box>
- );
- };
-
- export default BagConsumptionForm;
|