From f00f83d2b2a868e518b78c76d3e11bc01aabffa7 Mon Sep 17 00:00:00 2001
From: skyouc
Date: 星期六, 22 三月 2025 15:38:35 +0800
Subject: [PATCH] Merge branch 'front' of http://47.97.1.152:5880/r/wms-master into front

---
 rsf-admin/src/page/basicInfo/locArea/LocAreaEdit.jsx                 |    2 
 rsf-admin/src/page/basicInfo/locArea/LocAreaList.jsx                 |    2 
 rsf-admin/src/page/basicInfo/locAreaMatRela/LocAreaMatRelaList.jsx   |  160 ++++++
 rsf-admin/src/page/basicInfo/locAreaMatRela/LocAreaMatRelaEdit.jsx   |  151 ++++++
 rsf-admin/src/page/basicInfo/locType/LocTypeList.jsx                 |   33 +
 rsf-admin/src/page/basicInfo/locAreaMatRela/LocAreaMatRelaPanel.jsx  |   87 +++
 rsf-admin/src/page/basicInfo/loc/LocList.jsx                         |   38 +
 rsf-admin/src/page/basicInfo/matnr/PrintModal.jsx                    |    9 
 rsf-admin/src/page/basicInfo/loc/BindModal.jsx                       |  199 ++++++++
 rsf-admin/src/page/basicInfo/loc/InitModal.jsx                       |    2 
 rsf-admin/src/page/basicInfo/loc/LocCreate.jsx                       |    1 
 rsf-admin/src/page/basicInfo/locType/BindModal.jsx                   |  199 ++++++++
 rsf-admin/src/page/basicInfo/matnr/BindModal.jsx                     |  186 +++++++
 rsf-admin/src/page/basicInfo/locArea/LocAreaCreate.jsx               |    2 
 rsf-admin/src/page/basicInfo/matnrGroup/MatnrGroupEdit.jsx           |   77 +-
 rsf-admin/src/page/basicInfo/locAreaMatRela/index.jsx                |   18 
 rsf-admin/src/i18n/zh.js                                             |   13 
 rsf-admin/src/page/basicInfo/loc/LocEdit.jsx                         |    1 
 rsf-admin/src/page/basicInfo/matnr/MatnrList.jsx                     |   26 +
 rsf-admin/src/i18n/en.js                                             |   13 
 rsf-admin/src/page/ResourceContent.js                                |    4 
 rsf-admin/src/page/basicInfo/matnrGroup/MatnrGroupCreate.jsx         |    3 
 rsf-admin/src/page/basicInfo/locAreaMatRela/LocAreaMatRelaCreate.jsx |  179 +++++++
 23 files changed, 1,350 insertions(+), 55 deletions(-)

diff --git a/rsf-admin/src/i18n/en.js b/rsf-admin/src/i18n/en.js
index cb54b18..cda7790 100644
--- a/rsf-admin/src/i18n/en.js
+++ b/rsf-admin/src/i18n/en.js
@@ -129,6 +129,7 @@
         loc: 'Loc',
         locType: 'LocType',
         locArea: 'locArea',
+        locAreaMatRela: 'LocAreaMatRela',
         container: 'Container',
         contract: 'Contract',
         qlyInspect: 'QlyInspect',
@@ -367,6 +368,14 @@
                 name: "name",
                 code: "code",
                 areaId: "areaId",
+                locId: "locId",
+            },
+            locAreaMatRela: {
+                areaId: "areaId",
+                code: "code",
+                matnrId: "matnrId",
+                groupId: "groupId",
+                locTypeId: "locTypeId",
                 locId: "locId",
             },
             container: {
@@ -627,7 +636,9 @@
         locInit: 'loc init',
         batch: 'batch',
         confirm: 'confirm',
-        subzone: 'subzone'
+        subzone: 'subzone',
+        bindmatnr: 'bind matnr',
+        bindloc: 'bind loc',
     },
 };
 
diff --git a/rsf-admin/src/i18n/zh.js b/rsf-admin/src/i18n/zh.js
index 2f2f96b..bec9beb 100644
--- a/rsf-admin/src/i18n/zh.js
+++ b/rsf-admin/src/i18n/zh.js
@@ -129,6 +129,7 @@
         loc: '搴撲綅',
         locType: '搴撲綅绫诲瀷',
         locArea: '閫昏緫鍒嗗尯',
+        locAreaMatRela: '搴撳尯鐗╂枡鍏崇郴',
         container: '瀹瑰櫒绠$悊',
         contract: '鍚堝悓淇℃伅',
         qlyInspect: '璐ㄦ淇℃伅',
@@ -367,6 +368,14 @@
                 name: "鍚嶇О",
                 code: "缂栫爜",
                 areaId: "搴撳尯",
+                locId: "搴撲綅",
+            },
+            locAreaMatRela: {
+                areaId: "搴撳尯",
+                code: "缂栫爜",
+                matnrId: "鐗╂枡",
+                groupId: "鐗╂枡鍒嗙粍",
+                locTypeId: "搴撲綅绫诲瀷",
                 locId: "搴撲綅",
             },
             container: {
@@ -629,7 +638,9 @@
         locInit: '聽搴撲綅鍒濆鍖�',
         batch: '鎵归噺鎿嶄綔',
         confirm: '纭',
-        subzone: '缁戝畾鍒嗗尯'
+        subzone: '缁戝畾鍒嗗尯',
+        bindmatnr: '缁戝畾鐗╂枡',
+        bindloc: '缁戝畾搴撲綅',
     },
 };
 
diff --git a/rsf-admin/src/page/ResourceContent.js b/rsf-admin/src/page/ResourceContent.js
index b5b46b3..b17dc51 100644
--- a/rsf-admin/src/page/ResourceContent.js
+++ b/rsf-admin/src/page/ResourceContent.js
@@ -27,6 +27,7 @@
 import companys from './basicInfo/companys';
 import locType from './basicInfo/locType';
 import locArea from './basicInfo//locArea';
+import locAreaMatRela from './basicInfo/locAreaMatRela';
 import serialRuleItem from './system/serialRuleItem';
 import serialRule from './system/serialRule';
 import whMat from './basicInfo/whMat';
@@ -106,6 +107,9 @@
             return locType;
         case 'locArea':
             return locArea;
+        case 'locAreaMatRela':
+            return locAreaMatRela;
+
 
         default:
             return {
diff --git a/rsf-admin/src/page/basicInfo/loc/BindModal.jsx b/rsf-admin/src/page/basicInfo/loc/BindModal.jsx
new file mode 100644
index 0000000..0a8145f
--- /dev/null
+++ b/rsf-admin/src/page/basicInfo/loc/BindModal.jsx
@@ -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 = {
+            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;
\ No newline at end of file
diff --git a/rsf-admin/src/page/basicInfo/loc/InitModal.jsx b/rsf-admin/src/page/basicInfo/loc/InitModal.jsx
index 16a287a..931b943 100644
--- a/rsf-admin/src/page/basicInfo/loc/InitModal.jsx
+++ b/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>
 
diff --git a/rsf-admin/src/page/basicInfo/loc/LocCreate.jsx b/rsf-admin/src/page/basicInfo/loc/LocCreate.jsx
index e5eb67a..23465f9 100644
--- a/rsf-admin/src/page/basicInfo/loc/LocCreate.jsx
+++ b/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
diff --git a/rsf-admin/src/page/basicInfo/loc/LocEdit.jsx b/rsf-admin/src/page/basicInfo/loc/LocEdit.jsx
index 5c640c5..3c32e39 100644
--- a/rsf-admin/src/page/basicInfo/loc/LocEdit.jsx
+++ b/rsf-admin/src/page/basicInfo/loc/LocEdit.jsx
@@ -177,6 +177,7 @@
                                 <DictionarySelect
                                     label={translate("table.field.loc.useStatus")}
                                     name="useStatus"
+                                    validate={[required()]}
                                     size="small"
                                     dictTypeCode="sys_loc_use_stas"
                                 />
diff --git a/rsf-admin/src/page/basicInfo/loc/LocList.jsx b/rsf-admin/src/page/basicInfo/loc/LocList.jsx
index d07243d..1053f48 100644
--- a/rsf-admin/src/page/basicInfo/loc/LocList.jsx
+++ b/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': {
@@ -76,8 +76,8 @@
 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 +148,7 @@
                     bulkActionButtons={
                         <>
                             <BatchButton />
+                            <BindButton />
                             <SubzoneButton />
                             <BulkDeleteButton />
                         </>
@@ -157,9 +158,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 +283,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}
+            />
+        </>
+
+    )
 }
\ No newline at end of file
diff --git a/rsf-admin/src/page/basicInfo/locArea/LocAreaCreate.jsx b/rsf-admin/src/page/basicInfo/locArea/LocAreaCreate.jsx
index 38ac67a..363386b 100644
--- a/rsf-admin/src/page/basicInfo/locArea/LocAreaCreate.jsx
+++ b/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>
diff --git a/rsf-admin/src/page/basicInfo/locArea/LocAreaEdit.jsx b/rsf-admin/src/page/basicInfo/locArea/LocAreaEdit.jsx
index afd0a4c..8ddb456 100644
--- a/rsf-admin/src/page/basicInfo/locArea/LocAreaEdit.jsx
+++ b/rsf-admin/src/page/basicInfo/locArea/LocAreaEdit.jsx
@@ -67,6 +67,7 @@
                             <TextInput
                                 label="table.field.locArea.name"
                                 source="name"
+                                validate={[required()]}
                                 parse={v => v}
                                 autoFocus
                             />
@@ -86,6 +87,7 @@
                                 <AutocompleteInput
                                     label="table.field.locArea.areaId"
                                     optionText="name"
+                                    validate={[required()]}
                                     filterToQuery={(val) => ({ name: val })}
                                 />
                             </ReferenceInput>
diff --git a/rsf-admin/src/page/basicInfo/locArea/LocAreaList.jsx b/rsf-admin/src/page/basicInfo/locArea/LocAreaList.jsx
index 9f92799..faacd4e 100644
--- a/rsf-admin/src/page/basicInfo/locArea/LocAreaList.jsx
+++ b/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" />
diff --git a/rsf-admin/src/page/basicInfo/locAreaMatRela/LocAreaMatRelaCreate.jsx b/rsf-admin/src/page/basicInfo/locAreaMatRela/LocAreaMatRelaCreate.jsx
new file mode 100644
index 0000000..c685d20
--- /dev/null
+++ b/rsf-admin/src/page/basicInfo/locAreaMatRela/LocAreaMatRelaCreate.jsx
@@ -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;
diff --git a/rsf-admin/src/page/basicInfo/locAreaMatRela/LocAreaMatRelaEdit.jsx b/rsf-admin/src/page/basicInfo/locAreaMatRela/LocAreaMatRelaEdit.jsx
new file mode 100644
index 0000000..8a4f76a
--- /dev/null
+++ b/rsf-admin/src/page/basicInfo/locAreaMatRela/LocAreaMatRelaEdit.jsx
@@ -0,0 +1,151 @@
+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 />}
+        >
+            <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;
diff --git a/rsf-admin/src/page/basicInfo/locAreaMatRela/LocAreaMatRelaList.jsx b/rsf-admin/src/page/basicInfo/locAreaMatRela/LocAreaMatRelaList.jsx
new file mode 100644
index 0000000..c4c916d
--- /dev/null
+++ b/rsf-admin/src/page/basicInfo/locAreaMatRela/LocAreaMatRelaList.jsx
@@ -0,0 +1,160 @@
+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}
+                    expand={() => <LocAreaMatRelaPanel />}
+                    expandSingle={true}
+                    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;
diff --git a/rsf-admin/src/page/basicInfo/locAreaMatRela/LocAreaMatRelaPanel.jsx b/rsf-admin/src/page/basicInfo/locAreaMatRela/LocAreaMatRelaPanel.jsx
new file mode 100644
index 0000000..3805034
--- /dev/null
+++ b/rsf-admin/src/page/basicInfo/locAreaMatRela/LocAreaMatRelaPanel.jsx
@@ -0,0 +1,87 @@
+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 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.locAreaMatRela.areaId'))}: {record.areaId}
+                            </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.locAreaMatRela.areaId"
+                                property={record.areaId}
+                            />
+                        </Grid>
+                        <Grid item xs={6}>
+                            <PanelTypography
+                                title="table.field.locAreaMatRela.code"
+                                property={record.code}
+                            />
+                        </Grid>
+                        <Grid item xs={6}>
+                            <PanelTypography
+                                title="table.field.locAreaMatRela.matnrId"
+                                property={record.matnrId}
+                            />
+                        </Grid>
+                        <Grid item xs={6}>
+                            <PanelTypography
+                                title="table.field.locAreaMatRela.groupId"
+                                property={record.groupId}
+                            />
+                        </Grid>
+                        <Grid item xs={6}>
+                            <PanelTypography
+                                title="table.field.locAreaMatRela.locTypeId"
+                                property={record.locTypeId}
+                            />
+                        </Grid>
+                        <Grid item xs={6}>
+                            <PanelTypography
+                                title="table.field.locAreaMatRela.locId"
+                                property={record.locId}
+                            />
+                        </Grid>
+
+                    </Grid>
+                </CardContent>
+            </Card >
+        </>
+    );
+};
+
+export default LocAreaMatRelaPanel;
diff --git a/rsf-admin/src/page/basicInfo/locAreaMatRela/index.jsx b/rsf-admin/src/page/basicInfo/locAreaMatRela/index.jsx
new file mode 100644
index 0000000..87ce528
--- /dev/null
+++ b/rsf-admin/src/page/basicInfo/locAreaMatRela/index.jsx
@@ -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}`
+    }
+};
diff --git a/rsf-admin/src/page/basicInfo/locType/BindModal.jsx b/rsf-admin/src/page/basicInfo/locType/BindModal.jsx
new file mode 100644
index 0000000..310dd74
--- /dev/null
+++ b/rsf-admin/src/page/basicInfo/locType/BindModal.jsx
@@ -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;
\ No newline at end of file
diff --git a/rsf-admin/src/page/basicInfo/locType/LocTypeList.jsx b/rsf-admin/src/page/basicInfo/locType/LocTypeList.jsx
index 45a4e4d..5fd0003 100644
--- a/rsf-admin/src/page/basicInfo/locType/LocTypeList.jsx
+++ b/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}
+            />
+        </>
+
+    )
+}
diff --git a/rsf-admin/src/page/basicInfo/matnr/BindModal.jsx b/rsf-admin/src/page/basicInfo/matnr/BindModal.jsx
new file mode 100644
index 0000000..3ada880
--- /dev/null
+++ b/rsf-admin/src/page/basicInfo/matnr/BindModal.jsx
@@ -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;
\ No newline at end of file
diff --git a/rsf-admin/src/page/basicInfo/matnr/MatnrList.jsx b/rsf-admin/src/page/basicInfo/matnr/MatnrList.jsx
index e27b5e6..23079ee 100644
--- a/rsf-admin/src/page/basicInfo/matnr/MatnrList.jsx
+++ b/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': {
@@ -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}
+            />
+        </>
+
+    )
 }
\ No newline at end of file
diff --git a/rsf-admin/src/page/basicInfo/matnr/PrintModal.jsx b/rsf-admin/src/page/basicInfo/matnr/PrintModal.jsx
index 7513fbe..f618577 100644
--- a/rsf-admin/src/page/basicInfo/matnr/PrintModal.jsx
+++ b/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 {
diff --git a/rsf-admin/src/page/basicInfo/matnrGroup/MatnrGroupCreate.jsx b/rsf-admin/src/page/basicInfo/matnrGroup/MatnrGroupCreate.jsx
index 0146f24..4c9aa78 100644
--- a/rsf-admin/src/page/basicInfo/matnrGroup/MatnrGroupCreate.jsx
+++ b/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>
diff --git a/rsf-admin/src/page/basicInfo/matnrGroup/MatnrGroupEdit.jsx b/rsf-admin/src/page/basicInfo/matnrGroup/MatnrGroupEdit.jsx
index 206a847..1cfd61c 100644
--- a/rsf-admin/src/page/basicInfo/matnrGroup/MatnrGroupEdit.jsx
+++ b/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>
+        </>
     )
 }
 

--
Gitblit v1.9.1