Переглянути джерело

update 4F ticket hander name

stable1
CANCERYS\kw093 2 тижднів тому
джерело
коміт
42b058d86f
3 змінених файлів з 91 додано та 37 видалено
  1. +4
    -0
      src/app/api/pickOrder/actions.ts
  2. +49
    -33
      src/components/FinishedGoodSearch/FinishedGoodFloorLanePanel.tsx
  3. +38
    -4
      src/components/PickOrderSearch/newcreatitem.tsx

+ 4
- 0
src/app/api/pickOrder/actions.ts Переглянути файл

@@ -462,6 +462,7 @@ export interface LaneBtn {
loadingSequence?: number | null;
unassigned: number;
total: number;
handlerName: string;
}

export interface QrPickBatchSubmitRequest {
@@ -804,6 +805,7 @@ export const fetchFGPickOrdersByUserId = async (userId: number) => {
};

/** DO workbench: FG headers from `delivery_order_pick_order`, not `do_pick_order_line`. */

/*
export const fetchFGPickOrdersByUserIdWorkbench = async (userId: number) => {
return serverFetchJson<FGPickOrderResponse[]>(
@@ -1190,6 +1192,7 @@ export const fetchAllPickOrderLotsHierarchical = cache(async (userId: number): P
});

/** DO workbench: hierarchical lots where header is `delivery_order_pick_order`. */
/*
export const fetchAllPickOrderLotsHierarchicalWorkbench = cache(async (userId: number): Promise<any> => {
try {
const data = await serverFetchJson<any>(
@@ -1208,6 +1211,7 @@ export const fetchAllPickOrderLotsHierarchicalWorkbench = cache(async (userId: n
};
}
});
*/
export const fetchLotDetailsByDoPickOrderRecordId = async (doPickOrderRecordId: number): Promise<{
fgInfo: any;
pickOrders: any[];


+ 49
- 33
src/components/FinishedGoodSearch/FinishedGoodFloorLanePanel.tsx Переглянути файл

@@ -601,39 +601,55 @@ const getDateLabel = (offset: number) => {
flexWrap="wrap"
sx={{ flex: 1, gap: 1 }}
>
{slots.map((slot) => (
<Button
key={`${truckLanceCode}-${slot.sequenceIndex}-${slot.lane.truckLanceCode}-${slot.truckDepartureTime}`}
variant="outlined"
size="medium"
disabled={slot.lane.unassigned === 0 || isAssigning}
onClick={() =>
handleLaneButtonClick(
"4/F",
slot.truckDepartureTime,
slot.lane.truckLanceCode,
slot.lane.loadingSequence ?? null,
selectedDate,
slot.lane.unassigned,
slot.lane.total
)
}
sx={{
fontSize: "1rem",
py: 0.75,
px: 1.25,
borderWidth: 1,
borderColor: "#ccc",
fontWeight: 500,
"&:hover": {
borderColor: "#999",
backgroundColor: "#f5f5f5",
},
}}
>
{`${t("Loading sequence n", { n: slot.lane.loadingSequence ?? slot.sequenceIndex })} (${slot.lane.unassigned}/${slot.lane.total})`}
</Button>
))}
{slots.map((slot) => {
const hasHandler =
!!slot.lane.handlerName?.trim() && slot.lane.total > slot.lane.unassigned;

return (
<Button
key={`${truckLanceCode}-${slot.sequenceIndex}-${slot.lane.truckLanceCode}-${slot.truckDepartureTime}`}
variant="outlined"
size="medium"
disabled={slot.lane.unassigned === 0 || isAssigning}
onClick={() =>
handleLaneButtonClick(
"4/F",
slot.truckDepartureTime,
slot.lane.truckLanceCode,
slot.lane.loadingSequence ?? null,
selectedDate,
slot.lane.unassigned,
slot.lane.total
)
}
sx={{
fontSize: "1rem",
py: 0.75,
px: 1.25,
borderWidth: 1,
borderColor: hasHandler ? "#f59e0b" : "#ccc",
backgroundColor: hasHandler ? "#fff7e6" : "#fff",
color: hasHandler ? "#1f2937" : "primary.main",
fontWeight: 500,
"&:hover": {
borderColor: hasHandler ? "#d97706" : "#999",
backgroundColor: hasHandler ? "#ffefcc" : "#f5f5f5",
},
}}
>
<Box sx={{ display: "flex", alignItems: "center", gap: 0.75 }}>
<Typography component="span" sx={{ fontSize: "1rem", color: "inherit", fontWeight: 500 }}>
{`${t("Loading sequence n", { n: slot.lane.loadingSequence ?? slot.sequenceIndex })} (${slot.lane.unassigned}/${slot.lane.total})`}
</Typography>
{hasHandler && (
<Typography component="span" sx={{ fontSize: "1rem", fontWeight: 700, color: "#d97706" }}>
{slot.lane.handlerName!.trim()}
</Typography>
)}
</Box>
</Button>
);
})}
</Stack>
</Stack>
</Grid>


+ 38
- 4
src/components/PickOrderSearch/newcreatitem.tsx Переглянути файл

@@ -241,16 +241,24 @@ const NewCreateItem: React.FC<Props> = ({ filterArgs, searchQuery, onPickOrderCr

// Handle quantity change in search results
const handleSearchQtyChange = useCallback((itemId: number, newQty: number | null) => {
const getClampedQty = (qty: number | null, stock?: number) => {
if (qty === null) return null;
const maxQty = Math.max(0, stock ?? 0);
return Math.max(1, Math.min(qty, maxQty));
};

setFilteredItems(prev =>
prev.map(item =>
item.id === itemId ? { ...item, qty: newQty } : item
item.id === itemId ? { ...item, qty: getClampedQty(newQty, item.currentStockBalance) } : item
)
);
// Auto-update created items if this item exists there
setCreatedItems(prev =>
prev.map(item =>
item.itemId === itemId ? { ...item, qty: newQty || 1 } : item
item.itemId === itemId
? { ...item, qty: getClampedQty(newQty, item.currentStockBalance) || 1 }
: item
)
);
}, []);
@@ -297,7 +305,12 @@ const NewCreateItem: React.FC<Props> = ({ filterArgs, searchQuery, onPickOrderCr
const handleQtyChange = useCallback((itemId: number, newQty: number) => {
setCreatedItems(prev =>
prev.map(item =>
item.itemId === itemId ? { ...item, qty: newQty } : item
item.itemId === itemId
? {
...item,
qty: Math.max(1, Math.min(newQty, Math.max(0, item.currentStockBalance ?? 0))),
}
: item
)
);
}, []);
@@ -567,6 +580,15 @@ const handleQtyBlur = useCallback((itemId: number) => {
alert(t("Please select at least one item to submit"));
return;
}

const invalidQtyItems = selectedCreatedItems.filter((item) => {
const stock = item.currentStockBalance ?? 0;
return item.qty <= 0 || item.qty > stock;
});
if (invalidQtyItems.length > 0) {
alert(t("Order quantity cannot exceed available stock."));
return;
}
// 修复:自动填充 type 为 "Consumable",不再强制用户选择
// if (!data.type) {
@@ -946,6 +968,7 @@ const handleQtyBlur = useCallback((itemId: number) => {
}}
inputProps={{
min: 1,
max: item.currentStockBalance || 0,
step: 1,
style: { textAlign: 'center' }
}}
@@ -1033,6 +1056,7 @@ const handleQtyBlur = useCallback((itemId: number) => {
}}
inputProps={{
min: 1,
max: item.currentStockBalance || 0,
step: 1,
style: { textAlign: 'center' } // Center the text
}}
@@ -1118,9 +1142,15 @@ const handleQtyBlur = useCallback((itemId: number) => {

// 添加数量变更处理函数
const handleSecondSearchQtyChange = useCallback((itemId: number, newQty: number | null) => {
const getClampedQty = (qty: number | null, stock?: number) => {
if (qty === null) return null;
const maxQty = Math.max(0, stock ?? 0);
return Math.max(1, Math.min(qty, maxQty));
};

setSecondSearchResults(prev =>
prev.map(item =>
item.id === itemId ? { ...item, qty: newQty } : item
item.id === itemId ? { ...item, qty: getClampedQty(newQty, item.currentStockBalance) } : item
)
);
@@ -1254,6 +1284,8 @@ const handleQtyBlur = useCallback((itemId: number) => {
}
}}
inputProps={{
min: 1,
max: item.currentStockBalance || 0,
style: { textAlign: 'center' }
}}
sx={{
@@ -1797,6 +1829,8 @@ const CustomSearchResultsTable = () => {
handleQtyBlur(item.id);
}}
inputProps={{
min: 1,
max: item.currentStockBalance || 0,
style: { textAlign: 'center' }
}}
sx={{


Завантаження…
Відмінити
Зберегти