From 7e5973a3061989a976e2c19ef588bb2f34f29cf4 Mon Sep 17 00:00:00 2001
From: chen.lin <1442464845@qq.com>
Date: 星期三, 11 二月 2026 10:26:53 +0800
Subject: [PATCH] 下发任务校验

---
 rsf-server/src/main/java/com/vincent/rsf/server/manager/service/impl/OutStockServiceImpl.java |   60 +++++++++++---------
 rsf-admin/src/page/orders/outStock/OutStockSiteDialog.jsx                                     |   67 ++++++++++++++++------
 rsf-admin/src/layout/index.jsx                                                                |   33 ++++++----
 3 files changed, 101 insertions(+), 59 deletions(-)

diff --git a/rsf-admin/src/layout/index.jsx b/rsf-admin/src/layout/index.jsx
index d6ede1f..68e420c 100644
--- a/rsf-admin/src/layout/index.jsx
+++ b/rsf-admin/src/layout/index.jsx
@@ -1,3 +1,4 @@
+import { createPortal } from 'react-dom';
 import { Layout as RALayout, CheckForApplicationUpdate, useSidebarState } from "react-admin";
 import AppBar from './AppBar';
 import { MyMenu } from './MyMenu';
@@ -7,6 +8,23 @@
 const LayoutContent = ({ children }) => {
   const [sidebarIsOpen] = useSidebarState();
   const sidebarWidth = sidebarIsOpen ? 200 : 50;
+
+  const tabsBarEl = (
+    <Box sx={{
+      position: 'fixed',
+      top: 48,
+      left: sidebarWidth + 5,
+      right: 0,
+      zIndex: 1400, // 楂樹簬 Dialog/Modal(1300)锛岄�氳繃 Portal 鎸傚埌 body 鎵嶈兘鐩栦綇寮圭獥
+      transition: (theme) =>
+        theme.transitions.create('left', {
+          easing: theme.transitions.easing.sharp,
+          duration: theme.transitions.duration.leavingScreen,
+        }),
+    }}>
+      <TabsBar />
+    </Box>
+  );
 
   return (
     <RALayout
@@ -28,20 +46,7 @@
         }
       }}
     >
-      <Box sx={{
-        position: 'fixed',
-        top: 48,
-        left: sidebarWidth + 5,
-        right: 0,
-        zIndex: 1350, // 楂樹簬 Dialog(1300)锛岄伩鍏嶈彍鍗曞唴寮圭獥閬洊鏍囩椤�
-        transition: (theme) =>
-          theme.transitions.create('left', {
-            easing: theme.transitions.easing.sharp,
-            duration: theme.transitions.duration.leavingScreen,
-          }),
-      }}>
-        <TabsBar />
-      </Box>
+      {createPortal(tabsBarEl, document.body)}
       {children}
       <CheckForApplicationUpdate />
     </RALayout>
diff --git a/rsf-admin/src/page/orders/outStock/OutStockSiteDialog.jsx b/rsf-admin/src/page/orders/outStock/OutStockSiteDialog.jsx
index e0b0ced..1462658 100644
--- a/rsf-admin/src/page/orders/outStock/OutStockSiteDialog.jsx
+++ b/rsf-admin/src/page/orders/outStock/OutStockSiteDialog.jsx
@@ -1,14 +1,16 @@
-import { Box, Card, Grid, List, LinearProgress, Select, MenuItem, ListItemText, ListItemAvatar, Avatar, ListItemButton, Dialog, DialogTitle, ListItem } from "@mui/material";
+import { Box, Card, Grid, List, LinearProgress, Select, MenuItem, ListItemText, ListItemAvatar, Avatar, ListItemButton, Dialog, DialogTitle, ListItem, CircularProgress } from "@mui/material";
 import React, { useState, useRef, useEffect, useMemo } from "react";
 import { PAGE_DRAWER_WIDTH, OPERATE_MODE, DEFAULT_PAGE_SIZE, DEFAULT_ITEM_PAGE_SIZE } from '@/config/setting';
 import { Delete, Edit, Add } from '@mui/icons-material';
 import request from '@/utils/request';
-import { useTranslate } from "react-admin";
+import { useTranslate, useNotify } from "react-admin";
 
 const OutStockSiteDialog = (props) => {
     const translate = useTranslate();
+    const notify = useNotify();
     const { onClose, selectedValue, open } = props;
     const [siteNos, setSiteNos] = useState([]);
+    const [loading, setLoading] = useState(false);
 
     const handleClose = () => {
         onClose(selectedValue);
@@ -19,16 +21,31 @@
     }
 
     useEffect(() => {
-        getSiteNos()
+        if (open) {
+            getSiteNos();
+        } else {
+            setSiteNos([]);
+        }
     }, [open])
 
-
     const getSiteNos = async () => {
-        const { data: { code, data, msg } } = await request.get('/outStock/tasks/sites');
-        if (code === 200) {
-            setSiteNos(data);
-        } else {
-            notify(msg);
+        setLoading(true);
+        try {
+            const { data: res } = await request.get('/outStock/tasks/sites');
+            const code = res?.code;
+            const data = res?.data;
+            const msg = res?.msg;
+            if (code === 200) {
+                setSiteNos(Array.isArray(data) ? data : []);
+            } else {
+                notify(msg || '鑾峰彇搴撳彛鍒楄〃澶辫触');
+                setSiteNos([]);
+            }
+        } catch (err) {
+            notify(err?.message || '鑾峰彇搴撳彛鍒楄〃澶辫触');
+            setSiteNos([]);
+        } finally {
+            setLoading(false);
         }
     }
 
@@ -36,17 +53,31 @@
         <Dialog
             onClose={handleClose}
             open={open}
+            maxWidth="xs"
+            fullWidth
         >
             <DialogTitle>{translate("toolbar.modiftySite")}</DialogTitle>
-            <List sx={{ pt: 0 }}>
-                {siteNos.map((site) => (
-                    <ListItem disableGutters key={site?.id}>
-                        <ListItemButton onClick={() => handleListItemClick(site)}>
-                            <ListItemText primary={site.site} />
-                        </ListItemButton>
-                    </ListItem>
-                ))}
-            </List>
+            {loading ? (
+                <Box sx={{ display: 'flex', justifyContent: 'center', py: 3 }}>
+                    <CircularProgress />
+                </Box>
+            ) : (
+                <List sx={{ pt: 0, minHeight: 120 }}>
+                    {siteNos.length === 0 && !loading ? (
+                        <ListItem>
+                            <ListItemText primary="鏆傛棤搴撳彛鏁版嵁" />
+                        </ListItem>
+                    ) : (
+                        siteNos.map((site) => (
+                            <ListItem disableGutters key={site?.id}>
+                                <ListItemButton onClick={() => handleListItemClick(site)}>
+                                    <ListItemText primary={site?.site ?? site?.name ?? '-'} />
+                                </ListItemButton>
+                            </ListItem>
+                        ))
+                    )}
+                </List>
+            )}
         </Dialog>
     );
 }
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 2bc9667..bcbf5f9 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
@@ -699,37 +699,43 @@
             for (LocItem locItem : locItems) {
                 Loc loc = locService.getById(locItem.getLocId());
                 List<LocItem> itemList = locItemService.list(new LambdaQueryWrapper<LocItem>().eq(LocItem::getLocCode, locItem.getLocCode()));
-                if (issued.compareTo(ISSUED_TOLERANCE) > 0) {
-                    ExistDto existDto = new ExistDto().setBatch(locItem.getBatch()).setMatnr(locItem.getMatnrCode()).setLocNo(locItem.getLocCode());
-                    if (existDtos.add(existDto)) {
-                        locItem.setOutQty(issued.doubleValue() >= locItem.getAnfme() ? locItem.getAnfme() : issued.doubleValue());
-                        locItem.setBarcode(loc.getBarcode());
-                        OrderOutItemDto orderOutItemDto = new OrderOutItemDto();
-                        orderOutItemDto.setLocItem(locItem);
+                if (issued.compareTo(ISSUED_TOLERANCE) <= 0) {
+                    break;
+                }
+                // 璇ュ簱浣嶅彲鍒嗛厤鏁伴噺锛氬彇鏈寰呭垎閰嶄笌搴撲綅搴撳瓨鐨勮緝灏忓��
+                double allocatable = Math.min(issued.doubleValue(), locItem.getAnfme() != null ? locItem.getAnfme() : 0);
+                ExistDto existDto = new ExistDto().setBatch(locItem.getBatch()).setMatnr(locItem.getMatnrCode()).setLocNo(locItem.getLocCode());
+                if (existDtos.add(existDto)) {
+                    // 棣栨浣跨敤璇ュ簱浣嶏細鍔犲叆鍒楄〃骞舵墸鍑� issued
+                    locItem.setOutQty(allocatable);
+                    locItem.setBarcode(loc.getBarcode());
+                    OrderOutItemDto orderOutItemDto = new OrderOutItemDto();
+                    orderOutItemDto.setLocItem(locItem);
 
-                        List<DeviceSite> deviceSites = deviceSiteService.list(new LambdaQueryWrapper<DeviceSite>()
-                                .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)
-                        );
+                    List<DeviceSite> deviceSites = deviceSiteService.list(new LambdaQueryWrapper<DeviceSite>()
+                            .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)
+                    );
 
-                        if (!deviceSites.isEmpty()) {
-                            List<OrderOutItemDto.staListDto> maps = new ArrayList<>();
-                            for (DeviceSite sta : deviceSites) {
-                                OrderOutItemDto.staListDto staListDto = new OrderOutItemDto.staListDto();
-                                staListDto.setStaNo(sta.getSite());
-                                staListDto.setStaName(sta.getSite());
-                                maps.add(staListDto);
-                            }
-                            orderOutItemDto.setStaNos(maps);
-                            //榛樿鑾峰彇绗竴绔欑偣
-                            DeviceSite deviceSite = deviceSites.stream().findFirst().get();
-                            orderOutItemDto.setSiteNo(deviceSite.getSite());
+                    if (!deviceSites.isEmpty()) {
+                        List<OrderOutItemDto.staListDto> maps = new ArrayList<>();
+                        for (DeviceSite sta : deviceSites) {
+                            OrderOutItemDto.staListDto staListDto = new OrderOutItemDto.staListDto();
+                            staListDto.setStaNo(sta.getSite());
+                            staListDto.setStaName(sta.getSite());
+                            maps.add(staListDto);
                         }
-
-                        list.add(orderOutItemDto);
-
-                        issued = issued.subtract(new BigDecimal(locItem.getAnfme().toString()));
+                        orderOutItemDto.setStaNos(maps);
+                        //榛樿鑾峰彇绗竴绔欑偣
+                        DeviceSite deviceSite = deviceSites.stream().findFirst().get();
+                        orderOutItemDto.setSiteNo(deviceSite.getSite());
                     }
+
+                    list.add(orderOutItemDto);
+                    issued = issued.subtract(new BigDecimal(locItem.getAnfme().toString()));
+                } else {
+                    // 璇ュ簱浣嶅凡琚墠搴忚鍗曡鍗犵敤锛氬彧鎵e噺 issued锛屼笉閲嶅鍔犲叆鍒楄〃锛岄伩鍏嶄骇鐢熲�滃簱瀛樹笉瓒斥�濊剰鏁版嵁
+                    issued = issued.subtract(new BigDecimal(String.valueOf(allocatable)));
                 }
             }
             if (issued.compareTo(ISSUED_TOLERANCE) > 0) {

--
Gitblit v1.9.1