CANCERYS\kw093 2 miesięcy temu
rodzic
commit
474abab629
5 zmienionych plików z 627 dodań i 36 usunięć
  1. +19
    -4
      src/app/api/jo/actions.ts
  2. +27
    -27
      src/components/Jodetail/JobPickExecutionsecondscan.tsx
  3. +8
    -4
      src/components/Jodetail/JodetailSearch.tsx
  4. +571
    -0
      src/components/Jodetail/completeJobOrderRecord.tsx
  5. +2
    -1
      src/i18n/zh/jo.json

+ 19
- 4
src/app/api/jo/actions.ts Wyświetl plik

@@ -101,6 +101,7 @@ export interface AssignJobOrderResponse {
message: string | null;
errorPosition: string | null;
}

export const recordSecondScanIssue = cache(async (
pickOrderId: number,
itemId: number,
@@ -179,11 +180,19 @@ export const fetchJobOrderLotsHierarchical = cache(async (userId: number) => {
},
);
});

// 获取已完成的 Job Order pick orders
export const fetchCompletedJobOrderPickOrders = cache(async (userId: number) => {
return serverFetchJson<any>(
`${BASE_API_URL}/jo/completed-job-order-pick-orders/${userId}`,
`${BASE_API_URL}/jo/completed-job-order-pick-orders${userId}`,
{
method: "GET",
next: { tags: ["jo-completed"] },
},
);
});
// 获取已完成的 Job Order pick orders
export const fetchCompletedJobOrderPickOrdersrecords = cache(async (userId: number) => {
return serverFetchJson<any>(
`${BASE_API_URL}/jo/completed-job-order-pick-orders-only/${userId}`,
{
method: "GET",
next: { tags: ["jo-completed"] },
@@ -300,4 +309,10 @@ export const fetchCompletedJobOrderPickOrderLotDetails = cache(async (pickOrderI
method: "GET",
headers: { "Content-Type": "application/json" }
})
})
})
export const fetchCompletedJobOrderPickOrderLotDetailsForCompletedPick = cache(async (pickOrderId: number) => {
return serverFetchJson<any[]>(`${BASE_API_URL}/jo/completed-job-order-pick-order-lot-details-completed-pick/${pickOrderId}`, {
method: "GET",
headers: { "Content-Type": "application/json" }
})
})

+ 27
- 27
src/components/Jodetail/JobPickExecutionsecondscan.tsx Wyświetl plik

@@ -1152,33 +1152,33 @@ const paginatedData = useMemo(() => {
</TableCell>
<TableCell align="center">
{lot.secondQrScanStatus?.toLowerCase() !== 'pending' ? (
<Box sx={{
display: 'flex',
justifyContent: 'center',
alignItems: 'center',
width: '100%',
height: '100%'
}}>
<Checkbox
checked={lot.secondQrScanStatus?.toLowerCase() !== 'pending'}
disabled={true}
readOnly={true}
size="large"
sx={{
color: lot.secondQrScanStatus?.toLowerCase() !== 'pending' ? 'success.main' : 'grey.400',
'&.Mui-checked': {
color: 'success.main',
},
transform: 'scale(1.3)',
'& .MuiSvgIcon-root': {
fontSize: '1.5rem',
}
}}
/>
</Box>
) : null}
</TableCell>
{lot.secondQrScanStatus?.toLowerCase() !== 'pending' ? (
<Box sx={{
display: 'flex',
justifyContent: 'center',
alignItems: 'center',
width: '100%',
height: '100%'
}}>
<Checkbox
checked={lot.secondQrScanStatus?.toLowerCase() !== 'pending'}
disabled={true}
readOnly={true}
size="large"
sx={{
color: lot.secondQrScanStatus?.toLowerCase() !== 'pending' ? 'success.main' : 'grey.400',
'&.Mui-checked': {
color: 'success.main',
},
transform: 'scale(1.3)',
'& .MuiSvgIcon-root': {
fontSize: '1.5rem',
}
}}
/>
</Box>
) : null}
</TableCell>

<TableCell align="center">
<Box sx={{ display: 'flex', justifyContent: 'center' }}>


+ 8
- 4
src/components/Jodetail/JodetailSearch.tsx Wyświetl plik

@@ -25,6 +25,7 @@ import { SessionWithTokens } from "@/config/authConfig";
import JobPickExecutionsecondscan from "./JobPickExecutionsecondscan";
import FInishedJobOrderRecord from "./FInishedJobOrderRecord";
import JobPickExecution from "./JobPickExecution";
import CompleteJobOrderRecord from "./completeJobOrderRecord";
import {
fetchUnassignedJobOrderPickOrders,
assignJobOrderPickOrder,
@@ -172,6 +173,7 @@ const hasAnyAssignedData = hasDataTab0 || hasDataTab1;
setUnassignedOrders(orders);
} catch (error) {
console.error("Error loading unassigned orders:", error);
setUnassignedOrders([]);
} finally {
setIsLoadingUnassigned(false);
}
@@ -419,7 +421,7 @@ const hasAnyAssignedData = hasDataTab0 || hasDataTab1;
{/* Last 2 buttons aligned right */}
<Grid item xs={6} >
{/* Unassigned Job Orders */}
{!hasAnyAssignedData && unassignedOrders.length > 0 && (
{!hasAnyAssignedData && unassignedOrders && unassignedOrders.length > 0 && (
<Box sx={{ mt: 2, p: 2, border: '1px solid #e0e0e0', borderRadius: 1 }}>
<Typography variant="h6" gutterBottom>
{t("Unassigned Job Orders")} ({unassignedOrders.length})
@@ -452,8 +454,9 @@ const hasAnyAssignedData = hasDataTab0 || hasDataTab1;
}}>
<Tabs value={tabIndex} onChange={handleTabChange} variant="scrollable">
<Tab label={t("Pick Order Detail")} iconPosition="end" />
<Tab label={t("Complete Job Order Record")} iconPosition="end" />
<Tab label={t("Job Order Match")} iconPosition="end" />
<Tab label={t("Finished Job Order Record")} iconPosition="end" />
{/* <Tab label={t("Finished Job Order Record")} iconPosition="end" /> */}
</Tabs>
</Box>
@@ -463,8 +466,9 @@ const hasAnyAssignedData = hasDataTab0 || hasDataTab1;
p: 2
}}>
{tabIndex === 0 && <JobPickExecution filterArgs={filterArgs} />}
{tabIndex === 1 && <JobPickExecutionsecondscan filterArgs={filterArgs} />}
{tabIndex === 2 && <FInishedJobOrderRecord filterArgs={filterArgs} />}
{tabIndex === 1 && <CompleteJobOrderRecord filterArgs={filterArgs} />}
{tabIndex === 2 && <JobPickExecutionsecondscan filterArgs={filterArgs} />}
{/* {tabIndex === 3 && <FInishedJobOrderRecord filterArgs={filterArgs} />} */}
</Box>
</Box>
);


+ 571
- 0
src/components/Jodetail/completeJobOrderRecord.tsx Wyświetl plik

@@ -0,0 +1,571 @@
"use client";

import {
Box,
Button,
Stack,
TextField,
Typography,
Alert,
CircularProgress,
Table,
TableBody,
TableCell,
TableContainer,
TableHead,
TableRow,
Paper,
TablePagination,
Modal,
Card,
CardContent,
CardActions,
Chip,
Accordion,
AccordionSummary,
AccordionDetails,
Checkbox,
} from "@mui/material";
import ExpandMoreIcon from '@mui/icons-material/ExpandMore';
import { useCallback, useEffect, useState, useRef, useMemo } from "react";
import { useTranslation } from "react-i18next";
import { useRouter } from "next/navigation";
import {
fetchCompletedJobOrderPickOrdersrecords,
fetchCompletedJobOrderPickOrderLotDetailsForCompletedPick
} from "@/app/api/jo/actions";
import { fetchNameList, NameList } from "@/app/api/user/actions";
import {
FormProvider,
useForm,
} from "react-hook-form";
import SearchBox, { Criterion } from "../SearchBox";
import { useSession } from "next-auth/react";
import { SessionWithTokens } from "@/config/authConfig";

interface Props {
filterArgs: Record<string, any>;
}

// ✅ 修改:已完成的 Job Order Pick Order 接口
interface CompletedJobOrderPickOrder {
id: number;
pickOrderId: number;
pickOrderCode: string;
pickOrderConsoCode: string;
pickOrderTargetDate: string;
pickOrderStatus: string;
completedDate: string;
jobOrderId: number;
jobOrderCode: string;
jobOrderName: string;
reqQty: number;
uom: string;
planStart: string;
planEnd: string;
secondScanCompleted: boolean;
totalItems: number;
completedItems: number;
}

// ✅ 新增:Lot 详情接口
interface LotDetail {
lotId: number;
lotNo: string;
expiryDate: string;
location: string;
availableQty: number;
requiredQty: number;
actualPickQty: number;
processingStatus: string;
lotAvailability: string;
pickOrderId: number;
pickOrderCode: string;
pickOrderConsoCode: string;
pickOrderLineId: number;
stockOutLineId: number;
stockOutLineStatus: string;
routerIndex: number;
routerArea: string;
routerRoute: string;
uomShortDesc: string;
secondQrScanStatus: string;
itemId: number;
itemCode: string;
itemName: string;
uomCode: string;
uomDesc: string;
}

const CompleteJobOrderRecord: React.FC<Props> = ({ filterArgs }) => {
const { t } = useTranslation("jo");
const router = useRouter();
const { data: session } = useSession() as { data: SessionWithTokens | null };
const currentUserId = session?.id ? parseInt(session.id) : undefined;
// ✅ 修改:已完成 Job Order Pick Orders 状态
const [completedJobOrderPickOrders, setCompletedJobOrderPickOrders] = useState<CompletedJobOrderPickOrder[]>([]);
const [completedJobOrderPickOrdersLoading, setCompletedJobOrderPickOrdersLoading] = useState(false);
// ✅ 修改:详情视图状态
const [selectedJobOrderPickOrder, setSelectedJobOrderPickOrder] = useState<CompletedJobOrderPickOrder | null>(null);
const [showDetailView, setShowDetailView] = useState(false);
const [detailLotData, setDetailLotData] = useState<LotDetail[]>([]);
const [detailLotDataLoading, setDetailLotDataLoading] = useState(false);
// ✅ 修改:搜索状态
const [searchQuery, setSearchQuery] = useState<Record<string, any>>({});
const [filteredJobOrderPickOrders, setFilteredJobOrderPickOrders] = useState<CompletedJobOrderPickOrder[]>([]);
// ✅ 修改:分页状态
const [paginationController, setPaginationController] = useState({
pageNum: 0,
pageSize: 10,
});

const formProps = useForm();
const errors = formProps.formState.errors;

// ✅ 修改:使用新的 Job Order API 获取已完成的 Job Order Pick Orders(仅完成pick的)
const fetchCompletedJobOrderPickOrdersData = useCallback(async () => {
if (!currentUserId) return;
setCompletedJobOrderPickOrdersLoading(true);
try {
console.log("🔍 Fetching completed Job Order pick orders (pick completed only)...");
const completedJobOrderPickOrders = await fetchCompletedJobOrderPickOrdersrecords(currentUserId);
// ✅ Fix: Ensure the data is always an array
const safeData = Array.isArray(completedJobOrderPickOrders) ? completedJobOrderPickOrders : [];
setCompletedJobOrderPickOrders(safeData);
setFilteredJobOrderPickOrders(safeData);
console.log("✅ Fetched completed Job Order pick orders:", safeData);
} catch (error) {
console.error("❌ Error fetching completed Job Order pick orders:", error);
setCompletedJobOrderPickOrders([]);
setFilteredJobOrderPickOrders([]);
} finally {
setCompletedJobOrderPickOrdersLoading(false);
}
}, [currentUserId]);

// ✅ 新增:获取 lot 详情数据(使用新的API)
const fetchLotDetailsData = useCallback(async (pickOrderId: number) => {
setDetailLotDataLoading(true);
try {
console.log("🔍 Fetching lot details for completed pick order:", pickOrderId);
const lotDetails = await fetchCompletedJobOrderPickOrderLotDetailsForCompletedPick(pickOrderId);
setDetailLotData(lotDetails);
console.log("✅ Fetched lot details:", lotDetails);
} catch (error) {
console.error("❌ Error fetching lot details:", error);
setDetailLotData([]);
} finally {
setDetailLotDataLoading(false);
}
}, []);

// ✅ 修改:初始化时获取数据
useEffect(() => {
if (currentUserId) {
fetchCompletedJobOrderPickOrdersData();
}
}, [currentUserId, fetchCompletedJobOrderPickOrdersData]);

// ✅ 修改:搜索功能
const handleSearch = useCallback((query: Record<string, any>) => {
setSearchQuery({ ...query });
console.log("Search query:", query);
// ✅ Fix: Ensure completedJobOrderPickOrders is an array before filtering
if (!Array.isArray(completedJobOrderPickOrders)) {
setFilteredJobOrderPickOrders([]);
return;
}
const filtered = completedJobOrderPickOrders.filter((pickOrder) => {
const pickOrderCodeMatch = !query.pickOrderCode ||
pickOrder.pickOrderCode?.toLowerCase().includes((query.pickOrderCode || "").toLowerCase());
const jobOrderCodeMatch = !query.jobOrderCode ||
pickOrder.jobOrderCode?.toLowerCase().includes((query.jobOrderCode || "").toLowerCase());
const jobOrderNameMatch = !query.jobOrderName ||
pickOrder.jobOrderName?.toLowerCase().includes((query.jobOrderName || "").toLowerCase());
return pickOrderCodeMatch && jobOrderCodeMatch && jobOrderNameMatch;
});
setFilteredJobOrderPickOrders(filtered);
console.log("Filtered Job Order pick orders count:", filtered.length);
}, [completedJobOrderPickOrders]);

// ✅ 修改:重置搜索
const handleSearchReset = useCallback(() => {
setSearchQuery({});
// ✅ Fix: Ensure completedJobOrderPickOrders is an array before setting
setFilteredJobOrderPickOrders(Array.isArray(completedJobOrderPickOrders) ? completedJobOrderPickOrders : []);
}, [completedJobOrderPickOrders]);

// ✅ 修改:分页功能
const handlePageChange = useCallback((event: unknown, newPage: number) => {
setPaginationController(prev => ({
...prev,
pageNum: newPage,
}));
}, []);

const handlePageSizeChange = useCallback((event: React.ChangeEvent<HTMLInputElement>) => {
const newPageSize = parseInt(event.target.value, 10);
setPaginationController({
pageNum: 0,
pageSize: newPageSize,
});
}, []);

// ✅ 修改:分页数据
const paginatedData = useMemo(() => {
// ✅ Fix: Ensure filteredJobOrderPickOrders is an array before calling slice
if (!Array.isArray(filteredJobOrderPickOrders)) {
return [];
}
const startIndex = paginationController.pageNum * paginationController.pageSize;
const endIndex = startIndex + paginationController.pageSize;
return filteredJobOrderPickOrders.slice(startIndex, endIndex);
}, [filteredJobOrderPickOrders, paginationController]);

// ✅ 修改:搜索条件
const searchCriteria: Criterion<any>[] = [
{
label: t("Pick Order Code"),
paramName: "pickOrderCode",
type: "text",
},
{
label: t("Job Order Code"),
paramName: "jobOrderCode",
type: "text",
},
{
label: t("Job Order Item Name"),
paramName: "jobOrderName",
type: "text",
}
];

// ✅ 修改:详情点击处理
const handleDetailClick = useCallback(async (jobOrderPickOrder: CompletedJobOrderPickOrder) => {
setSelectedJobOrderPickOrder(jobOrderPickOrder);
setShowDetailView(true);
// ✅ 获取 lot 详情数据(使用新的API)
await fetchLotDetailsData(jobOrderPickOrder.pickOrderId);
// ✅ 触发打印按钮状态更新 - 基于详情数据
const allCompleted = jobOrderPickOrder.secondScanCompleted;
// ✅ 发送事件,包含标签页信息
window.dispatchEvent(new CustomEvent('pickOrderCompletionStatus', {
detail: {
allLotsCompleted: allCompleted,
tabIndex: 3 // ✅ 明确指定这是来自标签页 3 的事件
}
}));
}, [fetchLotDetailsData]);

// ✅ 修改:返回列表视图
const handleBackToList = useCallback(() => {
setShowDetailView(false);
setSelectedJobOrderPickOrder(null);
setDetailLotData([]);
// ✅ 返回列表时禁用打印按钮
window.dispatchEvent(new CustomEvent('pickOrderCompletionStatus', {
detail: {
allLotsCompleted: false,
tabIndex: 3
}
}));
}, []);

// ✅ 修改:如果显示详情视图,渲染 Job Order 详情和 Lot 信息
if (showDetailView && selectedJobOrderPickOrder) {
return (
<FormProvider {...formProps}>
<Box>
{/* 返回按钮和标题 */}
<Box sx={{ mb: 2, display: 'flex', alignItems: 'center', gap: 2 }}>
<Button variant="outlined" onClick={handleBackToList}>
{t("Back to List")}
</Button>
<Typography variant="h6">
{t("Job Order Pick Order Details")}: {selectedJobOrderPickOrder.pickOrderCode}
</Typography>
</Box>

{/* Job Order 信息卡片 */}
<Card sx={{ mb: 2 }}>
<CardContent>
<Stack direction="row" spacing={4} useFlexGap flexWrap="wrap">
<Typography variant="subtitle1">
<strong>{t("Pick Order Code")}:</strong> {selectedJobOrderPickOrder.pickOrderCode}
</Typography>
<Typography variant="subtitle1">
<strong>{t("Job Order Code")}:</strong> {selectedJobOrderPickOrder.jobOrderCode}
</Typography>
<Typography variant="subtitle1">
<strong>{t("Job Order Item Name")}:</strong> {selectedJobOrderPickOrder.jobOrderName}
</Typography>
<Typography variant="subtitle1">
<strong>{t("Target Date")}:</strong> {selectedJobOrderPickOrder.pickOrderTargetDate}
</Typography>
</Stack>
<Stack direction="row" spacing={4} useFlexGap flexWrap="wrap" sx={{ mt: 2 }}>
<Typography variant="subtitle1">
<strong>{t("Required Qty")}:</strong> {selectedJobOrderPickOrder.reqQty} {selectedJobOrderPickOrder.uom}
</Typography>
</Stack>
</CardContent>
</Card>

{/* ✅ 修改:Lot 详情表格 - 添加复选框列 */}
<Card>
<CardContent>
<Typography variant="h6" gutterBottom>
{t("Lot Details")}
</Typography>
{detailLotDataLoading ? (
<Box sx={{ display: 'flex', justifyContent: 'center', p: 2 }}>
<CircularProgress />
</Box>
) : (
<TableContainer component={Paper}>
<Table>
<TableHead>
<TableRow>
<TableCell>{t("Index")}</TableCell>
<TableCell>{t("Route")}</TableCell>
<TableCell>{t("Item Code")}</TableCell>
<TableCell>{t("Item Name")}</TableCell>
<TableCell>{t("Lot No")}</TableCell>
<TableCell>{t("Location")}</TableCell>
<TableCell align="right">{t("Required Qty")}</TableCell>
<TableCell align="right">{t("Actual Pick Qty")}</TableCell>
<TableCell align="center">{t("Processing Status")}</TableCell>
<TableCell align="center">{t("Second Scan Status")}</TableCell>
</TableRow>
</TableHead>
<TableBody>
{detailLotData.length === 0 ? (
<TableRow>
<TableCell colSpan={10} align="center">
<Typography variant="body2" color="text.secondary">
{t("No lot details available")}
</Typography>
</TableCell>
</TableRow>
) : (
detailLotData.map((lot, index) => (
<TableRow key={lot.lotId}>
<TableCell>
<Typography variant="body2" fontWeight="bold">
{index + 1}
</Typography>
</TableCell>
<TableCell>
<Typography variant="body2">
{lot.routerRoute || '-'}
</Typography>
</TableCell>
<TableCell>{lot.itemCode}</TableCell>
<TableCell>{lot.itemName}</TableCell>
<TableCell>{lot.lotNo}</TableCell>
<TableCell>{lot.location}</TableCell>
<TableCell align="right">
{lot.requiredQty?.toLocaleString() || 0} ({lot.uomShortDesc})
</TableCell>
<TableCell align="right">
{lot.actualPickQty?.toLocaleString() || 0} ({lot.uomShortDesc})
</TableCell>
{/* ✅ 修改:Processing Status 使用复选框 */}
<TableCell align="center">
<Box sx={{
display: 'flex',
justifyContent: 'center',
alignItems: 'center',
width: '100%',
height: '100%'
}}>
<Checkbox
checked={lot.processingStatus === 'completed'}
disabled={true}
readOnly={true}
size="large"
sx={{
color: lot.processingStatus === 'completed' ? 'success.main' : 'grey.400',
'&.Mui-checked': {
color: 'success.main',
},
transform: 'scale(1.3)',
'& .MuiSvgIcon-root': {
fontSize: '1.5rem',
}
}}
/>
</Box>
</TableCell>
{/* ✅ 修改:Second Scan Status 使用复选框 */}
<TableCell align="center">
<Box sx={{
display: 'flex',
justifyContent: 'center',
alignItems: 'center',
width: '100%',
height: '100%'
}}>
<Checkbox
checked={lot.secondQrScanStatus === 'completed'}
disabled={true}
readOnly={true}
size="large"
sx={{
color: lot.secondQrScanStatus === 'completed' ? 'success.main' : 'grey.400',
'&.Mui-checked': {
color: 'success.main',
},
transform: 'scale(1.3)',
'& .MuiSvgIcon-root': {
fontSize: '1.5rem',
}
}}
/>
</Box>
</TableCell>
</TableRow>
))
)}
</TableBody>
</Table>
</TableContainer>
)}
</CardContent>
</Card>
</Box>
</FormProvider>
);
}

// ✅ 修改:默认列表视图
return (
<FormProvider {...formProps}>
<Box>
{/* 搜索框 */}
<Box sx={{ mb: 2 }}>
<SearchBox
criteria={searchCriteria}
onSearch={handleSearch}
onReset={handleSearchReset}
/>
</Box>

{/* 加载状态 */}
{completedJobOrderPickOrdersLoading ? (
<Box sx={{ display: 'flex', justifyContent: 'center', p: 3 }}>
<CircularProgress />
</Box>
) : (
<Box>
{/* 结果统计 */}
<Typography variant="body2" color="text.secondary" sx={{ mb: 2 }}>
{t("Total")}: {filteredJobOrderPickOrders.length} {t("completed Job Order pick orders with matching")}
</Typography>

{/* 列表 */}
{filteredJobOrderPickOrders.length === 0 ? (
<Box sx={{ p: 3, textAlign: 'center' }}>
<Typography variant="body2" color="text.secondary">
{t("No completed Job Order pick orders with matching found")}
</Typography>
</Box>
) : (
<Stack spacing={2}>
{paginatedData.map((jobOrderPickOrder) => (
<Card key={jobOrderPickOrder.id}>
<CardContent>
<Stack direction="row" justifyContent="space-between" alignItems="center">
<Box>
<Typography variant="h6">
{jobOrderPickOrder.pickOrderCode}
</Typography>
<Typography variant="body2" color="text.secondary">
{jobOrderPickOrder.jobOrderName} - {jobOrderPickOrder.jobOrderCode}
</Typography>
<Typography variant="body2" color="text.secondary">
{t("Completed")}: {new Date(jobOrderPickOrder.completedDate).toLocaleString()}
</Typography>
<Typography variant="body2" color="text.secondary">
{t("Target Date")}: {jobOrderPickOrder.pickOrderTargetDate}
</Typography>
</Box>
<Box>
<Chip
label={jobOrderPickOrder.pickOrderStatus}
color={jobOrderPickOrder.pickOrderStatus === 'completed' ? 'success' : 'default'}
size="small"
sx={{ mb: 1 }}
/>
<Typography variant="body2" color="text.secondary">
{jobOrderPickOrder.completedItems}/{jobOrderPickOrder.totalItems} {t("items completed")}
</Typography>
<Chip
label={jobOrderPickOrder.secondScanCompleted ? t("Second Scan Completed") : t("Second Scan Pending")}
color={jobOrderPickOrder.secondScanCompleted ? 'success' : 'warning'}
size="small"
sx={{ mt: 1 }}
/>
</Box>
</Stack>
</CardContent>
<CardActions>
<Button
variant="outlined"
onClick={() => handleDetailClick(jobOrderPickOrder)}
>
{t("View Details")}
</Button>
</CardActions>
</Card>
))}
</Stack>
)}

{/* 分页 */}
{filteredJobOrderPickOrders.length > 0 && (
<TablePagination
component="div"
count={filteredJobOrderPickOrders.length}
page={paginationController.pageNum}
rowsPerPage={paginationController.pageSize}
onPageChange={handlePageChange}
onRowsPerPageChange={handlePageSizeChange}
rowsPerPageOptions={[5, 10, 25, 50]}
/>
)}
</Box>
)}
</Box>
</FormProvider>
);
};

export default CompleteJobOrderRecord;

+ 2
- 1
src/i18n/zh/jo.json Wyświetl plik

@@ -103,6 +103,7 @@
"Create": "創建",
"Confirm Lot Substitution": "確認批號替換",
"Processing...": "處理中",
"Processing...": "處理中"
"Processing...": "處理中",
"Complete Job Order Record": "已完成工單記錄"

}

Ładowanie…
Anuluj
Zapisz