zcloud-gbs-appmenu-react/src/pages/Container/AppMenu/Menu/index.js

351 lines
10 KiB
JavaScript
Raw Normal View History

2026-02-02 08:43:26 +08:00
import useUrlState from "@ahooksjs/use-url-state";
2026-03-17 15:27:17 +08:00
import {ApiOutlined} from "@ant-design/icons";
import {Connect} from "@cqsjjb/jjb-dva-runtime";
import {Button, Form, message, Modal, Space, Tabs, Tag} from "antd";
import {useEffect, useRef, useState} from "react";
2026-02-02 08:43:26 +08:00
import FormBuilder from "zy-react-library/components/FormBuilder";
import AddIcon from "zy-react-library/components/Icon/AddIcon";
import Page from "zy-react-library/components/Page";
import Table from "zy-react-library/components/Table";
2026-03-17 15:27:17 +08:00
import {FORM_ITEM_RENDER_ENUM} from "zy-react-library/enum/formItemRender";
2026-02-02 08:43:26 +08:00
import useTable from "zy-react-library/hooks/useTable";
2026-03-17 15:27:17 +08:00
import {getLabelName, getMatchedItems} from "zy-react-library/utils";
import {NS_APP_MENU} from "~/enumerate/namespace";
2026-02-02 08:43:26 +08:00
const MENU_TYPE_ENUM = [
2026-03-17 15:27:17 +08:00
{bianma: 1, name: "菜单"},
{bianma: 2, name: "按钮"},
2026-02-02 08:43:26 +08:00
];
function Menu(props) {
const [currentId, setCurrentId] = useState("");
const [currentSort, setCurrentSort] = useState(0);
const [addModalVisible, setAddModalVisible] = useState(false);
2026-02-06 14:01:06 +08:00
const [roleBindingModalVisible, setRoleBindingModalVisible] = useState(false);
2026-02-02 08:43:26 +08:00
const [parentId, setParentId] = useState(0);
const [parentName, setParentName] = useState("");
2026-02-06 14:01:06 +08:00
const [menuAttribution, setMenuAttribution] = useState([]);
2026-02-02 08:43:26 +08:00
const [urlState, setUrlState] = useUrlState({
2026-02-06 14:01:06 +08:00
menuAttribution: "",
menuAttributionName: "",
2026-02-02 08:43:26 +08:00
}, {
navigateMode: "replace",
});
2026-03-17 15:27:17 +08:00
const {tableProps, getData} = useTable(props["appMenuListTree"], {
params: {eqMenuAttribution: urlState.menuAttribution},
2026-02-02 08:43:26 +08:00
usePagination: false,
2026-02-06 14:01:06 +08:00
manual: true,
2026-02-02 08:43:26 +08:00
});
2026-02-06 14:01:06 +08:00
const getMenuAppByTenantId = async () => {
2026-03-17 15:27:17 +08:00
const {data} = await props["appMenuGetMenuAppByTenantId"]();
2026-02-06 14:01:06 +08:00
setMenuAttribution(data);
const menuAttribution = data?.[0]?.menuAttribution;
const menuAttributionName = data?.[0]?.menuAttributionName;
2026-03-17 15:27:17 +08:00
setUrlState({menuAttribution, menuAttributionName});
2026-02-06 14:01:06 +08:00
menuAttribution && getData();
};
useEffect(() => {
getMenuAppByTenantId();
}, []);
2026-02-02 08:43:26 +08:00
const onDelete = (id) => {
Modal.confirm({
title: "删除",
content: "确定要删除吗?",
okText: "确定",
cancelText: "取消",
onOk: async () => {
2026-03-17 15:27:17 +08:00
const {success} = await props["appMenuDelete"]({id});
2026-02-02 08:43:26 +08:00
if (success) {
message.success("删除成功");
getData();
}
},
});
};
return (
<Page isShowAllAction={false}>
<Table
showIndexColumn={false}
toolBarRender={() => (
<Space>
2026-02-06 14:01:06 +08:00
{urlState.menuAttribution
&& (
<>
<Button
type="primary"
2026-03-17 15:27:17 +08:00
icon={(<AddIcon/>)}
2026-02-06 14:01:06 +08:00
onClick={() => {
setAddModalVisible(true);
setParentId(0);
setParentName("");
setCurrentSort(tableProps.dataSource.length + 1);
}}
>
新增一级菜单
</Button>
<Button
type="primary"
ghost
2026-03-17 15:27:17 +08:00
icon={(<ApiOutlined/>)}
2026-02-06 14:01:06 +08:00
onClick={() => {
setRoleBindingModalVisible(true);
}}
>
角色绑定
</Button>
</>
)}
2026-02-02 08:43:26 +08:00
</Space>
)}
headerTitle={(
<Tabs
activeKey={urlState.menuAttribution}
2026-03-17 15:27:17 +08:00
items={menuAttribution.map(item => ({key: item.menuAttribution, label: item.menuAttributionName}))}
2026-02-02 08:43:26 +08:00
onChange={(event) => {
2026-02-06 14:01:06 +08:00
setUrlState({
menuAttribution: event,
menuAttributionName: menuAttribution.find(item => item.menuAttribution === event)?.menuAttributionName,
});
2026-02-02 08:43:26 +08:00
getData();
}}
/>
)}
columns={[
2026-03-17 15:27:17 +08:00
{title: "名称", dataIndex: "menuName"},
{title: "路径", dataIndex: "menuUrl"},
{title: "标识", dataIndex: "menuPerms"},
2026-02-02 08:43:26 +08:00
{
title: "类型",
dataIndex: "menuType",
render: (_, record) => (
2026-03-17 09:05:54 +08:00
<Tag color={record.menuType === 1 ? "#108ee9" : "#8788ed"}>
{getLabelName({
list: MENU_TYPE_ENUM,
status: record.menuType,
})}
</Tag>
2026-02-02 08:43:26 +08:00
),
},
{
title: "操作",
width: 200,
fixed: "right",
render: (_, record) => (
<Space>
2026-02-09 17:00:23 +08:00
{record.menuType === 1 && (
<Button
type="link"
onClick={() => {
setAddModalVisible(true);
setParentId(record.id);
setParentName(record.menuName);
setCurrentSort((record.children?.length || 0) + 1);
}}
>
新增子级
</Button>
)}
2026-02-02 08:43:26 +08:00
<Button
type="link"
onClick={() => {
setAddModalVisible(true);
setParentId(record.id);
setCurrentId(record.id);
setParentName(record.menuName);
}}
>
修改
</Button>
<Button
type="link"
danger
onClick={() => {
onDelete(record.id);
}}
>
删除
</Button>
</Space>
),
},
]}
{...tableProps}
/>
{
addModalVisible && (
<AddModal
onCancel={() => {
setAddModalVisible(false);
setCurrentId("");
setParentId(0);
setParentName("");
setCurrentSort(0);
}}
getData={getData}
id={currentId}
parentId={parentId}
parentName={parentName}
sort={currentSort}
menuAttribution={urlState.menuAttribution}
/>
)
}
2026-02-06 14:01:06 +08:00
{
roleBindingModalVisible && (
<RoleBindingModal
onCancel={() => {
setRoleBindingModalVisible(false);
}}
menuAttribution={urlState.menuAttribution}
menuAttributionName={urlState.menuAttributionName}
/>
)
}
2026-02-02 08:43:26 +08:00
</Page>
);
}
const AddModalComponent = (props) => {
const [form] = Form.useForm();
const getData = async () => {
2026-03-17 15:27:17 +08:00
const {data} = await props["appMenuInfo"]({id: props.id});
2026-02-02 08:43:26 +08:00
form.setFieldsValue(data);
};
useEffect(() => {
if (props.id) {
getData();
}
}, [props.id]);
const onSubmit = async (values) => {
2026-03-17 15:27:17 +08:00
const {success} = await props[props.id ? "appMenuUpdate" : "appMenuAdd"]({
2026-02-02 08:43:26 +08:00
...values,
id: props.id,
parentId: props.parentId,
menuAttribution: props.menuAttribution,
});
if (success) {
message.success("保存成功");
props.onCancel();
props.getData();
}
};
return (
<Modal
open
title={props.id ? "修改" : "新增"}
maskClosable={false}
width={600}
onCancel={props.onCancel}
onOk={form.submit}
confirmLoading={props.appMenu.appMenuLoading}
>
<FormBuilder
showActionButtons={false}
span={24}
2026-03-17 15:27:17 +08:00
labelCol={{span: 6}}
2026-02-02 08:43:26 +08:00
loading={props.appMenu.appMenuLoading}
form={form}
onFinish={onSubmit}
values={{
menuType: 1,
sort: props.sort,
}}
options={[
{
name: "parentName",
label: "父级",
required: false,
render: (<Tag color="#108ee9">{props.parentName || "无(此项为顶级)"}</Tag>),
},
2026-03-17 09:05:54 +08:00
{
name: "menuType",
label: "类型",
render: FORM_ITEM_RENDER_ENUM.RADIO,
2026-03-17 15:27:17 +08:00
items: props.parentId === 0 ? getMatchedItems({list: MENU_TYPE_ENUM, value: [1]}) : MENU_TYPE_ENUM,
2026-03-17 09:05:54 +08:00
},
2026-03-17 15:27:17 +08:00
{name: "menuName", label: "名称"},
{name: "menuUrl", label: "路径", useConstraints: false},
{name: "menuPerms", label: "标识", useConstraints: false},
{name: "sort", label: "排序", onlyForLabel: true},
2026-02-06 14:01:06 +08:00
]}
/>
</Modal>
);
};
const RoleBindingModalComponent = (props) => {
const [selectedRowKeys, setSelectedRowKeys] = useState([]);
const selectedRowsRef = useRef([]);
2026-03-17 15:27:17 +08:00
const {tableProps} = useTable(props["systemPermsGroupsList"], {
2026-02-06 14:01:06 +08:00
useStorageQueryCriteria: false,
});
const getData = async () => {
2026-03-17 15:27:17 +08:00
const {data} = await props["appMenuGetMenuRoleByMenuAttribution"]({menuAttribution: props.menuAttribution});
2026-02-06 14:01:06 +08:00
setSelectedRowKeys(data.map(item => item.roleId));
2026-03-17 15:27:17 +08:00
selectedRowsRef.current = data.map(item => ({id: item.roleId, roleName: item.roleName}));
2026-02-06 14:01:06 +08:00
};
useEffect(() => {
getData();
}, []);
const onSubmit = async () => {
2026-03-17 15:27:17 +08:00
const {success} = await props["appMenuGetMenuRoleByMenuAttributionSave"]({
2026-02-06 14:01:06 +08:00
menuAttribution: props.menuAttribution,
menuAttributionName: props.menuAttributionName,
2026-03-17 15:27:17 +08:00
roleList: selectedRowsRef.current.map(item => ({roleId: item.id, roleName: item.roleName})),
2026-02-06 14:01:06 +08:00
});
if (success) {
message.success("保存成功");
props.onCancel();
}
};
return (
<Modal
open
title="角色绑定"
maskClosable={false}
width={800}
onCancel={props.onCancel}
onOk={onSubmit}
confirmLoading={props.appMenu.appMenuLoading}
>
2026-03-17 15:27:17 +08:00
<div style={{fontSize: 12, color: "red", marginBottom: 10}}>取消勾选会清空角色的APP使用权限请谨慎操作</div>
2026-02-06 14:01:06 +08:00
<Table
rowSelection={{
2026-02-26 15:30:29 +08:00
preserveSelectedRowKeys: true,
2026-02-06 14:01:06 +08:00
selectedRowKeys,
onChange: (selectedRowKeys, selectedRows) => {
setSelectedRowKeys(selectedRowKeys);
selectedRowsRef.current = selectedRows;
2026-02-02 08:43:26 +08:00
},
2026-02-06 14:01:06 +08:00
}}
options={false}
disabledResizer={true}
columns={[
2026-03-17 15:27:17 +08:00
{title: "角色名称(权限组)", dataIndex: "roleName"},
2026-02-02 08:43:26 +08:00
]}
2026-02-06 14:01:06 +08:00
{...tableProps}
2026-02-02 08:43:26 +08:00
/>
</Modal>
);
};
const AddModal = Connect([NS_APP_MENU], true)(AddModalComponent);
2026-02-06 14:01:06 +08:00
const RoleBindingModal = Connect([NS_APP_MENU], true)(RoleBindingModalComponent);
2026-02-02 08:43:26 +08:00
export default Connect([NS_APP_MENU], true)(Menu);