From 79edfec1f6e6789d3f6cc57db3cb0cfdffd64c32 Mon Sep 17 00:00:00 2001
From: chen.lin <1442464845@qq.com>
Date: 星期二, 24 二月 2026 15:50:32 +0800
Subject: [PATCH] 库位拣料出库数量调整

---
 rsf-server/src/main/java/com/vincent/rsf/server/manager/service/impl/OutStockServiceImpl.java   |  124 +++++++--
 rsf-admin/src/page/work/stockTransfer/stockTransferList.jsx                                     |    2 
 rsf-admin/src/page/stockItem/StockItemCreate.jsx                                                |   11 
 rsf-open-api/src/main/java/com/vincent/rsf/openApi/entity/params/ReportParams.java              |    2 
 rsf-server/src/main/java/com/vincent/rsf/server/common/utils/QuantityUtils.java                 |   77 ++++++
 rsf-server/src/main/java/com/vincent/rsf/server/manager/schedules/ScheduleJobs.java             |    2 
 rsf-admin/src/page/orders/outStock/SelectMatnrModal.jsx                                         |    7 
 rsf-admin/src/page/orders/transfer/TransferCreate.jsx                                           |    3 
 rsf-admin/src/page/stockItem/StockItemEdit.jsx                                                  |   11 
 rsf-server/src/main/java/com/vincent/rsf/server/manager/service/impl/TaskServiceImpl.java       |  173 ++++++++++---
 rsf-admin/src/page/locItem/LocItemList.jsx                                                      |    2 
 rsf-admin/src/page/orders/check/SelectMatnrModal.jsx                                            |    3 
 rsf-admin/src/page/orders/outStock/OutOrderPreview.jsx                                          |    3 
 rsf-admin/src/page/stockManage/locRevise/LocsReviseDetl.jsx                                     |    7 
 rsf-admin/src/page/orders/outStock/OutOrderModal.jsx                                            |    4 
 rsf-admin/src/page/orders/asnOrder/AsnOrderItemList.jsx                                         |    6 
 rsf-admin/src/page/locItem/LocItemEdit.jsx                                                      |    7 
 rsf-admin/src/page/orders/asnOrder/POItemModal.jsx                                              |    5 
 rsf-server/src/main/java/com/vincent/rsf/server/api/service/impl/PdaCheckOrderServiceImpl.java  |    2 
 rsf-admin/src/page/orders/transfer/ManualCreate.jsx                                             |    3 
 rsf-admin/src/page/orders/outStock/OutOrderList.jsx                                             |    6 
 rsf-admin/src/page/orders/asnOrder/AsnOrderPanel.jsx                                            |    8 
 rsf-admin/src/page/orders/outStock/OutOrderItemList.jsx                                         |    8 
 rsf-admin/src/page/work/components/locItemInfoModal.jsx                                         |    3 
 rsf-server/src/main/java/com/vincent/rsf/server/manager/service/impl/LocItemServiceImpl.java    |    6 
 rsf-admin/src/page/work/checkOutBound/CheckOutBoundList.jsx                                     |    2 
 rsf-admin/src/page/orders/asnOrder/AsnOrderList.jsx                                             |    4 
 rsf-admin/src/page/orders/outStock/OutStockPublic.jsx                                           |   18 
 rsf-admin/src/page/stockManage/locRevise/ReviseLogItemList.jsx                                  |    4 
 rsf-admin/src/page/task/TaskPanel.jsx                                                           |    2 
 rsf-server/src/main/resources/mapper/manager/LocItemMapper.xml                                  |   21 +
 rsf-server/src/main/java/com/vincent/rsf/server/manager/mapper/LocItemMapper.java               |    6 
 rsf-admin/src/page/components/QuantityInput.jsx                                                 |   23 +
 rsf-admin/src/page/task/TaskItemList.jsx                                                        |    4 
 rsf-admin/src/page/work/outBound/OutBoundList.jsx                                               |    6 
 rsf-admin/src/page/locItem/LocItemCreate.jsx                                                    |    7 
 rsf-admin/src/page/statistics/stockManage/WarehouseStockInfo.jsx                                |    5 
 rsf-admin/src/page/orders/asnOrder/AsnCreateByPoModal.jsx                                       |    4 
 rsf-server/src/main/java/com/vincent/rsf/server/api/service/impl/PdaOutStockServiceImpl.java    |   28 +
 rsf-admin/src/utils/common.js                                                                   |   32 ++
 rsf-admin/src/page/orders/asnOrder/AsnOrderModal.jsx                                            |    3 
 rsf-admin/src/page/orders/outStock/MatnrInfoModal.jsx                                           |   15 
 rsf-server/src/main/java/com/vincent/rsf/server/api/controller/pda/PdaCheckOrderController.java |    2 
 rsf-server/src/main/java/com/vincent/rsf/server/manager/enums/OrderWorkType.java                |    2 
 rsf-admin/src/page/orders/asnOrder/OrderPrintPreview.jsx                                        |    6 
 rsf-server/src/main/java/com/vincent/rsf/server/api/controller/erp/params/ReportParams.java     |    2 
 46 files changed, 518 insertions(+), 163 deletions(-)

diff --git a/rsf-admin/src/page/components/QuantityInput.jsx b/rsf-admin/src/page/components/QuantityInput.jsx
new file mode 100644
index 0000000..de7d7f6
--- /dev/null
+++ b/rsf-admin/src/page/components/QuantityInput.jsx
@@ -0,0 +1,23 @@
+import React from 'react';
+import { NumberInput } from 'react-admin';
+import { maxDecimalPlaces } from '@/utils/common';
+
+const MAX_DECIMALS = 6;
+const QUANTITY_VALIDATE = [maxDecimalPlaces(MAX_DECIMALS, '鏈�澶�6浣嶅皬鏁�')];
+
+/**
+ * 鏁伴噺杈撳叆妗嗭細鏀寔鏈�澶� 6 浣嶅皬鏁帮紝瓒呰繃鏃舵彁绀哄苟闃绘鎻愪氦
+ */
+const QuantityInput = (props) => {
+    const { validate = [], helperText, ...rest } = props;
+    const mergedValidate = Array.isArray(validate) ? [...QUANTITY_VALIDATE, ...validate] : [...QUANTITY_VALIDATE, validate];
+    return (
+        <NumberInput
+            validate={mergedValidate}
+            helperText={helperText ?? '鏈�澶�6浣嶅皬鏁�'}
+            {...rest}
+        />
+    );
+};
+
+export default QuantityInput;
diff --git a/rsf-admin/src/page/locItem/LocItemCreate.jsx b/rsf-admin/src/page/locItem/LocItemCreate.jsx
index 9dc1fde..8a78582 100644
--- a/rsf-admin/src/page/locItem/LocItemCreate.jsx
+++ b/rsf-admin/src/page/locItem/LocItemCreate.jsx
@@ -30,6 +30,7 @@
 import DialogCloseButton from "../components/DialogCloseButton";
 import StatusSelectInput from "../components/StatusSelectInput";
 import MemoInput from "../components/MemoInput";
+import QuantityInput from "../components/QuantityInput";
 
 const LocItemCreate = (props) => {
     const { open, setOpen } = props;
@@ -186,19 +187,19 @@
                                     />
                                 </Grid>
                                 <Grid item xs={6} display="flex" gap={1}>
-                                    <NumberInput
+                                    <QuantityInput
                                         label="table.field.locItem.anfme"
                                         source="anfme"
                                     />
                                 </Grid>
                                 <Grid item xs={6} display="flex" gap={1}>
-                                    <NumberInput
+                                    <QuantityInput
                                         label="table.field.locItem.qty"
                                         source="qty"
                                     />
                                 </Grid>
                                 <Grid item xs={6} display="flex" gap={1}>
-                                    <NumberInput
+                                    <QuantityInput
                                         label="table.field.locItem.workQty"
                                         source="workQty"
                                     />
diff --git a/rsf-admin/src/page/locItem/LocItemEdit.jsx b/rsf-admin/src/page/locItem/LocItemEdit.jsx
index 8073eed..5c85ef7 100644
--- a/rsf-admin/src/page/locItem/LocItemEdit.jsx
+++ b/rsf-admin/src/page/locItem/LocItemEdit.jsx
@@ -23,6 +23,7 @@
 import { useWatch, useFormContext } from "react-hook-form";
 import { Stack, Grid, Box, Typography } from '@mui/material';
 import * as Common from '@/utils/common';
+import QuantityInput from "../components/QuantityInput";
 import { EDIT_MODE, REFERENCE_INPUT_PAGESIZE } from '@/config/setting';
 import EditBaseAside from "../components/EditBaseAside";
 import CustomerTopToolBar from "../components/EditTopToolBar";
@@ -165,19 +166,19 @@
                             />
                         </Stack>
                         <Stack direction='row' gap={2}>
-                            <NumberInput
+                            <QuantityInput
                                 label="table.field.locItem.anfme"
                                 source="anfme"
                             />
                         </Stack>
                         <Stack direction='row' gap={2}>
-                            <NumberInput
+                            <QuantityInput
                                 label="table.field.locItem.qty"
                                 source="qty"
                             />
                         </Stack>
                         <Stack direction='row' gap={2}>
-                            <NumberInput
+                            <QuantityInput
                                 label="table.field.locItem.workQty"
                                 source="workQty"
                             />
diff --git a/rsf-admin/src/page/locItem/LocItemList.jsx b/rsf-admin/src/page/locItem/LocItemList.jsx
index 008c672..f293130 100644
--- a/rsf-admin/src/page/locItem/LocItemList.jsx
+++ b/rsf-admin/src/page/locItem/LocItemList.jsx
@@ -163,7 +163,7 @@
                 <TextField source="maktx" label="table.field.locItem.maktx" />,
                 <TextField source="matnrCode" label="table.field.locItem.matnrCode" />,
                 <TextField source="unit" label="table.field.locItem.unit" />,
-                <NumberField source="anfme" label="table.field.locItem.anfme" />,
+                <NumberField source="anfme" label="table.field.locItem.anfme" options={{ maximumFractionDigits: 6 }} />,
                 <TextField source="batch" label="table.field.locItem.batch" />,
                 <NumberField source="splrId" label="table.field.locItem.splrId" />,
                 <TextField source="spec" label="table.field.locItem.spec" />,
diff --git a/rsf-admin/src/page/orders/asnOrder/AsnCreateByPoModal.jsx b/rsf-admin/src/page/orders/asnOrder/AsnCreateByPoModal.jsx
index 5b99a52..cc1c6f1 100644
--- a/rsf-admin/src/page/orders/asnOrder/AsnCreateByPoModal.jsx
+++ b/rsf-admin/src/page/orders/asnOrder/AsnCreateByPoModal.jsx
@@ -175,8 +175,8 @@
                                     <TextField source="type$" label="table.field.purchase.type" />
                                     <TextField source="wkType$" label="table.field.purchase.wkType" />
                                     <TextField source="source" label="table.field.purchase.source" />
-                                    <NumberField source="anfme" label="table.field.purchase.anfme" />
-                                    <NumberField source="qty" label="table.field.purchase.qty" />
+                                    <NumberField source="anfme" label="table.field.purchase.anfme" options={{ maximumFractionDigits: 6 }} />
+                                    <NumberField source="qty" label="table.field.purchase.qty" options={{ maximumFractionDigits: 6 }} />
                                     <TextField source="channel" label="table.field.purchase.channel" />
                                     <TextField source="platCode" label="table.field.purchase.platCode" />
                                     <DateField source="preArr" label="table.field.purchase.preArr" showTime />
diff --git a/rsf-admin/src/page/orders/asnOrder/AsnOrderItemList.jsx b/rsf-admin/src/page/orders/asnOrder/AsnOrderItemList.jsx
index c659223..73cc1ac 100644
--- a/rsf-admin/src/page/orders/asnOrder/AsnOrderItemList.jsx
+++ b/rsf-admin/src/page/orders/asnOrder/AsnOrderItemList.jsx
@@ -190,10 +190,10 @@
         <TextField source="projectCode" label="table.field.asnOrderItem.projectCode" />,
         <TextField source="spec" label="table.field.asnOrderItem.spec" />,
         <TextField source="model" label="table.field.asnOrderItem.model" />,
-        <NumberField source="anfme" label="table.field.asnOrderItem.anfme" />,
-        <NumberField source="qty" label="table.field.asnOrderItem.qty" />,
+        <NumberField source="anfme" label="table.field.asnOrderItem.anfme" options={{ maximumFractionDigits: 6 }} />,
+        <NumberField source="qty" label="table.field.asnOrderItem.qty" options={{ maximumFractionDigits: 6 }} />,
         <TextField source="stockUnit" label="table.field.asnOrderItem.stockUnit" />,
-        <NumberField source="purQty" label="table.field.asnOrderItem.purQty" />,
+        <NumberField source="purQty" label="table.field.asnOrderItem.purQty" options={{ maximumFractionDigits: 6 }} />,
         <TextField source="purUnit" label="table.field.asnOrderItem.purUnit" />,
         <TextField source="splrCode" label="table.field.asnOrderItem.splrCode" />,
         <TextField source="splrName" label="table.field.asnOrderItem.splrName" />,
diff --git a/rsf-admin/src/page/orders/asnOrder/AsnOrderList.jsx b/rsf-admin/src/page/orders/asnOrder/AsnOrderList.jsx
index 11ed2a0..bbd50f4 100644
--- a/rsf-admin/src/page/orders/asnOrder/AsnOrderList.jsx
+++ b/rsf-admin/src/page/orders/asnOrder/AsnOrderList.jsx
@@ -166,8 +166,8 @@
           <NumberField source="poId" label="table.field.asnOrder.poId" />
           <TextField source="type$" label="table.field.asnOrder.type" />
           <TextField cellClassName="wkType" source="wkType$" label="table.field.asnOrder.wkType" />
-          <NumberField source="anfme" label="table.field.asnOrder.anfme" />
-          <NumberField source="qty" label="table.field.asnOrder.qty" />
+          <NumberField source="anfme" label="table.field.asnOrder.anfme" options={{ maximumFractionDigits: 6 }} />
+          <NumberField source="qty" label="table.field.asnOrder.qty" options={{ maximumFractionDigits: 6 }} />
           <DateField source="arrTime" label="table.field.asnOrder.arrTime" showTime />
           <TextField source="rleStatus$" label="table.field.asnOrder.rleStatus" sortable={false} />
           <TextField source="logisNo" label="table.field.asnOrder.logisNo" />
diff --git a/rsf-admin/src/page/orders/asnOrder/AsnOrderModal.jsx b/rsf-admin/src/page/orders/asnOrder/AsnOrderModal.jsx
index d26ea4c..c665217 100644
--- a/rsf-admin/src/page/orders/asnOrder/AsnOrderModal.jsx
+++ b/rsf-admin/src/page/orders/asnOrder/AsnOrderModal.jsx
@@ -59,6 +59,7 @@
 import SaveIcon from '@mui/icons-material/Save';
 import AsnWareModal from "./AsnWareModal";
 import request from '@/utils/request';
+import { formatQuantity } from '@/utils/common';
 import _, { set } from 'lodash';
 import "./asnOrder.css";
 
@@ -518,7 +519,7 @@
             minWidth: 100,
             flex: 1,
             editable: true,
-            valueFormatter: (val) => val < 0 ? 0 : val,
+            valueFormatter: (val) => formatQuantity(val != null && val >= 0 ? val : 0),
             headerClassName: "custom",
         },
         // {
diff --git a/rsf-admin/src/page/orders/asnOrder/AsnOrderPanel.jsx b/rsf-admin/src/page/orders/asnOrder/AsnOrderPanel.jsx
index 1353f3b..bd8a4c0 100644
--- a/rsf-admin/src/page/orders/asnOrder/AsnOrderPanel.jsx
+++ b/rsf-admin/src/page/orders/asnOrder/AsnOrderPanel.jsx
@@ -8,7 +8,7 @@
     useListContext,
 } from 'react-admin';
 import PanelTypography from "../../components/PanelTypography";
-import * as Common from '@/utils/common'
+import { formatQuantity } from '@/utils/common';
 import { styled } from "@mui/material/styles";
 import request from '@/utils/request';
 import debounce from 'lodash/debounce';
@@ -75,7 +75,8 @@
         },
         {
             field: 'anfme',
-            headerName: translate('table.field.asnOrderItem.purQty')
+            headerName: translate('table.field.asnOrderItem.purQty'),
+            valueFormatter: (v) => formatQuantity(v)
         },
         {
             field: 'stockUnit',
@@ -91,7 +92,8 @@
         },
         {
             field: 'qty',
-            headerName: translate('table.field.asnOrderItem.qty')
+            headerName: translate('table.field.asnOrderItem.qty'),
+            valueFormatter: (v) => formatQuantity(v)
         },
         {
             field: 'splrBatch',
diff --git a/rsf-admin/src/page/orders/asnOrder/OrderPrintPreview.jsx b/rsf-admin/src/page/orders/asnOrder/OrderPrintPreview.jsx
index 6f527d1..e09c0f4 100644
--- a/rsf-admin/src/page/orders/asnOrder/OrderPrintPreview.jsx
+++ b/rsf-admin/src/page/orders/asnOrder/OrderPrintPreview.jsx
@@ -208,9 +208,9 @@
                 <TextField source="matnrCode" label="table.field.asnOrderItem.matnrCode" />,
                 <TextField source="maktx" label="table.field.asnOrderItem.maktx" />,
                 <TextField source="splrBatch" label="table.field.asnOrderItem.splrBatch" />,
-                <NumberField source="anfme" label="table.field.asnOrderItem.anfme" />,
-                <NumberField source="qty" label="table.field.asnOrderItem.qty" />,
-                <NumberField source="purQty" label="table.field.asnOrderItem.purQty" />,
+                <NumberField source="anfme" label="table.field.asnOrderItem.anfme" options={{ maximumFractionDigits: 6 }} />,
+                <NumberField source="qty" label="table.field.asnOrderItem.qty" options={{ maximumFractionDigits: 6 }} />,
+                <NumberField source="purQty" label="table.field.asnOrderItem.purQty" options={{ maximumFractionDigits: 6 }} />,
                 // <TextField source="splrName" label="table.field.asnOrderItem.splrName" />,
                 <TextField source="isptResult$" label="table.field.asnOrderItem.isptResult" />,
                 // <TextField source="trackCode" label="table.field.asnOrderItem.barcode" />,
diff --git a/rsf-admin/src/page/orders/asnOrder/POItemModal.jsx b/rsf-admin/src/page/orders/asnOrder/POItemModal.jsx
index 65d8f88..a97eab4 100644
--- a/rsf-admin/src/page/orders/asnOrder/POItemModal.jsx
+++ b/rsf-admin/src/page/orders/asnOrder/POItemModal.jsx
@@ -50,6 +50,7 @@
 import { useForm, Controller, useWatch, FormProvider, useFormContext } from "react-hook-form";
 import SaveIcon from '@mui/icons-material/Save';
 import request from '@/utils/request';
+import { formatQuantity } from '@/utils/common';
 import { Add, Edit, Delete } from '@mui/icons-material';
 import _, { set } from 'lodash';
 import { DataGrid, useGridApiRef, GRID_DATE_COL_DEF, GRID_DATETIME_COL_DEF, getGridDateOperators, useGridApiContext } from '@mui/x-data-grid';
@@ -277,7 +278,7 @@
             minWidth: 100,
             flex: 1,
             editable: true,
-            valueFormatter: (val) => val < 0 ? 0 : val,
+            valueFormatter: (val) => formatQuantity(val != null && val >= 0 ? val : 0),
             headerClassName: "custom",
         },
         {
@@ -286,7 +287,7 @@
             type: 'number',
             minWidth: 100,
             flex: 1,
-            valueFormatter: (val) => val < 0 ? 0 : val,
+            valueFormatter: (val) => formatQuantity(val != null && val >= 0 ? val : 0),
         },
         {
             field: 'unit',
diff --git a/rsf-admin/src/page/orders/check/SelectMatnrModal.jsx b/rsf-admin/src/page/orders/check/SelectMatnrModal.jsx
index a25c4c0..e6bb6f6 100644
--- a/rsf-admin/src/page/orders/check/SelectMatnrModal.jsx
+++ b/rsf-admin/src/page/orders/check/SelectMatnrModal.jsx
@@ -48,6 +48,7 @@
 import MatnrInfoModal from "./MatnrInfoModal";
 import SaveIcon from '@mui/icons-material/Save';
 import request from '@/utils/request';
+import { formatQuantity } from '@/utils/common';
 import { Add, Edit, Delete } from '@mui/icons-material';
 import { DataGrid, useGridApiRef } from '@mui/x-data-grid';
 import DictionarySelect from "../../components/DictionarySelect";
@@ -416,7 +417,7 @@
             minWidth: 120,
             flex: 1,
             editable: true,
-            valueFormatter: (val) => val < 0 ? 0 : val,
+            valueFormatter: (val) => formatQuantity(val != null && val >= 0 ? val : 0),
             headerClassName: "custom",
         },
         {
diff --git a/rsf-admin/src/page/orders/outStock/MatnrInfoModal.jsx b/rsf-admin/src/page/orders/outStock/MatnrInfoModal.jsx
index e3d652a..b0834ab 100644
--- a/rsf-admin/src/page/orders/outStock/MatnrInfoModal.jsx
+++ b/rsf-admin/src/page/orders/outStock/MatnrInfoModal.jsx
@@ -20,6 +20,7 @@
 import { EDIT_MODE, DEFAULT_START_PAGE, DEFAULT_PAGE_SIZE, REFERENCE_INPUT_PAGESIZE } from '@/config/setting';
 import { useTranslate, useNotify, useRefresh } from 'react-admin';
 import request from '@/utils/request';
+import { formatQuantity } from '@/utils/common';
 import { DataGrid } from '@mui/x-data-grid';
 import SaveIcon from '@mui/icons-material/Save';
 import TreeSelectInput from "@/page/components/TreeSelectInput";
@@ -60,12 +61,14 @@
         })
     }
 
+    const getRowId = (row) => (row.locUseStatus$ != null ? `${row.id}_${row.locUseStatus$}` : String(row.id));
+
     const handleSubmit = () => {
         const hasarr = data.map(el => +el.matnrId);
         const selectedData = selectedRows
-            .filter((item) => !hasarr.includes(item))
-            .map((id) => tableData.find((row) => row.id === id))
-            .filter(Boolean);
+            .map((id) => tableData.find((row) => getRowId(row) === id))
+            .filter(Boolean)
+            .filter((row) => !hasarr.includes(row.id));
         const deduped = [...new Map(selectedData.map((s) => [s.id, s])).values()];
         const value = deduped.map((el, i) => {
             const dynamicFields = dyFields.reduce((acc, item) => {
@@ -200,6 +203,7 @@
                         setDyFields={setDyFields}
                         selectedRows={selectedRows}
                         setSelectedRows={setSelectedRows}
+                        getRowId={getRowId}
                     />
                 </Box>
             </DialogContent>
@@ -216,7 +220,7 @@
 
 export default MatnrInfoModal;
 
-const AsnWareModalTable = ({ tableData, setTableData, page, isLoading, pageSize, setPage, rowCount, selectedRows, setSelectedRows, dyFields, setDyFields }) => {
+const AsnWareModalTable = ({ tableData, setTableData, page, isLoading, pageSize, setPage, rowCount, selectedRows, setSelectedRows, dyFields, setDyFields, getRowId }) => {
     const translate = useTranslate();
     const notify = useNotify();
 
@@ -232,7 +236,7 @@
         { field: 'unit', headerName: translate('table.field.matnr.unit'), width: 100 },
         { field: 'purchaseUnit', headerName: translate('table.field.matnr.purUnit'), width: 100 },
         { field: 'stockUnit', headerName: translate('table.field.matnr.stockUnit'), width: 100 },
-        { field: 'stockQty', headerName: translate('table.field.matnr.stockQty') || '搴撳瓨鏁伴噺', width: 110, type: 'number', valueFormatter: (v) => (v != null ? Number(v) : 0) },
+        { field: 'stockQty', headerName: translate('table.field.matnr.stockQty') || '搴撳瓨鏁伴噺', width: 110, type: 'number', valueFormatter: (v) => formatQuantity(v) },
         { field: 'locUseStatus$', headerName: translate('table.field.loc.useStatus'), width: 120 },
         { field: 'locCodes$', headerName: translate('table.field.loc.locCode'), width: 180, flex: 1 },
         { field: 'stockLeval$', headerName: translate('table.field.matnr.stockLevel'), width: 100, sortable: false },
@@ -273,6 +277,7 @@
         <div style={{ height: 400, width: '100%' }}>
             <DataGrid
                 size="small"
+                getRowId={getRowId}
                 rows={tableData}
                 columns={columns}
                 checkboxSelection
diff --git a/rsf-admin/src/page/orders/outStock/OutOrderItemList.jsx b/rsf-admin/src/page/orders/outStock/OutOrderItemList.jsx
index c78604b..5fd6707 100644
--- a/rsf-admin/src/page/orders/outStock/OutOrderItemList.jsx
+++ b/rsf-admin/src/page/orders/outStock/OutOrderItemList.jsx
@@ -181,10 +181,10 @@
         <TextField source="matnrCode" label="table.field.outStockItem.matnrCode" />,
         <TextField source="maktx" label="table.field.outStockItem.maktx" />,
         <TextField source="platOrderCode" label="table.field.outStockItem.platOrderCode" />,
-        <NumberField source="anfme" label="table.field.outStockItem.anfme" />,
-        <NumberField source="purQty" label="table.field.outStockItem.purQty" />,
-        <NumberField source="workQty" label="table.field.outStockItem.workQty" />,
-        <NumberField source="qty" label="table.field.outStockItem.qty" />,
+        <NumberField source="anfme" label="table.field.outStockItem.anfme" options={{ maximumFractionDigits: 6 }} />,
+        <NumberField source="purQty" label="table.field.outStockItem.purQty" options={{ maximumFractionDigits: 6 }} />,
+        <NumberField source="workQty" label="table.field.outStockItem.workQty" options={{ maximumFractionDigits: 6 }} />,
+        <NumberField source="qty" label="table.field.outStockItem.qty" options={{ maximumFractionDigits: 6 }} />,
         <TextField source="stockUnit" label="table.field.outStockItem.stockUnit" />,
         <TextField source="splrBatch" label="table.field.outStockItem.splrBatch" />,
         <TextField source="purUnit" label="table.field.outStockItem.purUnit" />,
diff --git a/rsf-admin/src/page/orders/outStock/OutOrderList.jsx b/rsf-admin/src/page/orders/outStock/OutOrderList.jsx
index 944d128..873320e 100644
--- a/rsf-admin/src/page/orders/outStock/OutOrderList.jsx
+++ b/rsf-admin/src/page/orders/outStock/OutOrderList.jsx
@@ -216,9 +216,9 @@
           <TextField source="poCode" label="table.field.outStock.poCode" />
           <TextField source="type$" label="table.field.outStock.type" />
           <TextField cellClassName="wkType" source="wkType$" label="table.field.outStock.wkType" />
-          <NumberField source="anfme" label="table.field.outStock.anfme" />
-          <NumberField source="workQty" label="table.field.outStock.workQty" />
-          <NumberField source="qty" label="table.field.outStock.qty" />
+          <NumberField source="anfme" label="table.field.outStock.anfme" options={{ maximumFractionDigits: 6 }} />
+          <NumberField source="workQty" label="table.field.outStock.workQty" options={{ maximumFractionDigits: 6 }} />
+          <NumberField source="qty" label="table.field.outStock.qty" options={{ maximumFractionDigits: 6 }} />
           <TextField source="logisNo" label="table.field.outStock.logisNo" />
           <TextField source="rleStatus$" label="table.field.outStock.rleStatus" sortable={false} />
           <TextField source="updateBy$" label="common.field.updateBy" />
diff --git a/rsf-admin/src/page/orders/outStock/OutOrderModal.jsx b/rsf-admin/src/page/orders/outStock/OutOrderModal.jsx
index 67594a4..f7e5c60 100644
--- a/rsf-admin/src/page/orders/outStock/OutOrderModal.jsx
+++ b/rsf-admin/src/page/orders/outStock/OutOrderModal.jsx
@@ -270,8 +270,8 @@
                                     <TextField source="matnrCode" label="table.field.deliveryItem.matnrCode" />
                                     <TextField source="maktx" label="table.field.deliveryItem.matnrName" />
                                     <TextField source="unit" label="table.field.deliveryItem.unit" />
-                                    <NumberField source="anfme" label="table.field.deliveryItem.anfme" />
-                                    <NumberField source="workQty" label="table.field.outStockItem.workQty" />
+                                    <NumberField source="anfme" label="table.field.deliveryItem.anfme" options={{ maximumFractionDigits: 6 }} />
+                                    <NumberField source="workQty" label="table.field.outStockItem.workQty" options={{ maximumFractionDigits: 6 }} />
                                     <TextField source="splrName" label="table.field.deliveryItem.splrName" />
                                     <TextField source="splrBatch" label="table.field.deliveryItem.splrBatch" />
                                     <TextField source="updateBy$" label="common.field.updateBy" />
diff --git a/rsf-admin/src/page/orders/outStock/OutOrderPreview.jsx b/rsf-admin/src/page/orders/outStock/OutOrderPreview.jsx
index 6acbd99..ad5ced6 100644
--- a/rsf-admin/src/page/orders/outStock/OutOrderPreview.jsx
+++ b/rsf-admin/src/page/orders/outStock/OutOrderPreview.jsx
@@ -9,6 +9,7 @@
     useGetList,
 } from 'react-admin';
 import request from '@/utils/request';
+import { formatQuantity } from '@/utils/common';
 import { styled } from '@mui/material/styles';
 import { PAGE_DRAWER_WIDTH, OPERATE_MODE, DEFAULT_PAGE_SIZE } from '@/config/setting';
 import { DataGrid, useGridApiContext, GridActionsCellItem, useGridApiRef } from '@mui/x-data-grid';
@@ -105,6 +106,7 @@
         { field: 'maktx', headerName: '鐗╂枡鍚嶇О', width: 190 },
         {
             field: 'anfme', headerName: '鍑哄簱鏁伴噺', width: 110, type: 'number', editable: true,
+            valueFormatter: (v) => formatQuantity(v),
             valueGetter: (value, row) => {
                 return row.anfme - row.workQty - row.qty;
             },
@@ -119,6 +121,7 @@
         },
         {
             field: 'workQty', headerName: '鍓╀綑鏁伴噺', width: 110, type: 'number',
+            valueFormatter: (v) => formatQuantity(v),
             valueGetter: (value, row) => {
                 return row.anfme - row.workQty - row.qty;
             },
diff --git a/rsf-admin/src/page/orders/outStock/OutStockPublic.jsx b/rsf-admin/src/page/orders/outStock/OutStockPublic.jsx
index 2046043..9831e8c 100644
--- a/rsf-admin/src/page/orders/outStock/OutStockPublic.jsx
+++ b/rsf-admin/src/page/orders/outStock/OutStockPublic.jsx
@@ -43,6 +43,7 @@
 import { styled } from '@mui/material/styles';
 import { DataGrid, useGridApiContext, GridActionsCellItem, useGridApiRef } from '@mui/x-data-grid';
 import request from '@/utils/request';
+import { formatQuantity } from '@/utils/common';
 import ConfirmationNumberOutlinedIcon from '@mui/icons-material/ConfirmationNumberOutlined';
 import CloseSharpIcon from '@mui/icons-material/CloseSharp';
 import ConfirmButton from '../../components/ConfirmButton';
@@ -227,12 +228,14 @@
                 console.log('API杩斿洖鐨勬暟鎹�:', responseData);
                 // 澶勭悊杩斿洖鐨勬暟鎹紝纭繚鏁版嵁缁撴瀯姝g‘
                 const processedData = (responseData || []).map((item, index) => {
+                    // 鍑哄簱鍗曚笅鍙戜换鍔★細浼樺厛鐢ㄥ悗绔繑鍥炵殑 siteNo/sitesNo锛屾病鏈夊垯榛樿 1001
+                    const defaultSiteNo = item.siteNo || item.sitesNo || '1001';
                     // 濡傛灉鏁版嵁鏈� locItem 宓屽缁撴瀯锛岄渶瑕佸睍寮�
                     if (item.locItem) {
                         return {
                             ...item.locItem,
                             id: item.locItem.id || `temp_${index}`,
-                            siteNo: item.siteNo,
+                            siteNo: defaultSiteNo,
                             staNos: item.staNos || [],
                             sourceId: item.sourceId,
                             source: item.source
@@ -241,7 +244,8 @@
                     // 濡傛灉鏁版嵁宸茬粡鏄墎骞崇粨鏋勶紝鐩存帴杩斿洖
                     return {
                         ...item,
-                        id: item.id || `temp_${index}`
+                        id: item.id || `temp_${index}`,
+                        siteNo: defaultSiteNo
                     };
                 });
                 console.log('澶勭悊鍚庣殑鏁版嵁:', processedData);
@@ -334,9 +338,9 @@
                                     <TextField source="poCode" label="table.field.outStockItem.poCode" />
                                     <TextField source="matnrCode" label="table.field.outStockItem.matnrCode" />
                                     <TextField source="maktx" label="table.field.outStockItem.maktx" />
-                                    <NumberField source="anfme" label="table.field.outStockItem.anfme" />
-                                    <NumberField source="workQty" label="table.field.outStockItem.workQty" />
-                                    <NumberField source="qty" label="table.field.outStockItem.qty" />
+                                    <NumberField source="anfme" label="table.field.outStockItem.anfme" options={{ maximumFractionDigits: 6 }} />
+                                    <NumberField source="workQty" label="table.field.outStockItem.workQty" options={{ maximumFractionDigits: 6 }} />
+                                    <NumberField source="qty" label="table.field.outStockItem.qty" options={{ maximumFractionDigits: 6 }} />
                                     <TextField source="stockUnit" label="table.field.outStockItem.stockUnit" />
                                     <TextField source="splrName" label="table.field.outStockItem.splrName" />
                                 </StyledDatagrid>
@@ -393,7 +397,7 @@
         { field: 'matnrCode', headerName: '鐗╂枡缂栫爜', width: 120 },
         { field: 'batch', headerName: '鎵规', width: 90 },
         { field: 'unit', headerName: '鍗曚綅', width: 60 },
-        { field: 'outQty', headerName: '鍑哄簱鏁伴噺', width: 110, },
+        { field: 'outQty', headerName: '鍑哄簱鏁伴噺', width: 110, valueFormatter: (v) => formatQuantity(v) },
         {
             field: 'anfme', headerName: '搴撳瓨鏁伴噺', width: 110,
             renderCell: (params) => (
@@ -449,7 +453,7 @@
         return (
             hasStock ? (
                 <Box sx={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between' }}>
-                    <span>{value}</span>
+                    <span>{formatQuantity(value)}</span>
                 </Box>
             ) : (
                 <Box sx={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between' }}>
diff --git a/rsf-admin/src/page/orders/outStock/SelectMatnrModal.jsx b/rsf-admin/src/page/orders/outStock/SelectMatnrModal.jsx
index e3c59a2..cbf48e8 100644
--- a/rsf-admin/src/page/orders/outStock/SelectMatnrModal.jsx
+++ b/rsf-admin/src/page/orders/outStock/SelectMatnrModal.jsx
@@ -54,6 +54,7 @@
 import SaveIcon from '@mui/icons-material/Save';
 import MatnrInfoModal from "./MatnrInfoModal";
 import request from '@/utils/request';
+import { formatQuantity, hasMoreThan6Decimals } from '@/utils/common';
 import "./asnOrder.css";
 
 const SelectMatnrModal = (props) => {
@@ -123,6 +124,10 @@
 
     const handleSubmit = async () => {
         setFinally();
+        if (tabelData.some((item) => hasMoreThan6Decimals(item.anfme))) {
+            notify('鏈�澶�6浣嶅皬鏁�', { type: 'error' });
+            return;
+        }
         setDisabled(true);
         try {
             if (asnId === 0) {
@@ -435,7 +440,7 @@
             minWidth: 100,
             flex: 1,
             editable: true,
-            valueFormatter: (val) => val < 0 ? 0 : val,
+            valueFormatter: (val) => formatQuantity(val != null && val >= 0 ? val : 0),
             headerClassName: "custom",
         },
         {
diff --git a/rsf-admin/src/page/orders/transfer/ManualCreate.jsx b/rsf-admin/src/page/orders/transfer/ManualCreate.jsx
index 2990e16..60ef7a7 100644
--- a/rsf-admin/src/page/orders/transfer/ManualCreate.jsx
+++ b/rsf-admin/src/page/orders/transfer/ManualCreate.jsx
@@ -47,6 +47,7 @@
 import { minHeight, padding } from "@mui/system";
 import SaveIcon from '@mui/icons-material/Save';
 import request from '@/utils/request';
+import { formatQuantity } from '@/utils/common';
 import _, { set } from 'lodash';
 
 const ManualCreate = (props) => {
@@ -363,7 +364,7 @@
             minWidth: 100,
             flex: 1,
             editable: true,
-            valueFormatter: (val) => val < 0 ? 0 : val,
+            valueFormatter: (val) => formatQuantity(val != null && val >= 0 ? val : 0),
         },
         {
             field: 'splrCode',
diff --git a/rsf-admin/src/page/orders/transfer/TransferCreate.jsx b/rsf-admin/src/page/orders/transfer/TransferCreate.jsx
index a6a754e..088573a 100644
--- a/rsf-admin/src/page/orders/transfer/TransferCreate.jsx
+++ b/rsf-admin/src/page/orders/transfer/TransferCreate.jsx
@@ -36,6 +36,7 @@
 import DictSelect from "../../components/DictSelect";
 import SaveIcon from '@mui/icons-material/Save';
 import request from '@/utils/request';
+import { formatQuantity } from '@/utils/common';
 
 const TransferCreate = (props) => {
     const { open, setOpen, orderId } = props;
@@ -233,7 +234,7 @@
             minWidth: 100,
             flex: 1,
             editable: true,
-            valueFormatter: (val) => val < 0 ? 0 : val,
+            valueFormatter: (val) => formatQuantity(val != null && val >= 0 ? val : 0),
             headerClassName: "custom",
         },
         {
diff --git a/rsf-admin/src/page/statistics/stockManage/WarehouseStockInfo.jsx b/rsf-admin/src/page/statistics/stockManage/WarehouseStockInfo.jsx
index 6fc96b8..5cd738f 100644
--- a/rsf-admin/src/page/statistics/stockManage/WarehouseStockInfo.jsx
+++ b/rsf-admin/src/page/statistics/stockManage/WarehouseStockInfo.jsx
@@ -49,6 +49,7 @@
 import { useForm, Controller, useWatch, FormProvider, useFormContext } from "react-hook-form";
 import SaveIcon from '@mui/icons-material/Save';
 import request from '@/utils/request';
+import { formatQuantity } from '@/utils/common';
 import { Add, Edit, Delete } from '@mui/icons-material';
 import { DataGrid, useGridApiRef, GRID_DATE_COL_DEF, GRID_DATETIME_COL_DEF, getGridDateOperators, useGridApiContext } from '@mui/x-data-grid';
 import { LocalizationProvider, DatePicker, DateTimePicker } from '@mui/x-date-pickers';
@@ -293,7 +294,7 @@
             minWidth: 100,
             flex: 1,
             editable: false,
-            valueFormatter: (val) => val < 0 ? 0 : val,
+            valueFormatter: (val) => formatQuantity(val != null && val >= 0 ? val : 0),
         },
         {
             field: 'workQty',
@@ -301,7 +302,7 @@
             type: 'number',
             minWidth: 100,
             flex: 1,
-            valueFormatter: (val) => val < 0 ? 0 : val,
+            valueFormatter: (val) => formatQuantity(val != null && val >= 0 ? val : 0),
         },
         {
             field: 'unit',
diff --git a/rsf-admin/src/page/stockItem/StockItemCreate.jsx b/rsf-admin/src/page/stockItem/StockItemCreate.jsx
index 925f54a..90bb02d 100644
--- a/rsf-admin/src/page/stockItem/StockItemCreate.jsx
+++ b/rsf-admin/src/page/stockItem/StockItemCreate.jsx
@@ -28,6 +28,7 @@
     Box,
 } from '@mui/material';
 import DialogCloseButton from "../components/DialogCloseButton";
+import QuantityInput from "../components/QuantityInput";
 import StatusSelectInput from "../components/StatusSelectInput";
 import MemoInput from "../components/MemoInput";
 
@@ -125,10 +126,10 @@
                                     />
                                 </Grid>
                                 <Grid item xs={6} display="flex" gap={1}>
-                                    <NumberInput
+                                    <QuantityInput
                                         label="table.field.stockItem.anfme"
                                         source="anfme"
-                                        validate={required()}
+                                        validate={[required()]}
                                     />
                                 </Grid>
                                 <Grid item xs={6} display="flex" gap={1}>
@@ -139,10 +140,10 @@
                                     />
                                 </Grid>
                                 <Grid item xs={6} display="flex" gap={1}>
-                                    <NumberInput
+                                    <QuantityInput
                                         label="table.field.stockItem.workQty"
                                         source="workQty"
-                                        validate={required()}
+                                        validate={[required()]}
                                     />
                                 </Grid>
                                 <Grid item xs={6} display="flex" gap={1}>
@@ -160,7 +161,7 @@
                                     />
                                 </Grid>
                                 <Grid item xs={6} display="flex" gap={1}>
-                                    <NumberInput
+                                    <QuantityInput
                                         label="table.field.stockItem.qty"
                                         source="qty"
                                     />
diff --git a/rsf-admin/src/page/stockItem/StockItemEdit.jsx b/rsf-admin/src/page/stockItem/StockItemEdit.jsx
index c87afcc..8c952ed 100644
--- a/rsf-admin/src/page/stockItem/StockItemEdit.jsx
+++ b/rsf-admin/src/page/stockItem/StockItemEdit.jsx
@@ -28,6 +28,7 @@
 import CustomerTopToolBar from "../components/EditTopToolBar";
 import MemoInput from "../components/MemoInput";
 import StatusSelectInput from "../components/StatusSelectInput";
+import QuantityInput from "../components/QuantityInput";
 
 const FormToolbar = () => {
     const { getValues } = useFormContext();
@@ -104,10 +105,10 @@
                             />
                         </Stack>
                         <Stack direction='row' gap={2}>
-                            <NumberInput
+                            <QuantityInput
                                 label="table.field.stockItem.anfme"
                                 source="anfme"
-                                validate={required()}
+                                validate={[required()]}
                             />
                         </Stack>
                         <Stack direction='row' gap={2}>
@@ -118,10 +119,10 @@
                             />
                         </Stack>
                         <Stack direction='row' gap={2}>
-                            <NumberInput
+                            <QuantityInput
                                 label="table.field.stockItem.workQty"
                                 source="workQty"
-                                validate={required()}
+                                validate={[required()]}
                             />
                         </Stack>
                         <Stack direction='row' gap={2}>
@@ -139,7 +140,7 @@
                             />
                         </Stack>
                         <Stack direction='row' gap={2}>
-                            <NumberInput
+                            <QuantityInput
                                 label="table.field.stockItem.qty"
                                 source="qty"
                             />
diff --git a/rsf-admin/src/page/stockManage/locRevise/LocsReviseDetl.jsx b/rsf-admin/src/page/stockManage/locRevise/LocsReviseDetl.jsx
index 5dc09cb..63661ba 100644
--- a/rsf-admin/src/page/stockManage/locRevise/LocsReviseDetl.jsx
+++ b/rsf-admin/src/page/stockManage/locRevise/LocsReviseDetl.jsx
@@ -24,6 +24,7 @@
 import SelectMatnrInfo from "./SelectMatnrInfo";
 import SaveIcon from '@mui/icons-material/Save';
 import request from '@/utils/request';
+import { formatQuantity, hasMoreThan6Decimals } from '@/utils/common';
 import "./asnOrder.css";
 
 const StyledDatagrid = styled(DatagridConfigurable)(({ theme }) => ({
@@ -80,6 +81,10 @@
             }
         }));
 
+        if (value.some((el) => hasMoreThan6Decimals(el.anfme) || hasMoreThan6Decimals(el.reviseQty))) {
+            notify('鏈�澶�6浣嶅皬鏁�');
+            return;
+        }
         saveReviseLog(value);
     };
 
@@ -238,6 +243,7 @@
             minWidth: 100,
             flex: 1,
             editable: false,
+            valueFormatter: (v) => formatQuantity(v),
         },
         {
             field: 'reviseQty',
@@ -247,6 +253,7 @@
             flex: 1,
             editable: true,
             headerClassName: "custom",
+            valueFormatter: (v) => formatQuantity(v),
         },
         {
             field: 'batch',
diff --git a/rsf-admin/src/page/stockManage/locRevise/ReviseLogItemList.jsx b/rsf-admin/src/page/stockManage/locRevise/ReviseLogItemList.jsx
index f848cf8..670c8ac 100644
--- a/rsf-admin/src/page/stockManage/locRevise/ReviseLogItemList.jsx
+++ b/rsf-admin/src/page/stockManage/locRevise/ReviseLogItemList.jsx
@@ -95,8 +95,8 @@
                     <TextField source="matnrCode" label="table.field.locItem.matnrCode" />
                     <TextField source="maktx" label="table.field.locItem.maktx" />
                     <TextField source="unit" label="table.field.locItem.unit" />
-                    <NumberField source="anfme" label="table.field.locItem.anfme" />
-                    <NumberField source="reviseQty" label="table.field.locItem.reviseQty" />
+                    <NumberField source="anfme" label="table.field.locItem.anfme" options={{ maximumFractionDigits: 6 }} />
+                    <NumberField source="reviseQty" label="table.field.locItem.reviseQty" options={{ maximumFractionDigits: 6 }} />
                     <CheckDiffField source="diffQty" label="table.field.locItem.diffQty" />
                     <TextField source="batch" label="table.field.locItem.batch" />
                     <TextField source="spec" label="table.field.locItem.spec" />
diff --git a/rsf-admin/src/page/task/TaskItemList.jsx b/rsf-admin/src/page/task/TaskItemList.jsx
index fc18fcd..3518ae1 100644
--- a/rsf-admin/src/page/task/TaskItemList.jsx
+++ b/rsf-admin/src/page/task/TaskItemList.jsx
@@ -153,8 +153,8 @@
                 <TextField source="maktx" label="table.field.taskItem.maktx" />,
                 <TextField source="matnrCode" label="table.field.taskItem.matnrCode" />,
                 <TextField source="unit" label="table.field.taskItem.unit" />,
-                <NumberField source="anfme" label="table.field.taskItem.anfme" />,
-                <NumberField source="qty" label="table.field.taskItem.qty" />,
+                <NumberField source="anfme" label="table.field.taskItem.anfme" options={{ maximumFractionDigits: 6 }} />,
+                <NumberField source="qty" label="table.field.taskItem.qty" options={{ maximumFractionDigits: 6 }} />,
                 <TextField source="platOrderCode" label="table.field.asnOrderItem.platOrderCode" />,
                 <TextField source="platWorkCode" label="table.field.asnOrderItem.platWorkCode" />,
                 <TextField source="projectCode" label="table.field.asnOrderItem.projectCode" />,
diff --git a/rsf-admin/src/page/task/TaskPanel.jsx b/rsf-admin/src/page/task/TaskPanel.jsx
index c9c429d..0a001ad 100644
--- a/rsf-admin/src/page/task/TaskPanel.jsx
+++ b/rsf-admin/src/page/task/TaskPanel.jsx
@@ -70,7 +70,7 @@
                         <TextField source="maktx" label="table.field.taskItem.maktx" />
                         <TextField source="matnrCode" label="table.field.taskItem.matnrCode" />
                         <TextField source="unit" label="table.field.taskItem.unit" />
-                        <NumberField source="anfme" label="table.field.taskItem.anfme" />
+                        <NumberField source="anfme" label="table.field.taskItem.anfme" options={{ maximumFractionDigits: 6 }} />
                         <TextField source="batch" label="table.field.taskItem.batch" />
                         <TextField source="spec" label="table.field.taskItem.spec" />
                         <TextField source="model" label="table.field.taskItem.model" />
diff --git a/rsf-admin/src/page/work/checkOutBound/CheckOutBoundList.jsx b/rsf-admin/src/page/work/checkOutBound/CheckOutBoundList.jsx
index 89f8a5e..4fdab48 100644
--- a/rsf-admin/src/page/work/checkOutBound/CheckOutBoundList.jsx
+++ b/rsf-admin/src/page/work/checkOutBound/CheckOutBoundList.jsx
@@ -56,6 +56,7 @@
 import AddIcon from '@mui/icons-material/Add';
 import DeleteIcon from '@mui/icons-material/Delete';
 import request from '@/utils/request';
+import { formatQuantity } from '@/utils/common';
 import LocItemInfoModal from "../components/locItemInfoModal";
 import { Delete } from '@mui/icons-material';
 import _, { set } from 'lodash';
@@ -220,6 +221,7 @@
             type: 'number',
             width: 100,
             editable: false,
+            valueFormatter: (v) => formatQuantity(v),
         },
         // {
         //     field: 'workQty',
diff --git a/rsf-admin/src/page/work/components/locItemInfoModal.jsx b/rsf-admin/src/page/work/components/locItemInfoModal.jsx
index c986926..c589cd8 100644
--- a/rsf-admin/src/page/work/components/locItemInfoModal.jsx
+++ b/rsf-admin/src/page/work/components/locItemInfoModal.jsx
@@ -15,6 +15,7 @@
 import DialogCloseButton from "../../components/DialogCloseButton";
 import { useTranslate, useNotify, useRefresh } from 'react-admin';
 import request from '@/utils/request';
+import { formatQuantity } from '@/utils/common';
 import { DataGrid } from '@mui/x-data-grid';
 import SaveIcon from '@mui/icons-material/Save';
 import TreeSelectInput from "@/page/components/TreeSelectInput";
@@ -179,7 +180,7 @@
         { field: 'matnrCode', headerName: translate('table.field.locItem.matnrCode'), width: 200 },
         { field: 'maktx', headerName: translate('table.field.locItem.maktx'), width: 300 },
         { field: 'batch', headerName: translate('table.field.locItem.batch'), width: 100 },
-        { field: 'anfme', headerName: translate('table.field.locItem.anfme'), width: 100 },
+        { field: 'anfme', headerName: translate('table.field.locItem.anfme'), width: 100, valueFormatter: (v) => formatQuantity(v) },
         { field: 'unit', headerName: translate('table.field.locItem.unit'), width: 100 },
     ])
 
diff --git a/rsf-admin/src/page/work/outBound/OutBoundList.jsx b/rsf-admin/src/page/work/outBound/OutBoundList.jsx
index f36d6f0..dc70f67 100644
--- a/rsf-admin/src/page/work/outBound/OutBoundList.jsx
+++ b/rsf-admin/src/page/work/outBound/OutBoundList.jsx
@@ -57,6 +57,7 @@
 import AddIcon from '@mui/icons-material/Add';
 import DeleteIcon from '@mui/icons-material/Delete';
 import request from '@/utils/request';
+import { formatQuantity } from '@/utils/common';
 import LocItemInfoModal from "../components/locItemInfoModal";
 import { Delete } from '@mui/icons-material';
 import StaSelect from "../components/StaSelect";
@@ -219,8 +220,8 @@
             width: 100,
             type: 'number',
             editable: true,
-            headerClassName: "custom",            
-            
+            headerClassName: "custom",
+            valueFormatter: (v) => formatQuantity(v),
         },
         {
             field: 'anfme',
@@ -228,6 +229,7 @@
             type: 'number',
             width: 100,
             editable: false,
+            valueFormatter: (v) => formatQuantity(v),
         },
         // {
         //     field: 'workQty',
diff --git a/rsf-admin/src/page/work/stockTransfer/stockTransferList.jsx b/rsf-admin/src/page/work/stockTransfer/stockTransferList.jsx
index a036f5e..a106b5b 100644
--- a/rsf-admin/src/page/work/stockTransfer/stockTransferList.jsx
+++ b/rsf-admin/src/page/work/stockTransfer/stockTransferList.jsx
@@ -57,6 +57,7 @@
 import AddIcon from '@mui/icons-material/Add';
 import DeleteIcon from '@mui/icons-material/Delete';
 import request from '@/utils/request';
+import { formatQuantity } from '@/utils/common';
 import LocItemInfoModal from "../components/locItemInfoModal";
 import { Delete } from '@mui/icons-material';
 import _, { set } from 'lodash';
@@ -268,6 +269,7 @@
             type: 'number',
             width: 100,
             editable: false,
+            valueFormatter: (v) => formatQuantity(v),
         },
         // {
         //     field: 'workQty',
diff --git a/rsf-admin/src/utils/common.js b/rsf-admin/src/utils/common.js
index 309c6eb..3874cd3 100644
--- a/rsf-admin/src/utils/common.js
+++ b/rsf-admin/src/utils/common.js
@@ -1,4 +1,36 @@
 
+/** 搴撳瓨/鏁伴噺鏄剧ず锛氫繚鐣欐渶澶�6浣嶅皬鏁帮紝鍘绘帀鏈熬澶氫綑鐨�0锛堜笉寮哄埗琛ラ浂锛� */
+export const formatQuantity = (value) => {
+    if (value == null || value === '') return '0';
+    const n = Number(value);
+    if (Number.isNaN(n)) return '0';
+    if (n < 0) return '0';
+    return n % 1 === 0 ? String(n) : n.toFixed(6).replace(/\.?0+$/, '');
+};
+
+/** 鏍¢獙鏈�澶� N 浣嶅皬鏁帮紝鐢ㄤ簬鏁伴噺绫诲瓧娈碉紱瓒呰繃鏃惰繑鍥為敊璇俊鎭苟闃绘鎻愪氦 */
+export const maxDecimalPlaces = (maxDecimals, message) => {
+    const factor = Math.pow(10, maxDecimals);
+    const msg = message || `鏈�澶�${maxDecimals}浣嶅皬鏁癭;
+    return (value) => {
+        if (value == null || value === '') return undefined;
+        const n = Number(value);
+        if (Number.isNaN(n)) return undefined;
+        const rounded = Math.round(n * factor) / factor;
+        if (Math.abs(n - rounded) > 1e-10) return msg;
+        return undefined;
+    };
+};
+
+/** 鍒ゆ柇鏁板�兼槸鍚﹁秴杩� 6 浣嶅皬鏁帮紙鐢ㄤ簬鎻愪氦鍓嶆牎楠岋級 */
+export const hasMoreThan6Decimals = (value) => {
+    if (value == null || value === '') return false;
+    const n = Number(value);
+    if (Number.isNaN(n)) return false;
+    const rounded = Math.round(n * 1e6) / 1e6;
+    return Math.abs(n - rounded) > 1e-10;
+};
+
 export const extractNavMenus = (data) => {
     if (!data) {
         return;
diff --git a/rsf-open-api/src/main/java/com/vincent/rsf/openApi/entity/params/ReportParams.java b/rsf-open-api/src/main/java/com/vincent/rsf/openApi/entity/params/ReportParams.java
index ed961ab..cb7d581 100644
--- a/rsf-open-api/src/main/java/com/vincent/rsf/openApi/entity/params/ReportParams.java
+++ b/rsf-open-api/src/main/java/com/vincent/rsf/openApi/entity/params/ReportParams.java
@@ -10,7 +10,7 @@
 
 @Data
 @Accessors(chain = true)
-@ApiModel(value = "ReportParams", description = "甯屾棩ERP涓婃姤鍙傛暟")
+@ApiModel(value = "ReportParams", description = "ERP涓婃姤鍙傛暟")
 public class ReportParams implements Serializable {
 
     @ApiModelProperty("璁㈠崟绫诲瀷")
diff --git a/rsf-server/src/main/java/com/vincent/rsf/server/api/controller/erp/params/ReportParams.java b/rsf-server/src/main/java/com/vincent/rsf/server/api/controller/erp/params/ReportParams.java
index 6d1e661..01c5289 100644
--- a/rsf-server/src/main/java/com/vincent/rsf/server/api/controller/erp/params/ReportParams.java
+++ b/rsf-server/src/main/java/com/vincent/rsf/server/api/controller/erp/params/ReportParams.java
@@ -11,7 +11,7 @@
 
 @Data
 @Accessors(chain = true)
-@ApiModel(value = "ReportParams", description = "甯屾棩ERP涓婃姤鍙傛暟")
+@ApiModel(value = "ReportParams", description = "ERP涓婃姤鍙傛暟")
 public class ReportParams implements Serializable {
 
     @ApiModelProperty("璁㈠崟绫诲瀷")
diff --git a/rsf-server/src/main/java/com/vincent/rsf/server/api/controller/pda/PdaCheckOrderController.java b/rsf-server/src/main/java/com/vincent/rsf/server/api/controller/pda/PdaCheckOrderController.java
index dd91c71..912479a 100644
--- a/rsf-server/src/main/java/com/vincent/rsf/server/api/controller/pda/PdaCheckOrderController.java
+++ b/rsf-server/src/main/java/com/vincent/rsf/server/api/controller/pda/PdaCheckOrderController.java
@@ -46,7 +46,7 @@
         return pdaCheckOrderService.getCheckTaskItemList2(map.get("barcode"));
     }
 
-    @ApiOperation("甯屾棩鏃犲崟鎹复鏃剁洏鐐�")
+    @ApiOperation("鏃犲崟鎹复鏃剁洏鐐�")
     @PostMapping("/check/temp/items")
     public R  tempCheckItem(@RequestBody Map<String, String> map) {
         if (Objects.isNull(map)) {
diff --git a/rsf-server/src/main/java/com/vincent/rsf/server/api/service/impl/PdaCheckOrderServiceImpl.java b/rsf-server/src/main/java/com/vincent/rsf/server/api/service/impl/PdaCheckOrderServiceImpl.java
index a14ca64..9252455 100644
--- a/rsf-server/src/main/java/com/vincent/rsf/server/api/service/impl/PdaCheckOrderServiceImpl.java
+++ b/rsf-server/src/main/java/com/vincent/rsf/server/api/service/impl/PdaCheckOrderServiceImpl.java
@@ -263,7 +263,7 @@
     /**
      * @author Ryan
      * @date 2025/11/5
-     * @description: 甯屾棩鏃犲崟鎹复鏃剁洏鐐�
+     * @description: 鏃犲崟鎹复鏃剁洏鐐�
      * @version 1.0
      */
     @Override
diff --git a/rsf-server/src/main/java/com/vincent/rsf/server/api/service/impl/PdaOutStockServiceImpl.java b/rsf-server/src/main/java/com/vincent/rsf/server/api/service/impl/PdaOutStockServiceImpl.java
index efc1a52..69b689b 100644
--- a/rsf-server/src/main/java/com/vincent/rsf/server/api/service/impl/PdaOutStockServiceImpl.java
+++ b/rsf-server/src/main/java/com/vincent/rsf/server/api/service/impl/PdaOutStockServiceImpl.java
@@ -79,7 +79,9 @@
     @Override
     public R getOutStockTaskItem(String barcode) {
         LambdaQueryWrapper<Task> lambdaQueryWrapper = new LambdaQueryWrapper<>();
-        lambdaQueryWrapper.eq(Task::getBarcode, barcode);
+        lambdaQueryWrapper.eq(Task::getBarcode, barcode)
+                .orderByDesc(Task::getId)
+                .last("limit 1");
         Task task = taskService.getOne(lambdaQueryWrapper);
         if (null == task) {
             return R.error("鏈煡璇㈠埌鐩稿叧浠诲姟");
@@ -97,12 +99,16 @@
     @Synchronized
     public R saveOutTaskSts(String barcode) {
         LambdaQueryWrapper<Task> lambdaQueryWrapper = new LambdaQueryWrapper<>();
-        lambdaQueryWrapper.eq(Task::getBarcode, barcode);
+        lambdaQueryWrapper.eq(Task::getBarcode, barcode)
+                .orderByDesc(Task::getId)
+                .last("limit 1");
         Task task = taskService.getOne(lambdaQueryWrapper);
         if (null == task) {
             throw new CoolException("鏈壘鍒板鍣ㄥ彿瀵瑰簲浠诲姟");
         }
-        if (!task.getTaskStatus().equals(TaskStsType.WAVE_SEED.id)) {
+        // 鍏佽 199锛圵AVE_SEED 鎾涓�/寰呯‘璁わ級鎴� 196锛圓WAIT 绛夊緟纭锛夛紝涓庣洏鐐� PDA 閫昏緫涓�鑷�
+        if (!task.getTaskStatus().equals(TaskStsType.WAVE_SEED.id)
+                && !task.getTaskStatus().equals(TaskStsType.AWAIT.id)) {
             return R.error("浠诲姟鐘舵�佷笉鏄瓑寰呯‘璁�");
         }
         
@@ -153,7 +159,9 @@
         if (Cools.isEmpty(barcode)) {
             throw new CoolException("鍙傛暟鏈夎");
         }
-        Task task = taskService.getOne(new LambdaQueryWrapper<Task>().eq(Task::getBarcode, barcode));
+        Task task = taskService.getOne(new LambdaQueryWrapper<Task>().eq(Task::getBarcode, barcode)
+                .orderByDesc(Task::getId)
+                .last("limit 1"));
         if (null == task) {
             throw new CoolException("鏈壘鍒板鍣ㄥ彿瀵瑰簲浠诲姟");
         }
@@ -232,7 +240,9 @@
         if (Objects.isNull(param.get("orderId"))) {
             return R.error("璁㈠崟ID涓嶈兘涓虹┖锛侊紒");
         }
-        Task task = taskService.getOne(new LambdaQueryWrapper<Task>().eq(Task::getBarcode, param.get("barcode").toString()));
+        Task task = taskService.getOne(new LambdaQueryWrapper<Task>().eq(Task::getBarcode, param.get("barcode").toString())
+                .orderByDesc(Task::getId)
+                .last("limit 1"));
         if (Objects.isNull(task)) {
             throw new CoolException("鏁版嵁閿欒锛屼换鍔℃。宸蹭笉瀛樺湪锛侊紒");
         }
@@ -280,7 +290,9 @@
         if (Objects.isNull(params.getTaskItems()) || params.getTaskItems().isEmpty()) {
             return R.error("鎷h揣鏄庣粏涓嶈兘涓虹┖锛�");
         }
-        Task task = taskService.getOne(new LambdaQueryWrapper<Task>().eq(Task::getBarcode, params.getBarcode()));
+        Task task = taskService.getOne(new LambdaQueryWrapper<Task>().eq(Task::getBarcode, params.getBarcode())
+                .orderByDesc(Task::getId)
+                .last("limit 1"));
         if (null == task) {
             return R.error("鏈壘鍒版墭鐩樺搴旂殑浠诲姟");
         }
@@ -542,7 +554,9 @@
             return R.error("鏁版嵁閿欒锛侊紒");
         }
 
-        Task task = taskService.getOne(new LambdaQueryWrapper<Task>().eq(Task::getBarcode, containerWaveParam.getContainer()));
+        Task task = taskService.getOne(new LambdaQueryWrapper<Task>().eq(Task::getBarcode, containerWaveParam.getContainer())
+                .orderByDesc(Task::getId)
+                .last("limit 1"));
         if (null == task) {
             return R.error("鏈壘鍒版墭鐩樺搴旂殑浠诲姟");
         }
diff --git a/rsf-server/src/main/java/com/vincent/rsf/server/common/utils/QuantityUtils.java b/rsf-server/src/main/java/com/vincent/rsf/server/common/utils/QuantityUtils.java
new file mode 100644
index 0000000..9f774f6
--- /dev/null
+++ b/rsf-server/src/main/java/com/vincent/rsf/server/common/utils/QuantityUtils.java
@@ -0,0 +1,77 @@
+package com.vincent.rsf.server.common.utils;
+
+import java.math.BigDecimal;
+import java.math.RoundingMode;
+
+/**
+ * 鏁伴噺杩愮畻宸ュ叿锛氫娇鐢� BigDecimal 閬垮厤 Double 绮惧害闂銆�
+ * 瀹炰綋浠嶄负 Double 鏃讹紝杩愮畻鐢ㄦ湰宸ュ叿鍐嶈浆鍥� Double锛堜繚鐣� 6 浣嶅皬鏁帮級銆�
+ */
+public final class QuantityUtils {
+
+    private static final int SCALE = 6;
+    private static final RoundingMode ROUNDING = RoundingMode.HALF_UP;
+
+    private QuantityUtils() {
+    }
+
+    private static BigDecimal toBigDecimal(Double v) {
+        if (v == null) {
+            return BigDecimal.ZERO;
+        }
+        return BigDecimal.valueOf(v);
+    }
+
+    /**
+     * 鍔犳硶锛歛 + b锛岀粨鏋滀繚鐣� 6 浣嶅皬鏁拌浆 Double
+     */
+    public static Double add(Double a, Double b) {
+        return toBigDecimal(a).add(toBigDecimal(b)).setScale(SCALE, ROUNDING).doubleValue();
+    }
+
+    /**
+     * 鍑忔硶锛歛 - b锛岀粨鏋滀繚鐣� 6 浣嶅皬鏁拌浆 Double
+     */
+    public static Double subtract(Double a, Double b) {
+        return toBigDecimal(a).subtract(toBigDecimal(b)).setScale(SCALE, ROUNDING).doubleValue();
+    }
+
+    /**
+     * 姣旇緝锛歛 涓� b 澶у皬锛岄伩鍏嶇洿鎺ョ敤 Double 姣旇緝銆�
+     * 杩斿洖 a.compareTo(b)锛氳礋/0/姝�
+     */
+    public static int compare(Double a, Double b) {
+        return toBigDecimal(a).compareTo(toBigDecimal(b));
+    }
+
+    /**
+     * a &gt; 0
+     */
+    public static boolean isPositive(Double a) {
+        return compare(a, 0.0) > 0;
+    }
+
+    /**
+     * a &gt;= 0
+     */
+    public static boolean isNonNegative(Double a) {
+        return compare(a, 0.0) >= 0;
+    }
+
+    /**
+     * a &lt;= 0
+     */
+    public static boolean isNonPositive(Double a) {
+        return compare(a, 0.0) <= 0;
+    }
+
+    /**
+     * 缁熶竴鑸嶅叆鍒� 6 浣嶅皬鏁板悗杞� Double锛堢敤浜庡瓨搴�/灞曠ず锛岄伩鍏嶆诞鐐瑰熬宸級
+     */
+    public static Double roundToScale(Double v) {
+        if (v == null) {
+            return 0.0;
+        }
+        return toBigDecimal(v).setScale(SCALE, ROUNDING).doubleValue();
+    }
+}
diff --git a/rsf-server/src/main/java/com/vincent/rsf/server/manager/enums/OrderWorkType.java b/rsf-server/src/main/java/com/vincent/rsf/server/manager/enums/OrderWorkType.java
index 8ccb1bf..6ff6f2f 100644
--- a/rsf-server/src/main/java/com/vincent/rsf/server/manager/enums/OrderWorkType.java
+++ b/rsf-server/src/main/java/com/vincent/rsf/server/manager/enums/OrderWorkType.java
@@ -15,7 +15,7 @@
     ORDER_WORK_TYPE_SALE("4", "閿�鍞��鍥炲叆搴撳崟"),
     ORDER_WORK_TYPE_OTHER_IN("5", "鍏跺畠鍏ュ簱鍗�"),
     ORDER_WORK_TYPE_OTHER_TERANSFER_IN("6", "璋冩嫈鍏ュ簱鍗�"),
-    ORDER_WORK_TYPE_OTHER_TERANSFER("8", "璋冩嫈鍏ュ簱鍗�"),//甯屾棩椤圭洰涓存椂淇敼
+    ORDER_WORK_TYPE_OTHER_TERANSFER("8", "璋冩嫈鍏ュ簱鍗�"),//椤圭洰涓存椂淇敼
     ORDER_WORK_TYPE_STOCK_REVISE("7", "搴撳瓨璋冩暣鍗�"),
     ORDER_WORK_TYPE_SUPPLIER("11", "閿�鍞嚭搴撳崟"),
     ORDER_WORK_TYPE_RETURN_ORDER("12", "棰嗘枡鍑哄簱鍗�"),
diff --git a/rsf-server/src/main/java/com/vincent/rsf/server/manager/mapper/LocItemMapper.java b/rsf-server/src/main/java/com/vincent/rsf/server/manager/mapper/LocItemMapper.java
index 4c42b43..73fbada 100644
--- a/rsf-server/src/main/java/com/vincent/rsf/server/manager/mapper/LocItemMapper.java
+++ b/rsf-server/src/main/java/com/vincent/rsf/server/manager/mapper/LocItemMapper.java
@@ -23,5 +23,9 @@
      * @param locUseStatus 搴撲綅鐘舵�侊紝涓虹┖鍒欎笉杩囨护
      * @return 姣忚: matnrId, stockQty, locStatuses(閫楀彿鍒嗛殧鐨勫簱浣嶇姸鎬侊紝浠呭綋 locUseStatus 涓虹┖鏃惰繑鍥�)
      */
-    List<Map<String, Object>> listStockByMatnrIds(@Param("matnrIds") List<Long> matnrIds, @Param("locUseStatus") String locUseStatus);
+    /**
+     * 鎸夌墿鏂�+鐘舵��+搴撲綅鍒嗙粍锛氭瘡琛� (matnrId, useStatus, locCode, locQty)銆�
+     * 姹囨�� stockQty 涓庢嫾鎺� "搴撲綅(鏁伴噺)" 鍦� Java 涓畬鎴愶紝鍑忚交鏁版嵁搴撳帇鍔涖��
+     */
+    List<Map<String, Object>> listStockByMatnrIdsGroupByStatusAndLoc(@Param("matnrIds") List<Long> matnrIds, @Param("locUseStatus") String locUseStatus);
 }
diff --git a/rsf-server/src/main/java/com/vincent/rsf/server/manager/schedules/ScheduleJobs.java b/rsf-server/src/main/java/com/vincent/rsf/server/manager/schedules/ScheduleJobs.java
index 4ad7c8f..1de8060 100644
--- a/rsf-server/src/main/java/com/vincent/rsf/server/manager/schedules/ScheduleJobs.java
+++ b/rsf-server/src/main/java/com/vincent/rsf/server/manager/schedules/ScheduleJobs.java
@@ -193,7 +193,7 @@
 
         WarehouseAreasItem warehousItem = warehouseAreasItemService.getOne(new LambdaQueryWrapper<WarehouseAreasItem>().eq(StringUtils.isNotBlank(orderItem.getFieldsIndex()), WarehouseAreasItem::getFieldsIndex, orderItem.getFieldsIndex()));
         if (!Objects.isNull(warehousItem)) {
-            //甯屾棩鐩稿悓绁ㄥ彿锛屾敹璐у尯涓嶅彲鏂板鐩稿悓绁ㄥ彿鏁版嵁
+            //鐩稿悓绁ㄥ彿锛屾敹璐у尯涓嶅彲鏂板鐩稿悓绁ㄥ彿鏁版嵁
             FieldsItem fieldsItem = fieldsItemService.getOne(new LambdaQueryWrapper<FieldsItem>()
                     .eq(FieldsItem::getUuid, orderItem.getFieldsIndex()).last("LIMIT 1"));
             if (!Objects.isNull(fieldsItem)) {
diff --git a/rsf-server/src/main/java/com/vincent/rsf/server/manager/service/impl/LocItemServiceImpl.java b/rsf-server/src/main/java/com/vincent/rsf/server/manager/service/impl/LocItemServiceImpl.java
index 666c054..61531c0 100644
--- a/rsf-server/src/main/java/com/vincent/rsf/server/manager/service/impl/LocItemServiceImpl.java
+++ b/rsf-server/src/main/java/com/vincent/rsf/server/manager/service/impl/LocItemServiceImpl.java
@@ -66,13 +66,11 @@
     @Synchronized
     @Transactional(rollbackFor = Exception.class)
     public synchronized void generateTask(Short resouce, LocToTaskParams map, Long loginUserId) throws Exception {
-        if (Objects.isNull(map.getSiteNo())) {
-            throw new CoolException("绔欑偣涓嶈兘涓虹┖锛�");
-        }
+        // 鍑哄簱鍙f湭浼犳椂榛樿 1001
+        String siteNo = StringUtils.isNotBlank(map.getSiteNo()) ? map.getSiteNo() : "1001";
         if (Objects.isNull(map.getItems()) || map.getItems().isEmpty()) {
             throw new CoolException("鏄庣粏涓嶈兘涓虹┖锛�");
         }
-        String siteNo = map.getSiteNo();
         List<LocItem> items = map.getItems();
         Map<Long, List<LocItem>> listMap = items.stream().collect(Collectors.groupingBy(LocItem::getLocId));
         WkOrder order;
diff --git a/rsf-server/src/main/java/com/vincent/rsf/server/manager/service/impl/OutStockServiceImpl.java b/rsf-server/src/main/java/com/vincent/rsf/server/manager/service/impl/OutStockServiceImpl.java
index a42985b..e2cf9c4 100644
--- a/rsf-server/src/main/java/com/vincent/rsf/server/manager/service/impl/OutStockServiceImpl.java
+++ b/rsf-server/src/main/java/com/vincent/rsf/server/manager/service/impl/OutStockServiceImpl.java
@@ -92,44 +92,96 @@
 
     @Override
     public PageParam<Matnr, BaseParam> pageMatnrForOutStock(PageParam<Matnr, BaseParam> pageParam, Map<String, Object> params) {
+        // 鍦� getMatnrPage 涔嬪墠鍙栧嚭 locUseStatus锛歡etMatnrPage 浼氫粠 where.map 涓� remove 鎺夎閿紙涓� params 鍚屽紩鐢級锛屽鑷村悗缁彇涓嶅埌
+        String locUseStatus = params.get("locUseStatus") != null ? params.get("locUseStatus").toString().trim() : null;
+        if (locUseStatus != null && locUseStatus.isEmpty()) locUseStatus = null;
+
         PageParam<Matnr, BaseParam> page = matnrService.getMatnrPage(pageParam, params);
         List<Matnr> records = page.getRecords();
         if (records == null || records.isEmpty()) {
             return page;
         }
         List<Long> matnrIds = records.stream().map(Matnr::getId).collect(Collectors.toList());
-        String locUseStatus = params.get("locUseStatus") != null ? params.get("locUseStatus").toString() : null;
-        List<Map<String, Object>> stockList = locItemMapper.listStockByMatnrIds(matnrIds, locUseStatus);
-        Map<Long, Double> stockQtyMap = new HashMap<>();
-        Map<Long, String> locStatusDescMap = new HashMap<>();
-        Map<Long, String> locCodesMap = new HashMap<>();
-        for (Map<String, Object> row : stockList) {
-            Long matnrId = getLong(row, "matnrId", "matnrid");
-            if (matnrId == null) continue;
-            Object qty = getAny(row, "stockQty", "stockqty");
-            double v = qty instanceof Number ? ((Number) qty).doubleValue() : 0d;
-            stockQtyMap.put(matnrId, v);
-            String locCodes = getStr(row, "locCodes", "loccodes");
-            if (locCodes != null && !locCodes.isEmpty()) {
-                locCodesMap.put(matnrId, locCodes);
-            }
-            String locStatuses = getStr(row, "locStatuses", "locstatuses");
-            if (locStatuses != null && !locStatuses.isEmpty()) {
-                String desc = Arrays.stream(locStatuses.split(","))
-                        .map(String::trim)
-                        .map(LocStsType::getDescByType)
-                        .collect(Collectors.joining(","));
-                locStatusDescMap.put(matnrId, desc);
-            } else if (locUseStatus != null && !locUseStatus.isEmpty()) {
-                locStatusDescMap.put(matnrId, LocStsType.getDescByType(locUseStatus));
-            }
-        }
+        List<Map<String, Object>> stockByLocList = locItemMapper.listStockByMatnrIdsGroupByStatusAndLoc(matnrIds, locUseStatus);
+        Map<Long, List<Map<String, Object>>> rowsByMatnr = buildRowsByMatnrFromPerLoc(stockByLocList);
+        List<Matnr> expanded = new ArrayList<>();
         for (Matnr record : records) {
-            record.setStockQty(stockQtyMap.getOrDefault(record.getId(), 0d));
-            record.setLocUseStatus$(locStatusDescMap.get(record.getId()));
-            record.setLocCodes$(locCodesMap.get(record.getId()));
+            List<Map<String, Object>> statusRows = rowsByMatnr.get(record.getId());
+            if (statusRows == null || statusRows.isEmpty()) {
+                record.setStockQty(0d);
+                record.setLocUseStatus$(null);
+                record.setLocCodes$(null);
+                expanded.add(record);
+                continue;
+            }
+            for (Map<String, Object> row : statusRows) {
+                double v = row.get("stockQty") instanceof Number ? ((Number) row.get("stockQty")).doubleValue() : 0d;
+                String useStatus = getStr(row, "useStatus", "usestatus");
+                String statusDesc = useStatus != null ? LocStsType.getDescByType(useStatus) : null;
+                String locCodesWithQty = getStr(row, "locCodes$", "loccodes$");
+                Matnr copy = cloneMatnrForRow(record);
+                copy.setStockQty(v);
+                copy.setLocUseStatus$(statusDesc);
+                copy.setLocCodes$(locCodesWithQty);
+                expanded.add(copy);
+            }
         }
+        page.setRecords(expanded);
         return page;
+    }
+
+    /** 澶嶅埗鐗╂枡鐢ㄤ簬鎸夌姸鎬佸睍寮�琛岋紙浠呭鍒跺睍绀虹敤瀛楁锛宨d 淇濇寔鍘熸牱渚涘墠绔�夎鐢級 */
+    private static Matnr cloneMatnrForRow(Matnr source) {
+        Matnr copy = new Matnr();
+        BeanUtils.copyProperties(source, copy, "stockQty", "locUseStatus$", "locCodes$");
+        return copy;
+    }
+
+    /**
+     * 浠呯敤銆屾寜搴撲綅鏄庣粏銆嶆煡璇㈢粨鏋滃湪鍐呭瓨涓垎缁勬眹鎬伙細鎸� (matnrId, useStatus) 鑱氬悎锛�
+     * 寰楀埌 stockQty銆乴ocCodes$锛堝簱浣�(鏁伴噺),...锛夛紝鍑忚交鏁版嵁搴撳帇鍔涖��
+     */
+    private static Map<Long, List<Map<String, Object>>> buildRowsByMatnrFromPerLoc(List<Map<String, Object>> stockByLocList) {
+        Map<String, List<Map<String, Object>>> perLocByMatnrAndStatus = new HashMap<>();
+        for (Map<String, Object> locRow : stockByLocList) {
+            Long mid = getLong(locRow, "matnrId", "matnrid");
+            String us = getStr(locRow, "useStatus", "usestatus");
+            if (mid == null || us == null) continue;
+            String key = mid + ":" + us;
+            perLocByMatnrAndStatus.computeIfAbsent(key, k -> new ArrayList<>()).add(locRow);
+        }
+        Map<Long, List<Map<String, Object>>> rowsByMatnr = new HashMap<>();
+        for (Map.Entry<String, List<Map<String, Object>>> e : perLocByMatnrAndStatus.entrySet()) {
+            String[] parts = e.getKey().split(":", 2);
+            if (parts.length != 2) continue;
+            Long matnrId;
+            try { matnrId = Long.parseLong(parts[0]); } catch (NumberFormatException ex) { continue; }
+            String useStatus = parts[1];
+            List<Map<String, Object>> locs = e.getValue();
+            double stockQty = 0d;
+            StringBuilder sb = new StringBuilder();
+            for (Map<String, Object> locRow : locs) {
+                Object q = getAny(locRow, "locQty", "locqty");
+                double qty = q instanceof Number ? ((Number) q).doubleValue() : 0d;
+                stockQty += qty;
+                String code = getStr(locRow, "locCode", "loccode");
+                if (sb.length() > 0) sb.append(",");
+                sb.append(code != null ? code : "").append("(").append(formatQtyForLoc(qty)).append(")");
+            }
+            Map<String, Object> statusRow = new HashMap<>();
+            statusRow.put("matnrId", matnrId);
+            statusRow.put("useStatus", useStatus);
+            statusRow.put("stockQty", stockQty);
+            statusRow.put("locCodes$", sb.toString());
+            rowsByMatnr.computeIfAbsent(matnrId, k -> new ArrayList<>()).add(statusRow);
+        }
+        return rowsByMatnr;
+    }
+
+    private static String formatQtyForLoc(double qty) {
+        if (qty == (long) qty) return String.valueOf((long) qty);
+        String s = BigDecimal.valueOf(qty).setScale(6, RoundingMode.HALF_UP).stripTrailingZeros().toPlainString();
+        return s;
     }
 
     private static Long getLong(Map<String, Object> map, String... keys) {
@@ -748,11 +800,13 @@
                 locItems.add(locItem);
 
                 LocToTaskParams taskParams = new LocToTaskParams();
+                // 鍑哄簱鍗曚笅鍙戜换鍔℃椂锛屽嚭搴撳彛鏈紶鍒欓粯璁� 1001
+                String siteNo = StringUtils.isNotBlank(param.getSiteNo()) ? param.getSiteNo() : "1001";
                 taskParams.setType(Constants.TASK_TYPE_ORDER_OUT_STOCK)
                         .setOrgLoc(loc.getCode())
                         .setItems(locItems)
                         .setSourceId(outId)
-                        .setSiteNo(param.getSiteNo());
+                        .setSiteNo(siteNo);
                 try {
                     //鐢熸垚鍑哄簱浠诲姟
                     locItemService.generateTask(TaskResouceType.TASK_RESOUCE_ORDER_TYPE.val, taskParams, loginUserId);
@@ -892,6 +946,14 @@
                             .eq(DeviceSite::getChannel, loc.getChannel())
                             .eq(DeviceSite::getType, issued.doubleValue() >= locItem.getAnfme() && itemList.size() == 1 ? TaskType.TASK_TYPE_OUT.type : TaskType.TASK_TYPE_PICK_AGAIN_OUT.type)
                     );
+                    // 鍑哄簱鍙e垪琛ㄦ帓搴忥細1001 鎺掔涓�锛屼綔涓洪粯璁�
+                    deviceSites.sort((a, b) -> {
+                        boolean a1001 = "1001".equals(a.getSite());
+                        boolean b1001 = "1001".equals(b.getSite());
+                        if (a1001 && !b1001) return -1;
+                        if (!a1001 && b1001) return 1;
+                        return 0;
+                    });
 
                     if (!deviceSites.isEmpty()) {
                         List<OrderOutItemDto.staListDto> maps = new ArrayList<>();
@@ -904,7 +966,7 @@
                         orderOutItemDto.setStaNos(maps);
                         //榛樿鑾峰彇绗竴绔欑偣
                         DeviceSite deviceSite = deviceSites.stream().findFirst().get();
-                        orderOutItemDto.setSiteNo(deviceSite.getSite());
+                        orderOutItemDto.setSitesNo(deviceSite.getSite());
                     }
 
                     list.add(orderOutItemDto);
diff --git a/rsf-server/src/main/java/com/vincent/rsf/server/manager/service/impl/TaskServiceImpl.java b/rsf-server/src/main/java/com/vincent/rsf/server/manager/service/impl/TaskServiceImpl.java
index 09ff644..476bf94 100644
--- a/rsf-server/src/main/java/com/vincent/rsf/server/manager/service/impl/TaskServiceImpl.java
+++ b/rsf-server/src/main/java/com/vincent/rsf/server/manager/service/impl/TaskServiceImpl.java
@@ -18,6 +18,7 @@
 import com.vincent.rsf.server.api.entity.params.WcsTaskParams;
 import com.vincent.rsf.server.api.service.WcsService;
 import com.vincent.rsf.server.common.constant.Constants;
+import com.vincent.rsf.server.common.utils.QuantityUtils;
 import com.vincent.rsf.server.manager.controller.params.LocToTaskParams;
 import com.vincent.rsf.server.manager.controller.params.PakinItem;
 import com.vincent.rsf.server.manager.enums.*;
@@ -860,33 +861,37 @@
             throw new CoolException("浠诲姟鏄庣粏涓嶅瓨鍦紒锛�");
         }
 
-        List<LocItem> items = new ArrayList<>();
-        for (TaskItem taskItem : taskItems) {
-            LocItem locItem = new LocItem();
-            LocItemWorking locWorking = locItemWorkingService.getOne(new LambdaQueryWrapper<LocItemWorking>()
-                    .eq(LocItemWorking::getTaskId, taskItem.getTaskId())
-                    .eq(StringUtils.isNotBlank(taskItem.getFieldsIndex()), LocItemWorking::getFieldsIndex, taskItem.getFieldsIndex())
-                    .eq(StringUtils.isNotEmpty(taskItem.getBatch()), LocItemWorking::getBatch, taskItem.getBatch())
-                    .eq(LocItemWorking::getMatnrId, taskItem.getMatnrId()));
-            if (Objects.isNull(locWorking)) {
-               continue;
+        if (TaskType.TASK_TYPE_PICK_IN.type.equals(task.getTaskType())) {
+            // 鎷f枡鍐嶅叆搴擄細鍑哄簱鏃跺凡鍦� pickOrCheckTask 涓墸鍑忓師搴撲綅锛�1100 -> 1089.899锛夛紝
+            // 鍏ュ簱瀹屾垚鏃朵笉鍐嶅洖鍐�/绱姞搴撲綅鏄庣粏锛屼繚鎸� 1 鏉� 1089.899锛岄伩鍏嶅嚭鐜颁袱鏉� 1100
+            // 浠呮洿鏂板簱浣嶇姸鎬併�佹竻鐞� LocItemWorking銆佷换鍔$姸鎬佸強娴佹按
+        } else {
+            // 鐩樼偣鍏ュ簱绛夛細娌跨敤鍘熼�昏緫锛屼粠 LocItemWorking 鍥炲啓骞� saveBatch
+            List<LocItem> items = new ArrayList<>();
+            for (TaskItem taskItem : taskItems) {
+                LocItem locItem = new LocItem();
+                LocItemWorking locWorking = locItemWorkingService.getOne(new LambdaQueryWrapper<LocItemWorking>()
+                        .eq(LocItemWorking::getTaskId, taskItem.getTaskId())
+                        .eq(StringUtils.isNotBlank(taskItem.getFieldsIndex()), LocItemWorking::getFieldsIndex, taskItem.getFieldsIndex())
+                        .eq(StringUtils.isNotEmpty(taskItem.getBatch()), LocItemWorking::getBatch, taskItem.getBatch())
+                        .eq(LocItemWorking::getMatnrId, taskItem.getMatnrId()));
+                if (Objects.isNull(locWorking)) {
+                   continue;
+                }
+                if (task.getTaskType().equals(TaskType.TASK_TYPE_CHECK_IN.type)) {
+                    locWorking.setAnfme(taskItem.getAnfme());
+                }
+                BeanUtils.copyProperties(locWorking, locItem);
+                locItem.setWorkQty(0.0).setQty(0.0).setLocCode(loc.getCode()).setLocId(loc.getId()).setId(null).setUpdateBy(loginUserId).setUpdateTime(new Date());
+                //鏁伴噺涓洪浂鐨勪笉鍏ュ簱
+                if (locItem.getAnfme().compareTo(0.0) > 0) {
+                    items.add(locItem);
+                }
             }
-            if (task.getTaskType().equals(TaskType.TASK_TYPE_CHECK_IN.type)) {
-                locWorking.setAnfme(taskItem.getAnfme());
-            } else if (task.getTaskType().equals(TaskType.TASK_TYPE_PICK_IN.type) && taskItem.getQty() != null && taskItem.getQty().compareTo(0.0) > 0) {
-                // 鎷f枡鍐嶅叆搴擄細鍏ュ簱鏁伴噺涓烘湰娆℃嫞鏂欐暟閲�(taskItem.qty)锛屼繚璇佷笌鍑哄簱鎵e噺涓�鑷�
-                locWorking.setAnfme(taskItem.getQty());
-            }
-            BeanUtils.copyProperties(locWorking, locItem);
-            locItem.setWorkQty(0.0).setQty(0.0).setLocCode(loc.getCode()).setLocId(loc.getId()).setId(null).setUpdateBy(loginUserId).setUpdateTime(new Date());
-            //鏁伴噺涓洪浂鐨勪笉鍏ュ簱
-            if (locItem.getAnfme().compareTo(0.0) > 0) {
-                items.add(locItem);
-            }
-        }
 
-        if (!locItemService.saveBatch(items)) {
+            if (!items.isEmpty() && !locItemService.saveBatch(items)) {
 //            throw new CoolException("浣滀笟搴撳瓨鍥炲啓澶辫触锛侊紒");
+            }
         }
 
         TaskItem taskItem = taskItems.stream().findFirst().get();
@@ -1290,7 +1295,7 @@
 //        if (Objects.isNull(locInfo)) {
 //            throw new CoolException("鑾峰彇搴撲綅澶辫触锛侊紒");
 //        }
-        //甯屾棩涓婃姤鐗╂湁鎯呭喌锛屼笉闇�瑕佽幏鍙栨柊搴撲綅
+        //涓婃姤鐗╂湁鎯呭喌锛屼笉闇�瑕佽幏鍙栨柊搴撲綅
         task.setTargLoc(task.getOrgLoc())
                 .setOrgSite(task.getTargSite());
 
@@ -1299,16 +1304,70 @@
         }
         //鑾峰彇鍥犲綋鍓嶄换鍔″嚭搴撶殑鎵�鏈夌墿鏂欎俊鎭�
         List<LocItemWorking> tempLocs = locItemWorkingService.list(new LambdaQueryWrapper<LocItemWorking>().eq(LocItemWorking::getTaskId, task.getId()));
-        if (tempLocs.isEmpty()) {
-            throw new CoolException("鏁版嵁閿欒锛屼綔涓氫腑搴撳瓨鏁版嵁涓㈠け锛侊紒");
-        }
         List<TaskItem> taskItems = taskItemService.list(new LambdaQueryWrapper<TaskItem>().eq(TaskItem::getTaskId, task.getId()));
         if (taskItems.isEmpty()) {
             throw new CoolException("鏁版嵁閿欒锛氫换鍔℃槑缁嗕负绌猴紒锛�");
         }
+        // 涓庢煡璇竴鑷达細鑻ユ棤浣滀笟涓簱瀛樹絾瀛樺湪浠诲姟鏄庣粏锛岀敤浠诲姟鏄庣粏鍦ㄥ唴瀛樹腑鍏滃簳锛岄伩鍏嶁�滆兘鏌ュ埌鍗存棤娉曠‘璁も��
+        if (tempLocs.isEmpty()) {
+            tempLocs = taskItems.stream().map(ti -> {
+                LocItemWorking w = new LocItemWorking();
+                w.setTaskId(task.getId());
+                w.setFieldsIndex(ti.getFieldsIndex());
+                w.setAnfme(ti.getAnfme());
+                w.setMatnrId(ti.getMatnrId());
+                w.setMaktx(ti.getMaktx());
+                w.setMatnrCode(ti.getMatnrCode());
+                w.setSpec(ti.getSpec());
+                w.setBatch(ti.getBatch());
+                w.setUnit(ti.getUnit());
+                w.setModel(ti.getModel());
+                return w;
+            }).collect(Collectors.toList());
+        }
 
-        // 鎷f枡鍏ュ簱锛氬湪鐢熸垚鎷f枡鍏ュ簱鍗曟椂鎵e噺鍘熷簱浣嶆暟閲忥紝涓嶄緷璧栧嚭搴撳畬鎴愭椂搴撲綅鐘舵�佷负R
+        // 鎷f枡鍏ュ簱锛氬厛绠楀墿浣欐暟閲忓苟鏇存柊 taskItem.anfme锛屽凡鎷f暟閲� taskItem.qty = 鍘熷簱浣� - 鍓╀綑锛堜繚璇� 鏁伴噺=100銆佸凡鎷f暟閲�=1銆佸簱瀛樻槑缁�=100锛�
         if (TaskType.TASK_TYPE_PICK_IN.type.equals(type)) {
+            log.debug("[鎷f枡鍏ュ簱] 寮�濮嬪鐞� taskId={}, taskCode={}, orgLoc={}, tempLocs.size={}, taskItems.size={}",
+                    task.getId(), task.getTaskCode(), task.getOrgLoc(), tempLocs.size(), taskItems.size());
+            tempLocs.forEach(working -> {
+                taskItems.forEach(taskItem -> {
+                    if (Objects.equals(taskItem.getFieldsIndex(), working.getFieldsIndex())) {
+                        // 宸叉嫞鏁伴噺锛氫紭鍏堢敤 taskItem.qty锛涗负 0 鏃朵粠鍑哄簱鍗曟槑缁嗗彇 鎵ц鏁�(workQty) 鎴� 璁㈠崟鏁伴噺(anfme)锛岄伩鍏嶆墜鍔ㄥ畬缁撴湭濉� qty 瀵艰嚧涓嶆墸鍑�
+                        Double pickedQty = taskItem.getQty() != null && QuantityUtils.isPositive(taskItem.getQty())
+                                ? taskItem.getQty()
+                                : 0.0;
+                        log.debug("[鎷f枡鍏ュ簱] taskItemId={}, fieldsIndex={}, working.anfme={}, taskItem.qty={}, taskItem.orderItemId={}, pickedQty(鍒�)={}",
+                                taskItem.getId(), taskItem.getFieldsIndex(), working.getAnfme(), taskItem.getQty(), taskItem.getOrderItemId(), pickedQty);
+                        if (pickedQty <= 0 && taskItem.getOrderItemId() != null) {
+                            WkOrderItem orderItem = asnOrderItemService.getById(taskItem.getOrderItemId());
+                            log.debug("[鎷f枡鍏ュ簱] 鏌ュ嚭搴撳崟鏄庣粏 orderItemId={}, orderItem={}, workQty={}, anfme={}",
+                                    taskItem.getOrderItemId(), orderItem != null ? "瀛樺湪" : "null",
+                                    orderItem != null ? orderItem.getWorkQty() : null, orderItem != null ? orderItem.getAnfme() : null);
+                            if (orderItem != null) {
+                                if (orderItem.getWorkQty() != null && QuantityUtils.isPositive(orderItem.getWorkQty())) {
+                                    pickedQty = orderItem.getWorkQty();
+                                } else if (orderItem.getAnfme() != null && QuantityUtils.isPositive(orderItem.getAnfme())) {
+                                    pickedQty = orderItem.getAnfme();
+                                }
+                            }
+                        }
+                        Double minQty = QuantityUtils.subtract(working.getAnfme(), pickedQty);
+                        log.debug("[鎷f枡鍏ュ簱] 璁$畻鍚� pickedQty={}, minQty(鍓╀綑)={}, 灏嗘洿鏂� taskItem.anfme={}, taskItem.qty={}",
+                                pickedQty, minQty, minQty, pickedQty);
+                        if (QuantityUtils.isNonNegative(minQty)) {
+                            taskItem.setAnfme(minQty);
+                            taskItem.setQty(pickedQty);
+                            if (!taskItemService.updateById(taskItem)) {
+                                throw new CoolException("浠诲姟鏄庣粏淇敼澶辫触锛侊紒");
+                            }
+                        } else {
+                            log.warn("[鎷f枡鍏ュ簱] minQty<0 鏈洿鏂� taskItem, taskItemId={}", taskItem.getId());
+                        }
+                    }
+                });
+            });
+            log.debug("[鎷f枡鍏ュ簱] 鍗冲皢鎵e噺搴撲綅 locId={}, locCode={}", loc.getId(), loc.getCode());
             subtractLocItemByTaskItems(loc, taskItems, SystemAuthUtils.getLoginUserId());
         }
 
@@ -1317,19 +1376,19 @@
                 if (Objects.equals(taskItem.getFieldsIndex(), working.getFieldsIndex())) {
                     Double minQty = taskItem.getAnfme();
                     if (!task.getTaskType().equals(TaskType.TASK_TYPE_CHECK_IN.type)) {
-                        // 璁$畻鍓╀綑鏁伴噺锛氫粠LocItemWorking涓噺鍘籘askItem鐨勬嫞鏂欐暟閲�
-                        minQty = Math.round((working.getAnfme() - taskItem.getQty()) * 1000000) / 1000000.0;
+                        // 璁$畻鍓╀綑鏁伴噺
+                        minQty = QuantityUtils.subtract(working.getAnfme(), taskItem.getQty());
                     }
-                    if (minQty.compareTo(0.0) >= 0) {
+                    if (QuantityUtils.isNonNegative(minQty)) {
                         // 鏇存柊TaskItem鐨勫墿浣欐暟閲�
                         taskItem.setAnfme(minQty);
                         if (!taskItemService.updateById(taskItem)) {
                             throw new CoolException("浠诲姟鏄庣粏淇敼澶辫触锛侊紒");
                         }
-                        // 鏇存柊LocItemWorking鐨勫墿浣欐暟閲忥紙闈炵洏鐐瑰叆搴撴椂闇�瑕佹洿鏂帮級
+                        // 鏇存柊LocItemWorking鐨勫墿浣欐暟閲忥紙闈炵洏鐐瑰叆搴撴椂闇�瑕佹洿鏂帮級锛涗粎鎸佷箙鍖栬褰曟墠鍐欏簱
                         if (!task.getTaskType().equals(TaskType.TASK_TYPE_CHECK_IN.type)) {
                             working.setAnfme(minQty);
-                            if (!locItemWorkingService.updateById(working)) {
+                            if (working.getId() != null && !locItemWorkingService.updateById(working)) {
                                 throw new CoolException("浣滀笟搴撳瓨鏁伴噺鏇存柊澶辫触锛侊紒");
                             }
                         }
@@ -1384,9 +1443,9 @@
                     .setQty(0.0)
                     .setLocId(loc1.getId())
                     .setLocCode(loc1.getCode());
-            // 鎷f枡鍐嶅叆搴擄細鐩爣搴撲綅鏁伴噺搴斾负鏈鎷f枡鏁伴噺(taskItem.qty)锛屼笉鏄師搴撲綅鍓╀綑鏁伴噺(taskItem.anfme)
-            if (TaskType.TASK_TYPE_PICK_IN.type.equals(task.getTaskType()) && taskItem.getQty() != null && taskItem.getQty().compareTo(0.0) > 0) {
-                itemWorking.setAnfme(taskItem.getQty());
+            // 鎷f枡鍐嶅叆搴擄細鐩爣搴撲綅鏁伴噺搴斾负鍥炲簱鐨勫墿浣欐暟閲�(taskItem.anfme)锛屽嵆鍘熷簱浣嶅噺鎺夋湰娆℃嫞鍑哄悗鐨勬暟閲忥紙濡� 1000 鍑哄簱 10 鈫� 990锛�
+            if (TaskType.TASK_TYPE_PICK_IN.type.equals(task.getTaskType()) && taskItem.getAnfme() != null && taskItem.getAnfme().compareTo(0.0) > 0) {
+                itemWorking.setAnfme(taskItem.getAnfme());
             }
             workings.add(itemWorking);
         });
@@ -2066,18 +2125,37 @@
     @Transactional(rollbackFor = Exception.class)
     public void subtractLocItemByTaskItems(Loc loc, List<TaskItem> taskItems, Long loginUserId) {
         for (TaskItem taskItem : taskItems) {
-            // 鏌ヨ瀵瑰簲鐨勫簱浣嶆槑缁�
-            LocItem locItem = locItemService.getOne(new LambdaQueryWrapper<LocItem>()
+            LambdaQueryWrapper<LocItem> locItemWrapper = new LambdaQueryWrapper<LocItem>()
                     .eq(LocItem::getLocId, loc.getId())
-                    .eq(LocItem::getMatnrId, taskItem.getMatnrId())
-                    .eq(StringUtils.isNotBlank(taskItem.getBatch()), LocItem::getBatch, taskItem.getBatch())
-                    .eq(StringUtils.isNotBlank(taskItem.getFieldsIndex()), LocItem::getFieldsIndex, taskItem.getFieldsIndex()));
+                    .eq(LocItem::getMatnrId, taskItem.getMatnrId());
+            if (StringUtils.isNotBlank(taskItem.getBatch())) {
+                locItemWrapper.eq(LocItem::getBatch, taskItem.getBatch());
+            } else {
+                locItemWrapper.and(w -> w.isNull(LocItem::getBatch).or().eq(LocItem::getBatch, ""));
+            }
+            if (StringUtils.isNotBlank(taskItem.getFieldsIndex())) {
+                locItemWrapper.eq(LocItem::getFieldsIndex, taskItem.getFieldsIndex());
+            } else {
+                locItemWrapper.and(w -> w.isNull(LocItem::getFieldsIndex).or().eq(LocItem::getFieldsIndex, ""));
+            }
+            LocItem locItem = locItemService.getOne(locItemWrapper);
+
+            log.info("[鎷f枡鍏ュ簱-鎵e噺搴撲綅] taskItemId={}, locId={}, matnrId={}, batch={}, fieldsIndex={}, locItem={}, locItem.anfme={}, taskItem.qty={}, taskItem.anfme={}",
+                    taskItem.getId(), loc.getId(), taskItem.getMatnrId(), taskItem.getBatch(), taskItem.getFieldsIndex(),
+                    locItem != null ? "瀛樺湪" : "null", locItem != null ? locItem.getAnfme() : null, taskItem.getQty(), taskItem.getAnfme());
 
             if (Objects.nonNull(locItem)) {
-                // 璁$畻鎵e噺鍚庣殑鏁伴噺
-                Double newAnfme = Math.round((locItem.getAnfme() - taskItem.getQty()) * 1000000) / 1000000.0;
-                
-                if (newAnfme.compareTo(0.0) <= 0) {
+                // 鎵e噺閲忥細浼樺厛鐢ㄦ湰娆℃嫞鏂欐暟閲� taskItem.getQty()锛涜嫢涓� 0 涓� taskItem.anfme 宸蹭负鍓╀綑鏁伴噺锛屽垯鎵e噺 = 鍘熷簱浣� - 鍓╀綑锛堢敤 BigDecimal 閬垮厤 Double 绮惧害闂锛�
+                Double deductQty = QuantityUtils.isPositive(taskItem.getQty())
+                        ? taskItem.getQty()
+                        : (taskItem.getAnfme() != null && QuantityUtils.compare(taskItem.getAnfme(), locItem.getAnfme()) < 0
+                                ? QuantityUtils.subtract(locItem.getAnfme(), taskItem.getAnfme())
+                                : 0.0);
+                Double newAnfme = QuantityUtils.subtract(locItem.getAnfme(), deductQty);
+                log.info("[鎷f枡鍏ュ簱-鎵e噺搴撲綅] locItemId={}, deductQty={}, 鍘焌nfme={}, newAnfme={}, 鎿嶄綔={}",
+                        locItem.getId(), deductQty, locItem.getAnfme(), newAnfme, QuantityUtils.isNonPositive(newAnfme) ? "鍒犻櫎" : "鏇存柊");
+
+                if (QuantityUtils.isNonPositive(newAnfme)) {
                     // 鏁伴噺灏忎簬绛変簬0锛屽垹闄ゅ簱浣嶆槑缁�
                     locItemService.removeById(locItem.getId());
                 } else {
@@ -2089,6 +2167,9 @@
                         throw new CoolException("搴撲綅鏄庣粏鏁伴噺鎵e噺澶辫触锛侊紒");
                     }
                 }
+            } else {
+                log.warn("[鎷f枡鍏ュ簱-鎵e噺搴撲綅] 鏈煡鍒板簱浣嶆槑缁� locId={}, matnrId={}, batch={}, fieldsIndex={}锛屾湭鎵e噺",
+                        loc.getId(), taskItem.getMatnrId(), taskItem.getBatch(), taskItem.getFieldsIndex());
             }
         }
     }
diff --git a/rsf-server/src/main/resources/mapper/manager/LocItemMapper.xml b/rsf-server/src/main/resources/mapper/manager/LocItemMapper.xml
index 6db3133..e400a7a 100644
--- a/rsf-server/src/main/resources/mapper/manager/LocItemMapper.xml
+++ b/rsf-server/src/main/resources/mapper/manager/LocItemMapper.xml
@@ -55,4 +55,25 @@
         </if>
         GROUP BY li.matnr_id
     </select>
+
+    <!-- 鎸夌墿鏂�+鐘舵��+搴撲綅鍒嗙粍锛氭瘡琛屼竴涓簱浣嶅強鍏舵暟閲忥紝姹囨�讳笌鎷兼帴鍦� Java 涓畬鎴愪互鍑忚交搴撳帇鍔� -->
+    <select id="listStockByMatnrIdsGroupByStatusAndLoc" resultType="java.util.HashMap">
+        SELECT
+            li.matnr_id AS matnrId,
+            l.use_status AS useStatus,
+            li.loc_code AS locCode,
+            COALESCE(SUM(li.anfme), 0) AS locQty
+        FROM man_loc_item li
+        INNER JOIN man_loc l ON l.id = li.loc_id AND (l.deleted = 0 OR l.deleted IS NULL)
+        WHERE li.deleted = 0
+        AND li.matnr_id IN
+        <foreach collection="matnrIds" item="id" open="(" separator="," close=")">
+            #{id}
+        </foreach>
+        <if test="locUseStatus != null and locUseStatus != ''">
+            AND l.use_status = #{locUseStatus}
+        </if>
+        GROUP BY li.matnr_id, l.use_status, li.loc_code
+        ORDER BY li.matnr_id, l.use_status, li.loc_code
+    </select>
 </mapper>

--
Gitblit v1.9.1