Selaa lähdekoodia

update

master
CANCERYS\kw093 2 kuukautta sitten
vanhempi
commit
5590308d6e
3 muutettua tiedostoa jossa 348 lisäystä ja 197 poistoa
  1. +13
    -0
      src/app/api/jo/actions.ts
  2. +311
    -195
      src/components/Jodetail/FInishedJobOrderRecord.tsx
  3. +24
    -2
      src/i18n/zh/jo.json

+ 13
- 0
src/app/api/jo/actions.ts Näytä tiedosto

@@ -267,4 +267,17 @@ export const manualCreateJo = cache(async (data: SaveJo) => {
body: JSON.stringify(data),
headers: { "Content-Type": "application/json" }
})
})

export const fetchCompletedJobOrderPickOrdersWithCompletedSecondScan = cache(async (userId: number) => {
return serverFetchJson<any[]>(`${BASE_API_URL}/jo/completed-job-order-pick-orders-with-completed-second-scan/${userId}`, {
method: "GET",
headers: { "Content-Type": "application/json" }
})
})
export const fetchCompletedJobOrderPickOrderLotDetails = cache(async (pickOrderId: number) => {
return serverFetchJson<any[]>(`${BASE_API_URL}/jo/completed-job-order-pick-order-lot-details/${pickOrderId}`, {
method: "GET",
headers: { "Content-Type": "application/json" }
})
})

+ 311
- 195
src/components/Jodetail/FInishedJobOrderRecord.tsx Näytä tiedosto

@@ -24,102 +24,101 @@ import {
Accordion,
AccordionSummary,
AccordionDetails,
Checkbox, // ✅ Add Checkbox import
} 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 {
fetchALLPickOrderLineLotDetails,
updateStockOutLineStatus,
createStockOutLine,
recordPickExecutionIssue,
fetchFGPickOrders,
FGPickOrderResponse,
autoAssignAndReleasePickOrder,
AutoAssignReleaseResponse,
checkPickOrderCompletion,
PickOrderCompletionResponse,
checkAndCompletePickOrderByConsoCode,
fetchCompletedDoPickOrders, // ✅ 新增:使用新的 API
CompletedDoPickOrderResponse,
CompletedDoPickOrderSearchParams,
fetchLotDetailsByPickOrderId // ✅ 修复:导入类型
} from "@/app/api/pickOrder/actions";
fetchCompletedJobOrderPickOrdersWithCompletedSecondScan,
fetchCompletedJobOrderPickOrderLotDetails
} 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 { CreateStockOutLine } from "@/app/api/pickOrder/actions";
import { updateInventoryLotLineQuantities } from "@/app/api/inventory/actions";
import QrCodeIcon from '@mui/icons-material/QrCode';
import { useQrCodeScannerContext } from '../QrCodeScannerProvider/QrCodeScannerProvider';
import { useSession } from "next-auth/react";
import { SessionWithTokens } from "@/config/authConfig";
import { fetchStockInLineInfo } from "@/app/api/po/actions";
import GoodPickExecutionForm from "./JobPickExecutionForm";
import FGPickOrderCard from "./FGPickOrderCard";

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

// ✅ 新增:已完成的 DO Pick Order 接口
interface CompletedDoPickOrder {
// ✅ 修改:已完成的 Job Order Pick Order 接口
interface CompletedJobOrderPickOrder {
id: number;
pickOrderId: number;
pickOrderCode: string;
pickOrderConsoCode: string;
pickOrderTargetDate: string;
pickOrderStatus: string;
deliveryOrderId: number;
deliveryNo: string;
deliveryDate: string;
shopId: number;
shopCode: string;
shopName: string;
shopAddress: string;
ticketNo: string;
shopPoNo: string;
numberOfCartons: number;
truckNo: string;
storeId: string;
completedDate: string;
fgPickOrders: FGPickOrderResponse[];
jobOrderId: number;
jobOrderCode: string;
jobOrderName: string;
reqQty: number;
uom: string;
planStart: string;
planEnd: string;
secondScanCompleted: boolean;
totalItems: number;
completedItems: number;
}

// ✅ 新增:Pick Order 数据接口
interface PickOrderData {
// ✅ 新增: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;
pickOrderStatus: string;
completedDate: string;
lots: any[];
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 FInishedJobOrderRecord: React.FC<Props> = ({ filterArgs }) => {
const { t } = useTranslation("pickOrder");
const { t } = useTranslation("jo");
const router = useRouter();
const { data: session } = useSession() as { data: SessionWithTokens | null };
const currentUserId = session?.id ? parseInt(session.id) : undefined;
// ✅ 新增:已完成 DO Pick Orders 状态
const [completedDoPickOrders, setCompletedDoPickOrders] = useState<CompletedDoPickOrder[]>([]);
const [completedDoPickOrdersLoading, setCompletedDoPickOrdersLoading] = useState(false);
// ✅ 修改:已完成 Job Order Pick Orders 状态
const [completedJobOrderPickOrders, setCompletedJobOrderPickOrders] = useState<CompletedJobOrderPickOrder[]>([]);
const [completedJobOrderPickOrdersLoading, setCompletedJobOrderPickOrdersLoading] = useState(false);
// ✅ 新增:详情视图状态
const [selectedDoPickOrder, setSelectedDoPickOrder] = useState<CompletedDoPickOrder | null>(null);
// ✅ 修改:详情视图状态
const [selectedJobOrderPickOrder, setSelectedJobOrderPickOrder] = useState<CompletedJobOrderPickOrder | null>(null);
const [showDetailView, setShowDetailView] = useState(false);
const [detailLotData, setDetailLotData] = useState<any[]>([]);
const [detailLotData, setDetailLotData] = useState<LotDetail[]>([]);
const [detailLotDataLoading, setDetailLotDataLoading] = useState(false);
// ✅ 新增:搜索状态
// ✅ 修改:搜索状态
const [searchQuery, setSearchQuery] = useState<Record<string, any>>({});
const [filteredDoPickOrders, setFilteredDoPickOrders] = useState<CompletedDoPickOrder[]>([]);
const [filteredJobOrderPickOrders, setFilteredJobOrderPickOrders] = useState<CompletedJobOrderPickOrder[]>([]);
// ✅ 新增:分页状态
// ✅ 修改:分页状态
const [paginationController, setPaginationController] = useState({
pageNum: 0,
pageSize: 10,
@@ -128,58 +127,82 @@ const FInishedJobOrderRecord: React.FC<Props> = ({ filterArgs }) => {
const formProps = useForm();
const errors = formProps.formState.errors;

// ✅ 修改:使用新的 API 获取已完成的 DO Pick Orders
const fetchCompletedDoPickOrdersData = useCallback(async (searchParams?: CompletedDoPickOrderSearchParams) => {
// ✅ 修改:使用新的 Job Order API 获取已完成的 Job Order Pick Orders
const fetchCompletedJobOrderPickOrdersData = useCallback(async () => {
if (!currentUserId) return;
setCompletedDoPickOrdersLoading(true);
setCompletedJobOrderPickOrdersLoading(true);
try {
console.log("🔍 Fetching completed DO pick orders with params:", searchParams);
console.log("🔍 Fetching completed Job Order pick orders...");
const completedDoPickOrders = await fetchCompletedDoPickOrders(currentUserId, searchParams);
const completedJobOrderPickOrders = await fetchCompletedJobOrderPickOrdersWithCompletedSecondScan(currentUserId);
setCompletedDoPickOrders(completedDoPickOrders);
setFilteredDoPickOrders(completedDoPickOrders);
console.log("✅ Fetched completed DO pick orders:", completedDoPickOrders);
setCompletedJobOrderPickOrders(completedJobOrderPickOrders);
setFilteredJobOrderPickOrders(completedJobOrderPickOrders);
console.log("✅ Fetched completed Job Order pick orders:", completedJobOrderPickOrders);
} catch (error) {
console.error("❌ Error fetching completed DO pick orders:", error);
setCompletedDoPickOrders([]);
setFilteredDoPickOrders([]);
console.error("❌ Error fetching completed Job Order pick orders:", error);
setCompletedJobOrderPickOrders([]);
setFilteredJobOrderPickOrders([]);
} finally {
setCompletedDoPickOrdersLoading(false);
setCompletedJobOrderPickOrdersLoading(false);
}
}, [currentUserId]);

// ✅ 初始化时获取数据
// ✅ 新增:获取 lot 详情数据
const fetchLotDetailsData = useCallback(async (pickOrderId: number) => {
setDetailLotDataLoading(true);
try {
console.log("🔍 Fetching lot details for pick order:", pickOrderId);
const lotDetails = await fetchCompletedJobOrderPickOrderLotDetails(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) {
fetchCompletedDoPickOrdersData();
fetchCompletedJobOrderPickOrdersData();
}
}, [currentUserId, fetchCompletedDoPickOrdersData]);
}, [currentUserId, fetchCompletedJobOrderPickOrdersData]);

// ✅ 修改:搜索功能使用新的 API
// ✅ 修改:搜索功能
const handleSearch = useCallback((query: Record<string, any>) => {
setSearchQuery({ ...query });
console.log("Search query:", query);

const searchParams: CompletedDoPickOrderSearchParams = {
pickOrderCode: query.pickOrderCode || undefined,
shopName: query.shopName || undefined,
deliveryNo: query.deliveryNo || undefined,
//ticketNo: query.ticketNo || undefined,
};

// 使用新的 API 进行搜索
fetchCompletedDoPickOrdersData(searchParams);
}, [fetchCompletedDoPickOrdersData]);
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({});
fetchCompletedDoPickOrdersData(); // 重新获取所有数据
}, [fetchCompletedDoPickOrdersData]);
setFilteredJobOrderPickOrders(completedJobOrderPickOrders);
}, [completedJobOrderPickOrders]);

// ✅ 分页功能
// ✅ 修改:分页功能
const handlePageChange = useCallback((event: unknown, newPage: number) => {
setPaginationController(prev => ({
...prev,
@@ -195,14 +218,14 @@ const FInishedJobOrderRecord: React.FC<Props> = ({ filterArgs }) => {
});
}, []);

// ✅ 分页数据
// ✅ 修改:分页数据
const paginatedData = useMemo(() => {
const startIndex = paginationController.pageNum * paginationController.pageSize;
const endIndex = startIndex + paginationController.pageSize;
return filteredDoPickOrders.slice(startIndex, endIndex);
}, [filteredDoPickOrders, paginationController]);
return filteredJobOrderPickOrders.slice(startIndex, endIndex);
}, [filteredJobOrderPickOrders, paginationController]);

// ✅ 搜索条件
// ✅ 修改:搜索条件
const searchCriteria: Criterion<any>[] = [
{
label: t("Pick Order Code"),
@@ -210,59 +233,42 @@ const FInishedJobOrderRecord: React.FC<Props> = ({ filterArgs }) => {
type: "text",
},
{
label: t("Shop Name"),
paramName: "shopName",
label: t("Job Order Code"),
paramName: "jobOrderCode",
type: "text",
},
{
label: t("Delivery No"),
paramName: "deliveryNo",
label: t("Job Order Item Name"),
paramName: "jobOrderName",
type: "text",
}
];

const handleDetailClick = useCallback(async (doPickOrder: CompletedDoPickOrder) => {
setSelectedDoPickOrder(doPickOrder);
// ✅ 修改:详情点击处理
const handleDetailClick = useCallback(async (jobOrderPickOrder: CompletedJobOrderPickOrder) => {
setSelectedJobOrderPickOrder(jobOrderPickOrder);
setShowDetailView(true);
// ✅ 修复:使用新的 API 根据 pickOrderId 获取 lot 详情
try {
const lotDetails = await fetchLotDetailsByPickOrderId(doPickOrder.pickOrderId);
setDetailLotData(lotDetails);
console.log("✅ Loaded detail lot data for pick order:", doPickOrder.pickOrderCode, lotDetails);
// ✅ 触发打印按钮状态更新 - 基于详情数据
const allCompleted = lotDetails.length > 0 && lotDetails.every(lot =>
lot.processingStatus === 'completed'
);
// ✅ 发送事件,包含标签页信息
window.dispatchEvent(new CustomEvent('pickOrderCompletionStatus', {
detail: {
allLotsCompleted: allCompleted,
tabIndex: 2 // ✅ 明确指定这是来自标签页 2 的事件
}
}));
} catch (error) {
console.error("❌ Error loading detail lot data:", error);
setDetailLotData([]);
// ✅ 如果加载失败,禁用打印按钮
window.dispatchEvent(new CustomEvent('pickOrderCompletionStatus', {
detail: {
allLotsCompleted: false,
tabIndex: 2
}
}));
}
}, []);

// ✅ 获取 lot 详情数据
await fetchLotDetailsData(jobOrderPickOrder.pickOrderId);
// ✅ 触发打印按钮状态更新 - 基于详情数据
const allCompleted = jobOrderPickOrder.secondScanCompleted;
// ✅ 发送事件,包含标签页信息
window.dispatchEvent(new CustomEvent('pickOrderCompletionStatus', {
detail: {
allLotsCompleted: allCompleted,
tabIndex: 2 // ✅ 明确指定这是来自标签页 2 的事件
}
}));
}, [fetchLotDetailsData]);

// ✅ 返回列表视图
// ✅ 修改:返回列表视图
const handleBackToList = useCallback(() => {
setShowDetailView(false);
setSelectedDoPickOrder(null);
setSelectedJobOrderPickOrder(null);
setDetailLotData([]);
// ✅ 返回列表时禁用打印按钮
@@ -274,9 +280,8 @@ const FInishedJobOrderRecord: React.FC<Props> = ({ filterArgs }) => {
}));
}, []);


// ✅ 如果显示详情视图,渲染类似 GoodPickExecution 的表格
if (showDetailView && selectedDoPickOrder) {
// ✅ 修改:如果显示详情视图,渲染 Job Order 详情和 Lot 信息
if (showDetailView && selectedJobOrderPickOrder) {
return (
<FormProvider {...formProps}>
<Box>
@@ -286,64 +291,166 @@ const FInishedJobOrderRecord: React.FC<Props> = ({ filterArgs }) => {
{t("Back to List")}
</Button>
<Typography variant="h6">
{t("Pick Order Details")}: {selectedDoPickOrder.pickOrderCode}
{t("Job Order Pick Order Details")}: {selectedJobOrderPickOrder.pickOrderCode}
</Typography>
</Box>

{/* FG Pick Orders 信息 */}
<Box sx={{ mb: 2 }}>
{selectedDoPickOrder.fgPickOrders.map((fgOrder, index) => (
<FGPickOrderCard
key={index}
fgOrder={fgOrder}
onQrCodeClick={() => {}} // 只读模式
/>
))}
</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>

{/* 类似 GoodPickExecution 的表格 */}
<TableContainer component={Paper}>
<Table>
<TableHead>
<TableRow>
<TableCell>{t("Pick Order Code")}</TableCell>
<TableCell>{t("Item Code")}</TableCell>
<TableCell>{t("Item Name")}</TableCell>
<TableCell>{t("Lot No")}</TableCell>
<TableCell>{t("Location")}</TableCell>
<TableCell>{t("Required Qty")}</TableCell>
<TableCell>{t("Actual Pick Qty")}</TableCell>
<TableCell>{t("Submitted Status")}</TableCell>
</TableRow>
</TableHead>
<TableBody>
{detailLotData.map((lot, index) => (
<TableRow key={index}>
<TableCell>{lot.pickOrderCode}</TableCell>
<TableCell>{lot.itemCode}</TableCell>
<TableCell>{lot.itemName}</TableCell>
<TableCell>{lot.lotNo}</TableCell>
<TableCell>{lot.location}</TableCell>
<TableCell>{lot.requiredQty}</TableCell>
<TableCell>{lot.actualPickQty}</TableCell>
<TableCell>
<Chip
label={lot.processingStatus}
color={lot.processingStatus === 'completed' ? 'success' : 'default'}
size="small"
/>
</TableCell>
</TableRow>
))}
</TableBody>
</Table>
</TableContainer>
{/* ✅ 修改: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"> {/* ✅ 恢复原来的 colSpan */}
<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>
@@ -357,7 +464,7 @@ const FInishedJobOrderRecord: React.FC<Props> = ({ filterArgs }) => {
</Box>

{/* 加载状态 */}
{completedDoPickOrdersLoading ? (
{completedJobOrderPickOrdersLoading ? (
<Box sx={{ display: 'flex', justifyContent: 'center', p: 3 }}>
<CircularProgress />
</Box>
@@ -365,50 +472,59 @@ const FInishedJobOrderRecord: React.FC<Props> = ({ filterArgs }) => {
<Box>
{/* 结果统计 */}
<Typography variant="body2" color="text.secondary" sx={{ mb: 2 }}>
{t("Total")}: {filteredDoPickOrders.length} {t("completed DO pick orders")}
{t("Total")}: {filteredJobOrderPickOrders.length} {t("completed Job Order pick orders with matching")}
</Typography>

{/* 列表 */}
{filteredDoPickOrders.length === 0 ? (
{filteredJobOrderPickOrders.length === 0 ? (
<Box sx={{ p: 3, textAlign: 'center' }}>
<Typography variant="body2" color="text.secondary">
{t("No completed DO pick orders found")}
{t("No completed Job Order pick orders with matching found")}
</Typography>
</Box>
) : (
<Stack spacing={2}>
{paginatedData.map((doPickOrder) => (
<Card key={doPickOrder.id}>
{paginatedData.map((jobOrderPickOrder) => (
<Card key={jobOrderPickOrder.id}>
<CardContent>
<Stack direction="row" justifyContent="space-between" alignItems="center">
<Box>
<Typography variant="h6">
{doPickOrder.pickOrderCode}
{jobOrderPickOrder.pickOrderCode}
</Typography>
<Typography variant="body2" color="text.secondary">
{jobOrderPickOrder.jobOrderName} - {jobOrderPickOrder.jobOrderCode}
</Typography>
<Typography variant="body2" color="text.secondary">
{doPickOrder.shopName} - {doPickOrder.deliveryNo}
{t("Completed")}: {new Date(jobOrderPickOrder.completedDate).toLocaleString()}
</Typography>
<Typography variant="body2" color="text.secondary">
{t("Completed")}: {new Date(doPickOrder.completedDate).toLocaleString()}
{t("Target Date")}: {jobOrderPickOrder.pickOrderTargetDate}
</Typography>
</Box>
<Box>
<Chip
label={doPickOrder.pickOrderStatus}
color={doPickOrder.pickOrderStatus === 'completed' ? 'success' : 'default'}
label={jobOrderPickOrder.pickOrderStatus}
color={jobOrderPickOrder.pickOrderStatus === 'completed' ? 'success' : 'default'}
size="small"
sx={{ mb: 1 }}
/>
<Typography variant="body2" color="text.secondary">
{doPickOrder.fgPickOrders.length} {t("FG orders")}
{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(doPickOrder)}
onClick={() => handleDetailClick(jobOrderPickOrder)}
>
{t("View Details")}
</Button>
@@ -419,10 +535,10 @@ const FInishedJobOrderRecord: React.FC<Props> = ({ filterArgs }) => {
)}

{/* 分页 */}
{filteredDoPickOrders.length > 0 && (
{filteredJobOrderPickOrders.length > 0 && (
<TablePagination
component="div"
count={filteredDoPickOrders.length}
count={filteredJobOrderPickOrders.length}
page={paginationController.pageNum}
rowsPerPage={paginationController.pageSize}
onPageChange={handlePageChange}


+ 24
- 2
src/i18n/zh/jo.json Näytä tiedosto

@@ -21,7 +21,7 @@
"Job Order Detail": "工單細節",
"Pick Order Detail": "提料單細節",
"Finished Job Order Record": "已完成工單記錄",
"Index": "索引",
"Index": "編號",
"Route": "路線",
"Item Code": "物料編號",
"Item Name": "物料名稱",
@@ -42,5 +42,27 @@
"jodetail": "工單細節",
"Start QR Scan": "開始QR掃碼",
"Stop QR Scan": "停止QR掃碼",
"Rows per page": "每頁行數"
"Rows per page": "每頁行數",
"Job Order Item Name": "工單物料名稱",
"Job Order Code": "工單編號",
"View Details": "查看詳情",
"Required Qty": "需求數量",
"completed Job Order pick orders with Matching": "工單已完成提料和對料",
"No completed Job Order pick orders with matching found": "沒有匹配的工單",
"completed Job Order pick orders with matching": "工單已完成提料和對料",
"Total": "總數",
"Back to List": "返回列表",
"second Scan Status": "對料狀態",
"Actual Pick Qty": "實際提料數量",
"Processing Status": "處理狀態",
"Lot Availability": "批號可用性",
"Pick Order Id": "提料單編號",
"Pick Order Code": "提料單編號",
"Pick Order Conso Code": "提料單組合編號",
"Pick Order Target Date": "提料單需求日期",
"Pick Order Status": "提料單狀態",
"Second Scan Status": "對料狀態",
"Job Order Pick Order Details": "工單提料單詳情",
"Scanning": "掃碼中",
"Unassigned Job Orders": "未分配工單"
}

Ladataan…
Peruuta
Tallenna