cl
10 天以前 228b881e5a893ec010a194ac42011a4169d0c590
料箱码查询优化
14个文件已修改
142 ■■■■ 已修改文件
rsf-admin/src/App.jsx 27 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-admin/src/config/MyDataProvider.js 8 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-admin/src/i18n/en.js 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-admin/src/i18n/zh.js 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-admin/src/layout/TabsBar.jsx 7 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-admin/src/page/ResourceContent.js 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-admin/src/page/components/CardWithIcon.jsx 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-admin/src/page/statistics/stockManage/WarehouseHistories.jsx 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-admin/src/page/statistics/stockManage/WarehouseStockList.jsx 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-admin/src/utils/common.js 11 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-server/src/main/java/com/vincent/rsf/server/manager/controller/dto/DashboardDto.java 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-server/src/main/java/com/vincent/rsf/server/manager/service/impl/AsnOrderServiceImpl.java 30 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-server/src/main/java/com/vincent/rsf/server/system/controller/AuthController.java 40 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-server/src/main/java/com/vincent/rsf/server/system/service/impl/TenantServiceImpl.java 5 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-admin/src/App.jsx
@@ -103,19 +103,30 @@
        loginPage={Login}
        dashboard={Dashboard}
      >
        {(permissions) => (
          <>
            {Common.extractNavMenus(permissions)?.map((node) => {
              return (
        {(permissions) => {
          const nav = Common.extractNavMenus(permissions) || [];
          const components = new Set(
            nav.map((n) => n.component).filter(Boolean)
          );
          return (
            <>
              {nav.map((node) => (
                <Resource
                  key={node.id}
                  name={node.component}
                  {...ResourceContent(node)}
                />
              );
            })}
          </>
        )}
              ))}
              {!components.has("warehouseStock") && (
                <Resource
                  key="__warehouseStock"
                  name="warehouseStock"
                  {...ResourceContent({ component: "warehouseStock" })}
                />
              )}
            </>
          );
        }}
        {/* CustomRoutes don't trigger checkAuth */}
        <CustomRoutes>
          <Route path="/dashboard" element={<Dashboard />} />
rsf-admin/src/config/MyDataProvider.js
@@ -2,7 +2,13 @@
import * as Common from "../utils/common";
// 出库历史单与入库历史单共用 asnOrderLog 接口,仅前端 resource 不同
const getApiResource = (resource) => (resource === "outStockOrderLog" ? "asnOrderLog" : resource);
// 即时库存:前端 Resource 名 warehouseStock,后端路径 /warehouse/stock
const getApiResource = (resource) => {
  if (resource === "outStockOrderLog") return "asnOrderLog";
  if (resource === "warehouseStock") return "warehouse/stock";
  if (resource === "warehouseStockHistories") return "warehouse/stock/histories";
  return resource;
};
const MyDataProvider = {
  // *** https://marmelab.com/react-admin/DataProviderWriting.html ***
rsf-admin/src/i18n/en.js
@@ -212,6 +212,7 @@
        inStockPoces: 'In Stock Pocess',
        outStockPoces: 'Out Stock Pocess',
        warehouseStock: 'Instant Inventory',
        viewStockManage: 'Instant Inventory',
        deviceBind: 'Device Bind',
        tasks: 'Tasks',
        locItem: 'Loc Items',
rsf-admin/src/i18n/zh.js
@@ -222,6 +222,7 @@
        inStockPoces: '入库管理',
        outStockPoces: '出库管理',
        warehouseStock: '即时库存',
        viewStockManage: '即时库存',
        deviceBind: '设备绑定',
        tasks: '任务管理',
        wave: '波次管理',
rsf-admin/src/layout/TabsBar.jsx
@@ -146,8 +146,11 @@
            const menuName = findMenuName(tab.path, permissions);
            if (menuName) return translate(menuName);
        }
        return tab.path.replace(/^\//, '').split('/')[0] || tab.path;
    }, [translate, permissions, findMenuName]);
        const segment = tab.path.replace(/^\//, '').split('/')[0] || tab.path;
        const fromMenuKey = t(`menu.${segment}`, null);
        if (fromMenuKey != null) return fromMenuKey;
        return segment;
    }, [translate, permissions, findMenuName, t]);
    useEffect(() => {
        const currentPath = location.pathname;
rsf-admin/src/page/ResourceContent.js
@@ -102,6 +102,7 @@
    case "warehouseAreasItem":
      return warehouseAreasItem;
    case "warehouseStock":
    case "viewStockManage":
      return warehouseStock;
    case "loc":
      return loc;
rsf-admin/src/page/components/CardWithIcon.jsx
@@ -66,7 +66,7 @@
                            </Box>
                            <Box sx={{ display: 'flex', padding: '1em' }}>
                                <Typography color="textSecondary">{type == 'in' ? translate("page.dashboard.header.waitQty") : translate("page.dashboard.header.waitOutQty")}:</Typography>
                                <Typography color="textSecondary">{type == 'in' ? statistic?.taskIn : statistic?.taskOut}</Typography>
                                <Typography color="textSecondary">{type == 'in' ? statistic?.waitIn : statistic?.waitOut}</Typography>
                            </Box>
                        </Box>}
                    </Box> : <Box>
rsf-admin/src/page/statistics/stockManage/WarehouseHistories.jsx
@@ -135,7 +135,7 @@
                        <Grid item sx={24}>
                            <Box display="flex">
                                <List
                                    resource="warehouse/stock/histories"
                                    resource="warehouseStockHistories"
                                    sx={{
                                        flexGrow: 1,
                                        transition: (theme) =>
rsf-admin/src/page/statistics/stockManage/WarehouseStockList.jsx
@@ -100,7 +100,6 @@
                            width: '200px'
                        }
                    }}
                    resource="warehouse/stock"
                    title={"common.button.detail"}
                    empty={false}
                    // filter={{aggType: "matnr"}}
rsf-admin/src/utils/common.js
@@ -41,10 +41,15 @@
    const navMenus = [];
    const traverse = (nodes) => {
        nodes.forEach((node) => {
            if (!node.children) {
                navMenus.push(node);
            // 叶子:无子或 children 为空数组;仅收集有 component 的节点(页面资源)
            const children = node.children;
            const hasChildren = Array.isArray(children) && children.length > 0;
            if (!hasChildren) {
                if (node.component) {
                    navMenus.push(node);
                }
            } else {
                traverse(node.children);
                traverse(children);
            }
        });
    };
rsf-server/src/main/java/com/vincent/rsf/server/manager/controller/dto/DashboardDto.java
@@ -22,6 +22,12 @@
    @ApiModelProperty("实际出库数量")
    private Integer taskOut;
    @ApiModelProperty("未完成入库单数量")
    private Integer waitIn;
    @ApiModelProperty("未完成出库单数量")
    private Integer waitOut;
    @ApiModelProperty("总入库数量")
    private Integer totalIn;
rsf-server/src/main/java/com/vincent/rsf/server/manager/service/impl/AsnOrderServiceImpl.java
@@ -448,11 +448,13 @@
        DashboardDto dto = new DashboardDto();
        //获取入库数量
        DashboardDto trandDto = this.baseMapper.getDashbord(OrderType.ORDER_IN.type, TaskType.TASK_TYPE_IN.type + "");
        dto.setInAnf(trandDto.getAnfme()).setTaskIn(trandDto.getRealAnfme()).setTotalIn(trandDto.getAnfme() + trandDto.getRealAnfme());
        dto.setInAnf(trandDto.getAnfme()).setTaskIn(trandDto.getRealAnfme()).setWaitIn(countPendingInOrders())
                .setTotalIn(trandDto.getAnfme() + trandDto.getRealAnfme());
        //获取出库单数量
        DashboardDto outTrand = this.baseMapper.getDashbord(OrderType.ORDER_OUT.type, TaskType.TASK_TYPE_OUT.type + "");
        dto.setOutAnf(outTrand.getAnfme()).setTaskOut(outTrand.getRealAnfme()).setTotalOut(outTrand.getAnfme() + outTrand.getRealAnfme());
        dto.setOutAnf(outTrand.getAnfme()).setTaskOut(outTrand.getRealAnfme()).setWaitOut(countPendingOutOrders())
                .setTotalOut(outTrand.getAnfme() + outTrand.getRealAnfme());
        //获取执行中任务数量
        List<Task> tasks = taskService.list(new LambdaQueryWrapper<>());
@@ -462,6 +464,30 @@
        return R.ok().add(dto);
    }
    /** 未完成入库单:非已完成/取消/关闭 */
    private int countPendingInOrders() {
        return Math.toIntExact(this.count(new LambdaQueryWrapper<WkOrder>()
                .eq(WkOrder::getType, OrderType.ORDER_IN.type)
                .eq(WkOrder::getDeleted, 0)
                .and(w -> w.isNull(WkOrder::getExceStatus).or()
                        .notIn(WkOrder::getExceStatus,
                                AsnExceStatus.ASN_EXCE_STATUS_TASK_DONE.val,
                                AsnExceStatus.ASN_EXCE_STATUS_TASK_CANCEL.val,
                                AsnExceStatus.ASN_EXCE_STATUS_TASK_CLOSE.val))));
    }
    /** 未完成出库单:非已完成/取消/关闭 */
    private int countPendingOutOrders() {
        return Math.toIntExact(this.count(new LambdaQueryWrapper<WkOrder>()
                .eq(WkOrder::getType, OrderType.ORDER_OUT.type)
                .eq(WkOrder::getDeleted, 0)
                .and(w -> w.isNull(WkOrder::getExceStatus).or()
                        .notIn(WkOrder::getExceStatus,
                                AsnExceStatus.OUT_STOCK_STATUS_TASK_DONE.val,
                                AsnExceStatus.ASN_EXCE_STATUS_TASK_CANCEL.val,
                                AsnExceStatus.ASN_EXCE_STATUS_TASK_CLOSE.val))));
    }
    /**
     * 获取出入库趋势
     * @return
rsf-server/src/main/java/com/vincent/rsf/server/system/controller/AuthController.java
@@ -20,12 +20,14 @@
import com.vincent.rsf.server.system.controller.result.LoginResult;
import com.vincent.rsf.server.system.controller.result.MenuVo;
import com.vincent.rsf.server.system.controller.result.SystemInfoVo;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.vincent.rsf.server.system.entity.Menu;
import com.vincent.rsf.server.system.entity.Tenant;
import com.vincent.rsf.server.system.entity.User;
import com.vincent.rsf.server.system.entity.UserLogin;
import com.vincent.rsf.server.system.enums.EmailType;
import com.vincent.rsf.server.system.enums.StatusType;
import com.vincent.rsf.server.system.service.MenuService;
import com.vincent.rsf.server.system.service.RoleMenuService;
import com.vincent.rsf.server.system.service.TenantService;
import com.vincent.rsf.server.system.service.UserLoginService;
@@ -35,7 +37,9 @@
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
/**
@@ -53,6 +57,8 @@
    private UserLoginService userLoginService;
    @Resource
    private RoleMenuService roleMenuService;
    @Resource
    private MenuService menuService;
    @Resource
    private TenantService tenantService;
    @Autowired
@@ -164,7 +170,13 @@
    @GetMapping("/auth/menu")
    public R userMenu() {
        List<Menu> menus = roleMenuService.listMenuByUserId(getLoginUserId(), Menu.TYPE_MENU);
        Long uid = getLoginUserId();
        List<Menu> grantedAll = roleMenuService.listMenuByUserId(uid, null);
        Set<Long> grantedMenuIds = grantedAll.stream().map(Menu::getId).collect(Collectors.toCollection(HashSet::new));
        List<Menu> allMenus = menuService.list(new LambdaQueryWrapper<Menu>().eq(Menu::getDeleted, 0));
        List<Menu> menus = roleMenuService.listMenuByUserId(uid, Menu.TYPE_MENU).stream()
                .filter(m -> menuPageGranted(m, grantedMenuIds, allMenus))
                .collect(Collectors.toList());
        List<MenuVo> voList = menus.stream().map(this::convertToVo).collect(Collectors.toList());
        // exclude tenant
        if (!configProperties.getSuperUserList().contains(getLoginUser().getUsername())) {
@@ -225,6 +237,32 @@
    // ----------------------------------------------------
    /**
     * 页面级菜单:若存在带 :list 的按钮权限子节点,则必须同时勾选至少一个该类按钮,才展示该页(与接口 @PreAuthorize 一致)
     */
    private boolean menuPageGranted(Menu m, Set<Long> grantedMenuIds, List<Menu> allMenus) {
        if (m == null || !Integer.valueOf(Menu.TYPE_MENU).equals(m.getType())) {
            return true;
        }
        if (Cools.isEmpty(m.getComponent())) {
            return true;
        }
        List<Menu> btnChildren = allMenus.stream()
                .filter(c -> m.getId().equals(c.getParentId()) && Integer.valueOf(Menu.TYPE_BTN).equals(c.getType()))
                .collect(Collectors.toList());
        if (btnChildren.isEmpty()) {
            return true;
        }
        boolean needListBtn = btnChildren.stream().anyMatch(c ->
                c.getAuthority() != null && c.getAuthority().contains(":list"));
        if (!needListBtn) {
            return true;
        }
        return btnChildren.stream()
                .filter(c -> c.getAuthority() != null && c.getAuthority().contains(":list"))
                .anyMatch(c -> grantedMenuIds.contains(c.getId()));
    }
    private MenuVo convertToVo(Menu menu) {
        if (menu == null) {
            return null;
rsf-server/src/main/java/com/vincent/rsf/server/system/service/impl/TenantServiceImpl.java
@@ -122,9 +122,12 @@
            throw new CoolException("failed to create userRole");
        }
        // save roleMenu
        // save roleMenu(HTTP 审计类菜单不默认下发,需在角色里显式勾选)
        List<Menu> menuList = menuService.list();
        for (Menu menu : menuList) {
            if ("httpAuditLog".equals(menu.getComponent()) || "httpAuditRule".equals(menu.getComponent())) {
                continue;
            }
            RoleMenu roleMenu = new RoleMenu();
            roleMenu.setRoleId(role.getId());
            roleMenu.setMenuId(menu.getId());