Bläddra i källkod

update job order record

stable1
CANCERYS\kw093 2 veckor sedan
förälder
incheckning
4fb0be7c9e
3 ändrade filer med 96 tillägg och 29 borttagningar
  1. +44
    -0
      src/app/api/jo/actions.ts
  2. +49
    -29
      src/components/Jodetail/completeJobOrderRecord.tsx
  3. +3
    -0
      src/i18n/zh/jo.json

+ 44
- 0
src/app/api/jo/actions.ts Visa fil

@@ -604,6 +604,9 @@ export interface StockOutLineDetailResponse {
location: string | null;
availableQty: number | null;
noLot: boolean;
/** Workbench API: matched suggest_pick_lot qty for this SOL lot line */
//suggestedPickQty?: number | null;
//suggestedPickLotId?: number | null;
}

export interface LotDetailResponse {
@@ -712,6 +715,21 @@ export const fetchJobOrderLotsHierarchicalByPickOrderId = cache(async (pickOrder
},
);
});

/** JO Workbench: in−out available (matches scan-pick); stockouts include suggestedPickQty / suggestedPickLotId when SPL matches SOL lot line */
/*
export const fetchJobOrderLotsHierarchicalByPickOrderIdWorkbench = cache(
async (pickOrderId: number) => {
return serverFetchJson<JobOrderLotsHierarchicalResponse>(
`${BASE_API_URL}/jo/all-lots-hierarchical-by-pick-order-workbench/${pickOrderId}`,
{
method: "GET",
next: { tags: ["jo-hierarchical-workbench"] },
},
);
},
);
*/
// NOTE: Do NOT wrap in `cache()` because the list needs to reflect just-completed lines
// immediately when navigating back from JobPickExecution.
export const fetchAllJoPickOrders = async (type?: string | null, floor?: string | null) => {
@@ -1076,6 +1094,32 @@ export const fetchCompletedJobOrderPickOrdersrecords = async (completedDate?: st
cache: "no-store",
});
};
export const fetchJobOrderPickOrdersrecords = async (
date?: string | null,
status?: string | null,
) => {
const params = new URLSearchParams();

if (date && String(date).trim() !== "") {
params.set("date", String(date).trim());
}
if (status && String(status).trim() !== "" && String(status) !== "All") {
params.set("status", String(status).trim());
}

const q = params.toString() ? `?${params.toString()}` : "";
return serverFetchJson<any>(`${BASE_API_URL}/jo/job-order-pick-orders${q}`, {
method: "GET",
cache: "no-store",
});
};

export const fetchJobOrderPickOrderLotDetailsForPick = cache(async (pickOrderId: number) => {
return serverFetchJson<any[]>(`${BASE_API_URL}/jo/job-order-pick-order-lot-details/${pickOrderId}`, {
method: "GET",
headers: { "Content-Type": "application/json" }
})
})
export const fetchJoForPrintQrCode = cache(async (date: string) => {
return serverFetchJson<JobOrderListForPrintQrCodeResponse[]>(
`${BASE_API_URL}/jo/joForPrintQrCode/${date}`,


+ 49
- 29
src/components/Jodetail/completeJobOrderRecord.tsx Visa fil

@@ -32,8 +32,8 @@ import { useCallback, useEffect, useState, useRef, useMemo } from "react";
import { useTranslation } from "react-i18next";
import { useRouter } from "next/navigation";
import {
fetchCompletedJobOrderPickOrdersrecords,
fetchCompletedJobOrderPickOrderLotDetailsForCompletedPick,
fetchJobOrderPickOrdersrecords,
fetchJobOrderPickOrderLotDetailsForPick,
PrintPickRecord
} from "@/app/api/jo/actions";
import { fetchNameList, NameList } from "@/app/api/user/actions";
@@ -148,8 +148,8 @@ const CompleteJobOrderRecord: React.FC<Props> = ({
const errors = formProps.formState.errors;

// 修改:使用新的 Job Order API 获取已完成的 Job Order Pick Orders(仅完成pick的)
const fetchCompletedJobOrderPickOrdersData = useCallback(
async (forDate?: string) => {
const fetchJobOrderPickOrdersData = useCallback(
async (forDate?: string, forStatus?: string) => {
if (!currentUserId) return;
setCompletedJobOrderPickOrdersLoading(true);
@@ -160,21 +160,27 @@ const CompleteJobOrderRecord: React.FC<Props> = ({
: searchQuery.completedDate
? String(searchQuery.completedDate)
: dayjs().format("YYYY-MM-DD");
const completedJobOrderPickOrders = await fetchCompletedJobOrderPickOrdersrecords(
dateParam.trim() ? dateParam.trim() : null,
const statusParam =
forStatus !== undefined
? forStatus
: searchQuery.pickOrderStatus
? String(searchQuery.pickOrderStatus)
: null;
const data = await fetchJobOrderPickOrdersrecords(
dateParam?.trim() ? dateParam.trim() : null,
statusParam?.trim() ? statusParam.trim() : null,
);
const safeData = Array.isArray(completedJobOrderPickOrders) ? completedJobOrderPickOrders : [];
const safeData = Array.isArray(data) ? data : [];
setCompletedJobOrderPickOrders(safeData);
setFilteredJobOrderPickOrders(safeData);
} catch (error) {
console.error("❌ Error fetching completed Job Order pick orders:", error);
setCompletedJobOrderPickOrders([]);
setFilteredJobOrderPickOrders([]);
} finally {
setCompletedJobOrderPickOrdersLoading(false);
}
},
[currentUserId, searchQuery.completedDate],
[currentUserId, searchQuery.completedDate, searchQuery.pickOrderStatus],
);
// 新增:获取 lot 详情数据(使用新的API)
const fetchLotDetailsData = useCallback(async (pickOrderId: number) => {
@@ -182,7 +188,7 @@ const CompleteJobOrderRecord: React.FC<Props> = ({
try {
console.log("🔍 Fetching lot details for completed pick order:", pickOrderId);
const lotDetails = await fetchCompletedJobOrderPickOrderLotDetailsForCompletedPick(pickOrderId);
const lotDetails = await fetchJobOrderPickOrderLotDetailsForPick(pickOrderId);
setDetailLotData(Array.isArray(lotDetails) ? lotDetails : []);
console.log(" Fetched lot details:", lotDetails);
@@ -198,9 +204,13 @@ const CompleteJobOrderRecord: React.FC<Props> = ({
useEffect(() => {
if (!currentUserId) return;
const d = searchQuery?.completedDate;
const s = searchQuery?.pickOrderStatus;
const dateStr = d != null && String(d).trim() !== "" ? String(d).trim() : "";
void fetchCompletedJobOrderPickOrdersData(dateStr || undefined);
}, [currentUserId, searchQuery?.completedDate, fetchCompletedJobOrderPickOrdersData]);
const statusStr = s != null && String(s).trim() !== "" ? String(s).trim() : "";
void fetchJobOrderPickOrdersData(dateStr || undefined, statusStr || undefined);
}, [currentUserId, searchQuery?.completedDate, searchQuery?.pickOrderStatus, fetchJobOrderPickOrdersData]);

// 修改:搜索功能(只更新 query;实际过滤交给 useEffect + date filter 统一处理)
const handleSearch = useCallback((query: Record<string, any>) => {
@@ -316,6 +326,15 @@ const CompleteJobOrderRecord: React.FC<Props> = ({
paramName: "jobOrderCode",
type: "text",
},
{
label: t("Pick Order Status"),
paramName: "pickOrderStatus",
type: "select-labelled",
options: [
{ label: t("Released"), value: "RELEASED" },
{ label: t("Completed"), value: "COMPLETED" },
], // 依你后端实际枚举
},
{
label: t("Job Order Item Name"),
paramName: "jobOrderName",
@@ -640,7 +659,9 @@ const CompleteJobOrderRecord: React.FC<Props> = ({
</Box>
) : (
<Stack spacing={2}>
{paginatedData.map((jobOrderPickOrder) => (
{paginatedData.map((jobOrderPickOrder) => {
const normalizedStatus = String(jobOrderPickOrder.pickOrderStatus ?? "").toLowerCase();
return (
<Card key={jobOrderPickOrder.id}>
<CardContent>
<Stack direction="row" justifyContent="space-between" alignItems="center">
@@ -660,21 +681,18 @@ const CompleteJobOrderRecord: React.FC<Props> = ({
</Box>
<Box>
<Chip
label={t(jobOrderPickOrder.pickOrderStatus) }
color={jobOrderPickOrder.pickOrderStatus === 'completed' ? 'success' : 'default'}
size="small"
sx={{ mb: 1 }}
/>
<Chip
label={t(jobOrderPickOrder.pickOrderStatus)}
color={normalizedStatus === "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>
@@ -694,7 +712,9 @@ const CompleteJobOrderRecord: React.FC<Props> = ({
</Button>
</CardActions>
</Card>
))}
);
})}
</Stack>
)}



+ 3
- 0
src/i18n/zh/jo.json Visa fil

@@ -167,6 +167,9 @@
"View Details": "查看詳情",
"Skip": "跳過",
"Handler": "提料員",
"RELEASED": "已放單",
"Released": "已放單",
"COMPLETED": "已完成",
"Now": "現時",
"Last updated": "最後更新",
"Auto-refresh every 5 minutes": "每5分鐘自動刷新",


Laddar…
Avbryt
Spara