skyouc
2025-03-25 eb8ded2565e746a360985f702c556b26f750d35a
Merge branch 'devlop' of http://47.97.1.152:5880/r/wms-master into devlop
28个文件已添加
5个文件已删除
57个文件已修改
4533 ■■■■ 已修改文件
rsf-admin/.env 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-admin/package-lock.json 432 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-admin/src/i18n/en.js 18 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-admin/src/i18n/zh.js 20 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-admin/src/page/ResourceContent.js 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-admin/src/page/asnOrderItem/AsnOrderItemList.jsx 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-admin/src/page/basicInfo/companys/CompanysEdit.jsx 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-admin/src/page/basicInfo/loc/BindModal.jsx 197 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-admin/src/page/basicInfo/loc/InitModal.jsx 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-admin/src/page/basicInfo/loc/LocCreate.jsx 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-admin/src/page/basicInfo/loc/LocEdit.jsx 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-admin/src/page/basicInfo/loc/LocList.jsx 41 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-admin/src/page/basicInfo/locArea/LocAreaCreate.jsx 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-admin/src/page/basicInfo/locArea/LocAreaEdit.jsx 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-admin/src/page/basicInfo/locArea/LocAreaList.jsx 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-admin/src/page/basicInfo/locAreaMat/BindLocModal.jsx 220 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-admin/src/page/basicInfo/locAreaMat/BindMatnrModal.jsx 216 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-admin/src/page/basicInfo/locAreaMat/LocAreaMatCreate.jsx 137 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-admin/src/page/basicInfo/locAreaMat/LocAreaMatEdit.jsx 109 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-admin/src/page/basicInfo/locAreaMat/LocAreaMatList.jsx 156 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-admin/src/page/basicInfo/locAreaMat/LocAreaMatPanel.jsx 411 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-admin/src/page/basicInfo/locAreaMat/index.jsx 18 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-admin/src/page/basicInfo/locAreaMatRela/LocAreaMatRelaCreate.jsx 179 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-admin/src/page/basicInfo/locAreaMatRela/LocAreaMatRelaEdit.jsx 152 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-admin/src/page/basicInfo/locAreaMatRela/LocAreaMatRelaList.jsx 158 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-admin/src/page/basicInfo/locAreaMatRela/LocAreaMatRelaPanel.jsx 28 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-admin/src/page/basicInfo/locAreaMatRela/index.jsx 18 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-admin/src/page/basicInfo/locAreaRela/LocAreaRelaCreate.jsx 123 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-admin/src/page/basicInfo/locAreaRela/LocAreaRelaEdit.jsx 95 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-admin/src/page/basicInfo/locAreaRela/LocAreaRelaList.jsx 154 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-admin/src/page/basicInfo/locAreaRela/LocAreaRelaPanel.jsx 63 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-admin/src/page/basicInfo/locAreaRela/index.jsx 18 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-admin/src/page/basicInfo/locType/BindModal.jsx 199 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-admin/src/page/basicInfo/locType/LocTypeEdit.jsx 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-admin/src/page/basicInfo/locType/LocTypeList.jsx 33 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-admin/src/page/basicInfo/matnr/BindModal.jsx 186 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-admin/src/page/basicInfo/matnr/MatnrEdit.jsx 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-admin/src/page/basicInfo/matnr/MatnrList.jsx 28 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-admin/src/page/basicInfo/matnr/PrintModal.jsx 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-admin/src/page/basicInfo/matnrGroup/MatnrGroupCreate.jsx 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-admin/src/page/basicInfo/matnrGroup/MatnrGroupEdit.jsx 77 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-admin/src/page/basicInfo/matnrGroup/MatnrGroupList.jsx 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-admin/src/page/basicInfo/warehouse/WarehouseEdit.jsx 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-admin/src/page/components/ConfirmModal.jsx 50 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-admin/src/page/container/ContainerEdit.jsx 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-admin/src/page/contract/ContractEdit.jsx 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-admin/src/page/fields/FieldsList.jsx 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-admin/src/page/fieldsItem/FieldsItemList.jsx 4 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-admin/src/page/purchaseItem/PurchaseItemList.jsx 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-admin/src/page/qlyInspect/QlyInspectList.jsx 4 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-admin/src/page/qlyIsptItem/QlyIsptItemList.jsx 4 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-admin/src/page/system/config/ConfigList.jsx 4 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-admin/src/page/system/dicts/dictData/DictDataCreate.jsx 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-admin/src/page/system/dicts/dictData/DictDataEdit.jsx 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-admin/src/page/system/dicts/dictData/DictDataList.jsx 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-admin/src/page/system/dicts/dictType/DictTypeList.jsx 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-admin/src/page/system/host/HostList.jsx 4 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-admin/src/page/system/serialRule/SerialRuleList.jsx 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-admin/src/page/system/serialRuleItem/SerialRuleItemList.jsx 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-admin/src/page/system/tenant/TenantList.jsx 4 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-admin/src/page/system/userLogin/UserLoginList.jsx 4 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-admin/src/page/warehouseAreas/WarehouseAreasList.jsx 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-admin/src/page/warehouseAreasItem/WarehouseAreasItemList.jsx 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-common/src/main/java/com/vincent/rsf/common/utils/Utils.java 20 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-server/src/main/java/asnOrderItemLog.sql 43 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-server/src/main/java/asnOrderLog.sql 32 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-server/src/main/java/com/vincent/rsf/server/common/CodeBuilder.java 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-server/src/main/java/com/vincent/rsf/server/manager/controller/LocAreaMatController.java 112 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-server/src/main/java/com/vincent/rsf/server/manager/controller/LocAreaMatRelaController.java 82 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-server/src/main/java/com/vincent/rsf/server/manager/controller/MatnrGroupController.java 15 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-server/src/main/java/com/vincent/rsf/server/manager/controller/WarehouseAreasController.java 8 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-server/src/main/java/com/vincent/rsf/server/manager/controller/params/LocAreaMatsParam.java 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-server/src/main/java/com/vincent/rsf/server/manager/entity/LocAreaMat.java 217 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-server/src/main/java/com/vincent/rsf/server/manager/entity/LocAreaMatRela.java 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-server/src/main/java/com/vincent/rsf/server/manager/entity/LocTypeRela.java 38 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-server/src/main/java/com/vincent/rsf/server/manager/mapper/LocAreaMatMapper.java 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-server/src/main/java/com/vincent/rsf/server/manager/service/LocAreaMatRelaService.java 14 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-server/src/main/java/com/vincent/rsf/server/manager/service/LocAreaMatService.java 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-server/src/main/java/com/vincent/rsf/server/manager/service/MatnrGroupService.java 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-server/src/main/java/com/vincent/rsf/server/manager/service/impl/LocAreaMatRelaServiceImpl.java 115 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-server/src/main/java/com/vincent/rsf/server/manager/service/impl/LocAreaMatServiceImpl.java 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-server/src/main/java/com/vincent/rsf/server/manager/service/impl/MatnrGroupServiceImpl.java 32 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-server/src/main/java/com/vincent/rsf/server/system/controller/DictDataController.java 15 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-server/src/main/java/com/vincent/rsf/server/system/controller/DictTypeController.java 14 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-server/src/main/java/locArea.sql 25 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-server/src/main/java/locAreaMatRela.sql 27 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-server/src/main/java/locAreaRela.sql 23 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-server/src/main/resources/application.yml 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-server/src/main/resources/mapper/manager/LocAreaMatMapper.xml 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-server/src/main/resources/mapper/test/LocAreaMatMapper.xml 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-admin/.env
@@ -1,3 +1,3 @@
VITE_BASE_IP=192.168.4.16
#VITE_BASE_IP=47.76.147.249
VITE_BASE_IP=192.168.4.24
# VITE_BASE_IP=47.76.147.249
VITE_BASE_PORT=8080
rsf-admin/package-lock.json
@@ -23,17 +23,14 @@
        "pixi.js": "^7.4.0",
        "prop-types": "^15.8.1",
        "ra-i18n-polyglot": "^5.6.2",
        "ra-language-chinese": "^2.0.10",
        "ra-language-english": "^5.6.2",
        "react": "^18.3.0",
        "react-admin": "^5.6.3",
        "react-barcode": "^1.6.1",
        "react-admin": "^5.1.0",
        "react-dom": "^18.3.0",
        "react-hook-form": "^7.53.0",
        "react-router": "^6.22.0",
        "react-router-dom": "^6.26.1",
        "react-syntax-highlighter": "^15.5.0",
        "react-to-print": "^3.0.5",
        "three": "^0.155.0",
        "tweedle.js": "^2.1.0"
      },
@@ -369,16 +366,15 @@
      }
    },
    "node_modules/@emotion/babel-plugin": {
      "version": "11.13.5",
      "resolved": "https://registry.npmmirror.com/@emotion/babel-plugin/-/babel-plugin-11.13.5.tgz",
      "integrity": "sha512-pxHCpT2ex+0q+HH91/zsdHkw/lXd468DIN2zvfvLtPKLLMo6gQj7oLObq8PhkrxOZb/gGCq03S3Z7PDhS8pduQ==",
      "license": "MIT",
      "version": "11.12.0",
      "resolved": "https://registry.npmmirror.com/@emotion/babel-plugin/-/babel-plugin-11.12.0.tgz",
      "integrity": "sha512-y2WQb+oP8Jqvvclh8Q55gLUyb7UFvgv7eJfsj7td5TToBrIUtPay2kMrZi4xjq9qw2vD0ZR5fSho0yqoFgX7Rw==",
      "dependencies": {
        "@babel/helper-module-imports": "^7.16.7",
        "@babel/runtime": "^7.18.3",
        "@emotion/hash": "^0.9.2",
        "@emotion/memoize": "^0.9.0",
        "@emotion/serialize": "^1.3.3",
        "@emotion/serialize": "^1.2.0",
        "babel-plugin-macros": "^3.1.0",
        "convert-source-map": "^1.5.0",
        "escape-string-regexp": "^4.0.0",
@@ -390,14 +386,12 @@
    "node_modules/@emotion/babel-plugin/node_modules/convert-source-map": {
      "version": "1.9.0",
      "resolved": "https://registry.npmmirror.com/convert-source-map/-/convert-source-map-1.9.0.tgz",
      "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==",
      "license": "MIT"
      "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A=="
    },
    "node_modules/@emotion/babel-plugin/node_modules/escape-string-regexp": {
      "version": "4.0.0",
      "resolved": "https://registry.npmmirror.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz",
      "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==",
      "license": "MIT",
      "engines": {
        "node": ">=10"
      },
@@ -437,17 +431,16 @@
      "integrity": "sha512-30FAj7/EoJ5mwVPOWhAyCX+FPfMDrVecJAM+Iw9NRoSl4BBAQeqj4cApHHUXOVvIPgLVDsCFoz/hGD+5QQD1GQ=="
    },
    "node_modules/@emotion/react": {
      "version": "11.14.0",
      "resolved": "https://registry.npmmirror.com/@emotion/react/-/react-11.14.0.tgz",
      "integrity": "sha512-O000MLDBDdk/EohJPFUqvnp4qnHeYkVP5B0xEG0D/L7cOKP9kefu2DXn8dj74cQfsEzUqh+sr1RzFqiL1o+PpA==",
      "license": "MIT",
      "version": "11.13.3",
      "resolved": "https://registry.npmmirror.com/@emotion/react/-/react-11.13.3.tgz",
      "integrity": "sha512-lIsdU6JNrmYfJ5EbUCf4xW1ovy5wKQ2CkPRM4xogziOxH1nXxBSjpC9YqbFAP7circxMfYp+6x676BqWcEiixg==",
      "dependencies": {
        "@babel/runtime": "^7.18.3",
        "@emotion/babel-plugin": "^11.13.5",
        "@emotion/cache": "^11.14.0",
        "@emotion/serialize": "^1.3.3",
        "@emotion/use-insertion-effect-with-fallbacks": "^1.2.0",
        "@emotion/utils": "^1.4.2",
        "@emotion/babel-plugin": "^11.12.0",
        "@emotion/cache": "^11.13.0",
        "@emotion/serialize": "^1.3.1",
        "@emotion/use-insertion-effect-with-fallbacks": "^1.1.0",
        "@emotion/utils": "^1.4.0",
        "@emotion/weak-memoize": "^0.4.0",
        "hoist-non-react-statics": "^3.3.1"
      },
@@ -479,17 +472,16 @@
      "integrity": "sha512-fTBW9/8r2w3dXWYM4HCB1Rdp8NLibOw2+XELH5m5+AkWiL/KqYX6dc0kKYlaYyKjrQ6ds33MCdMPEwgs2z1rqg=="
    },
    "node_modules/@emotion/styled": {
      "version": "11.14.0",
      "resolved": "https://registry.npmmirror.com/@emotion/styled/-/styled-11.14.0.tgz",
      "integrity": "sha512-XxfOnXFffatap2IyCeJyNov3kiDQWoR08gPUQxvbL7fxKryGBKUZUkG6Hz48DZwVrJSVh9sJboyV1Ds4OW6SgA==",
      "license": "MIT",
      "version": "11.13.0",
      "resolved": "https://registry.npmmirror.com/@emotion/styled/-/styled-11.13.0.tgz",
      "integrity": "sha512-tkzkY7nQhW/zC4hztlwucpT8QEZ6eUzpXDRhww/Eej4tFfO0FxQYWRyg/c5CCXa4d/f174kqeXYjuQRnhzf6dA==",
      "dependencies": {
        "@babel/runtime": "^7.18.3",
        "@emotion/babel-plugin": "^11.13.5",
        "@emotion/babel-plugin": "^11.12.0",
        "@emotion/is-prop-valid": "^1.3.0",
        "@emotion/serialize": "^1.3.3",
        "@emotion/use-insertion-effect-with-fallbacks": "^1.2.0",
        "@emotion/utils": "^1.4.2"
        "@emotion/serialize": "^1.3.0",
        "@emotion/use-insertion-effect-with-fallbacks": "^1.1.0",
        "@emotion/utils": "^1.4.0"
      },
      "peerDependencies": {
        "@emotion/react": "^11.0.0-rc.0",
@@ -507,10 +499,9 @@
      "integrity": "sha512-dFoMUuQA20zvtVTuxZww6OHoJYgrzfKM1t52mVySDJnMSEa08ruEvdYQbhvyu6soU+NeLVd3yKfTfT0NeV6qGg=="
    },
    "node_modules/@emotion/use-insertion-effect-with-fallbacks": {
      "version": "1.2.0",
      "resolved": "https://registry.npmmirror.com/@emotion/use-insertion-effect-with-fallbacks/-/use-insertion-effect-with-fallbacks-1.2.0.tgz",
      "integrity": "sha512-yJMtVdH59sxi/aVJBpk9FQq+OR8ll5GT8oWd57UpeaKEVGab41JWaCFA7FRLoMLloOZF/c/wsPoe+bfGmRKgDg==",
      "license": "MIT",
      "version": "1.1.0",
      "resolved": "https://registry.npmmirror.com/@emotion/use-insertion-effect-with-fallbacks/-/use-insertion-effect-with-fallbacks-1.1.0.tgz",
      "integrity": "sha512-+wBOcIV5snwGgI2ya3u99D7/FJquOIniQT1IKyDsBmEgwvpxMNeS65Oib7OnE2d2aY+3BU4OiH+0Wchf8yk3Hw==",
      "peerDependencies": {
        "react": ">=16.8.0"
      }
@@ -1249,13 +1240,13 @@
      "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg=="
    },
    "node_modules/@mui/private-theming": {
      "version": "6.4.8",
      "resolved": "https://registry.npmmirror.com/@mui/private-theming/-/private-theming-6.4.8.tgz",
      "integrity": "sha512-sWwQoNSn6elsPTAtSqCf+w5aaGoh7AASURNmpy+QTTD/zwJ0Jgwt0ZaaP6mXq2IcgHxYnYloM/+vJgHPMkRKTQ==",
      "version": "6.4.6",
      "resolved": "https://registry.npmjs.org/@mui/private-theming/-/private-theming-6.4.6.tgz",
      "integrity": "sha512-T5FxdPzCELuOrhpA2g4Pi6241HAxRwZudzAuL9vBvniuB5YU82HCmrARw32AuCiyTfWzbrYGGpZ4zyeqqp9RvQ==",
      "license": "MIT",
      "dependencies": {
        "@babel/runtime": "^7.26.0",
        "@mui/utils": "^6.4.8",
        "@mui/utils": "^6.4.6",
        "prop-types": "^15.8.1"
      },
      "engines": {
@@ -1276,13 +1267,13 @@
      }
    },
    "node_modules/@mui/private-theming/node_modules/@mui/utils": {
      "version": "6.4.8",
      "resolved": "https://registry.npmmirror.com/@mui/utils/-/utils-6.4.8.tgz",
      "integrity": "sha512-C86gfiZ5BfZ51KqzqoHi1WuuM2QdSKoFhbkZeAfQRB+jCc4YNhhj11UXFVMMsqBgZ+Zy8IHNJW3M9Wj/LOwRXQ==",
      "version": "6.4.6",
      "resolved": "https://registry.npmjs.org/@mui/utils/-/utils-6.4.6.tgz",
      "integrity": "sha512-43nZeE1pJF2anGafNydUcYFPtHwAqiBiauRtaMvurdrZI3YrUjHkAu43RBsxef7OFtJMXGiHFvq43kb7lig0sA==",
      "license": "MIT",
      "dependencies": {
        "@babel/runtime": "^7.26.0",
        "@mui/types": "~7.2.24",
        "@mui/types": "^7.2.21",
        "@types/prop-types": "^15.7.14",
        "clsx": "^2.1.1",
        "prop-types": "^15.8.1",
@@ -1307,14 +1298,14 @@
    },
    "node_modules/@mui/private-theming/node_modules/react-is": {
      "version": "19.0.0",
      "resolved": "https://registry.npmmirror.com/react-is/-/react-is-19.0.0.tgz",
      "resolved": "https://registry.npmjs.org/react-is/-/react-is-19.0.0.tgz",
      "integrity": "sha512-H91OHcwjZsbq3ClIDHMzBShc1rotbfACdWENsmEf0IFvZ3FgGPtdHMcsv45bQ1hAbgdfiA8SnxTKfDS+x/8m2g==",
      "license": "MIT"
    },
    "node_modules/@mui/styled-engine": {
      "version": "6.4.8",
      "resolved": "https://registry.npmmirror.com/@mui/styled-engine/-/styled-engine-6.4.8.tgz",
      "integrity": "sha512-oyjx1b1FvUCI85ZMO4trrjNxGm90eLN3Ohy0AP/SqK5gWvRQg1677UjNf7t6iETOKAleHctJjuq0B3aXO2gtmw==",
      "version": "6.4.6",
      "resolved": "https://registry.npmjs.org/@mui/styled-engine/-/styled-engine-6.4.6.tgz",
      "integrity": "sha512-vSWYc9ZLX46be5gP+FCzWVn5rvDr4cXC5JBZwSIkYk9xbC7GeV+0kCvB8Q6XLFQJy+a62bbqtmdwS4Ghi9NBlQ==",
      "license": "MIT",
      "dependencies": {
        "@babel/runtime": "^7.26.0",
@@ -1346,16 +1337,16 @@
      }
    },
    "node_modules/@mui/system": {
      "version": "6.4.8",
      "resolved": "https://registry.npmmirror.com/@mui/system/-/system-6.4.8.tgz",
      "integrity": "sha512-gV7iBHoqlsIenU2BP0wq14BefRoZcASZ/4LeyuQglayBl+DfLX5rEd3EYR3J409V2EZpR0NOM1LATAGlNk2cyA==",
      "version": "6.4.7",
      "resolved": "https://registry.npmjs.org/@mui/system/-/system-6.4.7.tgz",
      "integrity": "sha512-7wwc4++Ak6tGIooEVA9AY7FhH2p9fvBMORT4vNLMAysH3Yus/9B9RYMbrn3ANgsOyvT3Z7nE+SP8/+3FimQmcg==",
      "license": "MIT",
      "dependencies": {
        "@babel/runtime": "^7.26.0",
        "@mui/private-theming": "^6.4.8",
        "@mui/styled-engine": "^6.4.8",
        "@mui/types": "~7.2.24",
        "@mui/utils": "^6.4.8",
        "@mui/private-theming": "^6.4.6",
        "@mui/styled-engine": "^6.4.6",
        "@mui/types": "^7.2.21",
        "@mui/utils": "^6.4.6",
        "clsx": "^2.1.1",
        "csstype": "^3.1.3",
        "prop-types": "^15.8.1"
@@ -1386,13 +1377,13 @@
      }
    },
    "node_modules/@mui/system/node_modules/@mui/utils": {
      "version": "6.4.8",
      "resolved": "https://registry.npmmirror.com/@mui/utils/-/utils-6.4.8.tgz",
      "integrity": "sha512-C86gfiZ5BfZ51KqzqoHi1WuuM2QdSKoFhbkZeAfQRB+jCc4YNhhj11UXFVMMsqBgZ+Zy8IHNJW3M9Wj/LOwRXQ==",
      "version": "6.4.6",
      "resolved": "https://registry.npmjs.org/@mui/utils/-/utils-6.4.6.tgz",
      "integrity": "sha512-43nZeE1pJF2anGafNydUcYFPtHwAqiBiauRtaMvurdrZI3YrUjHkAu43RBsxef7OFtJMXGiHFvq43kb7lig0sA==",
      "license": "MIT",
      "dependencies": {
        "@babel/runtime": "^7.26.0",
        "@mui/types": "~7.2.24",
        "@mui/types": "^7.2.21",
        "@types/prop-types": "^15.7.14",
        "clsx": "^2.1.1",
        "prop-types": "^15.8.1",
@@ -1417,14 +1408,14 @@
    },
    "node_modules/@mui/system/node_modules/react-is": {
      "version": "19.0.0",
      "resolved": "https://registry.npmmirror.com/react-is/-/react-is-19.0.0.tgz",
      "resolved": "https://registry.npmjs.org/react-is/-/react-is-19.0.0.tgz",
      "integrity": "sha512-H91OHcwjZsbq3ClIDHMzBShc1rotbfACdWENsmEf0IFvZ3FgGPtdHMcsv45bQ1hAbgdfiA8SnxTKfDS+x/8m2g==",
      "license": "MIT"
    },
    "node_modules/@mui/types": {
      "version": "7.2.24",
      "resolved": "https://registry.npmmirror.com/@mui/types/-/types-7.2.24.tgz",
      "integrity": "sha512-3c8tRt/CbWZ+pEg7QpSwbdxOk36EfmhbKf6AGZsD1EcLDLTSZoxxJ86FVtcjxvjuhdyBiWKSTGZFaXCnidO2kw==",
      "version": "7.2.21",
      "resolved": "https://registry.npmjs.org/@mui/types/-/types-7.2.21.tgz",
      "integrity": "sha512-6HstngiUxNqLU+/DPqlUJDIPbzUBxIVHb1MmXP0eTWDIROiCR2viugXpEif0PPe2mLqqakPzzRClWAnK+8UJww==",
      "license": "MIT",
      "peerDependencies": {
        "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0"
@@ -2315,8 +2306,7 @@
    "node_modules/@types/parse-json": {
      "version": "4.0.2",
      "resolved": "https://registry.npmmirror.com/@types/parse-json/-/parse-json-4.0.2.tgz",
      "integrity": "sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw==",
      "license": "MIT"
      "integrity": "sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw=="
    },
    "node_modules/@types/prop-types": {
      "version": "15.7.14",
@@ -2343,11 +2333,10 @@
      }
    },
    "node_modules/@types/react-transition-group": {
      "version": "4.4.12",
      "resolved": "https://registry.npmmirror.com/@types/react-transition-group/-/react-transition-group-4.4.12.tgz",
      "integrity": "sha512-8TV6R3h2j7a91c+1DXdJi3Syo69zzIZbz7Lg5tORM5LEJG7X/E6a1V3drRyBRZq7/utz7A+c4OgYLiLcYGHG6w==",
      "license": "MIT",
      "peerDependencies": {
      "version": "4.4.11",
      "resolved": "https://registry.npmmirror.com/@types/react-transition-group/-/react-transition-group-4.4.11.tgz",
      "integrity": "sha512-RM05tAniPZ5DZPzzNFP+DmrcOdD0efDUxMy3145oljWSl3x9ZV5vhme98gTxFrj2lhXvmGNnUiuDyJgY9IKkNA==",
      "dependencies": {
        "@types/react": "*"
      }
    },
@@ -2356,13 +2345,6 @@
      "resolved": "https://registry.npmmirror.com/@types/semver/-/semver-7.5.8.tgz",
      "integrity": "sha512-I8EUhyrgfLrcTkzV3TSsGyl1tSuPrEDzr0yd5m90UgNxQkyDXULk3b6MlQqTCpZpNtWe1K0hzclnZkTcLBe2UQ==",
      "dev": true
    },
    "node_modules/@types/trusted-types": {
      "version": "2.0.7",
      "resolved": "https://registry.npmmirror.com/@types/trusted-types/-/trusted-types-2.0.7.tgz",
      "integrity": "sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==",
      "license": "MIT",
      "optional": true
    },
    "node_modules/@types/unist": {
      "version": "2.0.11",
@@ -2795,10 +2777,9 @@
      "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q=="
    },
    "node_modules/attr-accept": {
      "version": "2.2.5",
      "resolved": "https://registry.npmmirror.com/attr-accept/-/attr-accept-2.2.5.tgz",
      "integrity": "sha512-0bDNnY/u6pPwHDMoF0FieU354oBi0a8rD9FcsLwzcGWbc8KS8KPIi7y+s13OlVY+gMWc/9xEMUgNE6Qm8ZllYQ==",
      "license": "MIT",
      "version": "2.2.2",
      "resolved": "https://registry.npmmirror.com/attr-accept/-/attr-accept-2.2.2.tgz",
      "integrity": "sha512-7prDjvt9HmqiZ0cl5CRjtS84sEyhsHP2coDkaZKRKVfCDo9s7iw7ChVmar78Gu9pC4SoR/28wFu/G5JJhTnqEg==",
      "engines": {
        "node": ">=4"
      }
@@ -2807,7 +2788,6 @@
      "version": "3.3.4",
      "resolved": "https://registry.npmmirror.com/autosuggest-highlight/-/autosuggest-highlight-3.3.4.tgz",
      "integrity": "sha512-j6RETBD2xYnrVcoV1S5R4t3WxOlWZKyDQjkwnggDPSjF5L4jV98ZltBpvPvbkM1HtoSe5o+bNrTHyjPbieGeYA==",
      "license": "MIT",
      "dependencies": {
        "remove-accents": "^0.4.2"
      }
@@ -2841,7 +2821,6 @@
      "version": "3.1.0",
      "resolved": "https://registry.npmmirror.com/babel-plugin-macros/-/babel-plugin-macros-3.1.0.tgz",
      "integrity": "sha512-Cg7TFGpIr01vOQNODXOOaGz2NpCU5gl8x1qJFbb6hbZxR7XrcE2vtbAsTAbJ7/xwJtUuJEw8K8Zr/AE0LHlesg==",
      "license": "MIT",
      "dependencies": {
        "@babel/runtime": "^7.12.5",
        "cosmiconfig": "^7.0.0",
@@ -2853,20 +2832,16 @@
      }
    },
    "node_modules/babel-plugin-macros/node_modules/resolve": {
      "version": "1.22.10",
      "resolved": "https://registry.npmmirror.com/resolve/-/resolve-1.22.10.tgz",
      "integrity": "sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w==",
      "license": "MIT",
      "version": "1.22.8",
      "resolved": "https://registry.npmmirror.com/resolve/-/resolve-1.22.8.tgz",
      "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==",
      "dependencies": {
        "is-core-module": "^2.16.0",
        "is-core-module": "^2.13.0",
        "path-parse": "^1.0.7",
        "supports-preserve-symlinks-flag": "^1.0.0"
      },
      "bin": {
        "resolve": "bin/resolve"
      },
      "engines": {
        "node": ">= 0.4"
      },
      "funding": {
        "url": "https://github.com/sponsors/ljharb"
@@ -3075,7 +3050,6 @@
      "version": "7.1.0",
      "resolved": "https://registry.npmmirror.com/cosmiconfig/-/cosmiconfig-7.1.0.tgz",
      "integrity": "sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA==",
      "license": "MIT",
      "dependencies": {
        "@types/parse-json": "^4.0.0",
        "import-fresh": "^3.2.1",
@@ -3112,8 +3086,7 @@
    "node_modules/css-mediaquery": {
      "version": "0.1.2",
      "resolved": "https://registry.npmmirror.com/css-mediaquery/-/css-mediaquery-0.1.2.tgz",
      "integrity": "sha512-COtn4EROW5dBGlE/4PiKnh6rZpAPxDeFLaEEwt4i10jpDMFt2EhQGS79QmmrO+iKCHv0PU/HrOWEhijFd1x99Q==",
      "license": "BSD"
      "integrity": "sha512-COtn4EROW5dBGlE/4PiKnh6rZpAPxDeFLaEEwt4i10jpDMFt2EhQGS79QmmrO+iKCHv0PU/HrOWEhijFd1x99Q=="
    },
    "node_modules/csstype": {
      "version": "3.1.3",
@@ -3284,13 +3257,9 @@
      }
    },
    "node_modules/dompurify": {
      "version": "3.2.4",
      "resolved": "https://registry.npmmirror.com/dompurify/-/dompurify-3.2.4.tgz",
      "integrity": "sha512-ysFSFEDVduQpyhzAob/kkuJjf5zWkZD8/A9ywSp1byueyuCfHamrCBa14/Oc2iiB0e51B+NpxSl5gmzn+Ms/mg==",
      "license": "(MPL-2.0 OR Apache-2.0)",
      "optionalDependencies": {
        "@types/trusted-types": "^2.0.7"
      }
      "version": "2.5.6",
      "resolved": "https://registry.npmmirror.com/dompurify/-/dompurify-2.5.6.tgz",
      "integrity": "sha512-zUTaUBO8pY4+iJMPE1B9XlO2tXVYIcEA4SNGtvDELzTSCQO7RzH+j7S180BmhmJId78lqGU2z19vgVx2Sxs/PQ=="
    },
    "node_modules/earcut": {
      "version": "2.2.4",
@@ -3307,7 +3276,6 @@
      "version": "1.3.2",
      "resolved": "https://registry.npmmirror.com/error-ex/-/error-ex-1.3.2.tgz",
      "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==",
      "license": "MIT",
      "dependencies": {
        "is-arrayish": "^0.2.1"
      }
@@ -3945,22 +3913,20 @@
      }
    },
    "node_modules/file-selector": {
      "version": "2.1.2",
      "resolved": "https://registry.npmmirror.com/file-selector/-/file-selector-2.1.2.tgz",
      "integrity": "sha512-QgXo+mXTe8ljeqUFaX3QVHc5osSItJ/Km+xpocx0aSqWGMSCf6qYs/VnzZgS864Pjn5iceMRFigeAV7AfTlaig==",
      "license": "MIT",
      "version": "0.6.0",
      "resolved": "https://registry.npmmirror.com/file-selector/-/file-selector-0.6.0.tgz",
      "integrity": "sha512-QlZ5yJC0VxHxQQsQhXvBaC7VRJ2uaxTf+Tfpu4Z/OcVQJVpZO+DGU0rkoVW5ce2SccxugvpBJoMvUs59iILYdw==",
      "dependencies": {
        "tslib": "^2.7.0"
        "tslib": "^2.4.0"
      },
      "engines": {
        "node": ">= 12"
      }
    },
    "node_modules/file-selector/node_modules/tslib": {
      "version": "2.8.1",
      "resolved": "https://registry.npmmirror.com/tslib/-/tslib-2.8.1.tgz",
      "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==",
      "license": "0BSD"
      "version": "2.6.3",
      "resolved": "https://registry.npmmirror.com/tslib/-/tslib-2.6.3.tgz",
      "integrity": "sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ=="
    },
    "node_modules/fill-range": {
      "version": "7.1.1",
@@ -3985,8 +3951,7 @@
    "node_modules/find-root": {
      "version": "1.1.0",
      "resolved": "https://registry.npmmirror.com/find-root/-/find-root-1.1.0.tgz",
      "integrity": "sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng==",
      "license": "MIT"
      "integrity": "sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng=="
    },
    "node_modules/find-up": {
      "version": "5.0.0",
@@ -4416,6 +4381,11 @@
        "react-is": "^16.7.0"
      }
    },
    "node_modules/hotscript": {
      "version": "1.0.13",
      "resolved": "https://registry.npmmirror.com/hotscript/-/hotscript-1.0.13.tgz",
      "integrity": "sha512-C++tTF1GqkGYecL+2S1wJTfoH6APGAsbb7PAWQ3iVIwgG/EFseAfEVOKFgAFq4yK3+6j1EjUD4UQ9dRJHX/sSQ=="
    },
    "node_modules/ignore": {
      "version": "5.3.2",
      "resolved": "https://registry.npmmirror.com/ignore/-/ignore-5.3.2.tgz",
@@ -4529,8 +4499,7 @@
    "node_modules/is-arrayish": {
      "version": "0.2.1",
      "resolved": "https://registry.npmmirror.com/is-arrayish/-/is-arrayish-0.2.1.tgz",
      "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==",
      "license": "MIT"
      "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg=="
    },
    "node_modules/is-async-function": {
      "version": "2.0.0",
@@ -4588,10 +4557,9 @@
      }
    },
    "node_modules/is-core-module": {
      "version": "2.16.1",
      "resolved": "https://registry.npmmirror.com/is-core-module/-/is-core-module-2.16.1.tgz",
      "integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==",
      "license": "MIT",
      "version": "2.15.1",
      "resolved": "https://registry.npmmirror.com/is-core-module/-/is-core-module-2.15.1.tgz",
      "integrity": "sha512-z0vtXSwucUJtANQWldhbtbt7BnL0vxiFjIdDLAatwhDYty2bad6s+rijD6Ri4YuYJubLzIJLUidCh09e1djEVQ==",
      "dependencies": {
        "hasown": "^2.0.2"
      },
@@ -4930,12 +4898,6 @@
        "js-yaml": "bin/js-yaml.js"
      }
    },
    "node_modules/jsbarcode": {
      "version": "3.11.6",
      "resolved": "https://registry.npmmirror.com/jsbarcode/-/jsbarcode-3.11.6.tgz",
      "integrity": "sha512-G5TKGyKY1zJo0ZQKFM1IIMfy0nF2rs92BLlCz+cU4/TazIc4ZH+X1GYeDRt7TKjrYqmPfTjwTBkU/QnQlsYiuA==",
      "license": "MIT"
    },
    "node_modules/jsesc": {
      "version": "2.5.2",
      "resolved": "https://registry.npmmirror.com/jsesc/-/jsesc-2.5.2.tgz",
@@ -4956,8 +4918,7 @@
    "node_modules/json-parse-even-better-errors": {
      "version": "2.3.1",
      "resolved": "https://registry.npmmirror.com/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz",
      "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==",
      "license": "MIT"
      "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w=="
    },
    "node_modules/json-schema-traverse": {
      "version": "0.4.1",
@@ -5031,8 +4992,7 @@
    "node_modules/lines-and-columns": {
      "version": "1.2.4",
      "resolved": "https://registry.npmmirror.com/lines-and-columns/-/lines-and-columns-1.2.4.tgz",
      "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==",
      "license": "MIT"
      "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg=="
    },
    "node_modules/locate-path": {
      "version": "6.0.0",
@@ -5438,7 +5398,6 @@
      "version": "5.2.0",
      "resolved": "https://registry.npmmirror.com/parse-json/-/parse-json-5.2.0.tgz",
      "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==",
      "license": "MIT",
      "dependencies": {
        "@babel/code-frame": "^7.0.0",
        "error-ex": "^1.3.1",
@@ -5746,12 +5705,6 @@
        "ra-core": "^5.6.3"
      }
    },
    "node_modules/ra-language-chinese": {
      "version": "2.0.10",
      "resolved": "https://registry.npmmirror.com/ra-language-chinese/-/ra-language-chinese-2.0.10.tgz",
      "integrity": "sha512-k+X6XdkBEZnmpKIJZj9Lb77Lj8LCmterilJTj2ovp3i8/H/dLo9IujASfjFypjHnVUpN7Y63LT19kgPrS6+row==",
      "license": "MIT"
    },
    "node_modules/ra-language-english": {
      "version": "5.6.3",
      "resolved": "https://registry.npmjs.org/ra-language-english/-/ra-language-english-5.6.3.tgz",
@@ -5778,154 +5731,38 @@
      }
    },
    "node_modules/react-admin": {
      "version": "5.6.3",
      "resolved": "https://registry.npmmirror.com/react-admin/-/react-admin-5.6.3.tgz",
      "integrity": "sha512-nZAlX1uRKgQKAQcOxMwugkjbDL7CPuU799lxoaxLK59O7AbkQl161uVqWLNUo4eaZRCpXCVqIe2an4lGlxs10g==",
      "license": "MIT",
      "version": "5.1.2",
      "resolved": "https://registry.npmmirror.com/react-admin/-/react-admin-5.1.2.tgz",
      "integrity": "sha512-f3L0XVEQrmMx5kbaApbE4GDJA5oSz9MPORlBD2ZHdVqcTJCfkbbDpR5McTT6Je6QRT8KSrOdWhcJQc3UTdHFyw==",
      "dependencies": {
        "@emotion/react": "^11.14.0",
        "@emotion/styled": "^11.14.0",
        "@mui/icons-material": "^5.16.12 || ^6.0.0",
        "@mui/material": "^5.16.12 || ^6.0.0",
        "ra-core": "^5.6.3",
        "ra-i18n-polyglot": "^5.6.3",
        "ra-language-english": "^5.6.3",
        "ra-ui-materialui": "^5.6.3",
        "react-hook-form": "^7.53.0",
        "react-router": "^6.28.1 || ^7.1.1",
        "react-router-dom": "^6.28.1 || ^7.1.1"
        "@emotion/react": "^11.4.1",
        "@emotion/styled": "^11.3.0",
        "@mui/icons-material": "^5.15.20",
        "@mui/material": "^5.15.20",
        "ra-core": "^5.1.2",
        "ra-i18n-polyglot": "^5.1.2",
        "ra-language-english": "^5.1.2",
        "ra-ui-materialui": "^5.1.2",
        "react-hook-form": "^7.52.0",
        "react-router": "^6.22.0",
        "react-router-dom": "^6.22.0"
      },
      "peerDependencies": {
        "react": "^18.0.0 || ^19.0.0",
        "react-dom": "^18.0.0 || ^19.0.0"
      }
    },
    "node_modules/react-admin/node_modules/@mui/core-downloads-tracker": {
      "version": "6.4.8",
      "resolved": "https://registry.npmmirror.com/@mui/core-downloads-tracker/-/core-downloads-tracker-6.4.8.tgz",
      "integrity": "sha512-vjP4+A1ybyCRhDZC7r5EPWu/gLseFZxaGyPdDl94vzVvk6Yj6gahdaqcjbhkaCrJjdZj90m3VioltWPAnWF/zw==",
      "license": "MIT",
      "funding": {
        "type": "opencollective",
        "url": "https://opencollective.com/mui-org"
      }
    },
    "node_modules/react-admin/node_modules/@mui/icons-material": {
      "version": "6.4.8",
      "resolved": "https://registry.npmmirror.com/@mui/icons-material/-/icons-material-6.4.8.tgz",
      "integrity": "sha512-LKGWiLWRyoOw3dWxZQ+lV//mK+4DVTTAiLd2ljmJdD6XV0rDB8JFKjRD9nyn9cJAU5XgWnii7ZR3c93ttUnMKg==",
      "license": "MIT",
      "dependencies": {
        "@babel/runtime": "^7.26.0"
      },
      "engines": {
        "node": ">=14.0.0"
      },
      "funding": {
        "type": "opencollective",
        "url": "https://opencollective.com/mui-org"
      },
      "peerDependencies": {
        "@mui/material": "^6.4.8",
        "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0",
        "react": "^17.0.0 || ^18.0.0 || ^19.0.0"
      },
      "peerDependenciesMeta": {
        "@types/react": {
          "optional": true
        }
      }
    },
    "node_modules/react-admin/node_modules/@mui/material": {
      "version": "6.4.8",
      "resolved": "https://registry.npmmirror.com/@mui/material/-/material-6.4.8.tgz",
      "integrity": "sha512-5S9UTjKZZBd9GfbcYh/nYfD9cv6OXmj5Y7NgKYfk7JcSoshp8/pW5zP4wecRiroBSZX8wcrywSgogpVNO+5W0Q==",
      "license": "MIT",
      "dependencies": {
        "@babel/runtime": "^7.26.0",
        "@mui/core-downloads-tracker": "^6.4.8",
        "@mui/system": "^6.4.8",
        "@mui/types": "~7.2.24",
        "@mui/utils": "^6.4.8",
        "@popperjs/core": "^2.11.8",
        "@types/react-transition-group": "^4.4.12",
        "clsx": "^2.1.1",
        "csstype": "^3.1.3",
        "prop-types": "^15.8.1",
        "react-is": "^19.0.0",
        "react-transition-group": "^4.4.5"
      },
      "engines": {
        "node": ">=14.0.0"
      },
      "funding": {
        "type": "opencollective",
        "url": "https://opencollective.com/mui-org"
      },
      "peerDependencies": {
        "@emotion/react": "^11.5.0",
        "@emotion/styled": "^11.3.0",
        "@mui/material-pigment-css": "^6.4.8",
        "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0",
        "react": "^17.0.0 || ^18.0.0 || ^19.0.0",
        "react-dom": "^17.0.0 || ^18.0.0 || ^19.0.0"
      },
      "peerDependenciesMeta": {
        "@emotion/react": {
          "optional": true
        },
        "@emotion/styled": {
          "optional": true
        },
        "@mui/material-pigment-css": {
          "optional": true
        },
        "@types/react": {
          "optional": true
        }
      }
    },
    "node_modules/react-admin/node_modules/@mui/utils": {
      "version": "6.4.8",
      "resolved": "https://registry.npmmirror.com/@mui/utils/-/utils-6.4.8.tgz",
      "integrity": "sha512-C86gfiZ5BfZ51KqzqoHi1WuuM2QdSKoFhbkZeAfQRB+jCc4YNhhj11UXFVMMsqBgZ+Zy8IHNJW3M9Wj/LOwRXQ==",
      "license": "MIT",
      "dependencies": {
        "@babel/runtime": "^7.26.0",
        "@mui/types": "~7.2.24",
        "@types/prop-types": "^15.7.14",
        "clsx": "^2.1.1",
        "prop-types": "^15.8.1",
        "react-is": "^19.0.0"
      },
      "engines": {
        "node": ">=14.0.0"
      },
      "funding": {
        "type": "opencollective",
        "url": "https://opencollective.com/mui-org"
      },
      "peerDependencies": {
        "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0",
        "react": "^17.0.0 || ^18.0.0 || ^19.0.0"
      },
      "peerDependenciesMeta": {
        "@types/react": {
          "optional": true
        }
      }
    },
    "node_modules/react-admin/node_modules/ra-ui-materialui": {
      "version": "5.6.3",
      "resolved": "https://registry.npmmirror.com/ra-ui-materialui/-/ra-ui-materialui-5.6.3.tgz",
      "integrity": "sha512-3KOCo0JWBJ5BeqVb8g1cdnw00+GMnpI7jlX1VqX7YIyDT3TwDbFx1sDGUOvNiLrN7qZA5dIrZWfdYlutjZT/2Q==",
      "license": "MIT",
      "version": "5.1.2",
      "resolved": "https://registry.npmmirror.com/ra-ui-materialui/-/ra-ui-materialui-5.1.2.tgz",
      "integrity": "sha512-hhR5+NCC5tDNB6WtPl2sY7mKAqfs4A0S+x2Kh/GsYYxs7nFIRFIBMu7UE40vpVJqFrBCc2fyVB/3d9D2eEdoZA==",
      "dependencies": {
        "@tanstack/react-query": "^5.21.7",
        "@tanstack/react-query": "^5.8.4",
        "autosuggest-highlight": "^3.1.1",
        "clsx": "^2.1.1",
        "css-mediaquery": "^0.1.2",
        "dompurify": "^3.2.4",
        "dompurify": "^2.4.3",
        "hotscript": "^1.0.12",
        "inflection": "^3.0.0",
        "jsonexport": "^3.2.0",
        "lodash": "~4.17.5",
@@ -5935,36 +5772,22 @@
        "react-transition-group": "^4.4.5"
      },
      "peerDependencies": {
        "@mui/icons-material": "^5.16.12 || ^6.0.0",
        "@mui/material": "^5.16.12 || ^6.0.0",
        "@mui/utils": "^5.15.20 || ^6.0.0",
        "@mui/icons-material": "^5.15.20",
        "@mui/material": "^5.15.20",
        "ra-core": "^5.0.0",
        "react": "^18.0.0 || ^19.0.0",
        "react-dom": "^18.0.0 || ^19.0.0",
        "react-hook-form": "*",
        "react-is": "^18.0.0 || ^19.0.0",
        "react-router": "^6.28.1 || ^7.1.1",
        "react-router-dom": "^6.28.1 || ^7.1.1"
        "react-is": "^18.0.0",
        "react-router": "^6.22.0",
        "react-router-dom": "^6.22.0"
      }
    },
    "node_modules/react-admin/node_modules/react-is": {
      "version": "19.0.0",
      "resolved": "https://registry.npmmirror.com/react-is/-/react-is-19.0.0.tgz",
      "integrity": "sha512-H91OHcwjZsbq3ClIDHMzBShc1rotbfACdWENsmEf0IFvZ3FgGPtdHMcsv45bQ1hAbgdfiA8SnxTKfDS+x/8m2g==",
      "license": "MIT"
    },
    "node_modules/react-barcode": {
      "version": "1.6.1",
      "resolved": "https://registry.npmmirror.com/react-barcode/-/react-barcode-1.6.1.tgz",
      "integrity": "sha512-pc4ftnO5syHa/UjCruEeRsomlhoxKSugIgTA8T4dH0fvc89UMHL+/1Sp25IAphqG44pJkE5hMXhv89iS09jQyw==",
      "license": "ISC",
      "dependencies": {
        "jsbarcode": "^3.8.0",
        "prop-types": "^15.6.2"
      },
      "peerDependencies": {
        "react": "16 - 19"
      }
      "version": "18.3.1",
      "resolved": "https://registry.npmmirror.com/react-is/-/react-is-18.3.1.tgz",
      "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==",
      "peer": true
    },
    "node_modules/react-dom": {
      "version": "18.3.1",
@@ -5979,13 +5802,12 @@
      }
    },
    "node_modules/react-dropzone": {
      "version": "14.3.8",
      "resolved": "https://registry.npmmirror.com/react-dropzone/-/react-dropzone-14.3.8.tgz",
      "integrity": "sha512-sBgODnq+lcA4P296DY4wacOZz3JFpD99fp+hb//iBO2HHnyeZU3FwWyXJ6salNpqQdsZrgMrotuko/BdJMV8Ug==",
      "license": "MIT",
      "version": "14.2.3",
      "resolved": "https://registry.npmmirror.com/react-dropzone/-/react-dropzone-14.2.3.tgz",
      "integrity": "sha512-O3om8I+PkFKbxCukfIR3QAGftYXDZfOE2N1mr/7qebQJHs7U+/RSL/9xomJNpRg9kM5h9soQSdf0Gc7OHF5Fug==",
      "dependencies": {
        "attr-accept": "^2.2.4",
        "file-selector": "^2.1.0",
        "attr-accept": "^2.2.2",
        "file-selector": "^0.6.0",
        "prop-types": "^15.8.1"
      },
      "engines": {
@@ -6125,15 +5947,6 @@
        "react": ">= 0.14.0"
      }
    },
    "node_modules/react-to-print": {
      "version": "3.0.5",
      "resolved": "https://registry.npmmirror.com/react-to-print/-/react-to-print-3.0.5.tgz",
      "integrity": "sha512-Z15MwMOzYCHWi26CZeFNwflAg7Nr8uWD6FTj+EkfIOjYyjr0MXGbI0c7rF4Fgrbj3XG9hFndb1ourxpPz2RAiA==",
      "license": "MIT",
      "peerDependencies": {
        "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ~19"
      }
    },
    "node_modules/react-transition-group": {
      "version": "4.4.5",
      "resolved": "https://registry.npmmirror.com/react-transition-group/-/react-transition-group-4.4.5.tgz",
@@ -6226,8 +6039,7 @@
    "node_modules/remove-accents": {
      "version": "0.4.4",
      "resolved": "https://registry.npmmirror.com/remove-accents/-/remove-accents-0.4.4.tgz",
      "integrity": "sha512-EpFcOa/ISetVHEXqu+VwI96KZBmq+a8LJnGkaeFw45epGlxIZz5dhEEnNZMsQXgORu3qaMoLX4qJCzOik6ytAg==",
      "license": "MIT"
      "integrity": "sha512-EpFcOa/ISetVHEXqu+VwI96KZBmq+a8LJnGkaeFw45epGlxIZz5dhEEnNZMsQXgORu3qaMoLX4qJCzOik6ytAg=="
    },
    "node_modules/reselect": {
      "version": "5.1.1",
@@ -6481,7 +6293,6 @@
      "version": "0.5.7",
      "resolved": "https://registry.npmmirror.com/source-map/-/source-map-0.5.7.tgz",
      "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==",
      "license": "BSD-3-Clause",
      "engines": {
        "node": ">=0.10.0"
      }
@@ -7115,7 +6926,6 @@
      "version": "1.10.2",
      "resolved": "https://registry.npmmirror.com/yaml/-/yaml-1.10.2.tgz",
      "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==",
      "license": "ISC",
      "engines": {
        "node": ">= 6"
      }
rsf-admin/src/i18n/en.js
@@ -129,6 +129,8 @@
        loc: 'Loc',
        locType: 'LocType',
        locArea: 'locArea',
        LocAreaMat: 'LocAreaMat',
        locAreaMatRela: 'LocAreaMatRela',
        container: 'Container',
        contract: 'Contract',
        qlyInspect: 'QlyInspect',
@@ -367,6 +369,18 @@
                name: "name",
                code: "code",
                areaId: "areaId",
                locId: "locId",
            },
            locAreaMat: {
                code: "code",
                depict: "depict",
            },
            locAreaMatRela: {
                areaId: "areaId",
                code: "code",
                matnrId: "matnrId",
                groupId: "groupId",
                locTypeId: "locTypeId",
                locId: "locId",
            },
            container: {
@@ -627,7 +641,9 @@
        locInit: 'loc init',
        batch: 'batch',
        confirm: 'confirm',
        subzone: 'subzone'
        subzone: 'subzone',
        bindmatnr: 'bind matnr',
        bindloc: 'bind loc',
    },
};
rsf-admin/src/i18n/zh.js
@@ -129,6 +129,8 @@
        loc: '库位',
        locType: '库位类型',
        locArea: '逻辑分区',
        locAreaMat: '逻辑分区',
        locAreaMatRela: '库区物料关系',
        container: '容器管理',
        contract: '合同信息',
        qlyInspect: '质检信息',
@@ -299,7 +301,7 @@
            warehouseAreas: {
                uuid: "唯一编码",
                name: "名称",
                wareId: "仓库",
                wareId: "所属仓库",
                code: "编码",
                shipperId: "货主",
                supplierId: "供应商",
@@ -367,6 +369,18 @@
                name: "名称",
                code: "编码",
                areaId: "库区",
                locId: "库位",
            },
            locAreaMat: {
                code: "逻辑编码",
                depict: "逻辑描述",
            },
            locAreaMatRela: {
                areaId: "库区",
                code: "编码",
                matnrId: "物料",
                groupId: "物料分组",
                locTypeId: "库位类型",
                locId: "库位",
            },
            container: {
@@ -629,7 +643,9 @@
        locInit: ' 库位初始化',
        batch: '批量操作',
        confirm: '确认',
        subzone: '绑定分区'
        subzone: '绑定分区',
        bindmatnr: '绑定物料',
        bindloc: '绑定库位',
    },
};
rsf-admin/src/page/ResourceContent.js
@@ -27,6 +27,8 @@
import companys from './basicInfo/companys';
import locType from './basicInfo/locType';
import locArea from './basicInfo//locArea';
import locAreaMatRela from './basicInfo/locAreaMatRela';
import locAreaMat from './basicInfo/locAreaMat';
import serialRuleItem from './system/serialRuleItem';
import serialRule from './system/serialRule';
import whMat from './basicInfo/whMat';
@@ -106,6 +108,11 @@
            return locType;
        case 'locArea':
            return locArea;
        case 'locAreaMatRela':
            return locAreaMatRela;
        case 'locAreaMat':
            return locAreaMat;
        default:
            return {
rsf-admin/src/page/asnOrderItem/AsnOrderItemList.jsx
@@ -142,8 +142,6 @@
            preferenceKey='asnOrderItem'
            bulkActionButtons={() => <BulkDeleteButton mutationMode={OPERATE_MODE} />}
            rowClick={(id, resource, record) => false}
            expand={() => <AsnOrderItemPanel />}
            expandSingle={true}
            omit={['id', 'createTime', 'createBy', 'memo']}
          >
            <NumberField source="id" />
rsf-admin/src/page/basicInfo/companys/CompanysEdit.jsx
@@ -50,6 +50,7 @@
            mutationMode={EDIT_MODE}
            actions={<CustomerTopToolBar />}
            aside={<EditBaseAside />}
            title={"menu.companys"}
        >
            <SimpleForm
                shouldUnregister
rsf-admin/src/page/basicInfo/loc/BindModal.jsx
New file
@@ -0,0 +1,197 @@
import React, { useState, useRef, useEffect, useMemo } from "react";
import {
    CreateBase,
    useTranslate,
    TextInput,
    NumberInput,
    BooleanInput,
    DateInput,
    SaveButton,
    SelectInput,
    ReferenceInput,
    ReferenceArrayInput,
    AutocompleteInput,
    Toolbar,
    required,
    useDataProvider,
    useNotify,
    Form,
    useCreateController,
    useListContext,
    useRefresh,
    SelectArrayInput
} from 'react-admin';
import {
    Dialog,
    DialogActions,
    DialogContent,
    DialogTitle,
    Grid,
    TextField,
    Box,
    Button,
    Paper,
    TableContainer,
    Table,
    TableHead,
    TableBody,
    TableRow,
    TableCell,
    Tooltip,
    IconButton,
    styled,
} from '@mui/material';
import DialogCloseButton from "../../components/DialogCloseButton";
import DictionarySelect from "../../components/DictionarySelect";
import { useForm, Controller, useWatch, FormProvider, useFormContext } from "react-hook-form";
import SaveIcon from '@mui/icons-material/Save';
import request from '@/utils/request';
import { Add, Edit, Delete } from '@mui/icons-material';
import _ from 'lodash';
import { DataGrid } from '@mui/x-data-grid';
import StatusSelectInput from "../../components/StatusSelectInput";
import TreeSelectInput from "@/page/components/TreeSelectInput";
const MatnrModal = ({ open, setOpen }) => {
    const refresh = useRefresh();
    const translate = useTranslate();
    const notify = useNotify();
    const [formData, setFormData] = useState({
        areaId: null,
        groupId: null,
        matnrId: null,
    });
    const { selectedIds, onUnselectItems } = useListContext();
    const handleClose = (event, reason) => {
        if (reason !== "backdropClick") {
            setOpen(false);
            reset()
            refresh();
            onUnselectItems()
        }
    };
    const reset = () => {
        setFormData({
            areaId: null,
            groupId: null,
            matnrId: null,
        })
    }
    const handleReset = (e) => {
        e.preventDefault();
    };
    const handleChange = (value, name) => {
        setFormData((prevData) => ({
            ...prevData,
            [name]: value
        }));
        refresh()
    };
    const removeEmptyKeys = (obj) => {
        return _.pickBy(obj, (value) => {
            if (_.isObject(value)) {
                const newObj = removeEmptyKeys(value);
                return !_.isEmpty(newObj);
            }
            return !_.isNil(value) && (_.isNumber(value) ? value !== 0 : !_.isEmpty(value));
        });
    }
    const handleSubmit = async () => {
        const parmas = {
            locId: selectedIds,
            areaId: formData.areaId,
            matnrId: formData.matnrId,
        }
        const res = await request.post(`/locAreaMatRela/matnr/bind`, parmas);
        if (res?.data?.code === 200) {
            handleClose()
        } else {
            notify(res.data.msg);
        }
    }
    const [groupId, setGroupId] = useState();
    const warehouseChange = (e) => {
        setGroupId(e.target.value)
    }
    return (
        <Dialog open={open} maxWidth="md" fullWidth>
            <Form onSubmit={handleSubmit}>
                <DialogCloseButton onClose={handleClose} />
                <DialogTitle>{translate('toolbar.bindmatnr')}</DialogTitle>
                <DialogContent sx={{ mt: 2 }}>
                    <Box sx={{ display: 'flex', flexDirection: 'column', gap: 3 }}>
                        <Grid container spacing={2}>
                            <Grid item xs={4}>
                                <ReferenceInput
                                    source="areaId"
                                    reference="warehouseAreas"
                                >
                                    <AutocompleteInput
                                        label="table.field.loc.areaId"
                                        optionText="name"
                                        onChange={(value) => handleChange(value, 'areaId')}
                                        value={formData.areaId}
                                        validate={required()}
                                        filterToQuery={(val) => ({ name: val })}
                                    />
                                </ReferenceInput>
                            </Grid>
                            <Grid item xs={4}>
                                <TreeSelectInput
                                    label="table.field.locAreaMatRela.groupId"
                                    resource={'matnrGroup'}
                                    source="groupId"
                                    value={formData.groupId}
                                    onChange={(e) => handleChange(e.target.value, 'groupId')}
                                />
                            </Grid>
                            <Grid item xs={4}>
                                <ReferenceArrayInput source="matnrId" reference="matnr" filter={{ groupId: formData.groupId }}>
                                    <SelectArrayInput
                                        label="table.field.locAreaMatRela.matnrId"
                                        validate={required()}
                                        value={formData.matnrId}
                                        onChange={(e) => handleChange(e.target.value, 'matnrId')}
                                    />
                                </ReferenceArrayInput>
                            </Grid>
                        </Grid>
                    </Box>
                </DialogContent>
                <DialogActions sx={{ position: 'sticky', bottom: 0, backgroundColor: 'background.paper', zIndex: 1000 }}>
                    <Box sx={{ width: '100%', display: 'flex', justifyContent: 'space-between' }}>
                        <Button type="submit" variant="contained" startIcon={<SaveIcon />}>
                            {translate('toolbar.confirm')}
                        </Button>
                    </Box>
                </DialogActions>
            </Form>
        </Dialog>
    );
}
export default MatnrModal;
rsf-admin/src/page/basicInfo/loc/InitModal.jsx
@@ -153,7 +153,7 @@
                            <Grid item xs={4}>
                                <ReferenceArrayInput source="typeIds" reference="locType" >
                                    <SelectArrayInput label="table.field.loc.type" onChange={(e) => handleChange(e.target.value, 'typeIds')} />
                                    <SelectArrayInput label="table.field.loc.type" onChange={(e) => handleChange(e.target.value, 'typeIds')} validate={[required()]} />
                                </ReferenceArrayInput>
                            </Grid>
rsf-admin/src/page/basicInfo/loc/LocCreate.jsx
@@ -270,6 +270,7 @@
                                        label={translate("table.field.loc.useStatus")}
                                        name="useStatus"
                                        size="small"
                                        validate={[required()]}
                                        dictTypeCode="sys_loc_use_stas"
                                    />
                                    {/* <ReferenceInput
rsf-admin/src/page/basicInfo/loc/LocEdit.jsx
@@ -59,6 +59,7 @@
            mutationMode={EDIT_MODE}
            actions={<CustomerTopToolBar />}
            aside={<EditBaseAside />}
            title={"menu.loc"}
        >
            <SimpleForm
                shouldUnregister
@@ -177,6 +178,7 @@
                                <DictionarySelect
                                    label={translate("table.field.loc.useStatus")}
                                    name="useStatus"
                                    validate={[required()]}
                                    size="small"
                                    dictTypeCode="sys_loc_use_stas"
                                />
rsf-admin/src/page/basicInfo/loc/LocList.jsx
@@ -38,7 +38,7 @@
import { Box, Typography, Card, Stack } from '@mui/material';
import { styled } from '@mui/material/styles';
import LocCreate from "./LocCreate";
import LocPanel from "./LocPanel";
import BindModal from "./BindModal";
import EmptyData from "../../components/EmptyData";
import DynamicField from "../../components/DynamicField";
import MyCreateButton from "../../components/MyCreateButton";
@@ -54,7 +54,7 @@
import EditIcon from '@mui/icons-material/Edit';
import request from '@/utils/request';
import DiscountIcon from '@mui/icons-material/Discount';
import { textAlign } from "@mui/system";
import LinkIcon from '@mui/icons-material/Link';
const StyledDatagrid = styled(DatagridConfigurable)(({ theme }) => ({
    '& .css-1vooibu-MuiSvgIcon-root': {
@@ -70,14 +70,17 @@
    },
    '& .RaDatagrid-headerCell': {
        textAlign: 'left'
    },
    '& .RaDatagrid-rowCell': {
        textAlign: 'left'
    }
}));
const filters = [
    <SearchInput source="condition" alwaysOn />,
    <NumberField source="warehouseId$" label="table.field.loc.warehouseId" />,
    <NumberField source="areaId$" label="table.field.loc.areaId" />,
    <TextInput source="warehouseId$" label="table.field.loc.warehouseId" />,
    <TextInput source="areaId$" label="table.field.loc.areaId" />,
    <TextInput source="code" label="table.field.loc.code" />,
    <TextInput source="type" label="table.field.loc.type" />,
    <TextInput source="name" label="table.field.loc.name" />,
@@ -148,6 +151,7 @@
                    bulkActionButtons={
                        <>
                            <BatchButton />
                            <BindButton />
                            <SubzoneButton />
                            <BulkDeleteButton />
                        </>
@@ -157,9 +161,9 @@
                >
                    <NumberField source="id" />
                    <NumberField source="warehouseId$" label="table.field.loc.warehouseId" />
                    <NumberField source="areaId$" label="table.field.loc.areaId" align="left" />
                    <TextField source="code" label="table.field.loc.code" align="left" />
                    <TextField source="typeIds$" label="table.field.loc.type" align="left" />
                    <NumberField source="areaId$" label="table.field.loc.areaId" />
                    <TextField source="code" label="table.field.loc.code" />
                    <TextField source="typeIds$" label="table.field.loc.type" />
                    {/* <TextField source="name" label="table.field.loc.name" /> */}
                    {/* <NumberField source="flagLogic" label="table.field.loc.flagLogic" />
                    <TextField source="fucAtrrs" label="table.field.loc.fucAtrrs" />
@@ -282,4 +286,27 @@
        </>
    )
}
const BindButton = () => {
    const record = useRecordContext();
    const notify = useNotify();
    const refresh = useRefresh();
    const [createDialog, setCreateDialog] = useState(false);
    return (
        <>
            <Button onClick={() => setCreateDialog(true)} label={"toolbar.bindmatnr"}>
                <LinkIcon />
            </Button>
            <BindModal
                open={createDialog}
                setOpen={setCreateDialog}
            />
        </>
    )
}
rsf-admin/src/page/basicInfo/locArea/LocAreaCreate.jsx
@@ -88,6 +88,7 @@
                                    <TextInput
                                        label="table.field.locArea.name"
                                        source="name"
                                        validate={[required()]}
                                        parse={v => v}
                                        autoFocus
                                    />
@@ -107,6 +108,7 @@
                                        <AutocompleteInput
                                            label="table.field.locArea.areaId"
                                            optionText="name"
                                            validate={[required()]}
                                            filterToQuery={(val) => ({ name: val })}
                                        />
                                    </ReferenceInput>
rsf-admin/src/page/basicInfo/locArea/LocAreaEdit.jsx
@@ -49,6 +49,7 @@
            mutationMode={EDIT_MODE}
            actions={<CustomerTopToolBar />}
            aside={<EditBaseAside />}
            title={"menu.locArea"}
        >
            <SimpleForm
                shouldUnregister
@@ -67,6 +68,7 @@
                            <TextInput
                                label="table.field.locArea.name"
                                source="name"
                                validate={[required()]}
                                parse={v => v}
                                autoFocus
                            />
@@ -86,6 +88,7 @@
                                <AutocompleteInput
                                    label="table.field.locArea.areaId"
                                    optionText="name"
                                    validate={[required()]}
                                    filterToQuery={(val) => ({ name: val })}
                                />
                            </ReferenceInput>
rsf-admin/src/page/basicInfo/locArea/LocAreaList.jsx
@@ -115,8 +115,6 @@
                    preferenceKey='locArea'
                    bulkActionButtons={() => <BulkDeleteButton mutationMode={OPERATE_MODE} />}
                    rowClick={(id, resource, record) => false}
                    expand={() => <LocAreaPanel />}
                    expandSingle={true}
                    omit={['id', 'createTime', 'createBy', 'memo']}
                >
                    <NumberField source="id" />
rsf-admin/src/page/basicInfo/locAreaMat/BindLocModal.jsx
New file
@@ -0,0 +1,220 @@
import React, { useState, useRef, useEffect, useMemo } from "react";
import {
    CreateBase,
    useTranslate,
    TextInput,
    NumberInput,
    BooleanInput,
    DateInput,
    SaveButton,
    SelectInput,
    ReferenceInput,
    ReferenceArrayInput,
    AutocompleteInput,
    Toolbar,
    required,
    useDataProvider,
    useNotify,
    Form,
    useCreateController,
    useListContext,
    useRefresh,
    SelectArrayInput,
    useRecordContext,
} from 'react-admin';
import {
    Dialog,
    DialogActions,
    DialogContent,
    DialogTitle,
    Grid,
    TextField,
    Box,
    Button,
    Paper,
    TableContainer,
    Table,
    TableHead,
    TableBody,
    TableRow,
    TableCell,
    Tooltip,
    IconButton,
    styled,
} from '@mui/material';
import DialogCloseButton from "../../components/DialogCloseButton";
import DictionarySelect from "../../components/DictionarySelect";
import { useForm, Controller, useWatch, FormProvider, useFormContext } from "react-hook-form";
import SaveIcon from '@mui/icons-material/Save';
import request from '@/utils/request';
import { Add, Edit, Delete } from '@mui/icons-material';
import _ from 'lodash';
import { DataGrid } from '@mui/x-data-grid';
import StatusSelectInput from "../../components/StatusSelectInput";
import TreeSelectInput from "@/page/components/TreeSelectInput";
const BindMatnrModal = ({ open, setOpen, reload }) => {
    const refresh = useRefresh();
    const translate = useTranslate();
    const record = useRecordContext();
    const notify = useNotify();
    const [formData, setFormData] = useState({
        areaId: null,
        warehouseId: null,
        matnrId: null,
        typeId: null,
    });
    const handleClose = (event, reason) => {
        if (reason !== "backdropClick") {
            setOpen(false);
            reset()
        }
    };
    const reset = () => {
        setFormData({
            areaId: null,
            matnrId: null,
            warehouseId: null,
            typeId: null,
        })
    }
    const handleChange = (value, name) => {
        setFormData((prevData) => ({
            ...prevData,
            [name]: value
        }));
        refresh()
    };
    const removeEmptyKeys = (obj) => {
        return _.pickBy(obj, (value) => {
            if (_.isObject(value)) {
                const newObj = removeEmptyKeys(value);
                return !_.isEmpty(newObj);
            }
            return !_.isNil(value) && (_.isNumber(value) ? value !== 0 : !_.isEmpty(value));
        });
    }
    const handleSubmit = async () => {
        const parmas = {
            areaMatId: record.id,
            matnrId: formData.matnrId,
            areaId: formData.areaId,
            warehouseId: formData.warehouseId,
            typeId: formData.typeId,
        }
        const res = await request.post(`/locAreaMatRela/matnr/bind`, parmas);
        if (res?.data?.code === 200) {
            handleClose()
            reload()
        } else {
            notify(res.data.msg);
        }
    }
    const [groupId, setGroupId] = useState();
    const warehouseChange = (e) => {
        setGroupId(e.target.value)
    }
    return (
        <Dialog open={open} maxWidth="md" fullWidth>
            <Form onSubmit={handleSubmit}>
                <DialogCloseButton onClose={handleClose} />
                <DialogTitle>{translate('toolbar.bindmatnr')}</DialogTitle>
                <DialogContent sx={{ mt: 2 }}>
                    <Box sx={{ display: 'flex', flexDirection: 'column', gap: 3 }}>
                        <Grid container spacing={2}>
                            <Grid item xs={4}>
                                <ReferenceInput
                                    source="warehouseId"
                                    reference="warehouse"
                                >
                                    <AutocompleteInput
                                        label="table.field.loc.warehouseId"
                                        optionText="name"
                                        onChange={(value) => handleChange(value, 'warehouseId')}
                                        value={formData.warehouseId}
                                        validate={required()}
                                        filterToQuery={(val) => ({ name: val })}
                                    />
                                </ReferenceInput>
                            </Grid>
                            <Grid item xs={4}>
                                <ReferenceInput
                                    source="areaId"
                                    reference="warehouseAreas"
                                >
                                    <AutocompleteInput
                                        label="table.field.loc.areaId"
                                        optionText="name"
                                        onChange={(value) => handleChange(value, 'areaId')}
                                        value={formData.areaId}
                                        validate={required()}
                                        filterToQuery={(val) => ({ name: val })}
                                    />
                                </ReferenceInput>
                            </Grid>
                            <Grid item xs={4}>
                                <ReferenceArrayInput source="typeId" reference="locType" >
                                    <SelectArrayInput
                                        label="table.field.locAreaMatRela.locTypeId"
                                        validate={required()}
                                        optionText={'name'}
                                        value={formData.typeId}
                                        onChange={(e) => handleChange(e.target.value, 'typeId')}
                                    />
                                </ReferenceArrayInput>
                            </Grid>
                            <Grid item xs={4}>
                                <ReferenceArrayInput source="matnrId" reference="matnr" filter={{ groupId: formData.groupId }}>
                                    <SelectArrayInput
                                        label="table.field.locAreaMatRela.matnrId"
                                        validate={required()}
                                        value={formData.matnrId}
                                        onChange={(e) => handleChange(e.target.value, 'matnrId')}
                                    />
                                </ReferenceArrayInput>
                            </Grid>
                        </Grid>
                    </Box>
                </DialogContent>
                <DialogActions sx={{ position: 'sticky', bottom: 0, backgroundColor: 'background.paper', zIndex: 1000 }}>
                    <Box sx={{ width: '100%', display: 'flex', justifyContent: 'space-between' }}>
                        <Button type="submit" variant="contained" startIcon={<SaveIcon />}>
                            {translate('toolbar.confirm')}
                        </Button>
                    </Box>
                </DialogActions>
            </Form>
        </Dialog>
    );
}
export default BindMatnrModal;
rsf-admin/src/page/basicInfo/locAreaMat/BindMatnrModal.jsx
New file
@@ -0,0 +1,216 @@
import React, { useState, useRef, useEffect, useMemo } from "react";
import {
    CreateBase,
    useTranslate,
    TextInput,
    NumberInput,
    BooleanInput,
    DateInput,
    SaveButton,
    SelectInput,
    ReferenceInput,
    ReferenceArrayInput,
    AutocompleteInput,
    Toolbar,
    required,
    useDataProvider,
    useNotify,
    Form,
    useCreateController,
    useListContext,
    useRefresh,
    SelectArrayInput,
    useRecordContext,
} from 'react-admin';
import {
    Dialog,
    DialogActions,
    DialogContent,
    DialogTitle,
    Grid,
    TextField,
    Box,
    Button,
    Paper,
    TableContainer,
    Table,
    TableHead,
    TableBody,
    TableRow,
    TableCell,
    Tooltip,
    IconButton,
    styled,
} from '@mui/material';
import DialogCloseButton from "../../components/DialogCloseButton";
import DictionarySelect from "../../components/DictionarySelect";
import { useForm, Controller, useWatch, FormProvider, useFormContext } from "react-hook-form";
import SaveIcon from '@mui/icons-material/Save';
import request from '@/utils/request';
import { Add, Edit, Delete } from '@mui/icons-material';
import _ from 'lodash';
import { DataGrid } from '@mui/x-data-grid';
import StatusSelectInput from "../../components/StatusSelectInput";
import TreeSelectInput from "@/page/components/TreeSelectInput";
const BindMatnrModal = ({ open, setOpen, reload }) => {
    const refresh = useRefresh();
    const translate = useTranslate();
    const record = useRecordContext();
    const notify = useNotify();
    const [formData, setFormData] = useState({
        areaId: null,
        warehouseId: null,
        groupId: null,
        locId: null,
    });
    const handleClose = (event, reason) => {
        if (reason !== "backdropClick") {
            setOpen(false);
            reset()
        }
    };
    const reset = () => {
        setFormData({
            areaId: null,
            warehouseId: null,
            groupId: null,
            locId: null,
        })
    }
    const handleChange = (value, name) => {
        setFormData((prevData) => ({
            ...prevData,
            [name]: value
        }));
        refresh()
    };
    const removeEmptyKeys = (obj) => {
        return _.pickBy(obj, (value) => {
            if (_.isObject(value)) {
                const newObj = removeEmptyKeys(value);
                return !_.isEmpty(newObj);
            }
            return !_.isNil(value) && (_.isNumber(value) ? value !== 0 : !_.isEmpty(value));
        });
    }
    const handleSubmit = async () => {
        const parmas = {
            areaMatId: record.id,
            groupId: [formData.groupId],
            areaId: formData.areaId,
            warehouseId: formData.warehouseId,
            locId: formData.locId,
        }
        const res = await request.post(`/locAreaMatRela/matnr/bind`, parmas);
        if (res?.data?.code === 200) {
            handleClose()
            reload()
        } else {
            notify(res.data.msg);
        }
    }
    const [groupId, setGroupId] = useState();
    const warehouseChange = (e) => {
        setGroupId(e.target.value)
    }
    return (
        <Dialog open={open} maxWidth="md" fullWidth>
            <Form onSubmit={handleSubmit}>
                <DialogCloseButton onClose={handleClose} />
                <DialogTitle>{translate('toolbar.bindloc')}</DialogTitle>
                <DialogContent sx={{ mt: 2 }}>
                    <Box sx={{ display: 'flex', flexDirection: 'column', gap: 3 }}>
                        <Grid container spacing={2}>
                            <Grid item xs={4}>
                                <ReferenceInput
                                    source="warehouseId"
                                    reference="warehouse"
                                >
                                    <AutocompleteInput
                                        label="table.field.loc.warehouseId"
                                        optionText="name"
                                        onChange={(value) => handleChange(value, 'warehouseId')}
                                        value={formData.warehouseId}
                                        validate={required()}
                                        filterToQuery={(val) => ({ name: val })}
                                    />
                                </ReferenceInput>
                            </Grid>
                            <Grid item xs={4}>
                                <ReferenceInput
                                    source="areaId"
                                    reference="warehouseAreas"
                                >
                                    <AutocompleteInput
                                        label="table.field.loc.areaId"
                                        optionText="name"
                                        onChange={(value) => handleChange(value, 'areaId')}
                                        value={formData.areaId}
                                        validate={required()}
                                        filterToQuery={(val) => ({ name: val })}
                                    />
                                </ReferenceInput>
                            </Grid>
                            <Grid item xs={4}>
                                <TreeSelectInput
                                    label="table.field.locAreaMatRela.groupId"
                                    resource={'matnrGroup'}
                                    source="groupId"
                                    value={formData.groupId}
                                    onChange={(e) => handleChange(e.target.value, 'groupId')}
                                />
                            </Grid>
                            <Grid item xs={4}>
                                <ReferenceArrayInput source="locId" reference="loc" >
                                    <SelectArrayInput
                                        label="table.field.locAreaMatRela.locId"
                                        validate={required()}
                                        optionText={'code'}
                                        value={formData.locId}
                                        onChange={(e) => handleChange(e.target.value, 'locId')}
                                    />
                                </ReferenceArrayInput>
                            </Grid>
                        </Grid>
                    </Box>
                </DialogContent>
                <DialogActions sx={{ position: 'sticky', bottom: 0, backgroundColor: 'background.paper', zIndex: 1000 }}>
                    <Box sx={{ width: '100%', display: 'flex', justifyContent: 'space-between' }}>
                        <Button type="submit" variant="contained" startIcon={<SaveIcon />}>
                            {translate('toolbar.confirm')}
                        </Button>
                    </Box>
                </DialogActions>
            </Form>
        </Dialog>
    );
}
export default BindMatnrModal;
rsf-admin/src/page/basicInfo/locAreaMat/LocAreaMatCreate.jsx
New file
@@ -0,0 +1,137 @@
import React, { useState, useRef, useEffect, useMemo } from "react";
import {
    CreateBase,
    useTranslate,
    TextInput,
    NumberInput,
    BooleanInput,
    DateInput,
    SaveButton,
    SelectInput,
    ReferenceInput,
    ReferenceArrayInput,
    AutocompleteInput,
    Toolbar,
    required,
    useDataProvider,
    useNotify,
    Form,
    useCreateController,
} from 'react-admin';
import {
    Dialog,
    DialogActions,
    DialogContent,
    DialogTitle,
    Stack,
    Grid,
    Box,
} from '@mui/material';
import DialogCloseButton from "../../components/DialogCloseButton";
import StatusSelectInput from "../../components/StatusSelectInput";
import MemoInput from "../../components/MemoInput";
const LocAreaMatCreate = (props) => {
    const { open, setOpen } = props;
    const translate = useTranslate();
    const notify = useNotify();
    const handleClose = (event, reason) => {
        if (reason !== "backdropClick") {
            setOpen(false);
        }
    };
    const handleSuccess = async (data) => {
        setOpen(false);
        notify('common.response.success');
    };
    const handleError = async (error) => {
        notify(error.message || 'common.response.fail', { type: 'error', messageArgs: { _: error.message } });
    };
    return (
        <>
            <CreateBase
                record={{}}
                transform={(data) => {
                    return data;
                }}
                mutationOptions={{ onSuccess: handleSuccess, onError: handleError }}
            >
                <Dialog
                    open={open}
                    onClose={handleClose}
                    aria-labelledby="form-dialog-title"
                    fullWidth
                    disableRestoreFocus
                    maxWidth="md"   // 'xs' | 'sm' | 'md' | 'lg' | 'xl'
                >
                    <Form>
                        <DialogTitle id="form-dialog-title" sx={{
                            position: 'sticky',
                            top: 0,
                            backgroundColor: 'background.paper',
                            zIndex: 1000
                        }}
                        >
                            {translate('create.title')}
                            <Box sx={{ position: 'absolute', top: 8, right: 8, zIndex: 1001 }}>
                                <DialogCloseButton onClose={handleClose} />
                            </Box>
                        </DialogTitle>
                        <DialogContent sx={{ mt: 2 }}>
                            <Grid container rowSpacing={2} columnSpacing={2}>
                                <Grid item xs={6} display="flex" gap={1}>
                                    <TextInput
                                        label="table.field.locAreaMat.code"
                                        source="code"
                                        parse={v => v}
                                        autoFocus
                                    />
                                </Grid>
                                {/* <Grid item xs={6} display="flex" gap={1}>
                                    <NumberInput
                                        label="table.field.locAreaMat.warehouseId"
                                        source="warehouseId"
                                    />
                                </Grid>
                                <Grid item xs={6} display="flex" gap={1}>
                                    <NumberInput
                                        label="table.field.locAreaMat.areaId"
                                        source="areaId"
                                    />
                                </Grid> */}
                                <Grid item xs={6} display="flex" gap={1}>
                                    <TextInput
                                        label="table.field.locAreaMat.depict"
                                        source="depict"
                                        parse={v => v}
                                    />
                                </Grid>
                                <Grid item xs={6} display="flex" gap={1}>
                                    <StatusSelectInput />
                                </Grid>
                                <Grid item xs={12} display="flex" gap={1}>
                                    <Stack direction="column" spacing={1} width={'100%'}>
                                        <MemoInput />
                                    </Stack>
                                </Grid>
                            </Grid>
                        </DialogContent>
                        <DialogActions sx={{ position: 'sticky', bottom: 0, backgroundColor: 'background.paper', zIndex: 1000 }}>
                            <Toolbar sx={{ width: '100%', justifyContent: 'space-between' }}  >
                                <SaveButton />
                            </Toolbar>
                        </DialogActions>
                    </Form>
                </Dialog>
            </CreateBase>
        </>
    )
}
export default LocAreaMatCreate;
rsf-admin/src/page/basicInfo/locAreaMat/LocAreaMatEdit.jsx
New file
@@ -0,0 +1,109 @@
import React, { useState, useRef, useEffect, useMemo } from "react";
import {
    Edit,
    SimpleForm,
    FormDataConsumer,
    useTranslate,
    TextInput,
    NumberInput,
    BooleanInput,
    DateInput,
    SelectInput,
    ReferenceInput,
    ReferenceArrayInput,
    AutocompleteInput,
    SaveButton,
    Toolbar,
    Labeled,
    NumberField,
    required,
    useRecordContext,
    DeleteButton,
} from 'react-admin';
import { useWatch, useFormContext } from "react-hook-form";
import { Stack, Grid, Box, Typography } from '@mui/material';
import * as Common from '@/utils/common';
import { EDIT_MODE, REFERENCE_INPUT_PAGESIZE } from '@/config/setting';
import EditBaseAside from "../../components/EditBaseAside";
import CustomerTopToolBar from "../../components/EditTopToolBar";
import MemoInput from "../../components/MemoInput";
import StatusSelectInput from "../../components/StatusSelectInput";
const FormToolbar = () => {
    const { getValues } = useFormContext();
    return (
        <Toolbar sx={{ justifyContent: 'space-between' }}>
            <SaveButton />
            <DeleteButton mutationMode="optimistic" />
        </Toolbar>
    )
}
const LocAreaMatEdit = () => {
    const translate = useTranslate();
    return (
        <Edit
            redirect="list"
            mutationMode={EDIT_MODE}
            actions={<CustomerTopToolBar />}
            aside={<EditBaseAside />}
        >
            <SimpleForm
                shouldUnregister
                warnWhenUnsavedChanges
                toolbar={<FormToolbar />}
                mode="onTouched"
                defaultValues={{}}
            // validate={(values) => { }}
            >
                <Grid container width={{ xs: '100%', xl: '80%' }} rowSpacing={3} columnSpacing={3}>
                    <Grid item xs={12} md={8}>
                        <Typography variant="h6" gutterBottom>
                            {translate('common.edit.title.main')}
                        </Typography>
                        <Stack direction='row' gap={2}>
                            <TextInput
                                label="table.field.locAreaMat.code"
                                source="code"
                                parse={v => v}
                                autoFocus
                            />
                        </Stack>
                        {/* <Stack direction='row' gap={2}>
                            <NumberInput
                                label="table.field.locAreaMat.warehouseId"
                                source="warehouseId"
                            />
                        </Stack>
                        <Stack direction='row' gap={2}>
                            <NumberInput
                                label="table.field.locAreaMat.areaId"
                                source="areaId"
                            />
                        </Stack> */}
                        <Stack direction='row' gap={2}>
                            <TextInput
                                label="table.field.locAreaMat.depict"
                                source="depict"
                                parse={v => v}
                            />
                        </Stack>
                    </Grid>
                    <Grid item xs={12} md={4}>
                        <Typography variant="h6" gutterBottom>
                            {translate('common.edit.title.common')}
                        </Typography>
                        <StatusSelectInput />
                        <Box mt="2em" />
                        <MemoInput />
                    </Grid>
                </Grid>
            </SimpleForm>
        </Edit >
    )
}
export default LocAreaMatEdit;
rsf-admin/src/page/basicInfo/locAreaMat/LocAreaMatList.jsx
New file
@@ -0,0 +1,156 @@
import React, { useState, useRef, useEffect, useMemo, useCallback } from "react";
import { useNavigate } from 'react-router-dom';
import {
    List,
    DatagridConfigurable,
    SearchInput,
    TopToolbar,
    SelectColumnsButton,
    EditButton,
    FilterButton,
    CreateButton,
    ExportButton,
    BulkDeleteButton,
    WrapperField,
    useRecordContext,
    useTranslate,
    useNotify,
    useListContext,
    FunctionField,
    TextField,
    NumberField,
    DateField,
    BooleanField,
    ReferenceField,
    TextInput,
    DateTimeInput,
    DateInput,
    SelectInput,
    NumberInput,
    ReferenceInput,
    ReferenceArrayInput,
    AutocompleteInput,
    DeleteButton,
} from 'react-admin';
import { Box, Typography, Card, Stack } from '@mui/material';
import { styled } from '@mui/material/styles';
import LocAreaMatCreate from "./LocAreaMatCreate";
import LocAreaMatPanel from "./LocAreaMatPanel";
import EmptyData from "../../components/EmptyData";
import MyCreateButton from "../../components/MyCreateButton";
import MyExportButton from '../../components/MyExportButton';
import PageDrawer from "../../components/PageDrawer";
import MyField from "../../components/MyField";
import { PAGE_DRAWER_WIDTH, OPERATE_MODE, DEFAULT_PAGE_SIZE } from '@/config/setting';
import * as Common from '@/utils/common';
const StyledDatagrid = styled(DatagridConfigurable)(({ theme }) => ({
    '& .css-1vooibu-MuiSvgIcon-root': {
        height: '.9em'
    },
    '& .RaDatagrid-row': {
        cursor: 'auto'
    },
    '& .column-name': {
    },
    '& .opt': {
        width: 200
    },
}));
const filters = [
    <SearchInput source="condition" alwaysOn />,
    <TextInput source="code" label="table.field.locAreaMat.code" />,
    <NumberInput source="warehouseId" label="table.field.locAreaMat.warehouseId" />,
    <NumberInput source="areaId" label="table.field.locAreaMat.areaId" />,
    <TextInput source="depict" label="table.field.locAreaMat.depict" />,
    <TextInput label="common.field.memo" source="memo" />,
    <SelectInput
        label="common.field.status"
        source="status"
        choices={[
            { id: '1', name: 'common.enums.statusTrue' },
            { id: '0', name: 'common.enums.statusFalse' },
        ]}
        resettable
    />,
]
const LocAreaMatList = () => {
    const translate = useTranslate();
    const [createDialog, setCreateDialog] = useState(false);
    const [drawerVal, setDrawerVal] = useState(false);
    return (
        <Box display="flex">
            <List
                sx={{
                    flexGrow: 1,
                    transition: (theme) =>
                        theme.transitions.create(['all'], {
                            duration: theme.transitions.duration.enteringScreen,
                        }),
                    marginRight: drawerVal ? `${PAGE_DRAWER_WIDTH}px` : 0,
                }}
                title={"menu.locAreaMat"}
                empty={<EmptyData onClick={() => { setCreateDialog(true) }} />}
                filters={filters}
                sort={{ field: "create_time", order: "desc" }}
                actions={(
                    <TopToolbar>
                        <FilterButton />
                        <MyCreateButton onClick={() => { setCreateDialog(true) }} />
                        <SelectColumnsButton preferenceKey='locAreaMat' />
                        <MyExportButton />
                    </TopToolbar>
                )}
                perPage={DEFAULT_PAGE_SIZE}
            >
                <StyledDatagrid
                    preferenceKey='locAreaMat'
                    bulkActionButtons={() => <BulkDeleteButton mutationMode={OPERATE_MODE} />}
                    rowClick={(id, resource, record) => false}
                    expand={() => <LocAreaMatPanel />}
                    expandSingle={true}
                    omit={['id', 'createTime', 'createBy', 'memo']}
                >
                    <NumberField source="id" />
                    <TextField source="code" label="table.field.locAreaMat.code" />
                    {/* <NumberField source="warehouseId" label="table.field.locAreaMat.warehouseId" />
                    <NumberField source="areaId" label="table.field.locAreaMat.areaId" /> */}
                    <TextField source="depict" label="table.field.locAreaMat.depict" />
                    <ReferenceField source="updateBy" label="common.field.updateBy" reference="user" link={false} sortable={false}>
                        <TextField source="nickname" />
                    </ReferenceField>
                    <DateField source="updateTime" label="common.field.updateTime" showTime />
                    <ReferenceField source="createBy" label="common.field.createBy" reference="user" link={false} sortable={false}>
                        <TextField source="nickname" />
                    </ReferenceField>
                    <DateField source="createTime" label="common.field.createTime" showTime />
                    <BooleanField source="statusBool" label="common.field.status" sortable={false} />
                    <TextField source="memo" label="common.field.memo" sortable={false} />
                    <WrapperField cellClassName="opt" label="common.field.opt">
                        <EditButton sx={{ padding: '1px', fontSize: '.75rem' }} />
                        <DeleteButton sx={{ padding: '1px', fontSize: '.75rem' }} mutationMode={OPERATE_MODE} />
                    </WrapperField>
                </StyledDatagrid>
            </List>
            <LocAreaMatCreate
                open={createDialog}
                setOpen={setCreateDialog}
            />
            <PageDrawer
                title='LocAreaMat Detail'
                drawerVal={drawerVal}
                setDrawerVal={setDrawerVal}
            >
            </PageDrawer>
        </Box>
    )
}
export default LocAreaMatList;
rsf-admin/src/page/basicInfo/locAreaMat/LocAreaMatPanel.jsx
New file
@@ -0,0 +1,411 @@
import React, { useState, useRef, useEffect } from "react";
import {
    Grid, Card, Typography, Button, Checkbox, Tooltip,
    IconButton,
} from '@mui/material';
import { useTranslate, useRecordContext, useNotify } from 'react-admin';
import { RichTreeView } from '@mui/x-tree-view/RichTreeView';
import { TreeItem2 } from "@mui/x-tree-view/TreeItem2";
import { useTreeViewApiRef } from '@mui/x-tree-view/hooks';
import FiberManualRecordIcon from '@mui/icons-material/FiberManualRecord';
import AddIcon from '@mui/icons-material/Add';
import DeleteIcon from '@mui/icons-material/Delete';
import BindMatnrModal from './BindMatnrModal';
import BindLocModal from './BindLocModal';
import ConfirmModal from "@/page/components/ConfirmModal";
import { DataGrid } from '@mui/x-data-grid';
import request from '@/utils/request';
const LocAreaMatPanel = () => {
    const record = useRecordContext();
    if (!record) return null;
    const translate = useTranslate();
    const notify = useNotify();
    const columns = [
        { field: 'id', headerName: 'ID', width: 100 },
        { field: 'areaId$', headerName: translate('table.field.locAreaMatRela.areaId'), width: 100 },
        { field: 'matnrId$', headerName: translate('table.field.locAreaMatRela.matnrId'), width: 100 },
        { field: 'groupId$', headerName: translate('table.field.locAreaMatRela.groupId'), width: 100 },
        { field: 'locTypeId$', headerName: translate('table.field.locAreaMatRela.locTypeId'), width: 100 },
        { field: 'locId$', headerName: translate('table.field.locAreaMatRela.locId'), width: 100 },
        {
            field: 'action',
            headerName: '操作',
            minWidth: 100,
            sticky: 'left',
            flex: 1,
            renderCell: (params) => (
                <Tooltip title="Delete">
                    <IconButton onClick={(e) => handleDelete(params.row, e)}>
                        <DeleteIcon />
                    </IconButton>
                </Tooltip>
            ),
        },
    ];
    const handleDelete = async (row, e) => {
        e.stopPropagation()
        const { data: { code, data, msg } } = await request.post(`/locAreaMatRela/remove/${row.id}`);
        if (code === 200) {
            reload()
            notify(msg);
        } else {
            notify(msg);
        }
    }
    const [parmas, setParmas] = useState({
        areaMatId: record.id,
    });
    const [tableData, setTableData] = useState([]);
    const [matnrTree, setMatnrTree] = useState([]);
    const [locTree, setLocTree] = useState([]);
    useEffect(() => {
        reload()
    }, [parmas])
    const reload = () => {
        requestTable()
        requestMatnr()
        requestLocType()
    }
    const requestTable = async () => {
        const { data: { code, data, msg } } = await request.post(`/locAreaMatRela/page`, parmas);
        if (code === 200) {
            setTableData(data.records || [])
        } else {
            notify(msg);
        }
    }
    const requestMatnr = async () => {
        const { data: { code, data, msg } } = await request.get(`/locAreaMatRela/groups/${record.id}`);
        if (code === 200) {
            setMatnrTree(data || [])
        } else {
            notify(msg);
        }
    }
    const requestLocType = async () => {
        const { data: { code, data, msg } } = await request.get(`/locAreaMatRela/locType/${record.id}`);
        if (code === 200) {
            setLocTree(data || [])
        } else {
            notify(msg);
        }
    }
    return (
        <Grid container spacing={2}>
            {/* 物料分组 */}
            <Grid item xs={2}>
                <MatnrTree matnrTree={matnrTree} setParmas={setParmas} reload={reload} />
            </Grid>
            {/* 库位类型 */}
            <Grid item xs={2}>
                <LocTree locTree={locTree} setParmas={setParmas} reload={reload} />
            </Grid>
            {/* 其他内容 */}
            <Grid item xs={8}>
                <DataGrid
                    size="small"
                    rows={tableData}
                    columns={columns}
                    checkboxSelection
                    disableColumnMenu={true}
                    disableColumnSorting
                    disableMultipleColumnsSorting
                    columnBufferPx={100}
                />
            </Grid>
        </Grid>
    );
};
export default LocAreaMatPanel;
const MatnrTree = ({ matnrTree, setParmas, reload }) => {
    const record = useRecordContext();
    const notify = useNotify();
    function getItemDescendantsIds(item) {
        const ids = [];
        item.children?.forEach((child) => {
            ids.push(child.id);
            ids.push(...getItemDescendantsIds(child));
        });
        return ids;
    }
    const [selectedItems, setSelectedItems] = useState([]);
    const toggledItemRef = useRef({});
    const apiRef = useTreeViewApiRef();
    const handleItemSelectionToggle = (event, itemId, isSelected) => {
        event.stopPropagation()
        event.preventDefault();
        toggledItemRef.current[itemId] = isSelected;
    };
    const handleSelectedItemsChange = (event, newSelectedItems) => {
        event.stopPropagation()
        event.preventDefault();
        setSelectedItems(newSelectedItems);
        const itemsToSelect = [];
        const itemsToUnSelect = {};
        Object.entries(toggledItemRef.current).forEach(([itemId, isSelected]) => {
            const item = apiRef.current.getItem(itemId);
            if (isSelected) {
                itemsToSelect.push(...getItemDescendantsIds(item));
            } else {
                getItemDescendantsIds(item).forEach((descendantId) => {
                    itemsToUnSelect[descendantId] = true;
                });
            }
        });
        const newSelectedItemsWithChildren = Array.from(
            new Set(
                [...newSelectedItems, ...itemsToSelect].filter(
                    (itemId) => !itemsToUnSelect[itemId],
                ),
            ),
        );
        setSelectedItems(newSelectedItemsWithChildren);
        toggledItemRef.current = {};
    };
    const [addDialog, setAddDialog] = useState(false);
    const [delectDialog, setDelectDialog] = useState(false);
    const handleDelete = () => {
        if (selectedItems.length > 0) {
            setDelectDialog(true)
        } else {
            notify('请选择物料分组');
        }
    };
    const contirmDelete = async () => {
        const parmas = {
            aeaMatId: record.id,
            groupId: selectedItems
        }
        const res = await request.post(`/locAreaMatRela/group/remove/`, parmas);
        if (res?.data?.code === 200) {
            reload()
            notify(res.data.msg);
        } else {
            notify(res.data.msg);
        }
    };
    const handleAdd = () => {
        setAddDialog(true)
    };
    const handleNodeSelect = (event, nodeId) => {
        event.stopPropagation()
    };
    return (
        <Card sx={{ p: 1 }}>
            <div style={{ display: 'flex', justifyContent: 'space-between', paddingBottom: '3px', marginBottom: '3px', borderBottom: '1px dashed #d4d4d4' }}>
                <div style={{ fontSize: '17px' }}>物料分组</div>
                <div style={{ display: 'flex', alignItems: 'center', gap: '3px' }}>
                    <AddIcon color={'info'} sx={{ cursor: 'pointer' }} onClick={() => handleAdd()} />
                    <DeleteIcon color={'warning'} sx={{ cursor: 'pointer' }} onClick={() => handleDelete()} />
                </div>
            </div>
            <RichTreeView
                expansionTrigger="iconContainer"
                checkboxSelection
                multiSelect
                items={matnrTree}
                apiRef={apiRef}
                selectedItems={selectedItems}
                getItemId={(item) => item.id}
                getItemLabel={(item) => item.name}
                defaultExpandedItems={['grid']}
                onSelectedItemsChange={handleSelectedItemsChange}
                onItemSelectionToggle={handleItemSelectionToggle}
                onItemClick={handleNodeSelect}
            />
            <BindMatnrModal
                open={addDialog}
                setOpen={setAddDialog}
                selectedItems={selectedItems}
                reload={reload}
            />
            <ConfirmModal
                open={delectDialog}
                setOpen={setDelectDialog}
                onConfirm={contirmDelete}
            />
        </Card>
    )
}
const LocTree = ({ locTree, setParmas, reload }) => {
    const record = useRecordContext();
    const notify = useNotify();
    function getItemDescendantsIds(item) {
        const ids = [];
        item.children?.forEach((child) => {
            ids.push(child.id);
            ids.push(...getItemDescendantsIds(child));
        });
        return ids;
    }
    const [selectedItems, setSelectedItems] = useState([]);
    const toggledItemRef = useRef({});
    const apiRef = useTreeViewApiRef();
    const handleItemSelectionToggle = (event, itemId, isSelected) => {
        toggledItemRef.current[itemId] = isSelected;
    };
    const handleSelectedItemsChange = (event, newSelectedItems) => {
        setSelectedItems(newSelectedItems);
        const itemsToSelect = [];
        const itemsToUnSelect = {};
        Object.entries(toggledItemRef.current).forEach(([itemId, isSelected]) => {
            const item = apiRef.current.getItem(itemId);
            if (isSelected) {
                itemsToSelect.push(...getItemDescendantsIds(item));
            } else {
                getItemDescendantsIds(item).forEach((descendantId) => {
                    itemsToUnSelect[descendantId] = true;
                });
            }
        });
        const newSelectedItemsWithChildren = Array.from(
            new Set(
                [...newSelectedItems, ...itemsToSelect].filter(
                    (itemId) => !itemsToUnSelect[itemId],
                ),
            ),
        );
        setSelectedItems(newSelectedItemsWithChildren);
        toggledItemRef.current = {};
    };
    const [addDialog, setAddDialog] = useState(false);
    const [delectDialog, setDelectDialog] = useState(false);
    const handleDelete = () => {
        if (selectedItems.length > 0) {
            setDelectDialog(true)
        } else {
            notify('请选择库位类型');
        }
    };
    const contirmDelete = async () => {
        const parmas = {
            areaMatId: record.id,
            typeId: selectedItems
        }
        const res = await request.post(`/locAreaMatRela/locType/remove/`, parmas);
        if (res?.data?.code === 200) {
            reload()
            notify(res.data.msg);
        } else {
            notify(res.data.msg);
        }
    };
    const handleAdd = () => {
        setAddDialog(true)
    };
    const handleNodeSelect = (event, nodeId) => {
        // event.preventDefault();
        console.log(nodeId)
    };
    return (
        <Card sx={{ p: 1 }}>
            <div style={{ display: 'flex', justifyContent: 'space-between', paddingBottom: '3px', marginBottom: '3px', borderBottom: '1px dashed #d4d4d4' }}>
                <div style={{ fontSize: '17px' }}>库位类型</div>
                <div style={{ display: 'flex', alignItems: 'center', gap: '3px' }}>
                    <AddIcon color={'info'} sx={{ cursor: 'pointer' }} onClick={() => handleAdd()} />
                    <DeleteIcon color={'warning'} sx={{ cursor: 'pointer' }} onClick={() => handleDelete()} />
                </div>
            </div>
            <RichTreeView
                expansionTrigger="iconContainer"
                checkboxSelection
                multiSelect
                items={locTree}
                apiRef={apiRef}
                selectedItems={selectedItems}
                getItemId={(item) => item.id}
                getItemLabel={(item) => item.name}
                defaultExpandedItems={['grid']}
                onSelectedItemsChange={handleSelectedItemsChange}
                onItemSelectionToggle={handleItemSelectionToggle}
                onItemClick={handleNodeSelect}
            />
            <BindLocModal
                open={addDialog}
                setOpen={setAddDialog}
                selectedItems={selectedItems}
                reload={reload}
            />
            <ConfirmModal
                open={delectDialog}
                setOpen={setDelectDialog}
                onConfirm={contirmDelete}
            />
        </Card>
    )
}
rsf-admin/src/page/basicInfo/locAreaMat/index.jsx
New file
@@ -0,0 +1,18 @@
import React, { useState, useRef, useEffect, useMemo } from "react";
import {
    ListGuesser,
    EditGuesser,
    ShowGuesser,
} from "react-admin";
import LocAreaMatList from "./LocAreaMatList";
import LocAreaMatEdit from "./LocAreaMatEdit";
export default {
    list: LocAreaMatList,
    edit: LocAreaMatEdit,
    show: ShowGuesser,
    recordRepresentation: (record) => {
        return `${record.id}`
    }
};
rsf-admin/src/page/basicInfo/locAreaMatRela/LocAreaMatRelaCreate.jsx
New file
@@ -0,0 +1,179 @@
import React, { useState, useRef, useEffect, useMemo } from "react";
import {
    CreateBase,
    useTranslate,
    TextInput,
    NumberInput,
    BooleanInput,
    DateInput,
    SaveButton,
    SelectInput,
    ReferenceInput,
    ReferenceArrayInput,
    AutocompleteInput,
    SelectArrayInput,
    Toolbar,
    required,
    useDataProvider,
    useNotify,
    Form,
    useCreateController,
} from 'react-admin';
import {
    Dialog,
    DialogActions,
    DialogContent,
    DialogTitle,
    Stack,
    Grid,
    Box,
} from '@mui/material';
import DialogCloseButton from "../../components/DialogCloseButton";
import StatusSelectInput from "../../components/StatusSelectInput";
import MemoInput from "../../components/MemoInput";
import TreeSelectInput from "@/page/components/TreeSelectInput";
const LocAreaMatRelaCreate = (props) => {
    const { open, setOpen } = props;
    const translate = useTranslate();
    const notify = useNotify();
    const handleClose = (event, reason) => {
        if (reason !== "backdropClick") {
            setOpen(false);
        }
    };
    const handleSuccess = async (data) => {
        setOpen(false);
        notify('common.response.success');
    };
    const handleError = async (error) => {
        notify(error.message || 'common.response.fail', { type: 'error', messageArgs: { _: error.message } });
    };
    return (
        <>
            <CreateBase
                record={{}}
                transform={(data) => {
                    return data;
                }}
                mutationOptions={{ onSuccess: handleSuccess, onError: handleError }}
            >
                <Dialog
                    open={open}
                    onClose={handleClose}
                    aria-labelledby="form-dialog-title"
                    fullWidth
                    disableRestoreFocus
                    maxWidth="md"   // 'xs' | 'sm' | 'md' | 'lg' | 'xl'
                >
                    <Form>
                        <DialogTitle id="form-dialog-title" sx={{
                            position: 'sticky',
                            top: 0,
                            backgroundColor: 'background.paper',
                            zIndex: 1000
                        }}
                        >
                            {translate('create.title')}
                            <Box sx={{ position: 'absolute', top: 8, right: 8, zIndex: 1001 }}>
                                <DialogCloseButton onClose={handleClose} />
                            </Box>
                        </DialogTitle>
                        <DialogContent sx={{ mt: 2 }}>
                            <Grid container rowSpacing={2} columnSpacing={2}>
                                <Grid item xs={6} display="flex" gap={1}>
                                    <ReferenceInput
                                        source="areaId"
                                        reference="warehouseAreas"
                                    >
                                        <AutocompleteInput
                                            label="table.field.locAreaMatRela.areaId"
                                            optionText="name"
                                            validate={[required()]}
                                            filterToQuery={(val) => ({ name: val })}
                                        />
                                    </ReferenceInput>
                                </Grid>
                                <Grid item xs={6} display="flex" gap={1}>
                                    <TextInput
                                        label="table.field.locAreaMatRela.code"
                                        source="code"
                                        parse={v => v}
                                    />
                                </Grid>
                                <Grid item xs={6} display="flex" gap={1}>
                                    <ReferenceInput
                                        source="matnrId"
                                        reference="matnr"
                                    >
                                        <AutocompleteInput
                                            label="table.field.locAreaMatRela.matnrId"
                                            optionText="name"
                                            filterToQuery={(val) => ({ name: val })}
                                        />
                                    </ReferenceInput>
                                </Grid>
                                <Grid item xs={6} display="flex" gap={1}>
                                    <TreeSelectInput
                                        label="table.field.locAreaMatRela.groupId"
                                        resource={'matnrGroup'}
                                        source="groupId"
                                    />
                                </Grid>
                                <Grid item xs={6} display="flex" gap={1}>
                                    <ReferenceInput
                                        source="locId"
                                        reference="loc"
                                    >
                                        <AutocompleteInput
                                            label="table.field.locAreaMatRela.locId"
                                            optionText="code"
                                            filterToQuery={(val) => ({ code: val })}
                                        />
                                    </ReferenceInput>
                                </Grid>
                                <Grid item xs={6} display="flex" gap={1}>
                                    {/* <ReferenceArrayInput source="locTypeId" reference="locType" >
                                        <SelectArrayInput label="table.field.locAreaMatRela.locTypeId" />
                                    </ReferenceArrayInput> */}
                                    <ReferenceInput
                                        source="locTypeId"
                                        reference="locType"
                                    >
                                        <AutocompleteInput
                                            label="table.field.locAreaMatRela.locTypeId"
                                            optionText="name"
                                            filterToQuery={(val) => ({ name: val })}
                                        />
                                    </ReferenceInput>
                                </Grid>
                                <Grid item xs={6} display="flex" gap={1}>
                                    <StatusSelectInput />
                                </Grid>
                                <Grid item xs={12} display="flex" gap={1}>
                                    <Stack direction="column" spacing={1} width={'100%'}>
                                        <MemoInput />
                                    </Stack>
                                </Grid>
                            </Grid>
                        </DialogContent>
                        <DialogActions sx={{ position: 'sticky', bottom: 0, backgroundColor: 'background.paper', zIndex: 1000 }}>
                            <Toolbar sx={{ width: '100%', justifyContent: 'space-between' }}  >
                                <SaveButton />
                            </Toolbar>
                        </DialogActions>
                    </Form>
                </Dialog>
            </CreateBase>
        </>
    )
}
export default LocAreaMatRelaCreate;
rsf-admin/src/page/basicInfo/locAreaMatRela/LocAreaMatRelaEdit.jsx
New file
@@ -0,0 +1,152 @@
import React, { useState, useRef, useEffect, useMemo } from "react";
import {
    Edit,
    SimpleForm,
    FormDataConsumer,
    useTranslate,
    TextInput,
    NumberInput,
    BooleanInput,
    DateInput,
    SelectInput,
    ReferenceInput,
    ReferenceArrayInput,
    AutocompleteInput,
    SelectArrayInput,
    SaveButton,
    Toolbar,
    Labeled,
    NumberField,
    required,
    useRecordContext,
    DeleteButton,
} from 'react-admin';
import { useWatch, useFormContext } from "react-hook-form";
import { Stack, Grid, Box, Typography } from '@mui/material';
import * as Common from '@/utils/common';
import { EDIT_MODE, REFERENCE_INPUT_PAGESIZE } from '@/config/setting';
import EditBaseAside from "../../components/EditBaseAside";
import CustomerTopToolBar from "../../components/EditTopToolBar";
import MemoInput from "../../components/MemoInput";
import StatusSelectInput from "../../components/StatusSelectInput";
import TreeSelectInput from "@/page/components/TreeSelectInput";
const FormToolbar = () => {
    const { getValues } = useFormContext();
    return (
        <Toolbar sx={{ justifyContent: 'space-between' }}>
            <SaveButton />
            <DeleteButton mutationMode="optimistic" />
        </Toolbar>
    )
}
const LocAreaMatRelaEdit = () => {
    const translate = useTranslate();
    return (
        <Edit
            redirect="list"
            mutationMode={EDIT_MODE}
            actions={<CustomerTopToolBar />}
            aside={<EditBaseAside />}
            title={"menu.locAreaMatRela"}
        >
            <SimpleForm
                shouldUnregister
                warnWhenUnsavedChanges
                toolbar={<FormToolbar />}
                mode="onTouched"
                defaultValues={{}}
            // validate={(values) => { }}
            >
                <Grid container width={{ xs: '100%', xl: '80%' }} rowSpacing={3} columnSpacing={3}>
                    <Grid item xs={12} md={8}>
                        <Typography variant="h6" gutterBottom>
                            {translate('common.edit.title.main')}
                        </Typography>
                        <Stack direction='row' gap={2}>
                            <ReferenceInput
                                source="areaId"
                                reference="warehouseAreas"
                            >
                                <AutocompleteInput
                                    label="table.field.locAreaMatRela.areaId"
                                    optionText="name"
                                    validate={[required()]}
                                    filterToQuery={(val) => ({ name: val })}
                                />
                            </ReferenceInput>
                        </Stack>
                        <Stack direction='row' gap={2}>
                            <TextInput
                                label="table.field.locAreaMatRela.code"
                                source="code"
                                parse={v => v}
                            />
                        </Stack>
                        <Stack direction='row' gap={2}>
                            <ReferenceInput
                                source="matnrId"
                                reference="matnr"
                            >
                                <AutocompleteInput
                                    label="table.field.locAreaMatRela.matnrId"
                                    optionText="name"
                                    filterToQuery={(val) => ({ name: val })}
                                />
                            </ReferenceInput>
                        </Stack>
                        <Stack direction='row' gap={2}>
                            <TreeSelectInput
                                label="table.field.locAreaMatRela.groupId"
                                resource={'matnrGroup'}
                                source="groupId"
                            />
                        </Stack>
                        <Stack direction='row' gap={2}>
                            <ReferenceInput
                                source="locId"
                                reference="loc"
                            >
                                <AutocompleteInput
                                    label="table.field.locAreaMatRela.locId"
                                    optionText="code"
                                    filterToQuery={(val) => ({ code: val })}
                                />
                            </ReferenceInput>
                        </Stack>
                        <Stack direction='row' gap={2}>
                            {/* <ReferenceArrayInput source="locTypeId" reference="locType" >
                                <SelectArrayInput label="table.field.locAreaMatRela.locTypeId" />
                            </ReferenceArrayInput> */}
                            <ReferenceInput
                                source="locTypeId"
                                reference="locType"
                            >
                                <AutocompleteInput
                                    label="table.field.locAreaMatRela.locTypeId"
                                    optionText="name"
                                    filterToQuery={(val) => ({ name: val })}
                                />
                            </ReferenceInput>
                        </Stack>
                    </Grid>
                    <Grid item xs={12} md={4}>
                        <Typography variant="h6" gutterBottom>
                            {translate('common.edit.title.common')}
                        </Typography>
                        <StatusSelectInput />
                        <Box mt="2em" />
                        <MemoInput />
                    </Grid>
                </Grid>
            </SimpleForm>
        </Edit >
    )
}
export default LocAreaMatRelaEdit;
rsf-admin/src/page/basicInfo/locAreaMatRela/LocAreaMatRelaList.jsx
New file
@@ -0,0 +1,158 @@
import React, { useState, useRef, useEffect, useMemo, useCallback } from "react";
import { useNavigate } from 'react-router-dom';
import {
    List,
    DatagridConfigurable,
    SearchInput,
    TopToolbar,
    SelectColumnsButton,
    EditButton,
    FilterButton,
    CreateButton,
    ExportButton,
    BulkDeleteButton,
    WrapperField,
    useRecordContext,
    useTranslate,
    useNotify,
    useListContext,
    FunctionField,
    TextField,
    NumberField,
    DateField,
    BooleanField,
    ReferenceField,
    TextInput,
    DateTimeInput,
    DateInput,
    SelectInput,
    NumberInput,
    ReferenceInput,
    ReferenceArrayInput,
    AutocompleteInput,
    DeleteButton,
} from 'react-admin';
import { Box, Typography, Card, Stack } from '@mui/material';
import { styled } from '@mui/material/styles';
import LocAreaMatRelaCreate from "./LocAreaMatRelaCreate";
import LocAreaMatRelaPanel from "./LocAreaMatRelaPanel";
import EmptyData from "../../components/EmptyData";
import MyCreateButton from "../../components/MyCreateButton";
import MyExportButton from '../../components/MyExportButton';
import PageDrawer from "../../components/PageDrawer";
import MyField from "../../components/MyField";
import { PAGE_DRAWER_WIDTH, OPERATE_MODE, DEFAULT_PAGE_SIZE } from '@/config/setting';
import * as Common from '@/utils/common';
const StyledDatagrid = styled(DatagridConfigurable)(({ theme }) => ({
    '& .css-1vooibu-MuiSvgIcon-root': {
        height: '.9em'
    },
    '& .RaDatagrid-row': {
        cursor: 'auto'
    },
    '& .column-name': {
    },
    '& .opt': {
        width: 200
    },
}));
const filters = [
    <SearchInput source="condition" alwaysOn />,
    <NumberInput source="areaId" label="table.field.locAreaMatRela.areaId" />,
    <TextInput source="code" label="table.field.locAreaMatRela.code" />,
    <NumberInput source="matnrId" label="table.field.locAreaMatRela.matnrId" />,
    <NumberInput source="groupId" label="table.field.locAreaMatRela.groupId" />,
    <NumberInput source="locTypeId" label="table.field.locAreaMatRela.locTypeId" />,
    <NumberInput source="locId" label="table.field.locAreaMatRela.locId" />,
    <TextInput label="common.field.memo" source="memo" />,
    <SelectInput
        label="common.field.status"
        source="status"
        choices={[
            { id: '1', name: 'common.enums.statusTrue' },
            { id: '0', name: 'common.enums.statusFalse' },
        ]}
        resettable
    />,
]
const LocAreaMatRelaList = () => {
    const translate = useTranslate();
    const [createDialog, setCreateDialog] = useState(false);
    const [drawerVal, setDrawerVal] = useState(false);
    return (
        <Box display="flex">
            <List
                sx={{
                    flexGrow: 1,
                    transition: (theme) =>
                        theme.transitions.create(['all'], {
                            duration: theme.transitions.duration.enteringScreen,
                        }),
                    marginRight: drawerVal ? `${PAGE_DRAWER_WIDTH}px` : 0,
                }}
                title={"menu.locAreaMatRela"}
                empty={<EmptyData onClick={() => { setCreateDialog(true) }} />}
                filters={filters}
                sort={{ field: "create_time", order: "desc" }}
                actions={(
                    <TopToolbar>
                        <FilterButton />
                        <MyCreateButton onClick={() => { setCreateDialog(true) }} />
                        <SelectColumnsButton preferenceKey='locAreaMatRela' />
                        <MyExportButton />
                    </TopToolbar>
                )}
                perPage={DEFAULT_PAGE_SIZE}
            >
                <StyledDatagrid
                    preferenceKey='locAreaMatRela'
                    bulkActionButtons={() => <BulkDeleteButton mutationMode={OPERATE_MODE} />}
                    rowClick={(id, resource, record) => false}
                    omit={['id', 'createTime', 'createBy', 'memo']}
                >
                    <NumberField source="id" />
                    <NumberField source="areaId$" label="table.field.locAreaMatRela.areaId" />
                    <TextField source="code" label="table.field.locAreaMatRela.code" />
                    <NumberField source="matnrId$" label="table.field.locAreaMatRela.matnrId" />
                    <NumberField source="groupId$" label="table.field.locAreaMatRela.groupId" />
                    <NumberField source="locTypeId$" label="table.field.locAreaMatRela.locTypeId" />
                    <NumberField source="locId$" label="table.field.locAreaMatRela.locId" />
                    <ReferenceField source="updateBy" label="common.field.updateBy" reference="user" link={false} sortable={false}>
                        <TextField source="nickname" />
                    </ReferenceField>
                    <DateField source="updateTime" label="common.field.updateTime" showTime />
                    <ReferenceField source="createBy" label="common.field.createBy" reference="user" link={false} sortable={false}>
                        <TextField source="nickname" />
                    </ReferenceField>
                    <DateField source="createTime" label="common.field.createTime" showTime />
                    <BooleanField source="statusBool" label="common.field.status" sortable={false} />
                    <TextField source="memo" label="common.field.memo" sortable={false} />
                    <WrapperField cellClassName="opt" label="common.field.opt">
                        <EditButton sx={{ padding: '1px', fontSize: '.75rem' }} />
                        <DeleteButton sx={{ padding: '1px', fontSize: '.75rem' }} mutationMode={OPERATE_MODE} />
                    </WrapperField>
                </StyledDatagrid>
            </List>
            <LocAreaMatRelaCreate
                open={createDialog}
                setOpen={setCreateDialog}
            />
            <PageDrawer
                title='LocAreaMatRela Detail'
                drawerVal={drawerVal}
                setDrawerVal={setDrawerVal}
            >
            </PageDrawer>
        </Box>
    )
}
export default LocAreaMatRelaList;
rsf-admin/src/page/basicInfo/locAreaMatRela/LocAreaMatRelaPanel.jsx
New file
@@ -0,0 +1,28 @@
import React, { useState, useRef, useEffect, useMemo } from "react";
import { Box, Card, CardContent, Grid, Typography, Tooltip } from '@mui/material';
import {
    useTranslate,
    useRecordContext,
} from 'react-admin';
import PanelTypography from "../../components/PanelTypography";
import * as Common from '@/utils/common'
const LocAreaMatRelaPanel = () => {
    const record = useRecordContext();
    if (!record) return null;
    const translate = useTranslate();
    return (
        <>
            <Card >
                <CardContent>
                    <Grid container spacing={2}>1</Grid>
                    <Grid container spacing={2}>1</Grid>
                    <Grid container spacing={2}>1</Grid>
                </CardContent >
            </Card >
        </>
    );
};
export default LocAreaMatRelaPanel;
rsf-admin/src/page/basicInfo/locAreaMatRela/index.jsx
New file
@@ -0,0 +1,18 @@
import React, { useState, useRef, useEffect, useMemo } from "react";
import {
    ListGuesser,
    EditGuesser,
    ShowGuesser,
} from "react-admin";
import LocAreaMatRelaList from "./LocAreaMatRelaList";
import LocAreaMatRelaEdit from "./LocAreaMatRelaEdit";
export default {
    list: LocAreaMatRelaList,
    edit: LocAreaMatRelaEdit,
    show: ShowGuesser,
    recordRepresentation: (record) => {
        return `${record.areaId}`
    }
};
rsf-admin/src/page/basicInfo/locAreaRela/LocAreaRelaCreate.jsx
New file
@@ -0,0 +1,123 @@
import React, { useState, useRef, useEffect, useMemo } from "react";
import {
    CreateBase,
    useTranslate,
    TextInput,
    NumberInput,
    BooleanInput,
    DateInput,
    SaveButton,
    SelectInput,
    ReferenceInput,
    ReferenceArrayInput,
    AutocompleteInput,
    Toolbar,
    required,
    useDataProvider,
    useNotify,
    Form,
    useCreateController,
} from 'react-admin';
import {
    Dialog,
    DialogActions,
    DialogContent,
    DialogTitle,
    Stack,
    Grid,
    Box,
} from '@mui/material';
import DialogCloseButton from "../../components/DialogCloseButton";
import StatusSelectInput from "../../components/StatusSelectInput";
import MemoInput from "../../components/MemoInput";
const LocAreaRelaCreate = (props) => {
    const { open, setOpen } = props;
    const translate = useTranslate();
    const notify = useNotify();
    const handleClose = (event, reason) => {
        if (reason !== "backdropClick") {
            setOpen(false);
        }
    };
    const handleSuccess = async (data) => {
        setOpen(false);
        notify('common.response.success');
    };
    const handleError = async (error) => {
        notify(error.message || 'common.response.fail', { type: 'error', messageArgs: { _: error.message } });
    };
    return (
        <>
            <CreateBase
                record={{}}
                transform={(data) => {
                    return data;
                }}
                mutationOptions={{ onSuccess: handleSuccess, onError: handleError }}
            >
                <Dialog
                    open={open}
                    onClose={handleClose}
                    aria-labelledby="form-dialog-title"
                    fullWidth
                    disableRestoreFocus
                    maxWidth="md"   // 'xs' | 'sm' | 'md' | 'lg' | 'xl'
                >
                    <Form>
                        <DialogTitle id="form-dialog-title" sx={{
                            position: 'sticky',
                            top: 0,
                            backgroundColor: 'background.paper',
                            zIndex: 1000
                        }}
                        >
                            {translate('create.title')}
                            <Box sx={{ position: 'absolute', top: 8, right: 8, zIndex: 1001 }}>
                                <DialogCloseButton onClose={handleClose} />
                            </Box>
                        </DialogTitle>
                        <DialogContent sx={{ mt: 2 }}>
                            <Grid container rowSpacing={2} columnSpacing={2}>
                                <Grid item xs={6} display="flex" gap={1}>
                                    <NumberInput
                                        label="table.field.locAreaRela.locAreaId"
                                        source="locAreaId"
                                        autoFocus
                                    />
                                </Grid>
                                <Grid item xs={6} display="flex" gap={1}>
                                    <NumberInput
                                        label="table.field.locAreaRela.locId"
                                        source="locId"
                                    />
                                </Grid>
                                <Grid item xs={6} display="flex" gap={1}>
                                    <StatusSelectInput />
                                </Grid>
                                <Grid item xs={12} display="flex" gap={1}>
                                    <Stack direction="column" spacing={1} width={'100%'}>
                                        <MemoInput />
                                    </Stack>
                                </Grid>
                            </Grid>
                        </DialogContent>
                        <DialogActions sx={{ position: 'sticky', bottom: 0, backgroundColor: 'background.paper', zIndex: 1000 }}>
                            <Toolbar sx={{ width: '100%', justifyContent: 'space-between' }}  >
                                <SaveButton />
                            </Toolbar>
                        </DialogActions>
                    </Form>
                </Dialog>
            </CreateBase>
        </>
    )
}
export default LocAreaRelaCreate;
rsf-admin/src/page/basicInfo/locAreaRela/LocAreaRelaEdit.jsx
New file
@@ -0,0 +1,95 @@
import React, { useState, useRef, useEffect, useMemo } from "react";
import {
    Edit,
    SimpleForm,
    FormDataConsumer,
    useTranslate,
    TextInput,
    NumberInput,
    BooleanInput,
    DateInput,
    SelectInput,
    ReferenceInput,
    ReferenceArrayInput,
    AutocompleteInput,
    SaveButton,
    Toolbar,
    Labeled,
    NumberField,
    required,
    useRecordContext,
    DeleteButton,
} from 'react-admin';
import { useWatch, useFormContext } from "react-hook-form";
import { Stack, Grid, Box, Typography } from '@mui/material';
import * as Common from '@/utils/common';
import { EDIT_MODE, REFERENCE_INPUT_PAGESIZE } from '@/config/setting';
import EditBaseAside from "../../components/EditBaseAside";
import CustomerTopToolBar from "../../components/EditTopToolBar";
import MemoInput from "../../components/MemoInput";
import StatusSelectInput from "../../components/StatusSelectInput";
const FormToolbar = () => {
    const { getValues } = useFormContext();
    return (
        <Toolbar sx={{ justifyContent: 'space-between' }}>
            <SaveButton />
            <DeleteButton mutationMode="optimistic" />
        </Toolbar>
    )
}
const LocAreaRelaEdit = () => {
    const translate = useTranslate();
    return (
        <Edit
            redirect="list"
            mutationMode={EDIT_MODE}
            actions={<CustomerTopToolBar />}
            aside={<EditBaseAside />}
        >
            <SimpleForm
                shouldUnregister
                warnWhenUnsavedChanges
                toolbar={<FormToolbar />}
                mode="onTouched"
                defaultValues={{}}
            // validate={(values) => { }}
            >
                <Grid container width={{ xs: '100%', xl: '80%' }} rowSpacing={3} columnSpacing={3}>
                    <Grid item xs={12} md={8}>
                        <Typography variant="h6" gutterBottom>
                            {translate('common.edit.title.main')}
                        </Typography>
                        <Stack direction='row' gap={2}>
                            <NumberInput
                                label="table.field.locAreaRela.locAreaId"
                                source="locAreaId"
                                autoFocus
                            />
                        </Stack>
                        <Stack direction='row' gap={2}>
                            <NumberInput
                                label="table.field.locAreaRela.locId"
                                source="locId"
                            />
                        </Stack>
                    </Grid>
                    <Grid item xs={12} md={4}>
                        <Typography variant="h6" gutterBottom>
                            {translate('common.edit.title.common')}
                        </Typography>
                        <StatusSelectInput />
                        <Box mt="2em" />
                        <MemoInput />
                    </Grid>
                </Grid>
            </SimpleForm>
        </Edit >
    )
}
export default LocAreaRelaEdit;
rsf-admin/src/page/basicInfo/locAreaRela/LocAreaRelaList.jsx
New file
@@ -0,0 +1,154 @@
import React, { useState, useRef, useEffect, useMemo, useCallback } from "react";
import { useNavigate } from 'react-router-dom';
import {
    List,
    DatagridConfigurable,
    SearchInput,
    TopToolbar,
    SelectColumnsButton,
    EditButton,
    FilterButton,
    CreateButton,
    ExportButton,
    BulkDeleteButton,
    WrapperField,
    useRecordContext,
    useTranslate,
    useNotify,
    useListContext,
    FunctionField,
    TextField,
    NumberField,
    DateField,
    BooleanField,
    ReferenceField,
    TextInput,
    DateTimeInput,
    DateInput,
    SelectInput,
    NumberInput,
    ReferenceInput,
    ReferenceArrayInput,
    AutocompleteInput,
    DeleteButton,
} from 'react-admin';
import { Box, Typography, Card, Stack } from '@mui/material';
import { styled } from '@mui/material/styles';
import LocAreaRelaCreate from "./LocAreaRelaCreate";
import LocAreaRelaPanel from "./LocAreaRelaPanel";
import EmptyData from "../../components/EmptyData";
import MyCreateButton from "../../components/MyCreateButton";
import MyExportButton from '../../components/MyExportButton';
import PageDrawer from "../../components/PageDrawer";
import MyField from "../../components/MyField";
import { PAGE_DRAWER_WIDTH, OPERATE_MODE, DEFAULT_PAGE_SIZE } from '@/config/setting';
import * as Common from '@/utils/common';
const StyledDatagrid = styled(DatagridConfigurable)(({ theme }) => ({
    '& .css-1vooibu-MuiSvgIcon-root': {
        height: '.9em'
    },
    '& .RaDatagrid-row': {
        cursor: 'auto'
    },
    '& .column-name': {
    },
    '& .opt': {
        width: 200
    },
}));
const filters = [
    <SearchInput source="condition" alwaysOn />,
    <DateInput label='common.time.after' source="timeStart" alwaysOn />,
    <DateInput label='common.time.before' source="timeEnd" alwaysOn />,
    <NumberInput source="locAreaId" label="table.field.locAreaRela.locAreaId" />,
    <NumberInput source="locId" label="table.field.locAreaRela.locId" />,
    <TextInput label="common.field.memo" source="memo" />,
    <SelectInput
        label="common.field.status"
        source="status"
        choices={[
            { id: '1', name: 'common.enums.statusTrue' },
            { id: '0', name: 'common.enums.statusFalse' },
        ]}
        resettable
    />,
]
const LocAreaRelaList = () => {
    const translate = useTranslate();
    const [createDialog, setCreateDialog] = useState(false);
    const [drawerVal, setDrawerVal] = useState(false);
    return (
        <Box display="flex">
            <List
                sx={{
                    flexGrow: 1,
                    transition: (theme) =>
                        theme.transitions.create(['all'], {
                            duration: theme.transitions.duration.enteringScreen,
                        }),
                    marginRight: drawerVal ? `${PAGE_DRAWER_WIDTH}px` : 0,
                }}
                title={"menu.locAreaRela"}
                empty={<EmptyData onClick={() => { setCreateDialog(true) }} />}
                filters={filters}
                sort={{ field: "create_time", order: "desc" }}
                actions={(
                    <TopToolbar>
                        <FilterButton />
                        <MyCreateButton onClick={() => { setCreateDialog(true) }} />
                        <SelectColumnsButton preferenceKey='locAreaRela' />
                        <MyExportButton />
                    </TopToolbar>
                )}
                perPage={DEFAULT_PAGE_SIZE}
            >
                <StyledDatagrid
                    preferenceKey='locAreaRela'
                    bulkActionButtons={() => <BulkDeleteButton mutationMode={OPERATE_MODE} />}
                    rowClick={(id, resource, record) => false}
                    expand={() => <LocAreaRelaPanel />}
                    expandSingle={true}
                    omit={['id', 'createTime', 'createBy', 'memo']}
                >
                    <NumberField source="id" />
                    <NumberField source="locAreaId" label="table.field.locAreaRela.locAreaId" />
                    <NumberField source="locId" label="table.field.locAreaRela.locId" />
                    <ReferenceField source="updateBy" label="common.field.updateBy" reference="user" link={false} sortable={false}>
                        <TextField source="nickname" />
                    </ReferenceField>
                    <DateField source="updateTime" label="common.field.updateTime" showTime />
                    <ReferenceField source="createBy" label="common.field.createBy" reference="user" link={false} sortable={false}>
                        <TextField source="nickname" />
                    </ReferenceField>
                    <DateField source="createTime" label="common.field.createTime" showTime />
                    <BooleanField source="statusBool" label="common.field.status" sortable={false} />
                    <TextField source="memo" label="common.field.memo" sortable={false} />
                    <WrapperField cellClassName="opt" label="common.field.opt">
                        <EditButton sx={{ padding: '1px', fontSize: '.75rem' }} />
                        <DeleteButton sx={{ padding: '1px', fontSize: '.75rem' }} mutationMode={OPERATE_MODE} />
                    </WrapperField>
                </StyledDatagrid>
            </List>
            <LocAreaRelaCreate
                open={createDialog}
                setOpen={setCreateDialog}
            />
            <PageDrawer
                title='LocAreaRela Detail'
                drawerVal={drawerVal}
                setDrawerVal={setDrawerVal}
            >
            </PageDrawer>
        </Box>
    )
}
export default LocAreaRelaList;
rsf-admin/src/page/basicInfo/locAreaRela/LocAreaRelaPanel.jsx
New file
@@ -0,0 +1,63 @@
import React, { useState, useRef, useEffect, useMemo } from "react";
import { Box, Card, CardContent, Grid, Typography, Tooltip } from '@mui/material';
import {
    useTranslate,
    useRecordContext,
} from 'react-admin';
import PanelTypography from "../../components/PanelTypography";
import * as Common from '@/utils/common'
const LocAreaRelaPanel = () => {
    const record = useRecordContext();
    if (!record) return null;
    const translate = useTranslate();
    return (
        <>
            <Card sx={{ width: { xs: 300, sm: 500, md: 600, lg: 800 }, margin: 'auto' }}>
                <CardContent>
                    <Grid container spacing={2}>
                        <Grid item xs={12} sx={{ display: 'flex', justifyContent: 'space-between' }}>
                            <Typography variant="h6" gutterBottom align="left" sx={{
                                maxWidth: { xs: '100px', sm: '180px', md: '260px', lg: '360px' },
                                whiteSpace: 'nowrap',
                                overflow: 'hidden',
                                textOverflow: 'ellipsis',
                            }}>
                                {Common.camelToPascalWithSpaces(translate('table.field.locAreaRela.locAreaId'))}: {record.locAreaId}
                            </Typography>
                            {/*  inherit, primary, secondary, textPrimary, textSecondary, error */}
                            <Typography variant="h6" gutterBottom align="right" >
                                ID: {record.id}
                            </Typography>
                        </Grid>
                    </Grid>
                    <Grid container spacing={2}>
                        <Grid item xs={12} container alignContent="flex-end">
                            <Typography variant="caption" color="textSecondary" sx={{ wordWrap: 'break-word', wordBreak: 'break-all' }}>
                                {Common.camelToPascalWithSpaces(translate('common.field.memo'))}:{record.memo}
                            </Typography>
                        </Grid>
                    </Grid>
                    <Box height={20}>&nbsp;</Box>
                    <Grid container spacing={2}>
                        <Grid item xs={6}>
                            <PanelTypography
                                title="table.field.locAreaRela.locAreaId"
                                property={record.locAreaId}
                            />
                        </Grid>
                        <Grid item xs={6}>
                            <PanelTypography
                                title="table.field.locAreaRela.locId"
                                property={record.locId}
                            />
                        </Grid>
                    </Grid>
                </CardContent>
            </Card >
        </>
    );
};
export default LocAreaRelaPanel;
rsf-admin/src/page/basicInfo/locAreaRela/index.jsx
New file
@@ -0,0 +1,18 @@
import React, { useState, useRef, useEffect, useMemo } from "react";
import {
    ListGuesser,
    EditGuesser,
    ShowGuesser,
} from "react-admin";
import LocAreaRelaList from "./LocAreaRelaList";
import LocAreaRelaEdit from "./LocAreaRelaEdit";
export default {
    list: LocAreaRelaList,
    edit: LocAreaRelaEdit,
    show: ShowGuesser,
    recordRepresentation: (record) => {
        return `${record.locAreaId}`
    }
};
rsf-admin/src/page/basicInfo/locType/BindModal.jsx
New file
@@ -0,0 +1,199 @@
import React, { useState, useRef, useEffect, useMemo } from "react";
import {
    CreateBase,
    useTranslate,
    TextInput,
    NumberInput,
    BooleanInput,
    DateInput,
    SaveButton,
    SelectInput,
    ReferenceInput,
    ReferenceArrayInput,
    AutocompleteInput,
    Toolbar,
    required,
    useDataProvider,
    useNotify,
    Form,
    useCreateController,
    useListContext,
    useRefresh,
    SelectArrayInput
} from 'react-admin';
import {
    Dialog,
    DialogActions,
    DialogContent,
    DialogTitle,
    Grid,
    TextField,
    Box,
    Button,
    Paper,
    TableContainer,
    Table,
    TableHead,
    TableBody,
    TableRow,
    TableCell,
    Tooltip,
    IconButton,
    styled,
} from '@mui/material';
import DialogCloseButton from "../../components/DialogCloseButton";
import DictionarySelect from "../../components/DictionarySelect";
import { useForm, Controller, useWatch, FormProvider, useFormContext } from "react-hook-form";
import SaveIcon from '@mui/icons-material/Save';
import request from '@/utils/request';
import { Add, Edit, Delete } from '@mui/icons-material';
import _ from 'lodash';
import { DataGrid } from '@mui/x-data-grid';
import StatusSelectInput from "../../components/StatusSelectInput";
import TreeSelectInput from "@/page/components/TreeSelectInput";
const MatnrModal = ({ open, setOpen }) => {
    const refresh = useRefresh();
    const translate = useTranslate();
    const notify = useNotify();
    const [formData, setFormData] = useState({
        areaId: null,
        groupId: null,
        matnrId: null,
    });
    const { selectedIds, onUnselectItems } = useListContext();
    const handleClose = (event, reason) => {
        if (reason !== "backdropClick") {
            setOpen(false);
            reset()
            refresh();
            onUnselectItems()
        }
    };
    const reset = () => {
        setFormData({
            areaId: null,
            groupId: null,
            matnrId: null,
        })
    }
    const handleReset = (e) => {
        e.preventDefault();
    };
    const handleChange = (value, name) => {
        setFormData((prevData) => ({
            ...prevData,
            [name]: value
        }));
        refresh()
    };
    const removeEmptyKeys = (obj) => {
        return _.pickBy(obj, (value) => {
            if (_.isObject(value)) {
                const newObj = removeEmptyKeys(value);
                return !_.isEmpty(newObj);
            }
            return !_.isNil(value) && (_.isNumber(value) ? value !== 0 : !_.isEmpty(value));
        });
    }
    const handleSubmit = async () => {
        const parmas = {
            typeId: selectedIds,
            areaId: formData.areaId,
            matnrId: formData.matnrId,
        }
        const res = await request.post(`/locAreaMatRela/matnr/bind`, parmas);
        if (res?.data?.code === 200) {
            handleClose()
        } else {
            notify(res.data.msg);
        }
    }
    const [groupId, setGroupId] = useState();
    const warehouseChange = (e) => {
        setGroupId(e.target.value)
    }
    return (
        <Dialog open={open} maxWidth="md" fullWidth>
            <Form onSubmit={handleSubmit}>
                <DialogCloseButton onClose={handleClose} />
                <DialogTitle>{translate('toolbar.bindmatnr')}</DialogTitle>
                <DialogContent sx={{ mt: 2 }}>
                    <Box sx={{ display: 'flex', flexDirection: 'column', gap: 3 }}>
                        <Grid container spacing={2}>
                            <Grid item xs={4}>
                                <ReferenceInput
                                    source="areaId"
                                    reference="warehouseAreas"
                                >
                                    <AutocompleteInput
                                        label="table.field.loc.areaId"
                                        optionText="name"
                                        onChange={(value) => handleChange(value, 'areaId')}
                                        value={formData.areaId}
                                        validate={required()}
                                        filterToQuery={(val) => ({ name: val })}
                                    />
                                </ReferenceInput>
                            </Grid>
                            <Grid item xs={4}>
                                <TreeSelectInput
                                    label="table.field.locAreaMatRela.groupId"
                                    resource={'matnrGroup'}
                                    source="groupId"
                                    value={formData.groupId}
                                    onChange={(e) => handleChange(e.target.value, 'groupId')}
                                />
                            </Grid>
                            <Grid item xs={4}>
                                <ReferenceArrayInput source="matnrId" reference="matnr" filter={{ groupId: formData.groupId }}>
                                    <SelectArrayInput
                                        label="table.field.locAreaMatRela.matnrId"
                                        validate={required()}
                                        value={formData.matnrId}
                                        onChange={(e) => handleChange(e.target.value, 'matnrId')}
                                    />
                                </ReferenceArrayInput>
                            </Grid>
                        </Grid>
                    </Box>
                </DialogContent>
                <DialogActions sx={{ position: 'sticky', bottom: 0, backgroundColor: 'background.paper', zIndex: 1000 }}>
                    <Box sx={{ width: '100%', display: 'flex', justifyContent: 'space-between' }}>
                        <Button type="submit" variant="contained" startIcon={<SaveIcon />}>
                            {translate('toolbar.confirm')}
                        </Button>
                    </Box>
                </DialogActions>
            </Form>
        </Dialog>
    );
}
export default MatnrModal;
rsf-admin/src/page/basicInfo/locType/LocTypeEdit.jsx
@@ -49,6 +49,7 @@
            mutationMode={EDIT_MODE}
            actions={<CustomerTopToolBar />}
            aside={<EditBaseAside />}
            title={"menu.locType"}
        >
            <SimpleForm
                shouldUnregister
rsf-admin/src/page/basicInfo/locType/LocTypeList.jsx
@@ -31,6 +31,9 @@
    ReferenceArrayInput,
    AutocompleteInput,
    DeleteButton,
    useRefresh,
    Button,
    useList
} from 'react-admin';
import { Box, Typography, Card, Stack } from '@mui/material';
import { styled } from '@mui/material/styles';
@@ -42,6 +45,8 @@
import PageDrawer from "../../components/PageDrawer";
import { PAGE_DRAWER_WIDTH, OPERATE_MODE, DEFAULT_PAGE_SIZE } from '@/config/setting';
import * as Common from '@/utils/common';
import BindModal from "./BindModal";
import LinkIcon from '@mui/icons-material/Link';
const StyledDatagrid = styled(DatagridConfigurable)(({ theme }) => ({
    '& .css-1vooibu-MuiSvgIcon-root': {
@@ -109,7 +114,10 @@
            >
                <StyledDatagrid
                    preferenceKey='locType'
                    bulkActionButtons={() => <BulkDeleteButton mutationMode={OPERATE_MODE} />}
                    bulkActionButtons={<>
                        <BindButton />
                        <BulkDeleteButton />
                    </>}
                    rowClick={(id, resource, record) => false}
                    omit={['id', 'createTime', 'createBy', 'memo']}
                >
@@ -150,3 +158,26 @@
}
export default LocTypeList;
const BindButton = () => {
    const record = useRecordContext();
    const notify = useNotify();
    const refresh = useRefresh();
    const [createDialog, setCreateDialog] = useState(false);
    return (
        <>
            <Button onClick={() => setCreateDialog(true)} label={"toolbar.bindmatnr"}>
                <LinkIcon />
            </Button>
            <BindModal
                open={createDialog}
                setOpen={setCreateDialog}
            />
        </>
    )
}
rsf-admin/src/page/basicInfo/matnr/BindModal.jsx
New file
@@ -0,0 +1,186 @@
import React, { useState, useRef, useEffect, useMemo } from "react";
import {
    CreateBase,
    useTranslate,
    TextInput,
    NumberInput,
    BooleanInput,
    DateInput,
    SaveButton,
    SelectInput,
    ReferenceInput,
    ReferenceArrayInput,
    AutocompleteInput,
    Toolbar,
    required,
    useDataProvider,
    useNotify,
    Form,
    useCreateController,
    useListContext,
    useRefresh,
    SelectArrayInput
} from 'react-admin';
import {
    Dialog,
    DialogActions,
    DialogContent,
    DialogTitle,
    Grid,
    TextField,
    Box,
    Button,
    Paper,
    TableContainer,
    Table,
    TableHead,
    TableBody,
    TableRow,
    TableCell,
    Tooltip,
    IconButton,
    styled,
} from '@mui/material';
import DialogCloseButton from "../../components/DialogCloseButton";
import DictionarySelect from "../../components/DictionarySelect";
import { useForm, Controller, useWatch, FormProvider, useFormContext } from "react-hook-form";
import SaveIcon from '@mui/icons-material/Save';
import request from '@/utils/request';
import { Add, Edit, Delete } from '@mui/icons-material';
import _ from 'lodash';
import { DataGrid } from '@mui/x-data-grid';
import StatusSelectInput from "../../components/StatusSelectInput";
import TreeSelectInput from "@/page/components/TreeSelectInput";
const MatnrModal = ({ open, setOpen }) => {
    const refresh = useRefresh();
    const translate = useTranslate();
    const notify = useNotify();
    const [formData, setFormData] = useState({
        areaId: null,
        locId: null,
    });
    const { selectedIds, onUnselectItems } = useListContext();
    const handleClose = (event, reason) => {
        if (reason !== "backdropClick") {
            setOpen(false);
            reset()
            refresh();
            onUnselectItems()
        }
    };
    const reset = () => {
        setFormData({
            areaId: null,
            locId: null,
        })
    }
    const handleReset = (e) => {
        e.preventDefault();
    };
    const handleChange = (value, name) => {
        setFormData((prevData) => ({
            ...prevData,
            [name]: value
        }));
        refresh()
    };
    const removeEmptyKeys = (obj) => {
        return _.pickBy(obj, (value) => {
            if (_.isObject(value)) {
                const newObj = removeEmptyKeys(value);
                return !_.isEmpty(newObj);
            }
            return !_.isNil(value) && (_.isNumber(value) ? value !== 0 : !_.isEmpty(value));
        });
    }
    const handleSubmit = async () => {
        const parmas = {
            matnrId: selectedIds,
            areaId: formData.areaId,
            locId: formData.locId,
        }
        const res = await request.post(`/locAreaMatRela/matnr/bind`, parmas);
        if (res?.data?.code === 200) {
            handleClose()
        } else {
            notify(res.data.msg);
        }
    }
    const [groupId, setGroupId] = useState();
    const warehouseChange = (e) => {
        setGroupId(e.target.value)
    }
    return (
        <Dialog open={open} maxWidth="md" fullWidth>
            <Form onSubmit={handleSubmit}>
                <DialogCloseButton onClose={handleClose} />
                <DialogTitle>{translate('toolbar.bindloc')}</DialogTitle>
                <DialogContent sx={{ mt: 2 }}>
                    <Box sx={{ display: 'flex', flexDirection: 'column', gap: 3 }}>
                        <Grid container spacing={2}>
                            <Grid item xs={4}>
                                <ReferenceInput
                                    source="areaId"
                                    reference="warehouseAreas"
                                >
                                    <AutocompleteInput
                                        label="table.field.loc.areaId"
                                        optionText="name"
                                        onChange={(value) => handleChange(value, 'areaId')}
                                        value={formData.areaId}
                                        validate={required()}
                                        filterToQuery={(val) => ({ name: val })}
                                    />
                                </ReferenceInput>
                            </Grid>
                            <Grid item xs={4}>
                                <ReferenceArrayInput source="locId" reference="loc" >
                                    <SelectArrayInput
                                        label="table.field.locAreaMatRela.locId"
                                        validate={required()}
                                        optionText={'code'}
                                        value={formData.locId}
                                        onChange={(e) => handleChange(e.target.value, 'locId')}
                                    />
                                </ReferenceArrayInput>
                            </Grid>
                        </Grid>
                    </Box>
                </DialogContent>
                <DialogActions sx={{ position: 'sticky', bottom: 0, backgroundColor: 'background.paper', zIndex: 1000 }}>
                    <Box sx={{ width: '100%', display: 'flex', justifyContent: 'space-between' }}>
                        <Button type="submit" variant="contained" startIcon={<SaveIcon />}>
                            {translate('toolbar.confirm')}
                        </Button>
                    </Box>
                </DialogActions>
            </Form>
        </Dialog>
    );
}
export default MatnrModal;
rsf-admin/src/page/basicInfo/matnr/MatnrEdit.jsx
@@ -101,6 +101,7 @@
            mutationMode={EDIT_MODE}
            actions={<CustomerTopToolBar />}
            aside={<EditBaseAside />}
            title={"menu.matnr"}
        >
            <SimpleForm
                shouldUnregister
rsf-admin/src/page/basicInfo/matnr/MatnrList.jsx
@@ -55,6 +55,8 @@
import request from '@/utils/request';
import BatchModal from './BatchModal';
import PrintModal from './PrintModal';
import LinkIcon from '@mui/icons-material/Link';
import BindModal from './BindModal';
const StyledDatagrid = styled(DatagridConfigurable)(({ theme }) => ({
    '& .css-1vooibu-MuiSvgIcon-root': {
@@ -84,7 +86,7 @@
        overflow: 'hidden',
        textOverflow: 'ellipsis',
        display: 'block',
        width: '100px',
        width: '300px',
    },
    '& .RaDatagrid-table': {
        width: '100%'
@@ -238,6 +240,7 @@
                    preferenceKey='matnr'
                    bulkActionButtons={<>
                        <BatchButton />
                        <BindButton />
                        <PrintButton />
                        <BulkDeleteButton mutationMode={OPERATE_MODE} />
                    </>}
@@ -379,4 +382,27 @@
        </>
    )
}
const BindButton = () => {
    const record = useRecordContext();
    const notify = useNotify();
    const refresh = useRefresh();
    const [createDialog, setCreateDialog] = useState(false);
    return (
        <>
            <Button onClick={() => setCreateDialog(true)} label={"toolbar.bindloc"}>
                <LinkIcon />
            </Button>
            <BindModal
                open={createDialog}
                setOpen={setCreateDialog}
            />
        </>
    )
}
rsf-admin/src/page/basicInfo/matnr/PrintModal.jsx
@@ -210,9 +210,12 @@
                }
            }))
            setData(val)
            val.forEach((el) => {
                jsbarcode(`#barcode${el.code}`, el.code, { height: 30 });
            });
            setTimeout(() => {
                val.forEach((el) => {
                    jsbarcode(`#barcode${el.code}`, el.code, { height: 30 });
                });
            }, 10);
        } else {
rsf-admin/src/page/basicInfo/matnrGroup/MatnrGroupCreate.jsx
@@ -84,7 +84,7 @@
                        </DialogTitle>
                        <DialogContent sx={{ mt: 2 }}>
                            <Grid container rowSpacing={2} columnSpacing={2}>
                                <Grid item xs={6} display="flex" gap={1}>
                                    <TextInput
                                        label="table.field.matnrGroup.name"
@@ -104,6 +104,7 @@
                                <Grid item xs={6} display="flex" gap={1}>
                                    <NumberInput
                                        label="table.field.matnrGroup.parentId"
                                        validate={[required()]}
                                        source="parentId"
                                    />
                                </Grid>
rsf-admin/src/page/basicInfo/matnrGroup/MatnrGroupEdit.jsx
@@ -50,6 +50,7 @@
            <Grid item xs={6} display="flex" gap={1}>
                <TreeSelectInput
                    label="table.field.matnrGroup.parentId"
                    validate={[required()]}
                    value={editRecord?.parentId}
                    isTranslate
                    resource={resource}
@@ -76,7 +77,7 @@
const MatnrGroupEdit = (props) => {
    const { editRecord, open, setOpen, callback, resource } = props;
    const translate = useTranslate();
    const notify = useNotify();
@@ -138,43 +139,43 @@
    };
    return (
    <>
        <CreateBase>
            <Dialog
                open={open}
                onClose={handleClose}
                aria-labelledby="form-dialog-title"
                fullWidth
                disableRestoreFocus
                maxWidth="md"   // 'xs' | 'sm' | 'md' | 'lg' | 'xl'
            >
                <Form record={editRecord} onSubmit={onSubmit}>
                    <DialogTitle id="form-dialog-title" sx={{
                        position: 'sticky',
                        top: 0,
                        backgroundColor: 'background.paper',
                        zIndex: 1000
                    }}
                    >
                        {editRecord ? translate('update.title') : translate('create.title')}
                        <Box sx={{ position: 'absolute', top: 8, right: 8, zIndex: 1001 }}>
                            <DialogCloseButton onClose={handleClose} />
                        </Box>
                    </DialogTitle>
                    <DialogContent sx={{ mt: 2 }}>
                        <EditContent
                            editRecord={editRecord}
                        />
                    </DialogContent>
                    <DialogActions sx={{ position: 'sticky', bottom: 0, backgroundColor: 'background.paper', zIndex: 1000 }}>
                        <Toolbar sx={{ width: '100%', justifyContent: 'space-between' }}  >
                            <SaveButton />
                        </Toolbar>
                    </DialogActions>
                </Form>
            </Dialog>
        </CreateBase>
    </>
        <>
            <CreateBase>
                <Dialog
                    open={open}
                    onClose={handleClose}
                    aria-labelledby="form-dialog-title"
                    fullWidth
                    disableRestoreFocus
                    maxWidth="md"   // 'xs' | 'sm' | 'md' | 'lg' | 'xl'
                >
                    <Form record={editRecord} onSubmit={onSubmit}>
                        <DialogTitle id="form-dialog-title" sx={{
                            position: 'sticky',
                            top: 0,
                            backgroundColor: 'background.paper',
                            zIndex: 1000
                        }}
                        >
                            {editRecord ? translate('update.title') : translate('create.title')}
                            <Box sx={{ position: 'absolute', top: 8, right: 8, zIndex: 1001 }}>
                                <DialogCloseButton onClose={handleClose} />
                            </Box>
                        </DialogTitle>
                        <DialogContent sx={{ mt: 2 }}>
                            <EditContent
                                editRecord={editRecord}
                            />
                        </DialogContent>
                        <DialogActions sx={{ position: 'sticky', bottom: 0, backgroundColor: 'background.paper', zIndex: 1000 }}>
                            <Toolbar sx={{ width: '100%', justifyContent: 'space-between' }}  >
                                <SaveButton />
                            </Toolbar>
                        </DialogActions>
                    </Form>
                </Dialog>
            </CreateBase>
        </>
    )
}
rsf-admin/src/page/basicInfo/matnrGroup/MatnrGroupList.jsx
@@ -268,7 +268,7 @@
                    >
                        {expandAll ? translate('common.action.collapseAll') : translate('common.action.expandAll')}
                    </Button>
                    {/* <TextField
                    <TextField
                        label="Search"
                        value={filter}
                        onChange={({ target }) => {
@@ -278,7 +278,7 @@
                        size="small"
                        margin="dense"
                        fullWidth
                    /> */}
                    />
                </Box>
                <Box>
                    <Button
rsf-admin/src/page/basicInfo/warehouse/WarehouseEdit.jsx
@@ -49,6 +49,7 @@
            mutationMode={EDIT_MODE}
            actions={<CustomerTopToolBar />}
            aside={<EditBaseAside />}
            title={"menu.warehouse"}
        >
            <SimpleForm
                shouldUnregister
rsf-admin/src/page/components/ConfirmModal.jsx
New file
@@ -0,0 +1,50 @@
import React, { useState, useRef, useEffect, useMemo, useCallback } from "react";
import { Button, Dialog, DialogActions, DialogContent, DialogContentText, DialogTitle } from '@mui/material';
import {
    useTranslate,
} from 'react-admin';
const ConfirmModal = (props) => {
    const { open, onConfirm, setOpen } = props;
    const translate = useTranslate();
    const handleClose = (event) => {
        event.stopPropagation();
        setOpen(false);
    };
    const handleConfirm = (event) => {
        handleClose(event);
        onConfirm();
    };
    return (
        <>
            <Dialog
                aria-labelledby="dialog-title"
                aria-describedby="dialog-description"
                open={open}
                onClose={handleClose}
            >
                <DialogTitle>{translate('common.msg.confirm.tip')}</DialogTitle>
                <DialogContent>
                    <DialogContentText>
                        {translate('common.msg.confirm.desc')}
                    </DialogContentText>
                </DialogContent>
                <DialogActions>
                    <Button onClick={handleClose} color="primary">
                        {translate('ra.action.cancel')}
                    </Button>
                    <Button onClick={handleConfirm} color="primary">
                        {translate('ra.action.confirm')}
                    </Button>
                </DialogActions>
            </Dialog>
        </>
    )
}
export default ConfirmModal;
rsf-admin/src/page/container/ContainerEdit.jsx
@@ -50,6 +50,7 @@
            mutationMode={EDIT_MODE}
            actions={<CustomerTopToolBar />}
            aside={<EditBaseAside />}
            title={"menu.container"}
        >
            <SimpleForm
                shouldUnregister
rsf-admin/src/page/contract/ContractEdit.jsx
@@ -49,6 +49,7 @@
            mutationMode={EDIT_MODE}
            actions={<CustomerTopToolBar />}
            aside={<EditBaseAside />}
            title={"menu.contract"}
        >
            <SimpleForm
                shouldUnregister
rsf-admin/src/page/fields/FieldsList.jsx
@@ -68,13 +68,13 @@
    <SelectInput source="unique" label="table.field.fields.unique"
        choices={[
            { id: 0, name: ' 非唯一' },
            { id:   1, name: '  唯一' },
            { id: 1, name: '  唯一' },
        ]}
    />,
    <SelectInput source="flagEnable" label="table.field.fields.flagEnable"
        choices={[
            { id: 0, name: ' 不启用' },
            { id:  1, name: ' 启用' },
            { id: 1, name: ' 启用' },
        ]}
    />,
@@ -105,7 +105,7 @@
                        theme.transitions.create(['all'], {
                            duration: theme.transitions.duration.enteringScreen,
                        }),
                    marginRight: !!drawerVal ? `${PAGE_DRAWER_WIDTH}px` : 0,
                    marginRight: drawerVal ? `${PAGE_DRAWER_WIDTH}px` : 0,
                }}
                title={"menu.fields"}
                empty={<EmptyData onClick={() => { setCreateDialog(true) }} />}
@@ -125,8 +125,6 @@
                    preferenceKey='fields'
                    bulkActionButtons={() => <BulkDeleteButton mutationMode={OPERATE_MODE} />}
                    rowClick={(id, resource, record) => false}
                    expand={() => <FieldsPanel />}
                    expandSingle={true}
                    omit={['id', 'createTime', 'createBy', 'memo']}
                >
                    <NumberField source="id" />
rsf-admin/src/page/fieldsItem/FieldsItemList.jsx
@@ -96,7 +96,7 @@
                        theme.transitions.create(['all'], {
                            duration: theme.transitions.duration.enteringScreen,
                        }),
                    marginRight: !!drawerVal ? `${PAGE_DRAWER_WIDTH}px` : 0,
                    marginRight: drawerVal ? `${PAGE_DRAWER_WIDTH}px` : 0,
                }}
                title={"menu.fieldsItem"}
                empty={<EmptyData onClick={() => { setCreateDialog(true) }} />}
@@ -116,8 +116,6 @@
                    preferenceKey='fieldsItem'
                    bulkActionButtons={() => <BulkDeleteButton mutationMode={OPERATE_MODE} />}
                    rowClick={(id, resource, record) => false}
                    expand={() => <FieldsItemPanel />}
                    expandSingle={true}
                    omit={['id', 'createTime', 'createBy', 'memo']}
                >
                    <NumberField source="id" />
rsf-admin/src/page/purchaseItem/PurchaseItemList.jsx
@@ -129,8 +129,6 @@
            preferenceKey='purchaseItem'
            bulkActionButtons={() => <BulkDeleteButton mutationMode={OPERATE_MODE} />}
            rowClick={(id, resource, record) => false}
            expand={() => <PurchaseItemPanel />}
            expandSingle={true}
            omit={['id', 'createTime', 'createBy', 'memo']}
          >
            <NumberField source="id" />
rsf-admin/src/page/qlyInspect/QlyInspectList.jsx
@@ -97,7 +97,7 @@
                        theme.transitions.create(['all'], {
                            duration: theme.transitions.duration.enteringScreen,
                        }),
                    marginRight: !!drawerVal ? `${PAGE_DRAWER_WIDTH}px` : 0,
                    marginRight: drawerVal ? `${PAGE_DRAWER_WIDTH}px` : 0,
                }}
                title={"menu.qlyInspect"}
                empty={<EmptyData onClick={() => { setCreateDialog(true) }} />}
@@ -117,8 +117,6 @@
                    preferenceKey='qlyInspect'
                    bulkActionButtons={() => <BulkDeleteButton mutationMode={OPERATE_MODE} />}
                    rowClick={(id, resource, record) => false}
                    expand={() => <QlyInspectPanel />}
                    expandSingle={true}
                    omit={['id', 'createTime', 'createBy', 'memo']}
                >
                    <NumberField source="id" />
rsf-admin/src/page/qlyIsptItem/QlyIsptItemList.jsx
@@ -103,7 +103,7 @@
                        theme.transitions.create(['all'], {
                            duration: theme.transitions.duration.enteringScreen,
                        }),
                    marginRight: !!drawerVal ? `${PAGE_DRAWER_WIDTH}px` : 0,
                    marginRight: drawerVal ? `${PAGE_DRAWER_WIDTH}px` : 0,
                }}
                title={"menu.qlyIsptItem"}
                empty={<EmptyData onClick={() => { setCreateDialog(true) }} />}
@@ -123,8 +123,6 @@
                    preferenceKey='qlyIsptItem'
                    bulkActionButtons={() => <BulkDeleteButton mutationMode={OPERATE_MODE} />}
                    rowClick={(id, resource, record) => false}
                    expand={() => <QlyIsptItemPanel />}
                    expandSingle={true}
                    omit={['id', 'createTime', 'createBy', 'memo']}
                >
                    <NumberField source="id" />
rsf-admin/src/page/system/config/ConfigList.jsx
@@ -100,7 +100,7 @@
                        theme.transitions.create(['all'], {
                            duration: theme.transitions.duration.enteringScreen,
                        }),
                    marginRight: !!drawerVal ? `${PAGE_DRAWER_WIDTH}px` : 0,
                    marginRight: drawerVal ? `${PAGE_DRAWER_WIDTH}px` : 0,
                }}
                title={"menu.config"}
                empty={<EmptyData onClick={() => { setCreateDialog(true) }} />}
@@ -121,8 +121,6 @@
                    preferenceKey='config'
                    bulkActionButtons={() => <BulkDeleteButton mutationMode={OPERATE_MODE} />}
                    rowClick={(id, resource, record) => false}
                    expand={() => <ConfigPanel />}
                    expandSingle={true}
                    omit={['id', 'createTime', 'memo']}
                >
                    <NumberField source="id" />
rsf-admin/src/page/system/dicts/dictData/DictDataCreate.jsx
@@ -114,6 +114,7 @@
                                <Grid item xs={6} display="flex" gap={1}>
                                    <TextInput
                                        label="table.field.dictData.label"
                                        validate={required()}
                                        source="label"
                                        parse={v => v}
                                    />
rsf-admin/src/page/system/dicts/dictData/DictDataEdit.jsx
@@ -93,6 +93,7 @@
                            <TextInput
                                label="table.field.dictData.label"
                                source="label"
                                validate={required()}
                                parse={v => v}
                            />
                        </Stack>
rsf-admin/src/page/system/dicts/dictData/DictDataList.jsx
@@ -128,8 +128,6 @@
                        preferenceKey='dictData'
                        bulkActionButtons={() => <BulkDeleteButton mutationMode={OPERATE_MODE} />}
                        rowClick={(id, resource, record) => false}
                        expand={() => <DictDataPanel />}
                        expandSingle={true}
                        omit={['id', 'createTime', 'createBy', 'memo']}
                    >
                        <NumberField source="id" />
rsf-admin/src/page/system/dicts/dictType/DictTypeList.jsx
@@ -119,8 +119,6 @@
                    preferenceKey='dictType'
                    bulkActionButtons={() => <BulkDeleteButton mutationMode={OPERATE_MODE} />}
                    rowClick={(id, resource, record) => false}
                    expand={() => <DictTypePanel />}
                    expandSingle={true}
                    omit={['id', 'createTime', 'createBy', 'memo']}
                >
                    <NumberField source="id" />
rsf-admin/src/page/system/host/HostList.jsx
@@ -82,7 +82,7 @@
                        theme.transitions.create(['all'], {
                            duration: theme.transitions.duration.enteringScreen,
                        }),
                    marginRight: !!drawerVal ? `${PAGE_DRAWER_WIDTH}px` : 0,
                    marginRight: drawerVal ? `${PAGE_DRAWER_WIDTH}px` : 0,
                }}
                title={"menu.host"}
                empty={<EmptyData onClick={() => { setCreateDialog(true) }} />}
@@ -102,8 +102,6 @@
                    preferenceKey='host'
                    bulkActionButtons={() => <BulkDeleteButton mutationMode={OPERATE_MODE} />}
                    rowClick={(id, resource, record) => false}
                    expand={() => <HostPanel />}
                    expandSingle={true}
                    omit={['id', 'createTime', 'memo']}
                >
                    <NumberField source="id" />
rsf-admin/src/page/system/serialRule/SerialRuleList.jsx
@@ -146,8 +146,6 @@
            <BulkDeleteButton mutationMode={OPERATE_MODE} />
          )}
          rowClick={(id, resource, record) => false}
          expand={() => <SerialRulePanel />}
          expandSingle={true}
          omit={["id", "createTime", "createBy", "memo"]}
        >
          <NumberField source="id" />
rsf-admin/src/page/system/serialRuleItem/SerialRuleItemList.jsx
@@ -148,8 +148,6 @@
              <BulkDeleteButton mutationMode={OPERATE_MODE} />
            )}
            rowClick={(id, resource, record) => false}
            expand={() => <SerialRuleItemPanel />}
            expandSingle={true}
            omit={["id", "createTime", "createBy", "memo"]}
          >
            <NumberField source="id" />
rsf-admin/src/page/system/tenant/TenantList.jsx
@@ -86,7 +86,7 @@
                        theme.transitions.create(['all'], {
                            duration: theme.transitions.duration.enteringScreen,
                        }),
                    marginRight: !!drawerVal ? `${PAGE_DRAWER_WIDTH}px` : 0,
                    marginRight: drawerVal ? `${PAGE_DRAWER_WIDTH}px` : 0,
                }}
                title={"menu.tenant"}
                empty={<EmptyData onClick={() => { setCreateDialog(true) }} />}
@@ -106,8 +106,6 @@
                    preferenceKey='tenant'
                    bulkActionButtons={() => <BulkDeleteButton mutationMode={OPERATE_MODE} />}
                    rowClick={(id, resource, record) => false}
                    expand={() => <TenantPanel />}
                    expandSingle={true}
                    omit={['id', 'createTime', 'memo']}
                >
                    <NumberField source="id" />
rsf-admin/src/page/system/userLogin/UserLoginList.jsx
@@ -100,7 +100,7 @@
                        theme.transitions.create(['all'], {
                            duration: theme.transitions.duration.enteringScreen,
                        }),
                    marginRight: !!drawerVal ? `${PAGE_DRAWER_WIDTH}px` : 0,
                    marginRight: drawerVal ? `${PAGE_DRAWER_WIDTH}px` : 0,
                }}
                title={"menu.userLogin"}
                empty={<EmptyData onClick={() => { setCreateDialog(true) }} />}
@@ -120,8 +120,6 @@
                    preferenceKey='userLogin'
                    bulkActionButtons={() => <BulkDeleteButton mutationMode={OPERATE_MODE} />}
                    rowClick={(id, resource, record) => false}
                    expand={() => <UserLoginPanel />}
                    expandSingle={true}
                    omit={['id', 'memo', 'type', 'system', 'updateTime']}
                >
                    <NumberField source="id" />
rsf-admin/src/page/warehouseAreas/WarehouseAreasList.jsx
@@ -60,7 +60,7 @@
const filters = [
    <SearchInput source="condition" alwaysOn />,
    <TextField source="warehouseId" label="table.field.warehouseAreas.wareId" alwaysOn />,
    <TextInput source="uuid" label="table.field.warehouseAreas.uuid" />,
    <TextInput source="name" label="table.field.warehouseAreas.name" />,
    <TextInput source="code" label="table.field.warehouseAreas.code" />,
rsf-admin/src/page/warehouseAreasItem/WarehouseAreasItemList.jsx
@@ -127,8 +127,6 @@
                    preferenceKey='warehouseAreasItem'
                    bulkActionButtons={() => <BulkDeleteButton mutationMode={OPERATE_MODE} />}
                    rowClick={(id, resource, record) => false}
                    expand={() => <WarehouseAreasItemPanel />}
                    expandSingle={true}
                    omit={['id', 'createTime', 'createBy', 'memo']}
                >
                    <NumberField source="id" />
rsf-common/src/main/java/com/vincent/rsf/common/utils/Utils.java
@@ -48,6 +48,26 @@
        return result;
    }
    public static <T, R> List<T> getAllTree(List<T> data, R parentId, Function<? super T, ? extends R> parentIdMapper, Function<? super T, ? extends R> idMapper, BiConsumer<T, List<T>> consumer) {
        List<T> result = new ArrayList<>();
        for (T datum : data) {
            R dParentId = parentIdMapper.apply(datum);
            R dId = idMapper.apply(datum);
            if (dParentId.equals(dId)) {
                List<T> children = toTreeData(data, dId, parentIdMapper, idMapper, consumer);
                if (!children.isEmpty()) {
                    consumer.accept(datum, children);
                }
                result.add(datum);
            }
            if (dParentId.equals(dId)) {
                continue;
            }
        }
        return result;
    }
    public static <T> void treeRemove(List<T> list, String condition, Function<? super T, ? extends String> fetcher, Function<T, List<T>> childrenGetter) {
        Iterator<T> iterator = list.iterator();
        while (iterator.hasNext()) {
rsf-server/src/main/java/asnOrderItemLog.sql
File was deleted
rsf-server/src/main/java/asnOrderLog.sql
File was deleted
rsf-server/src/main/java/com/vincent/rsf/server/common/CodeBuilder.java
@@ -22,8 +22,8 @@
//        generator.username="sa";
//        generator.password="Zoneyung@zy56$";
        generator.table="man_loc_area_mat_rela";
        generator.tableDesc="loc areas mats rela";
        generator.table="man_loc_area_mat";
        generator.tableDesc="loc areas mats";
        generator.packagePath="com.vincent.rsf.server.test";
        generator.build();
rsf-server/src/main/java/com/vincent/rsf/server/manager/controller/LocAreaMatController.java
New file
@@ -0,0 +1,112 @@
package com.vincent.rsf.server.manager.controller;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.vincent.rsf.framework.common.Cools;
import com.vincent.rsf.framework.common.R;
import com.vincent.rsf.server.common.utils.ExcelUtil;
import com.vincent.rsf.server.common.annotation.OperationLog;
import com.vincent.rsf.server.common.domain.BaseParam;
import com.vincent.rsf.server.common.domain.KeyValVo;
import com.vincent.rsf.server.common.domain.PageParam;
import com.vincent.rsf.server.manager.entity.LocAreaMat;
import com.vincent.rsf.server.manager.service.LocAreaMatService;
import com.vincent.rsf.server.system.controller.BaseController;
import io.swagger.annotations.Api;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletResponse;
import java.util.*;
@Api(tags = "逻辑分区")
@RestController
public class LocAreaMatController extends BaseController {
    @Autowired
    private LocAreaMatService locAreaMatService;
    @PreAuthorize("hasAuthority('manager:locAreaMat:list')")
    @PostMapping("/locAreaMat/page")
    public R page(@RequestBody Map<String, Object> map) {
        BaseParam baseParam = buildParam(map, BaseParam.class);
        PageParam<LocAreaMat, BaseParam> pageParam = new PageParam<>(baseParam, LocAreaMat.class);
        return R.ok().add(locAreaMatService.page(pageParam, pageParam.buildWrapper(true)));
    }
    @PreAuthorize("hasAuthority('manager:locAreaMat:list')")
    @PostMapping("/locAreaMat/list")
    public R list(@RequestBody Map<String, Object> map) {
        return R.ok().add(locAreaMatService.list());
    }
    @PreAuthorize("hasAuthority('manager:locAreaMat:list')")
    @PostMapping({"/locAreaMat/many/{ids}", "/locAreaMats/many/{ids}"})
    public R many(@PathVariable Long[] ids) {
        return R.ok().add(locAreaMatService.listByIds(Arrays.asList(ids)));
    }
    @PreAuthorize("hasAuthority('manager:locAreaMat:list')")
    @GetMapping("/locAreaMat/{id}")
    public R get(@PathVariable("id") Long id) {
        return R.ok().add(locAreaMatService.getById(id));
    }
    @PreAuthorize("hasAuthority('manager:locAreaMat:save')")
    @OperationLog("Create loc areas mats")
    @PostMapping("/locAreaMat/save")
    public R save(@RequestBody LocAreaMat locAreaMat) {
        locAreaMat.setCreateBy(getLoginUserId());
        locAreaMat.setCreateTime(new Date());
        locAreaMat.setUpdateBy(getLoginUserId());
        locAreaMat.setUpdateTime(new Date());
        if (!locAreaMatService.save(locAreaMat)) {
            return R.error("Save Fail");
        }
        return R.ok("Save Success").add(locAreaMat);
    }
    @PreAuthorize("hasAuthority('manager:locAreaMat:update')")
    @OperationLog("Update loc areas mats")
    @PostMapping("/locAreaMat/update")
    public R update(@RequestBody LocAreaMat locAreaMat) {
        locAreaMat.setUpdateBy(getLoginUserId());
        locAreaMat.setUpdateTime(new Date());
        if (!locAreaMatService.updateById(locAreaMat)) {
            return R.error("Update Fail");
        }
        return R.ok("Update Success").add(locAreaMat);
    }
    @PreAuthorize("hasAuthority('manager:locAreaMat:remove')")
    @OperationLog("Delete loc areas mats")
    @PostMapping("/locAreaMat/remove/{ids}")
    public R remove(@PathVariable Long[] ids) {
        if (!locAreaMatService.removeByIds(Arrays.asList(ids))) {
            return R.error("Delete Fail");
        }
        return R.ok("Delete Success").add(ids);
    }
    @PreAuthorize("hasAuthority('manager:locAreaMat:list')")
    @PostMapping("/locAreaMat/query")
    public R query(@RequestParam(required = false) String condition) {
        List<KeyValVo> vos = new ArrayList<>();
        LambdaQueryWrapper<LocAreaMat> wrapper = new LambdaQueryWrapper<>();
        if (!Cools.isEmpty(condition)) {
            wrapper.like(LocAreaMat::getId, condition);
        }
        locAreaMatService.page(new Page<>(1, 30), wrapper).getRecords().forEach(
                item -> vos.add(new KeyValVo(item.getId(), item.getId()))
        );
        return R.ok().add(vos);
    }
    @PreAuthorize("hasAuthority('manager:locAreaMat:list')")
    @PostMapping("/locAreaMat/export")
    public void export(@RequestBody Map<String, Object> map, HttpServletResponse response) throws Exception {
        ExcelUtil.build(ExcelUtil.create(locAreaMatService.list(), LocAreaMat.class), response);
    }
}
rsf-server/src/main/java/com/vincent/rsf/server/manager/controller/LocAreaMatRelaController.java
@@ -16,6 +16,7 @@
import com.vincent.rsf.server.system.controller.BaseController;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;
@@ -60,10 +61,9 @@
    @OperationLog("Create loc areas mats rela")
    @PostMapping("/locAreaMatRela/save")
    public R save(@RequestBody LocAreaMatRela locAreaMatRela) {
        locAreaMatRela.setCreateBy(getLoginUserId());
        locAreaMatRela.setCreateTime(new Date());
        locAreaMatRela.setUpdateBy(getLoginUserId());
        locAreaMatRela.setUpdateTime(new Date());
        if (!locAreaMatRelaService.save(locAreaMatRela)) {
            return R.error("Save Fail");
        }
@@ -82,10 +82,53 @@
        return R.ok("Update Success").add(locAreaMatRela);
    }
    @PreAuthorize("hasAuthority('manager:locAreaMatRela:remove')")
    @ApiOperation("删除物料分组")
    @GetMapping("/locAreaMatRela/group")
    @PreAuthorize("hasAuthority('manager:locAreaMatRela:update')")
    public R remByGroup(@RequestBody Map<String, Object> map) {
        if (Objects.isNull(map)) {
            throw new CoolException("参数不能为空!!");
        }
        if (!StringUtils.isBlank(map.get("groupId").toString())) {
            throw new CoolException("库位类型不能为空!!");
        }
        if (!StringUtils.isBlank(map.get("areaMatId").toString())) {
            throw new CoolException("主单ID不能为空!!");
        }
        if (locAreaMatRelaService.removeByGroupId(map)) {
            return R.ok();
        } else {
            return R.error("删除失败!!");
        }
    }
    @ApiOperation("删除库位类型")
    @GetMapping("/locAreaMatRela/locType/remove")
    @PreAuthorize("hasAuthority('manager:locAreaMatRela:update')")
    public R removByLocType(@RequestBody Map<String, Object> param) {
        if (Objects.isNull(param)) {
            throw new CoolException("参数不能为空!!!");
        }
        if (!StringUtils.isBlank(param.get("typeId").toString())) {
            throw new CoolException("库位类型不能为空!!");
        }
        if (!StringUtils.isBlank(param.get("areaMatId").toString())) {
            throw new CoolException("主单ID不能为空!!");
        }
        if (locAreaMatRelaService.removeByLocType(param)) {
            return R.ok();
        } else {
            return R.ok("删除失败!!");
        }
    }
    @PreAuthorize("hasAuthority('manager:locAreaMatRela:list')")
    @OperationLog("Delete loc areas mats rela")
    @PostMapping("/locAreaMatRela/remove/{ids}")
    public R remove(@PathVariable Long[] ids) {
        if (Objects.isNull(ids)) {
            throw new CoolException("参数不能为空!!");
        }
        if (!locAreaMatRelaService.removeByIds(Arrays.asList(ids))) {
            return R.error("Delete Fail");
        }
@@ -107,6 +150,27 @@
    }
    @PreAuthorize("hasAuthority('manager:locAreaMatRela:list')")
    @ApiOperation("获取库区物料分组")
    @GetMapping("/locAreaMatRela/groups/{id}")
    public R getAreaMatGroup(@PathVariable Long id) {
        if (Objects.isNull(id)) {
            throw new CoolException("参数不能为空!!");
        }
        return R.ok(locAreaMatRelaService.getAllGroups(id));
    }
    @PreAuthorize("hasAuthority('manager:locAreaMatRela:list')")
    @ApiOperation("获取库区库位类型")
    @GetMapping("/locAreaMatRela/locType/{id}")
    public R getAreaMatLocType(@PathVariable Long id) {
        if (Objects.isNull(id)) {
            throw new CoolException("参数不能为空!!");
        }
        return R.ok(locAreaMatRelaService.getAllLocType(id));
    }
    @PreAuthorize("hasAuthority('manager:locAreaMatRela:list')")
    @PostMapping("/locAreaMatRela/export")
    public void export(@RequestBody Map<String, Object> map, HttpServletResponse response) throws Exception {
        ExcelUtil.build(ExcelUtil.create(locAreaMatRelaService.list(), LocAreaMatRela.class), response);
@@ -122,12 +186,12 @@
        if (Objects.isNull(param.getAreaId())) {
            throw new CoolException("库区不能为空!!");
        }
//        if (Objects.isNull(param.getTypeId()) || Objects.isNull(param.getLocId()) || param.getLocId().isEmpty() || param.getTypeId().isEmpty()) {
//            throw new CoolException("库位类型或库位不能为空!!");
//        }
//        if (Objects.isNull(param.getGroupId()) || Objects.isNull(param.getMatnrId()) || param.getMatnrId().isEmpty()) {
//            throw new CoolException("物料或物料分类不能为空!!");
//        }
        if (Objects.isNull(param.getWarehouseId())) {
            throw new CoolException("仓库不能为空!!");
        }
        if (Objects.isNull(param.getAreaMatId())) {
            throw new CoolException("主单ID不能为空!!");
        }
        return locAreaMatRelaService.binMatnrs(param);
    }
rsf-server/src/main/java/com/vincent/rsf/server/manager/controller/MatnrGroupController.java
@@ -23,6 +23,7 @@
import javax.servlet.http.HttpServletResponse;
import java.util.*;
import java.util.stream.Collectors;
@Api(tags = "物料分组")
@RestController
@@ -141,18 +142,12 @@
    @PreAuthorize("hasAuthority('manager:matnrGroup:list')")
    @PostMapping("/matnrGroup/tree")
    public R tree(@RequestBody(required = false) Map<String, Object> map) {
        List<MatnrGroup> matnrs = new ArrayList<>();
        if (Objects.isNull(map)) {
            matnrs = matnrGroupService.list(new LambdaQueryWrapper<MatnrGroup>().orderByAsc(MatnrGroup::getCode));
        } else {
            if (Objects.isNull(map.get("condition"))) {
                return R.ok("condition参数不能为空!!");
            }
            matnrs = matnrGroupService.list(new LambdaQueryWrapper<MatnrGroup>()
                    .like(MatnrGroup::getName, map.get("condition")).orderByAsc(MatnrGroup::getCode));
            return R.error("参数不能为空!!");
        }
        List<MatnrGroup> treeData = Utils.toTreeData(matnrs, 0L, MatnrGroup::getParentId, MatnrGroup::getId, MatnrGroup::setChildren);
        return R.ok().add(treeData);
        List<MatnrGroup> matnrs = matnrGroupService.getTreeData(map);
        return R.ok().add(matnrs);
    }
rsf-server/src/main/java/com/vincent/rsf/server/manager/controller/WarehouseAreasController.java
@@ -98,15 +98,15 @@
            throw new CoolException("数据错误:仓库库区不存在!!");
        }
        if (!warehouseAreas.getName().equals(areas.getName())) {
            List<WarehouseAreas> areasList = warehouseAreasService.list(new LambdaQueryWrapper<WarehouseAreas>().eq(WarehouseAreas::getName, areas.getName()));
            List<WarehouseAreas> areasList = warehouseAreasService.list(new LambdaQueryWrapper<WarehouseAreas>().eq(WarehouseAreas::getName, warehouseAreas.getName()));
            if (!areasList.isEmpty()) {
                throw new CoolException("仓库名已存在!!");
                throw new CoolException("名称已存在!!");
            }
        }
        if (!warehouseAreas.getCode().equals(areas.getCode())) {
            List<WarehouseAreas> areasList = warehouseAreasService.list(new LambdaQueryWrapper<WarehouseAreas>().eq(WarehouseAreas::getCode, areas.getCode()));
            List<WarehouseAreas> areasList = warehouseAreasService.list(new LambdaQueryWrapper<WarehouseAreas>().eq(WarehouseAreas::getCode, warehouseAreas.getCode()));
            if (!areasList.isEmpty()) {
                throw new CoolException("仓库编码已存在!!");
                throw new CoolException("编码已存在!!");
            }
        }
rsf-server/src/main/java/com/vincent/rsf/server/manager/controller/params/LocAreaMatsParam.java
@@ -26,6 +26,12 @@
    @ApiModelProperty("库区ID")
    private Long areaId;
    @ApiModelProperty("仓库ID")
    private Long warehouseId;
    @ApiModelProperty("主单ID")
    private Long areaMatId;
    @ApiModelProperty("库位类型")
    private List<Long> typeId;
rsf-server/src/main/java/com/vincent/rsf/server/manager/entity/LocAreaMat.java
New file
@@ -0,0 +1,217 @@
package com.vincent.rsf.server.manager.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableLogic;
import com.baomidou.mybatisplus.annotation.TableName;
import com.vincent.rsf.framework.common.Cools;
import com.vincent.rsf.framework.common.SpringUtils;
import com.vincent.rsf.server.manager.service.WarehouseAreasService;
import com.vincent.rsf.server.manager.service.WarehouseService;
import com.vincent.rsf.server.system.entity.User;
import com.vincent.rsf.server.system.service.UserService;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import org.springframework.format.annotation.DateTimeFormat;
import java.io.Serializable;
import java.text.SimpleDateFormat;
import java.util.Date;
@Data
@TableName("man_loc_area_mat")
public class LocAreaMat implements Serializable {
    private static final long serialVersionUID = 1L;
    /**
     * ID
     */
    @ApiModelProperty(value= "ID")
    @TableId(value = "id", type = IdType.AUTO)
    private Long id;
    /**
     * 逻辑编号
     */
    @ApiModelProperty(value= "逻辑编号")
    private String code;
    /**
     * 仓库ID(*)
     */
    @ApiModelProperty(value= "仓库ID(*)")
    private Long warehouseId;
    /**
     * 库区ID(*)
     */
    @ApiModelProperty(value= "库区ID(*)")
    private Long areaId;
    /**
     * 逻辑描述
     */
    @ApiModelProperty(value= "逻辑描述")
    private String depict;
    /**
     * 状态 1: 正常  0: 冻结
     */
    @ApiModelProperty(value= "状态 1: 正常  0: 冻结  ")
    private Integer status;
    /**
     * 是否删除 1: 是  0: 否
     */
    @ApiModelProperty(value= "是否删除 1: 是  0: 否  ")
    @TableLogic
    private Integer deleted;
    /**
     * 租户
     */
    @ApiModelProperty(value= "租户")
    private Integer tenantId;
    /**
     * 添加人员
     */
    @ApiModelProperty(value= "添加人员")
    private Long createBy;
    /**
     * 添加时间
     */
    @ApiModelProperty(value= "添加时间")
    @DateTimeFormat(pattern="yyyy-MM-dd HH:mm:ss")
    private Date createTime;
    /**
     * 修改人员
     */
    @ApiModelProperty(value= "修改人员")
    private Long updateBy;
    /**
     * 修改时间
     */
    @ApiModelProperty(value= "修改时间")
    @DateTimeFormat(pattern="yyyy-MM-dd HH:mm:ss")
    private Date updateTime;
    /**
     * 备注
     */
    @ApiModelProperty(value= "备注")
    private String memo;
    public LocAreaMat() {}
    public LocAreaMat(String code, Long warehouseId, Long areaId, String depict, Integer status, Integer deleted, Integer tenantId, Long createBy, Date createTime, Long updateBy, Date updateTime, String memo) {
        this.code = code;
        this.warehouseId = warehouseId;
        this.areaId = areaId;
        this.depict = depict;
        this.status = status;
        this.deleted = deleted;
        this.tenantId = tenantId;
        this.createBy = createBy;
        this.createTime = createTime;
        this.updateBy = updateBy;
        this.updateTime = updateTime;
        this.memo = memo;
    }
//    LocAreaMat locAreaMat = new LocAreaMat(
//            null,    // 逻辑编号
//            null,    // 仓库ID(*)
//            null,    // 库区ID(*)
//            null,    // 逻辑描述
//            null,    // 状态[非空]
//            null,    // 是否删除[非空]
//            null,    // 租户
//            null,    // 添加人员
//            null,    // 添加时间[非空]
//            null,    // 修改人员
//            null,    // 修改时间[非空]
//            null    // 备注
//    );
    public String getWarehouseId$(){
        WarehouseService service = SpringUtils.getBean(WarehouseService.class);
        Warehouse warehouse = service.getById(this.warehouseId);
        if (!Cools.isEmpty(warehouse)){
            return String.valueOf(warehouse.getName());
        }
        return null;
    }
    public String getAreaId$(){
        WarehouseAreasService service = SpringUtils.getBean(WarehouseAreasService.class);
        WarehouseAreas warehouseArea = service.getById(this.areaId);
        if (!Cools.isEmpty(warehouseArea)){
            return String.valueOf(warehouseArea.getName());
        }
        return null;
    }
    public String getStatus$(){
        if (null == this.status){ return null; }
        switch (this.status){
            case 1:
                return "正常";
            case 0:
                return "冻结";
            default:
                return String.valueOf(this.status);
        }
    }
    public String getCreateBy$(){
        UserService service = SpringUtils.getBean(UserService.class);
        User user = service.getById(this.createBy);
        if (!Cools.isEmpty(user)){
            return String.valueOf(user.getNickname());
        }
        return null;
    }
    public String getCreateTime$(){
        if (Cools.isEmpty(this.createTime)){
            return "";
        }
        return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(this.createTime);
    }
    public String getUpdateBy$(){
        UserService service = SpringUtils.getBean(UserService.class);
        User user = service.getById(this.updateBy);
        if (!Cools.isEmpty(user)){
            return String.valueOf(user.getNickname());
        }
        return null;
    }
    public String getUpdateTime$(){
        if (Cools.isEmpty(this.updateTime)){
            return "";
        }
        return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(this.updateTime);
    }
    public Boolean getStatusBool(){
        if (null == this.status){ return null; }
        switch (this.status){
            case 1:
                return true;
            case 0:
                return false;
            default:
                return null;
        }
    }
}
rsf-server/src/main/java/com/vincent/rsf/server/manager/entity/LocAreaMatRela.java
@@ -45,6 +45,12 @@
    private Long areaId;
    /**
     * 主单ID
     */
    @ApiModelProperty("主单ID")
    private Long areaMatId;
    /**
     * 编号
     */
    @ApiModelProperty(value= "编号")
rsf-server/src/main/java/com/vincent/rsf/server/manager/entity/LocTypeRela.java
@@ -5,6 +5,8 @@
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableLogic;
import com.baomidou.mybatisplus.annotation.TableName;
import com.vincent.rsf.server.manager.service.LocService;
import com.vincent.rsf.server.manager.service.WarehouseService;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
@@ -16,6 +18,7 @@
import java.io.Serializable;
import java.util.Date;
import java.util.Objects;
@Data
@Accessors(chain = true)
@@ -50,4 +53,39 @@
        this.typeId = typeId;
    }
//    /**
//     * @author Ryan
//     * @description 获取库位
//     * @param
//     * @return
//     * @time 2025/3/24 10:28
//     */
//    public String getLocId$() {
//        if (this.warehouseId == null) { return null; }
//        WarehouseService warehouseService = SpringUtils.getBean(WarehouseService.class);
//        Warehouse warehouse = warehouseService.getById(this.warehouseId);
//        if (Objects.isNull(warehouse)) {
//            return null;
//        }
//        return warehouse.getName();
//    }
    /**
     * @author Ryan
     * @description 获取库区名称
     * @param
     * @return
     * @time 2025/3/24 10:27
     */
    public String getAreaId$() {
        if (this.locId == null) { return null; }
        LocService locService = SpringUtils.getBean(LocService.class);
        Loc byId = locService.getById(this.locId);
        if (Objects.isNull(byId)) {
            return null;
        }
        return  byId.getCode();
    }
}
rsf-server/src/main/java/com/vincent/rsf/server/manager/mapper/LocAreaMatMapper.java
New file
@@ -0,0 +1,12 @@
package com.vincent.rsf.server.manager.mapper;
import com.vincent.rsf.server.manager.entity.LocAreaMat;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Mapper;
import org.springframework.stereotype.Repository;
@Mapper
@Repository
public interface LocAreaMatMapper extends BaseMapper<LocAreaMat> {
}
rsf-server/src/main/java/com/vincent/rsf/server/manager/service/LocAreaMatRelaService.java
@@ -4,8 +4,22 @@
import com.vincent.rsf.framework.common.R;
import com.vincent.rsf.server.manager.controller.params.LocAreaMatsParam;
import com.vincent.rsf.server.manager.entity.LocAreaMatRela;
import com.vincent.rsf.server.manager.entity.LocType;
import com.vincent.rsf.server.manager.entity.LocTypeRela;
import com.vincent.rsf.server.manager.entity.MatnrGroup;
import java.util.List;
import java.util.Map;
public interface LocAreaMatRelaService extends IService<LocAreaMatRela> {
    R binMatnrs(LocAreaMatsParam param);
    Boolean removeByGroupId(Map<String, Object> params);
    boolean removeByLocType(Map<String, Object> params);
    List<MatnrGroup> getAllGroups(Long id);
    List<LocType> getAllLocType(Long id);
}
rsf-server/src/main/java/com/vincent/rsf/server/manager/service/LocAreaMatService.java
New file
@@ -0,0 +1,8 @@
package com.vincent.rsf.server.manager.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.vincent.rsf.server.manager.entity.LocAreaMat;
public interface LocAreaMatService extends IService<LocAreaMat> {
}
rsf-server/src/main/java/com/vincent/rsf/server/manager/service/MatnrGroupService.java
@@ -3,7 +3,11 @@
import com.baomidou.mybatisplus.extension.service.IService;
import com.vincent.rsf.server.manager.entity.MatnrGroup;
import java.util.List;
import java.util.Map;
public interface MatnrGroupService extends IService<MatnrGroup> {
    List<MatnrGroup> getTreeData(Map<String, Object> map);
}
rsf-server/src/main/java/com/vincent/rsf/server/manager/service/impl/LocAreaMatRelaServiceImpl.java
@@ -4,20 +4,17 @@
import com.vincent.rsf.framework.common.R;
import com.vincent.rsf.framework.exception.CoolException;
import com.vincent.rsf.server.manager.controller.params.LocAreaMatsParam;
import com.vincent.rsf.server.manager.entity.LocTypeRela;
import com.vincent.rsf.server.manager.entity.Matnr;
import com.vincent.rsf.server.manager.entity.*;
import com.vincent.rsf.server.manager.mapper.LocAreaMatRelaMapper;
import com.vincent.rsf.server.manager.entity.LocAreaMatRela;
import com.vincent.rsf.server.manager.service.LocAreaMatRelaService;
import com.vincent.rsf.server.manager.service.*;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.vincent.rsf.server.manager.service.LocService;
import com.vincent.rsf.server.manager.service.LocTypeRelaService;
import com.vincent.rsf.server.manager.service.MatnrService;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;
@@ -31,7 +28,13 @@
    private LocService locService;
    @Autowired
    private MatnrGroupService matnrGroupService;
    @Autowired
    private LocTypeRelaService locTypeRelaService;
    @Autowired
    private LocTypeService locTypeService;
    /**
@@ -73,6 +76,7 @@
                    for (Matnr matnrId : matnrIds) {
                        LocAreaMatRela locAreaMatRela = new LocAreaMatRela();
                        locAreaMatRela
                                .setAreaMatId(param.getAreaMatId())
                                .setAreaId(param.getAreaId())
                                .setLocId(locId)
                                .setLocTypeId(typeId)
@@ -94,6 +98,7 @@
                    LocAreaMatRela locAreaMatRela = new LocAreaMatRela();
                    locAreaMatRela
                            .setAreaId(param.getAreaId())
                            .setAreaMatId(param.getAreaMatId())
                            .setLocId(locTypeRela.getLocId())
                            .setLocTypeId(locTypeRela.getTypeId())
                            .setMatnrId(matnr.getId())
@@ -107,4 +112,100 @@
        }
        return R.ok("绑定成功!!");
    }
    /**
     * @author Ryan
     * @description 移除物料分组下绑定关系
     * @param
     * @return
     * @time 2025/3/24 13:33
     */
    @Override
    public Boolean removeByGroupId(Map<String, Object> param) {
        if (Objects.isNull(param)) {
            throw new CoolException("物料分组ID不能为空!!");
        }
        if (!StringUtils.isBlank(param.get("groupId").toString())) {
            throw new CoolException("物料分类不能为空!!");
        }
        if (!StringUtils.isBlank(param.get("areaMatId").toString())) {
            throw new CoolException("主单ID不能为空!!");
        }
        if (!this.remove(new LambdaQueryWrapper<LocAreaMatRela>()
                .eq(LocAreaMatRela::getAreaMatId, Long.parseLong(param.get("areaMatId").toString()))
                .eq(LocAreaMatRela::getGroupId, Long.parseLong(param.get("groupId").toString())))) {
            throw new CoolException("删除失败!!");
        }
        return true;
    }
    /**
     * @author Ryan
     * @description 移除库位类型绑定关系
     * @param
     * @return
     * @time 2025/3/24 13:32
     */
    @Override
    public boolean removeByLocType(Map<String, Object> param) {
        if (Objects.isNull(param)) {
            throw new CoolException("库位类型ID不能为空!!");
        }
        if (!this.remove(new LambdaQueryWrapper<LocAreaMatRela>()
                        .eq(LocAreaMatRela::getAreaMatId, Long.parseLong(param.get("areaMatId").toString()))
                .eq(LocAreaMatRela::getLocTypeId, Long.parseLong(param.get("typeId").toString())))) {
            throw new CoolException("删除失败!!");
        }
        return true;
    }
    /**
     * @author Ryan
     * @description 获取物料分组
     * @param
     * @return
     * @time 2025/3/24 13:32
     */
    @Override
    public List<MatnrGroup> getAllGroups(Long id) {
        if (Objects.isNull(id)) {
            throw new CoolException("主单ID不能为空!!");
        }
        List<LocAreaMatRela> locAreaMatRelas = this.list(new LambdaQueryWrapper<LocAreaMatRela>().eq(LocAreaMatRela::getAreaMatId, id));
        if (locAreaMatRelas.isEmpty()) {
            throw new CoolException("库区绑定物料为空!!");
        }
        List<Long> longList = locAreaMatRelas.stream().map(LocAreaMatRela::getGroupId).collect(Collectors.toList());
        List<MatnrGroup> groups = matnrGroupService.list(new LambdaQueryWrapper<MatnrGroup>().in(MatnrGroup::getId, longList));
        if (groups.isEmpty()) {
            throw new CoolException("数据错误:物料分组不存在!!");
        }
        return groups;
    }
    /**
     * @author Ryan
     * @description 获取绑定库位物料
     * @param
     * @return
     * @time 2025/3/24 13:36
     */
    @Override
    public List<LocType> getAllLocType(Long id) {
        if (Objects.isNull(id)) {
            throw new CoolException("主单ID不能为空!!");
        }
        List<LocAreaMatRela> locAreaMatRelas = this.list(new LambdaQueryWrapper<LocAreaMatRela>().eq(LocAreaMatRela::getAreaMatId, id));
        if (locAreaMatRelas.isEmpty()) {
            throw new CoolException("库区绑定物料为空!!");
        }
        List<Long> longList = locAreaMatRelas.stream().map(LocAreaMatRela::getLocTypeId).collect(Collectors.toList());
        List<LocType> list = locTypeService.list(new LambdaQueryWrapper<LocType>().in(LocType::getId, longList));
        if (list.isEmpty()) {
            throw new CoolException("数据错误:库位类型不存在!!");
        }
        return list;
    }
}
rsf-server/src/main/java/com/vincent/rsf/server/manager/service/impl/LocAreaMatServiceImpl.java
New file
@@ -0,0 +1,12 @@
package com.vincent.rsf.server.manager.service.impl;
import com.vincent.rsf.server.manager.mapper.LocAreaMatMapper;
import com.vincent.rsf.server.manager.entity.LocAreaMat;
import com.vincent.rsf.server.manager.service.LocAreaMatService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.stereotype.Service;
@Service("locAreaMatService")
public class LocAreaMatServiceImpl extends ServiceImpl<LocAreaMatMapper, LocAreaMat> implements LocAreaMatService {
}
rsf-server/src/main/java/com/vincent/rsf/server/manager/service/impl/MatnrGroupServiceImpl.java
@@ -2,16 +2,48 @@
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.vincent.rsf.common.utils.Utils;
import com.vincent.rsf.framework.common.R;
import com.vincent.rsf.framework.exception.CoolException;
import com.vincent.rsf.server.manager.mapper.MatnrGroupMapper;
import com.vincent.rsf.server.manager.entity.MatnrGroup;
import com.vincent.rsf.server.manager.service.MatnrGroupService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;
@Service("matnrGroupService")
public class MatnrGroupServiceImpl extends ServiceImpl<MatnrGroupMapper, MatnrGroup> implements MatnrGroupService {
    @Override
    public List<MatnrGroup> getTreeData(Map<String, Object> map) {
        List<MatnrGroup> matnrs = new ArrayList<>();
        if (Objects.isNull(map)) {
            matnrs = this.list(new LambdaQueryWrapper<MatnrGroup>().orderByAsc(MatnrGroup::getCode));
        } else {
            if (Objects.isNull(map.get("condition"))) {
                 throw new CoolException("condition参数不能为空!!");
            }
            if (!StringUtils.isBlank(map.get("condition").toString())) {
                List<MatnrGroup> groups = this.list(new LambdaQueryWrapper<MatnrGroup>()
                        .like(MatnrGroup::getName, map.get("condition"))
                        .orderByAsc(MatnrGroup::getCode));
                List<Long> collect = groups.stream().map(MatnrGroup::getId).collect(Collectors.toList());
                List<MatnrGroup> list = this.list(new LambdaQueryWrapper<MatnrGroup>().in(MatnrGroup::getId, collect));
                matnrs.addAll(list);
                List<MatnrGroup> treeData = Utils.toTreeData(matnrs, 0L, MatnrGroup::getParentId, MatnrGroup::getId, MatnrGroup::setChildren);
                return treeData;
            } else {
                matnrs = this.list(new LambdaQueryWrapper<MatnrGroup>().orderByAsc(MatnrGroup::getCode));
            }
        }
        List<MatnrGroup> treeData = Utils.toTreeData(matnrs, 0L, MatnrGroup::getParentId, MatnrGroup::getId, MatnrGroup::setChildren);
        return treeData;
    }
}
rsf-server/src/main/java/com/vincent/rsf/server/system/controller/DictDataController.java
@@ -4,6 +4,7 @@
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.vincent.rsf.framework.common.Cools;
import com.vincent.rsf.framework.common.R;
import com.vincent.rsf.framework.exception.CoolException;
import com.vincent.rsf.server.common.utils.ExcelUtil;
import com.vincent.rsf.server.common.annotation.OperationLog;
import com.vincent.rsf.server.common.domain.BaseParam;
@@ -55,10 +56,20 @@
    @OperationLog("Create 字典数据集")
    @PostMapping("/dictData/save")
    public R save(@RequestBody DictData dictData) {
        if (Objects.isNull(dictData.getLabel())) {
            throw new CoolException("别名不能为空!!");
        }
        if (Objects.isNull(dictData.getValue())) {
            throw new CoolException("值不能为空!!");
        }
        if (Objects.isNull(dictData.getDictTypeCode())) {
            throw new CoolException("编码不能为空!!");
        }
        if (Objects.isNull(dictData.getDictTypeId())) {
            throw new CoolException("主单ID不能为空!!");
        }
        dictData.setCreateBy(getLoginUserId());
        dictData.setCreateTime(new Date());
        dictData.setUpdateBy(getLoginUserId());
        dictData.setUpdateTime(new Date());
        if (!dictDataService.save(dictData)) {
            return R.error("Save Fail");
        }
rsf-server/src/main/java/com/vincent/rsf/server/system/controller/DictTypeController.java
@@ -61,13 +61,15 @@
        if (Objects.isNull(dictType.getName())) {
            throw new CoolException("字典名称不能为空!!");
        }
        if (Objects.isNull(dictType.getDescription())) {
            throw new CoolException("字典描述不能为空!!");
        }
        if (Objects.isNull(dictType.getCode())) {
            throw new CoolException("字典编码不能为空!!");
        }
        if (!dictTypeService.list(new LambdaQueryWrapper<DictType>().eq(DictType::getCode, dictType.getCode())).isEmpty()) {
            throw new CoolException("编码不能重复!!");
        }
        if (!dictTypeService.list(new LambdaQueryWrapper<DictType>().eq(DictType::getName, dictType.getName())).isEmpty()) {
            throw new CoolException("名称不能重复!!");
        }
        if (!dictTypeService.save(dictType)) {
            return R.error("Save Fail");
        }
@@ -78,8 +80,10 @@
    @OperationLog("Update 数据字典")
    @PostMapping("/dictType/update")
    public R update(@RequestBody DictType dictType) {
        if (Objects.isNull(dictType)) {
            throw new CoolException("参数不能为空!!");
        }
        dictType.setUpdateBy(getLoginUserId());
        dictType.setUpdateTime(new Date());
        if (!dictTypeService.updateById(dictType)) {
            return R.error("Update Fail");
        }
rsf-server/src/main/java/locArea.sql
File was deleted
rsf-server/src/main/java/locAreaMatRela.sql
File was deleted
rsf-server/src/main/java/locAreaRela.sql
File was deleted
rsf-server/src/main/resources/application.yml
@@ -31,8 +31,8 @@
    :banner: false
    db-config:
      id-type: auto
      logic-delete-value: 1
      logic-not-delete-value: 0
#      logic-delete-value: 1
#      logic-not-delete-value: 0
super:
  pwd: xltys1995
rsf-server/src/main/resources/mapper/manager/LocAreaMatMapper.xml
New file
@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.vincent.rsf.server.manager.mapper.LocAreaMatMapper">
</mapper>
rsf-server/src/main/resources/mapper/test/LocAreaMatMapper.xml
New file
@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.vincent.rsf.server.test.mapper.LocAreaMatMapper">
</mapper>