verou
2025-03-17 b6f3ff15c1222ee1d54cc7b65a83c8d577f29e1b
feat:TooltipField组件
11个文件已修改
2个文件已添加
332 ■■■■ 已修改文件
rsf-admin/src/i18n/en.js 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-admin/src/i18n/zh.js 8 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-admin/src/page/asnOrder/AsnOrderList.jsx 36 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-admin/src/page/basicInfo/loc/LocCreate.jsx 29 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-admin/src/page/basicInfo/loc/LocEdit.jsx 22 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-admin/src/page/basicInfo/loc/LocList.jsx 10 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-admin/src/page/basicInfo/matnr/MatnrCreate.jsx 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-admin/src/page/basicInfo/matnr/MatnrList.jsx 80 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-admin/src/page/basicInfo/matnr/MatnrListAside.jsx 58 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-admin/src/page/basicInfo/matnrGroup/MatnrGroupList.jsx 21 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-admin/src/page/basicInfo/whMat/whMatCreate.jsx 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-admin/src/page/components/BatchButton.jsx 30 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-admin/src/page/components/TooltipField.jsx 28 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-admin/src/i18n/en.js
@@ -68,6 +68,7 @@
            deprecate: 'Deprecate',
            resend: 'RESEND',
            selected: 'selected',
            batch: 'batch'
        },
        msg: {
            confirm: {
@@ -334,6 +335,9 @@
                barcode: "Barcode",
                unit: "Unit",
                size: "Size",
                length: "length",
                width: "width",
                height: "height",
                row: "Row",
                col: "Col",
                lev: "Lev",
rsf-admin/src/i18n/zh.js
@@ -68,6 +68,7 @@
            deprecate: '废弃',
            resend: '重发',
            selected: '项选中',
            batch: '批量编辑'
        },
        msg: {
            confirm: {
@@ -121,7 +122,7 @@
        userLogin: '登录日志',
        customer: '客户表',
        shipper: '货主信息',
        matnr: '物料表',
        matnr: '物料数据',
        matnrGroup: '物料分组',
        warehouse: '仓库信息',
        warehouseAreas: '仓库库区',
@@ -280,7 +281,7 @@
            matnrGroup: {
                name: "名称",
                code: "编码",
                parentId: "父类标识",
                parentId: "上级标识",
            },
            warehouse: {
                name: "仓库名称",
@@ -333,6 +334,9 @@
                barcode: "容器码",
                unit: "单位",
                size: "长/宽/高",
                length: "长",
                width: "宽",
                height: "高",
                row: "排",
                col: "列",
                lev: "层",
rsf-admin/src/page/asnOrder/AsnOrderList.jsx
@@ -109,7 +109,32 @@
  const inspection = () => { };
  const print = () => { };
  const print = () => {
    const imageUrls = ['https://www.baidu.com/img/flexible/logo/pc/result@2.png',]
    const iframe = document.createElement('iframe');
    iframe.style.display = 'none';
    document.body.appendChild(iframe);
    const iframeDoc = iframe.contentDocument || iframe.contentWindow.document;
    iframeDoc.open();
    iframeDoc.write('<html><head><title>Print Images</title></head><body>');
    // 将图片插入到 iframe 中
    imageUrls.forEach((imageUrl) => {
      iframeDoc.write(`<img src="${imageUrl}" style="margin: 10px;">`);
    });
    iframeDoc.write('</body></html>');
    iframeDoc.close();
    // 等待图片加载完成后触发打印
    iframe.contentWindow.onload = () => {
      iframe.contentWindow.print();
      // 打印完成后移除 iframe
      document.body.removeChild(iframe);
    };
  };
  return (
@@ -151,14 +176,7 @@
          omit={['id', 'createTime', 'createBy', 'memo']}
        >
          <NumberField source="id" />
          <MyField
            source="code"
            label="table.field.asnOrder.code"
            onClick={(event, record, val) => {
              event.stopPropagation();
              assign(record);
            }}
          />
          <TextField source="code" label="table.field.asnOrder.code" />
          <TextField source="poCode" label="table.field.asnOrder.poCode" />
          <NumberField source="poId" label="table.field.asnOrder.poId" />
          <TextField source="type" label="table.field.asnOrder.type" />
rsf-admin/src/page/basicInfo/loc/LocCreate.jsx
@@ -126,13 +126,13 @@
                                        validate={required()}
                                    />
                                </Grid>
                                <Grid item xs={6} display="flex" gap={1}>
                                {/* <Grid item xs={6} display="flex" gap={1}>
                                    <TextInput
                                        label="table.field.loc.name"
                                        source="name"
                                        parse={v => v}
                                    />
                                </Grid>
                                </Grid> */}
                                <Grid item xs={6} display="flex" gap={1}>
                                    <NumberInput
                                        label="table.field.loc.flagLogic"
@@ -153,24 +153,41 @@
                                        parse={v => v}
                                    />
                                </Grid>
                                <Grid item xs={6} display="flex" gap={1}>
                                {/* <Grid item xs={6} display="flex" gap={1}>
                                    <TextInput
                                        label="table.field.loc.unit"
                                        source="unit"
                                        parse={v => v}
                                    />
                                </Grid>
                                <Grid item xs={6} display="flex" gap={1}>
                                </Grid> */}
                                {/* <Grid item xs={6} display="flex" gap={1}>
                                    <TextInput
                                        label="table.field.loc.size"
                                        source="size"
                                        parse={v => v}
                                    />
                                </Grid> */}
                                <Grid item xs={6} display="flex" gap={1}>
                                    <NumberInput
                                        label="table.field.loc.length"
                                        source="length"
                                        validate={required()}
                                    />
                                    <NumberInput
                                        label="table.field.loc.width"
                                        source="width"
                                        validate={required()}
                                    />
                                    <NumberInput
                                        label="table.field.loc.height"
                                        source="height"
                                        validate={required()}
                                    />
                                </Grid>
                                <Grid item xs={6} display="flex" gap={1}>
                                    <NumberInput
                                        label="table.field.loc.row"
                                        source="lrow"
                                        source="row"
                                        validate={required()}
                                    />
                                    <NumberInput
rsf-admin/src/page/basicInfo/loc/LocEdit.jsx
@@ -141,10 +141,24 @@
                                />
                            </Grid>
                            <Grid item xs={6} display="flex" gap={1}>
                                <TextInput
                                    label="table.field.loc.size"
                                    source="size"
                                    parse={v => v}
                                <NumberInput
                                    label="table.field.loc.length"
                                    source="length"
                                    validate={required()}
                                />
                            </Grid>
                            <Grid item xs={6} display="flex" gap={1}>
                                <NumberInput
                                    label="table.field.loc.width"
                                    source="width"
                                    validate={required()}
                                />
                            </Grid>
                            <Grid item xs={6} display="flex" gap={1}>
                                <NumberInput
                                    label="table.field.loc.height"
                                    source="height"
                                    validate={required()}
                                />
                            </Grid>
                            <Grid item xs={6} display="flex" gap={1}>
rsf-admin/src/page/basicInfo/loc/LocList.jsx
@@ -60,8 +60,6 @@
const filters = [
    <SearchInput source="condition" alwaysOn />,
    <DateInput label='common.time.after' source="timeStart" alwaysOn />,
    <DateInput label='common.time.before' source="timeEnd" alwaysOn />,
    <NumberField source="warehouseId$" label="table.field.loc.warehouseId" />,
    <NumberField source="areaId$" label="table.field.loc.areaId" />,
@@ -109,7 +107,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.loc"}
                empty={<EmptyData onClick={() => { setCreateDialog(true) }} />}
@@ -143,7 +141,9 @@
                    <TextField source="fucAtrrs" label="table.field.loc.fucAtrrs" />
                    <TextField source="barcode" label="table.field.loc.barcode" />
                    <TextField source="unit" label="table.field.loc.unit" />
                    <TextField source="size" label="table.field.loc.size" />
                    <TextField source="size" label="table.field.loc.length" />
                    <TextField source="size" label="table.field.loc.width" />
                    <TextField source="size" label="table.field.loc.height" />
                    <NumberField source="lrow" label="table.field.loc.row" />
                    <NumberField source="col" label="table.field.loc.col" />
                    <NumberField source="lev" label="table.field.loc.lev" />
@@ -164,7 +164,7 @@
                    <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} />
                        {/* <DeleteButton sx={{ padding: '1px', fontSize: '.75rem' }} mutationMode={OPERATE_MODE} /> */}
                    </WrapperField>
                </StyledDatagrid>
            </List>
rsf-admin/src/page/basicInfo/matnr/MatnrCreate.jsx
@@ -94,7 +94,7 @@
    //     if (!values.shipperId) errors.shipperId = translate('form.matnr.shipper');
    //     if (!values.groupId) errors.groupId = translate('form.matnr.groupId');
    //     if (!values.code) errors.code = translate('form.matnr.code');
    //     return errors;
    // };
rsf-admin/src/page/basicInfo/matnr/MatnrList.jsx
@@ -31,8 +31,9 @@
    ReferenceArrayInput,
    AutocompleteInput,
    DeleteButton,
} from 'react-admin';
import { Box, Typography, Card, Stack,LinearProgress } from '@mui/material';
import { Box, Typography, Card, Stack, LinearProgress, Tooltip } from '@mui/material';
import { styled } from '@mui/material/styles';
import MatnrCreate from "./MatnrCreate";
import MatnrPanel from "./MatnrPanel";
@@ -40,33 +41,50 @@
import MyCreateButton from "@/page/components/MyCreateButton";
import MyExportButton from '@/page/components/MyExportButton';
import PageDrawer from "@/page/components/PageDrawer";
import MyField from "@/page/components/MyField";
import TooltipField from "@/page/components/TooltipField";
import { PAGE_DRAWER_WIDTH, OPERATE_MODE, DEFAULT_PAGE_SIZE } from '@/config/setting';
import * as Common from '@/utils/common';
import ImportButton from "../../components/ImportButton";
import MatListAside from './MatnrListAside';
import { display, height } from "@mui/system";
const StyledDatagrid = styled(DatagridConfigurable)(({ theme }) => ({
    '& .css-1vooibu-MuiSvgIcon-root': {
        height: '.9em'
    },
    '& .RaDatagrid-row': {
        cursor: 'auto'
    },
    '& .RaList-content': {
        width: '200px'
    },
    '& .RaList-main': {
        minHeight: '80vh'
    },
    '& .column-name': {
    },
    '& .opt': {
        width: 200
    },
    '& .name': {
        width: '100px',
    },
    '& .name .MuiTypography-root': {
        whiteSpace: 'nowrap',
        overflow: 'hidden',
        textOverflow: 'ellipsis',
        display: 'block',
        width: '100px',
    }
}));
const filters = [
    <SearchInput source="condition" alwaysOn />,
    <DateInput label='common.time.after' source="timeStart" alwaysOn />,
    <DateInput label='common.time.before' source="timeEnd" alwaysOn />,
    <TextInput source="name" label="table.field.matnr.name" />,
    <TextInput source="code" label="table.field.matnr.code" />,
    <TextInput source="name" label="table.field.matnr.name" alwaysOn />,
    <TextInput source="code" label="table.field.matnr.code" alwaysOn />,
    <ReferenceInput source="shipperId$" label="table.field.matnr.shipperId" reference="shipper">
        <AutocompleteInput label="table.field.matnr.shipperId" optionText="name" filterToQuery={(val) => ({ name: val })} />
    </ReferenceInput>,
@@ -90,14 +108,14 @@
    <SelectInput source="stockLeval" label="table.field.matnr.stockLevel"
        choices={[
            { id: 0, name: ' A' },
            { id:   1, name: ' B' },
            { id:   2, name: 'C' },
            { id: 1, name: ' B' },
            { id: 2, name: 'C' },
        ]}
    />,
    <SelectInput source="isLabelMange" label="table.field.matnr.isLabelMange"
        choices={[
            { id: 0, name: ' 否' },
            { id:  1, name: ' 是' },
            { id: 1, name: ' 是' },
        ]}
    />,
    <NumberInput source="safeQty" label="table.field.matnr.safeQty" />,
@@ -125,31 +143,33 @@
    const { isLoading } = useListContext();
    return (
        <Box sx={{ position: 'relative' }}>
                {isLoading && (
                    <LinearProgress
                        sx={{
                            height: "2px",
                            position: 'absolute',
                            top: 0,
                            left: 0,
                            right: 0,
                        }}
                    />
                )}
            <StyledDatagrid
        <Box sx={{ position: 'relative', minHeight: "40vh", }}>
            {isLoading && (
                <LinearProgress
                    sx={{
                        height: "2px",
                        position: 'absolute',
                        top: 0,
                        left: 0,
                        right: 0,
                    }}
                />
            )}
            <StyledDatagrid
                preferenceKey='matnr'
                bulkActionButtons={() => <BulkDeleteButton mutationMode={OPERATE_MODE} />}
                rowClick={(id, resource, record) => false}
                expand={() => <MatnrPanel />}
                expandSingle={true}
                omit={['id','shipperId','platCode','spec','model','weight','color','size','describle'
                    ,'nromNum','unit','purchaseUnit','stockUnit','stockLeval','isLabelMange','safeQty'
                    ,'minQty','maxQty','stagn','valid','validWarn','flagCheck','updateTime', 'updateBy'
                omit={['id', 'shipperId', 'platCode', 'spec', 'model', 'weight', 'color', 'size', 'describle'
                    , 'nromNum', 'unit', 'purchaseUnit', 'stockUnit', 'stockLeval', 'isLabelMange', 'safeQty'
                    , 'minQty', 'maxQty', 'stagn', 'valid', 'validWarn', 'flagCheck', 'updateTime', 'updateBy'
                    , 'createTime', 'createBy', 'memo']}
            >
                <NumberField source="id" />
                <TextField source="name" label="table.field.matnr.name" />
                <TooltipField source="name" label="table.field.matnr.name" cellClassName="name" />
                <TextField source="code" label="table.field.matnr.code" />
                <ReferenceField source="shipperId" label="table.field.matnr.shipperId" reference="shipper" link={false} sortable={false}>
                    <TextField source="name" />
@@ -193,12 +213,12 @@
                <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} />
                    {/* <DeleteButton sx={{ padding: '1px', fontSize: '.75rem' }} mutationMode={OPERATE_MODE} /> */}
                </WrapperField>
            </StyledDatagrid>
        </Box>
    );
}
const MatnrList = () => {
@@ -217,7 +237,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.matnr"}
                empty={<EmptyData onClick={() => { setCreateDialog(true) }} />}
@@ -235,7 +255,7 @@
                    </TopToolbar>
                )}
                perPage={DEFAULT_PAGE_SIZE}
                aside={ <MatListAside /> }
                aside={<MatListAside />}
            >
                <MatnrListContent />
            </List>
rsf-admin/src/page/basicInfo/matnr/MatnrListAside.jsx
@@ -11,14 +11,27 @@
import { RichTreeView } from "@mui/x-tree-view/RichTreeView";
import { TreeItem2 } from "@mui/x-tree-view/TreeItem2";
const MatListAside = () => {
    const theme = useTheme();
    const notify = useNotify();
    const { setFilters } = useListContext(); // 获取列表上下文
    const [selectedOption, setSelectedOption] = useState(null);
    const [treeData, setTreeData] = useState([]);
    const trees = []
    // 用于管理展开项的状态
    const [expandedItems, setExpandedItems] = useState([]);
    // 递归收集所有节点的 id
    const collectAllNodeIds = (nodes) => {
        let allIds = [];
        nodes.forEach((node) => {
            allIds.push(node.id.toString());
            if (node.children && Array.isArray(node.children)) {
                allIds = allIds.concat(collectAllNodeIds(node.children));
            }
        });
        return allIds;
    };
    const haveChildren = (item) => {
        // 如果 item 是一个数组,遍历数组中的每个元素
        if (Array.isArray(item)) {
@@ -40,13 +53,16 @@
        return item;
    };
    useEffect(() => {
        request.post('/matnrGroup/tree')
            .then(res => {
                if (res?.data?.code === 200) {
                    let data = res.data.data;
                    let items = haveChildren(data)
                    setTreeData(items)
                    let items = haveChildren(data);
                    setTreeData(items);
                    // 当树数据更新时,更新展开项状态
                    setExpandedItems(collectAllNodeIds(items));
                } else {
                    notify(res.data.msg);
                }
@@ -54,12 +70,7 @@
            .catch(error => {
                notify('Error fetching tree data');
            });
    }, []);
    const treeData1 = [
        {
@@ -68,8 +79,12 @@
            editable: true,
            children: [
                {
                    id: 'grid-community', label: '@mui/x-data-grid', editable: true, children: [
                        { id: 'grid-community22', label: '@mui/x-data-grid', editable: true },]
                    id: 'grid-community',
                    label: '@mui/x-data-grid',
                    editable: true,
                    children: [
                        { id: 'grid-community22', label: '@mui/x-data-grid', editable: true },
                    ],
                },
                { id: 'grid-pro', label: '@mui/x-data-grid-pro', editable: true },
                { id: 'grid-premium', label: '@mui/x-data-grid-premium', editable: true },
@@ -95,15 +110,16 @@
            children: [{ id: 'tree-view-community1', label: '@mui/x-tree-view' }],
        },
    ];
    const handleNodeSelect = (event, nodeId) => {
        console.log('Selected Node ID:', nodeId);
        setFilters({ groupId: nodeId });
        // 在这里可以根据 nodeId 更新主内容区域
    };
    const handleSearch = () => {
        console.log('Search Input:', selectedOption);
    };
    const CustomCheckbox = React.forwardRef(function CustomCheckbox(props, ref) {
        return <input type="checkbox" ref={ref} {...props} />;
@@ -121,33 +137,35 @@
        );
    });
    return (
        <Card
            sx={{
                display: { xs: 'none', md: 'block', },
                order: -1,
                mr: 2,
                mt: 8,
                alignSelf: 'flex-start',
                border: theme.palette.mode === 'light' && '1px solid #e0e0e3',
                width: 250
                width: 250,
                minWidth: 150,
                height: `calc(100% - 120px)`,
            }}
        >
            <CardContent>
                <SavedQueriesList icon={<BookmarkIcon />} />
                <FilterLiveSearch source="condition" />
                <RichTreeView
                    defaultExpandedItems={['grid', 'pickers']}
                    // 使用 expandedItems 控制展开状态
                    expandedItems={expandedItems}
                    // 处理展开项状态的变化
                    onExpandedItemsChange={(newExpandedItems) => setExpandedItems(newExpandedItems)}
                    expansionTrigger="iconContainer"
                    items={treeData}
                    slots={CustomTreeItem}
                    onItemClick={handleNodeSelect} // 监听节点点击事件
                />
            </CardContent>
        </Card>
    )
}
    );
};
export default MatListAside;
export default MatListAside;
rsf-admin/src/page/basicInfo/matnrGroup/MatnrGroupList.jsx
@@ -160,7 +160,7 @@
    const [createDialog, setCreateDialog] = React.useState(false);
    const [editRecord, setEditRecord] = React.useState(null);
    const [openNodes, setOpenNodes] = React.useState({});
    const [expandAll, setExpandAll] = React.useState(false);
    const [expandAll, setExpandAll] = React.useState(true);
    const http = async () => {
        const res = await request.post(RESOURCE + '/tree', {
@@ -226,6 +226,23 @@
            return newExpandAll;
        });
    };
    // 初始化 openNodes 以展开所有节点
    React.useEffect(() => {
        if (treeData) {
            const newOpenNodes = {};
            const updateOpenNodes = (nodes) => {
                nodes.forEach(node => {
                    newOpenNodes[node.id] = true;
                    if (node.children) {
                        updateOpenNodes(node.children);
                    }
                });
            };
            updateOpenNodes(treeData);
            setOpenNodes(newOpenNodes);
        }
    }, [treeData]);
    return (
        <div>
@@ -336,4 +353,4 @@
    );
}
export default MatnrGroupList;
export default MatnrGroupList;
rsf-admin/src/page/basicInfo/whMat/whMatCreate.jsx
@@ -180,7 +180,7 @@
          <Checkbox
            key={row.id}
            checked={row.checked}
            // onChange={() => { row.checked = !row.checked; }}
          // onChange={() => { row.checked = !row.checked; }}
          />
        </StyledTableCell>
        {columns.map((column, idx) => {
@@ -626,7 +626,7 @@
          </TableBody>
        </Table>
      </TableContainer>
      <WhTable data={treeDatas} />
      {/* <WhTable data={treeDatas} /> */}
    </>
  );
};
rsf-admin/src/page/components/BatchButton.jsx
New file
@@ -0,0 +1,30 @@
import UploadIcon from '@mui/icons-material/Upload';
import { useState } from 'react';
import { Button } from 'react-admin';
import ImportModal from './ImportModal';
const ImportButton = (props) => {
    const [modalOpen, setModalOpen] = useState(false);
    const handleOpenModal = () => {
        setModalOpen(true);
    };
    const handleCloseModal = () => {
        setModalOpen(false);
    };
    return (
        <>
            <Button
                startIcon={<UploadIcon />}
                label="common.action.import.title"
                onClick={handleOpenModal}
            />
            <ImportModal open={modalOpen} onClose={handleCloseModal} {...props} />
        </>
    );
};
export default ImportButton;
rsf-admin/src/page/components/TooltipField.jsx
New file
@@ -0,0 +1,28 @@
import React, { useState, useRef, useEffect, useMemo, useCallback } from "react";
import {
    useRecordContext,
} from 'react-admin';
import { Box, Typography, Card, Stack, Tooltip } from '@mui/material';
import { useTheme } from '@mui/material/styles';
const MyField = ({ source, onClick }) => {
    const record = useRecordContext();
    const theme = useTheme();
    return record ? (
        <Box
        >
            <Typography
                variant="body2"
            >
                <Tooltip title={record[source]} placement="top">
                    <span>{record[source]}</span>
                </Tooltip>
            </Typography >
        </Box>
    ) : null;
}
export default MyField;