hejianhao
2025-02-25 9f5783515e51f4f76b2e7fe4755d7a5523519036
角色权限模块、未读提醒、接口请求token拼接、项目样式修改
7个文件已修改
3个文件已添加
439 ■■■■■ 已修改文件
management/config/routes.ts 11 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
management/src/app.tsx 14 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
management/src/components/RightContent/AvatarDropdown.tsx 27 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
management/src/components/RightContent/service.js 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
management/src/global.less 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
management/src/pages/setting/role/components/addAndEdit.jsx 192 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
management/src/pages/setting/role/index.jsx 127 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
management/src/pages/setting/role/service.js 47 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
management/src/requestErrorConfig.ts 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
management/src/utils/antdUtils.js 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
management/config/routes.ts
@@ -36,19 +36,24 @@
  {
    path: '/setting',
    // layout: false,
    name:'系统设置',
    name: '系统设置',
    routes: [
      {
        name: '职位管理',
        path: '/setting/career',
        component: './setting/career/index',
      },
      {
        name: '角色管理',
        path: '/setting/role',
        component: './setting/role',
      },
    ],
  },
  {
    path: '/work-order',
    // layout: false,
    name:'工单事项管理',
    name: '工单事项管理',
    routes: [
      {
        name: '工单事项配置',
@@ -70,7 +75,7 @@
  {
    path: '/message-notification',
    // layout: false,
    name:'消息通知',
    name: '消息通知',
    routes: [
      {
        name: '消息通知',
management/src/app.tsx
@@ -7,6 +7,7 @@
import { errorConfig } from './requestErrorConfig';
const loginPath = '/login';
import '../public/font.css'
import { useEffect, useState } from 'react';
/**
@@ -39,8 +40,21 @@
// ProLayout 支持的api https://procomponents.ant.design/components/layout
export const layout: RunTimeLayoutConfig = ({ initialState, setInitialState }) => {
  const [title, setTitle] = useState('');
  useEffect(() => {
    const updateTitle = () => {
      const now = new Date();
      const days = ['周日', '周一', '周二', '周三', '周四', '周五', '周六'];
      const formattedDate = `${now.getFullYear()}-${now.getMonth() + 1}-${now.getDate()} ${now.getHours()}:${now.getMinutes()} ${days[now.getDay()]}`;
      setTitle(formattedDate);
    };
    updateTitle();
    const interval = setInterval(updateTitle, 1000); // 每分钟更新一次
    return () => clearInterval(interval); // 清除定时器
  }, []);
  return {
    title,
    logo: false,
    avatarProps: {
      title: <AvatarName />,
management/src/components/RightContent/AvatarDropdown.tsx
@@ -1,7 +1,8 @@
import { outLogin } from './service';
import { outLogin, getUnreadCount } from './service';
import { LogoutOutlined } from '@ant-design/icons';
import { useModel } from '@umijs/max';
import React from 'react';
import React, { useEffect, useState } from 'react';
import { Access, history, useAccess } from 'umi';
import { flushSync } from 'react-dom';
import './style.less';
@@ -22,6 +23,17 @@
  const { initialState, setInitialState } = useModel('@@initialState');
  const [unreadCount, setUnreadCount] = useState(0);
  useEffect(() => {
    const timer = setInterval(() => {
      getUnreadCount().then((res: any) => {
        setUnreadCount(res.data || 0);
      });
    }, 1000 * 5)
    return () => clearInterval(timer);
  }, []);
  const onMenuClick = async () => {
    await outLogin();
@@ -33,10 +45,13 @@
  }
  return <div style={{ display: 'flex', alignItems: 'center', color: '#000' }}>
    <div className='unread' >
      <div>未读提醒</div>
      <div style={{ border: '1px solid red', borderRadius: '50%', width: '18px', lineHeight: '18px', marginLeft: '5px', textAlign: 'center', color: 'red' }}>1</div>
    </div>
    {
      unreadCount > 0 &&
      <div className='unread' onClick={() => { history.push('/message-notification/list') }}>
        <div>未读提醒</div>
        <div style={{ border: '1px solid red', borderRadius: '50%', width: '18px', lineHeight: '16px', marginLeft: '5px', textAlign: 'center', color: 'red', flexShrink: 0 }}>{unreadCount}</div>
      </div>
    }
    <div className="logoOut" onClick={onMenuClick}>退出登录<LogoutOutlined style={{ marginLeft: '5px' }} /></div>
  </div>
};
management/src/components/RightContent/service.js
@@ -1,8 +1,17 @@
import { request } from '@umijs/max';
// 退出登录
export async function outLogin(data) {
  return request('/api/huacheng-sangeshenbian/systemUser/logout', {
    method: 'POST',
    data,
  });
}
// 获取未读数量
export async function getUnreadCount(data) {
  return request('/api/huacheng-sangeshenbian/messageNotification/unreadCount', {
    method: 'GET',
    data,
  });
}
management/src/global.less
@@ -55,6 +55,12 @@
    }
  }
}
.ant-pro-global-header-header-actions-avatar>div:hover {
  background: #fff;
}
:where(.css-dev-only-do-not-override-17md30i).ant-menu-light .ant-menu-submenu-selected>.ant-menu-submenu-title,
:where(.css-dev-only-do-not-override-17md30i).ant-menu-light>.ant-menu .ant-menu-submenu-selected>.ant-menu-submenu-title{
  color: rgba(0, 0, 0, 0.95);
}
management/src/pages/setting/role/components/addAndEdit.jsx
New file
@@ -0,0 +1,192 @@
import { Form, Input, Modal, Tree, Button, Spin } from 'antd';
import { forwardRef, useImperativeHandle, useState } from 'react';
import { useEffect } from 'react';
import { getTree, getAddTree } from '../service';
const formItemLayout = {
    labelCol: { span: 6 },
    wrapperCol: { span: 18 },
};
const AddAndEdit = ({ visible, onSave, onUpdate, onCancel }, ref) => {
    const [form] = Form.useForm();
    const [data, setData] = useState({})
    const [treeData, setTreeData] = useState([]);//权限树
    const [treeSeletKeys, setTreeSeletKeys] = useState([]); //勾选权限
    const [detailType, setDetailType] = useState(false);//是否详情
    const [spinning, setSpinning] = useState(false);
    useEffect(() => {
        // 获取权限树
        getAddTree().then(res => {
            setTreeData(res.data)
        })
    }, [])
    useImperativeHandle(ref, () => {
        return {
            refreshData: (data, type) => {
                setDetailType(type || false)
                if (data.id) {
                    // 获取角色的权限树
                    getTree(data.id).then(res => {
                        setTreeSeletKeys(res.data.systemMenuIds || []);
                    })
                }
                setData(data)
                form.setFieldsValue(data);
            },
            clean: () => {
                setSpinning(false)
            },
        };
    });
    // 保存
    const okHandle = () => {
        form.validateFields().then((values) => {
            setSpinning(true)
            values.menuIds = treeSeletKeys
            delete values.tree
            if (data.id) {
                values.id = data.id
                onUpdate(values)
            } else {
                onSave(values);
            }
        });
    };
    // 选中树
    const onCheck = (e, row) => {
        let seletKeys = e.checked;
        treeData.find(item => {
            if (item.children) {
                let arr1 = item.children.find((item1) => {//循环子路由
                    if (item1.children) {
                        let arr2 = item1.children.find((item2) => {//循环子路由下按钮
                            return item2.id == row.node.id;
                        });
                        if (row.checked) {
                            if (arr2 && !seletKeys.includes(item1.id)) {
                                seletKeys.push(item1.id);
                            }
                            if (arr2 && !seletKeys.includes(item.id)) {
                                seletKeys.push(item.id);
                            }
                        } else {
                            let isCheck = item1.children.find((item2) => seletKeys.includes(item2.id));
                            if (!isCheck) {
                                let arr = seletKeys.filter((it) => it != item1.id);
                                seletKeys = arr;
                            }
                        }
                    }
                    return item1.id == row.node.id;
                });
                if (row.checked) {
                    if (arr1 && !seletKeys.includes(item.id)) {
                        seletKeys.push(item.id);
                    }
                } else {
                    let isCheck = item.children.find((item1) => seletKeys.includes(item1.id));
                    if (!isCheck) {
                        let arr = seletKeys.filter((it) => it != item.id);
                        seletKeys = arr;
                    }
                }
            }
            return item.id == row.node.id;
        });
        if (row.node.children.length != 0) {
            row.node.children.map((item) => {
                if (row.checked) {
                    if (!seletKeys.includes(item.id)) {
                        seletKeys.push(item.id);
                    }
                } else {
                    seletKeys = seletKeys.filter((item1) => item1 != item.id);
                }
                if (item.children.length != 0) {
                    item.children.map((item1) => {
                        if (row.checked) {
                            if (!seletKeys.includes(item1.id)) {
                                seletKeys.push(item1.id);
                            }
                        } else {
                            seletKeys = seletKeys.filter((item2) => item2 != item1.id);
                        }
                    });
                }
            });
        }
        setTreeSeletKeys(seletKeys);
    };
    return (
        <Modal
            getContainer={false}
            width="20%"
            destroyOnClose
            title={detailType ? '角色详情' : data.id ? '编辑角色' : '添加角色'}
            open={visible}
            onCancel={() => onCancel(false)}
            afterClose={() => {
                form.resetFields()
                setTreeSeletKeys([])
            }}
            footer={
                !detailType ?
                    [
                        <Button key="back" onClick={() => onCancel(false)}>取消</Button>,
                        <Button key="submit" type="primary" onClick={okHandle}>
                            确定
                        </Button>
                    ]
                    :
                    <Button key="back" onClick={() => onCancel(false)}>关闭</Button>
            }
        >
            <Form layout="horizontal" {...formItemLayout} form={form} scrollToFirstError>
                <Form.Item
                    name="name"
                    label="角色名称"
                    rules={[{ required: true, message: '请输入角色名称' }]}
                >
                    <Input disabled={detailType} placeholder='请输入角色名称' />
                </Form.Item>
                <Form.Item
                    name="tree"
                    label="角色权限"
                    rules={[{
                        required: true,
                        validator: (rule, value) => {
                            return new Promise((resolve, reject) => {
                                if (value) {
                                    resolve('');
                                } else {
                                    if (treeSeletKeys.length === 0) {
                                        reject(new Error('请选择角色权限'));
                                    }
                                    resolve('');
                                }
                            })
                        }
                    }]}>
                    <Tree
                        checkable
                        checkStrictly
                        checkedKeys={treeSeletKeys}
                        treeData={treeData}
                        disabled={detailType}
                        fieldNames={{ title: 'name', key: 'id' }}
                        onCheck={onCheck}
                    />
                </Form.Item>
            </Form>
            <Spin spinning={spinning} fullscreen />
        </Modal >
    );
};
export default forwardRef(AddAndEdit);
management/src/pages/setting/role/index.jsx
New file
@@ -0,0 +1,127 @@
import { PageContainer, ProTable } from '@ant-design/pro-components';
import { buildProTableDataSource, sendRequest, showDelConfirm } from '@/utils/antdUtils';
import { Button, Space } from 'antd';
import { useRef, useState } from 'react';
import { Access, history, useAccess } from 'umi';
import { getList, del, edit, add } from './service'
import AddAndEdit from './components/addAndEdit'
const Role = () => {
    const actionRef = useRef();
    const addViewRef = useRef();
    const [modalVisible, handleModalVisibles] = useState(false);
    const access = useAccess();
    const columns = [
        {
            title: '角色名称',
            dataIndex: 'name',
        },
        {
            title: '操作',
            hideInSearch: true,
            render: (text, record) => {
                return (
                    <Space>
                        {
                            record.roleId != 1 &&
                            // <Access accessible={access.settings_role_edit}>
                            <Button
                                type="link"
                                onClick={() => {
                                    addViewRef.current.refreshData(record);
                                    handleModalVisibles(true)
                                }}
                            >
                                编辑
                            </Button>
                            //  </Access>
                        }
                        {
                            record.roleId != 1 &&
                            // <Access accessible={access.settings_role_detele}>
                            <Button
                                type="link"
                                onClick={() => {
                                    showDelConfirm(async () => {
                                        let status = await sendRequest(del, record.id)
                                        if (status) {
                                            actionRef.current.reload();
                                        }
                                    }, '确认删除所选信息吗?');
                                }}
                            >
                                删除
                            </Button>
                            //  </Access>
                        }
                        {/* <Access accessible={access.settings_role_detail}> */}
                        <Button
                            type="link"
                            onClick={() => {
                                addViewRef.current.refreshData(record, true);
                                handleModalVisibles(true)
                            }}
                        >
                            查看详情
                        </Button>
                        {/* </Access> */}
                    </Space >
                );
            },
        },
    ]
    return <PageContainer title='角色管理'>
        <ProTable
            rowKey='id'
            actionRef={actionRef}
            columns={columns}
            pagination={{
                showSizeChanger: true,
                showQuickJumper: true,
                defaultPageSize: 10,
            }}
            request={(params) => buildProTableDataSource(getList, params)}
            toolBarRender={(action, selectRows) => [
                // <Access accessible={access.settings_role_add}>
                <Space>
                    <Button
                        type="primary"
                        onClick={() => {
                            addViewRef.current.refreshData({});
                            handleModalVisibles(true)
                        }}
                    >
                        添加
                    </Button>
                </Space>
                //  </Access>
            ]}
        />
        <AddAndEdit
            ref={addViewRef}
            visible={modalVisible}
            onSave={async (fileds) => {
                let success = await sendRequest(add, fileds);
                if (success) {
                    handleModalVisibles(false);
                    actionRef.current.reload();
                }
                addViewRef.current.clean();
            }}
            onUpdate={async (fileds) => {
                let success = await sendRequest(edit, fileds);
                if (success) {
                    handleModalVisibles(false);
                    actionRef.current.reload();
                }
                addViewRef.current.clean();
            }}
            onCancel={() => handleModalVisibles(false)}
        />
    </PageContainer>
};
export default Role;
management/src/pages/setting/role/service.js
New file
@@ -0,0 +1,47 @@
import { request } from '@umijs/max';
// 列表
export const getList = async (params) => {
    return request(`/api/huacheng-sangeshenbian/systemRole/list`, {
        method: 'GET',
        params
    });
}
// 编辑获取角色权限树
export const getTree = async (id) => {
    return request(`/api/huacheng-sangeshenbian/systemRole/getSystemRoleInfo/${id}`, {
        method: 'GET',
    });
}
// 新增获取权限树
export const getAddTree = async (id) => {
    return request(`/api/huacheng-sangeshenbian/systemMenu/getSystemMenuList`, {
        method: 'GET',
    });
}
// 新增
export const add = async (data) => {
    return request('/api/huacheng-sangeshenbian/systemRole/add', {
        method: 'POST',
        data,
    });
}
// 编辑
export const edit = async (data) => {
    return request('/api/huacheng-sangeshenbian/systemRole/edit', {
        method: 'POST',
        data,
    });
}
// 删除
export const del = async (id) => {
    return request(`/api/huacheng-sangeshenbian/systemRole/delete/${id}`, {
        method: 'DELETE',
    });
}
management/src/requestErrorConfig.ts
@@ -36,7 +36,7 @@
      o.headers = {
        ...config.headers,
        Authorization,
        Authorization:'Bearer ' + Authorization,
      }
      // }
      // 拦截请求配置,进行个性化处理。
management/src/utils/antdUtils.js
@@ -103,11 +103,11 @@
}
export async function buildProTableDataSource(fun, params) {
  params.pageCurr = params.current;
  params.pageNum = params.current;
  delete params.current
  const response = await fun(params);
  const data = Promise.resolve({
    data: response.data.list || [],
    data: response.data.records || [],
    total: response.data.total || 0,
    success: true,
    pageSize: response.data.size || 10,