Parcourir la source

update

master
CANCERYS\kw093 il y a 3 mois
Parent
révision
9bed0dc8cb
7 fichiers modifiés avec 118 ajouts et 34 suppressions
  1. +6
    -5
      src/app/api/pickOrder/actions.ts
  2. +12
    -7
      src/components/FinishedGoodSearch/AssignAndRelease.tsx
  3. +57
    -4
      src/components/FinishedGoodSearch/FinishedGoodSearch.tsx
  4. +24
    -11
      src/components/FinishedGoodSearch/GoodPickExecution.tsx
  5. +4
    -4
      src/components/PickOrderSearch/AssignAndRelease.tsx
  6. +7
    -1
      src/components/PickOrderSearch/newcreatitem.tsx
  7. +8
    -2
      src/i18n/zh/pickOrder.json

+ 6
- 5
src/app/api/pickOrder/actions.ts Voir le fichier

@@ -550,24 +550,25 @@ const fetchSuggestionsWithStatus = async (pickOrderLineId: number) => {
}
};

// Update the existing function to use the non-auto-assign endpoint
export const fetchALLPickOrderLineLotDetails = cache(async (userId: number): Promise<any[]> => {
try {
console.log("🔍 Fetching all pick order line lot details for userId:", userId);
// ✅ 使用 serverFetchJson 而不是直接的 fetch
// ✅ Use the non-auto-assign endpoint
const data = await serverFetchJson<any[]>(
`${BASE_API_URL}/pickOrder/all-lots-with-details/${userId}`,
`${BASE_API_URL}/pickOrder/all-lots-with-details-no-auto-assign/${userId}`,
{
method: 'GET',
next: { tags: ["pickorder"] },
}
);
console.log("✅ API Response:", data);
console.log("✅ Fetched lot details:", data);
return data;
} catch (error) {
console.error("❌ Error fetching all pick order line lot details:", error);
throw error;
console.error("❌ Error fetching lot details:", error);
return [];
}
});
export const fetchAllPickOrderDetails = cache(async (userId?: number) => {


+ 12
- 7
src/components/FinishedGoodSearch/AssignAndRelease.tsx Voir le fichier

@@ -156,7 +156,10 @@ const AssignAndRelease: React.FC<Props> = ({ filterArgs }) => {
if (res && res.records) {
console.log("Records received:", res.records.length);
console.log("First record:", res.records[0]);
console.log("First record targetDate:", res.records[0]?.targetDate);
console.log("First record targetDate type:", typeof res.records[0]?.targetDate);
console.log("First record targetDate parsed:", new Date(res.records[0]?.targetDate));
console.log("First record targetDate formatted:", new Date(res.records[0]?.targetDate).toLocaleDateString());
// 新增:在前端也过滤掉 "assigned" 状态的项目
const filteredRecords = res.records.filter((item: any) => item.status !== "assigned");
@@ -496,12 +499,14 @@ const AssignAndRelease: React.FC<Props> = ({ filterArgs }) => {
{/* Target Date - 只在第一个项目显示 */}
<TableCell>
{index === 0 ? (
arrayToDayjs(item.targetDate)
.add(-1, "month")
.format(OUTPUT_DATE_FORMAT)
) : null}
</TableCell>
{index === 0 ? (
(() => {
console.log("targetDate:", item.targetDate);
console.log("formatted:", arrayToDayjs(item.targetDate).format(OUTPUT_DATE_FORMAT));
return arrayToDayjs(item.targetDate).format(OUTPUT_DATE_FORMAT);
})()
) : null}
</TableCell>
{/* Pick Order Status - 只在第一个项目显示 */}
<TableCell>


+ 57
- 4
src/components/FinishedGoodSearch/FinishedGoodSearch.tsx Voir le fichier

@@ -24,8 +24,10 @@ import NewCreateItem from "./newcreatitem";
import AssignAndRelease from "./AssignAndRelease";
import AssignTo from "./assignTo";
import { fetchAllItemsInClient, ItemCombo } from "@/app/api/settings/item/actions";
import { fetchPickOrderClient } from "@/app/api/pickOrder/actions";
import { fetchPickOrderClient, autoAssignAndReleasePickOrder } from "@/app/api/pickOrder/actions";
import Jobcreatitem from "./Jobcreatitem";
import { useSession } from "next-auth/react";
import { SessionWithTokens } from "@/config/authConfig";

interface Props {
pickOrders: PickOrderResult[];
@@ -39,6 +41,8 @@ type SearchParamNames = keyof SearchQuery;

const PickOrderSearch: React.FC<Props> = ({ pickOrders }) => {
const { t } = useTranslation("pickOrder");
const { data: session } = useSession() as { data: SessionWithTokens | null };
const currentUserId = session?.id ? parseInt(session.id) : undefined;

const [isOpenCreateModal, setIsOpenCreateModal] = useState(false)
const [items, setItems] = useState<ItemCombo[]>([])
@@ -47,6 +51,37 @@ const PickOrderSearch: React.FC<Props> = ({ pickOrders }) => {
const [searchQuery, setSearchQuery] = useState<Record<string, any>>({});
const [tabIndex, setTabIndex] = useState(0);
const [totalCount, setTotalCount] = useState<number>();
const [isAssigning, setIsAssigning] = useState(false);

// ✅ Manual assignment handler - uses the action function
const handleManualAssign = useCallback(async () => {
if (!currentUserId || isAssigning) return;
setIsAssigning(true);
try {
console.log("🎯 Manual assignment triggered for user:", currentUserId);
// ✅ Use the action function instead of direct fetch
const result = await autoAssignAndReleasePickOrder(currentUserId);
console.log("✅ Manual assignment result:", result);
if (result.code === "SUCCESS") {
console.log("✅ Successfully assigned pick order manually");
// Trigger refresh of the PickExecution component
window.dispatchEvent(new CustomEvent('pickOrderAssigned'));
} else if (result.code === "EXISTS") {
console.log("ℹ️ User already has active pick orders");
// Still trigger refresh to show existing orders
window.dispatchEvent(new CustomEvent('pickOrderAssigned'));
} else {
console.log("ℹ️ No available pick orders or other status:", result.message);
}
} catch (error) {
console.error("❌ Error in manual assignment:", error);
} finally {
setIsAssigning(false);
}
}, [currentUserId, isAssigning]);

const handleTabChange = useCallback<NonNullable<TabsProps["onChange"]>>(
(_e, newValue) => {
@@ -266,13 +301,31 @@ const PickOrderSearch: React.FC<Props> = ({ pickOrders }) => {
</Stack>
</Box>

{/* Tabs section */}
{/* Tabs section - ✅ Move the click handler here */}
<Box sx={{
borderBottom: '1px solid #e0e0e0'
}}>
<Tabs value={tabIndex} onChange={handleTabChange} variant="scrollable">
<Tab label={t("Pick Execution")} iconPosition="end" />
<Tab
label={t("Pick Execution")}
iconPosition="end"
onClick={handleManualAssign}
sx={{
cursor: 'pointer',
'&:hover': {
color: 'primary.main',
}
}}
title={t("Click to assign a new pick order")}
/>
</Tabs>
{isAssigning && (
<Box sx={{ p: 1, textAlign: 'center' }}>
<Typography variant="caption" color="primary">
{t("Assigning pick order...")}
</Typography>
</Box>
)}
</Box>

{/* Content section - NO overflow: 'auto' here */}
@@ -285,4 +338,4 @@ const PickOrderSearch: React.FC<Props> = ({ pickOrders }) => {
);
};

export default PickOrderSearch;
export default PickOrderSearch;

+ 24
- 11
src/components/FinishedGoodSearch/GoodPickExecution.tsx Voir le fichier

@@ -415,7 +415,7 @@ const PickExecution: React.FC<Props> = ({ filterArgs }) => {
return;
}
// ✅ 使用新的API路径,后端会自动处理分配逻辑
// ✅ Use the non-auto-assign endpoint - this only fetches existing data
const allLotDetails = await fetchALLPickOrderLineLotDetails(userIdToUse);
console.log("✅ All combined lot details:", allLotDetails);
setCombinedLotData(allLotDetails);
@@ -429,19 +429,30 @@ const PickExecution: React.FC<Props> = ({ filterArgs }) => {
}
}, [currentUserId]);

// ✅ 简化初始化逻辑,移除前端的自动分配检查
// ✅ Only fetch existing data when session is ready, no auto-assignment
useEffect(() => {
if (session && currentUserId && !initializationRef.current) {
console.log("✅ Session loaded, initializing pick order...");
initializationRef.current = true;
// ✅ 直接获取数据,后端会自动处理分配逻辑
// ✅ Only fetch existing data, no auto-assignment
fetchAllCombinedLotData();
}
}, [session, currentUserId, fetchAllCombinedLotData]);

// ✅ 移除前端的自动分配逻辑,因为后端已经处理了
// const handleAutoAssignAndRelease = useCallback(async () => { ... }); // 删除这个函数
// ✅ Add event listener for manual assignment
useEffect(() => {
const handlePickOrderAssigned = () => {
console.log("🔄 Pick order assigned event received, refreshing data...");
fetchAllCombinedLotData();
};

window.addEventListener('pickOrderAssigned', handlePickOrderAssigned);
return () => {
window.removeEventListener('pickOrderAssigned', handlePickOrderAssigned);
};
}, [fetchAllCombinedLotData]);

// ✅ Handle QR code submission for matched lot (external scanning)
// ✅ Handle QR code submission for matched lot (external scanning)
@@ -925,13 +936,15 @@ const PickExecution: React.FC<Props> = ({ filterArgs }) => {
<FormProvider {...formProps}>
<Stack spacing={2}>
{/* Search Box */}
<Box>
{/*
<Box sx={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', mb: 2 }}>
<Typography variant="h6" gutterBottom sx={{ mb: 0 }}>
{t("FG Pick Orders")}
</Typography>
</Box>
*/}
{fgPickOrdersLoading ? (
<Box sx={{ display: 'flex', justifyContent: 'center', p: 3 }}>
<CircularProgress />
@@ -980,11 +993,11 @@ const PickExecution: React.FC<Props> = ({ filterArgs }) => {
<TableCell>{t("Item Name")}</TableCell>
<TableCell>{t("Lot#")}</TableCell>
<TableCell>{t("Target Date")}</TableCell>
<TableCell>{t("Lot Location")}</TableCell>
{/* <TableCell>{t("Lot Location")}</TableCell> */}
<TableCell align="right">{t("Lot Required Pick Qty")}</TableCell>
<TableCell align="right">{t("Original Available Qty")}</TableCell>
<TableCell align="center">{t("Lot Actual Pick Qty")}</TableCell>
<TableCell align="right">{t("Remaining Available Qty")}</TableCell>
{/* <TableCell align="right">{t("Remaining Available Qty")}</TableCell> */}
<TableCell align="center">{t("Action")}</TableCell>
</TableRow>
</TableHead>
@@ -1033,7 +1046,7 @@ const PickExecution: React.FC<Props> = ({ filterArgs }) => {
</Box>
</TableCell>
<TableCell>{lot.pickOrderTargetDate}</TableCell>
<TableCell>{lot.location}</TableCell>
{/* <TableCell>{lot.location}</TableCell> */}
<TableCell align="right">{calculateRemainingRequiredQty(lot).toLocaleString()}</TableCell>
<TableCell align="right">
{(() => {
@@ -1123,14 +1136,14 @@ const PickExecution: React.FC<Props> = ({ filterArgs }) => {
</Stack>
)}
</TableCell>
<TableCell align="right">
{/* <TableCell align="right">
{(() => {
const inQty = lot.inQty || 0;
const outQty = lot.outQty || 0;
const result = inQty - outQty;
return result.toLocaleString();
})()}
</TableCell>
</TableCell> */}
<TableCell align="center">
<Stack direction="column" spacing={1} alignItems="center">
<Button


+ 4
- 4
src/components/PickOrderSearch/AssignAndRelease.tsx Voir le fichier

@@ -470,7 +470,7 @@ const AssignAndRelease: React.FC<Props> = ({ filterArgs }) => {
</TableCell>
{/* Group Name */}
<TableCell>
{index === 0 ? (item.groupName || "No Group") : null}
{index === 0 ? (item.groupName || t("No Group")) : null}
</TableCell>
{/* Item Code */}
<TableCell>{item.itemCode}</TableCell>
@@ -607,8 +607,8 @@ const AssignAndRelease: React.FC<Props> = ({ filterArgs }) => {
{...params}
label={t("Assign To")}
error={!!errors.assignTo}
helperText={errors.assignTo?.message}
required
//helperText={errors.assignTo?.message}
//required
/>
)}
/>
@@ -616,7 +616,7 @@ const AssignAndRelease: React.FC<Props> = ({ filterArgs }) => {
</Grid>
<Grid item xs={12}>
<Typography variant="body2" color="warning.main">
{t("Select an action for the assigned pick orders.")}
{t("Please assgin/release the pickorders to picker")}
</Typography>
</Grid>
<Grid item xs={12}>


+ 7
- 1
src/components/PickOrderSearch/newcreatitem.tsx Voir le fichier

@@ -595,7 +595,7 @@ const handleQtyBlur = useCallback((itemId: number) => {
try {
// 获取组的名称和目标日期
const group = groups.find(g => g.id === Number(groupId));
const groupName = group?.name || 'No Group';
const groupName = group?.name || t('No Group');
// Use the group's target date, fallback to item's target date, then form's target date
let groupTargetDate = group?.targetDate;
@@ -913,6 +913,12 @@ const handleQtyBlur = useCallback((itemId: number) => {
{groups.map((group) => (
<MenuItem key={group.id} value={group.id.toString()}>
{group.name}
if(group.name === t("No Group")){
<em>{t("No Group")}</em>
} else {
group.name
}
</MenuItem>
))}
</Select>


+ 8
- 2
src/i18n/zh/pickOrder.json Voir le fichier

@@ -189,7 +189,7 @@
"Location": "位置",
"All Pick Order Lots": "所有提料單批次",
"Completed": "已完成",
"Finished Good Order": "成品訂單",
"Finished Good Order": "成品出倉",
"Assign and Release": "分派並放單",
"Original Available Qty": "原可用數",
"Remaining Available Qty": "剩餘",
@@ -215,5 +215,11 @@
"QR Scan Result:": "QR 掃描結果:",
"Action": "操作",
"Please finish pick order.": "請完成提料。",
"Lot": "批號"
"Lot": "批號",
"Assign Pick Orders": "分派提料單",
"Selected Pick Orders": "已選擇提料單數量",
"Please assgin/release the pickorders to picker": "請分派/放單提料單給提料員。",
"Assign To": "分派給",
"No Group": "沒有分組",
"Selected items will join above created group": "已選擇的貨品將加入以上建立的分組"
}

Chargement…
Annuler
Enregistrer