2026-02-02 08:43:26 +08:00
|
|
|
import useUrlState from "@ahooksjs/use-url-state";
|
2026-02-06 14:01:06 +08:00
|
|
|
import { ApiOutlined } from "@ant-design/icons";
|
2026-02-02 08:43:26 +08:00
|
|
|
import { Connect } from "@cqsjjb/jjb-dva-runtime";
|
|
|
|
|
import { Button, Form, message, Modal, Space, Tabs, Tag } from "antd";
|
2026-02-06 14:01:06 +08:00
|
|
|
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";
|
|
|
|
|
import { FORM_ITEM_RENDER_ENUM } from "zy-react-library/enum/formItemRender";
|
|
|
|
|
import useTable from "zy-react-library/hooks/useTable";
|
|
|
|
|
import { getLabelName } from "zy-react-library/utils";
|
|
|
|
|
import { NS_APP_MENU } from "~/enumerate/namespace";
|
|
|
|
|
|
|
|
|
|
const MENU_TYPE_ENUM = [
|
|
|
|
|
{ bianma: 1, name: "菜单" },
|
|
|
|
|
{ bianma: 2, name: "按钮" },
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
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",
|
|
|
|
|
});
|
|
|
|
|
const { tableProps, getData } = useTable(props["appMenuListTree"], {
|
|
|
|
|
params: { eqMenuAttribution: urlState.menuAttribution },
|
|
|
|
|
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 () => {
|
|
|
|
|
const { data } = await props["appMenuGetMenuAppByTenantId"]();
|
|
|
|
|
setMenuAttribution(data);
|
|
|
|
|
const menuAttribution = data?.[0]?.menuAttribution;
|
|
|
|
|
const menuAttributionName = data?.[0]?.menuAttributionName;
|
|
|
|
|
setUrlState({ menuAttribution, menuAttributionName });
|
|
|
|
|
menuAttribution && getData();
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
useEffect(() => {
|
|
|
|
|
getMenuAppByTenantId();
|
|
|
|
|
}, []);
|
|
|
|
|
|
2026-02-02 08:43:26 +08:00
|
|
|
const onDelete = (id) => {
|
|
|
|
|
Modal.confirm({
|
|
|
|
|
title: "删除",
|
|
|
|
|
content: "确定要删除吗?",
|
|
|
|
|
okText: "确定",
|
|
|
|
|
cancelText: "取消",
|
|
|
|
|
onOk: async () => {
|
|
|
|
|
const { success } = await props["appMenuDelete"]({ id });
|
|
|
|
|
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"
|
|
|
|
|
icon={(<AddIcon />)}
|
|
|
|
|
onClick={() => {
|
|
|
|
|
setAddModalVisible(true);
|
|
|
|
|
setParentId(0);
|
|
|
|
|
setParentName("");
|
|
|
|
|
setCurrentSort(tableProps.dataSource.length + 1);
|
|
|
|
|
}}
|
|
|
|
|
>
|
|
|
|
|
新增一级菜单
|
|
|
|
|
</Button>
|
|
|
|
|
<Button
|
|
|
|
|
type="primary"
|
|
|
|
|
ghost
|
|
|
|
|
icon={(<ApiOutlined />)}
|
|
|
|
|
onClick={() => {
|
|
|
|
|
setRoleBindingModalVisible(true);
|
|
|
|
|
}}
|
|
|
|
|
>
|
|
|
|
|
角色绑定
|
|
|
|
|
</Button>
|
|
|
|
|
</>
|
|
|
|
|
)}
|
2026-02-02 08:43:26 +08:00
|
|
|
</Space>
|
|
|
|
|
)}
|
|
|
|
|
headerTitle={(
|
|
|
|
|
<Tabs
|
|
|
|
|
activeKey={urlState.menuAttribution}
|
2026-02-06 14:01:06 +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={[
|
|
|
|
|
{ title: "名称", dataIndex: "menuName" },
|
|
|
|
|
{ title: "路径", dataIndex: "menuUrl" },
|
|
|
|
|
{ title: "标识", dataIndex: "menuPerms" },
|
|
|
|
|
{
|
|
|
|
|
title: "类型",
|
|
|
|
|
dataIndex: "menuType",
|
|
|
|
|
render: (_, record) => (
|
|
|
|
|
<Tag color="#108ee9">{getLabelName({ list: MENU_TYPE_ENUM, status: record.menuType })}</Tag>
|
|
|
|
|
),
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
title: "操作",
|
|
|
|
|
width: 200,
|
|
|
|
|
fixed: "right",
|
|
|
|
|
render: (_, record) => (
|
|
|
|
|
<Space>
|
|
|
|
|
<Button
|
|
|
|
|
type="link"
|
|
|
|
|
onClick={() => {
|
|
|
|
|
setAddModalVisible(true);
|
|
|
|
|
setParentId(record.id);
|
|
|
|
|
setParentName(record.menuName);
|
2026-02-06 14:01:06 +08:00
|
|
|
setCurrentSort((record.children?.length || 0) + 1);
|
2026-02-02 08:43:26 +08:00
|
|
|
}}
|
|
|
|
|
>
|
|
|
|
|
新增子级
|
|
|
|
|
</Button>
|
|
|
|
|
<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 () => {
|
|
|
|
|
const { data } = await props["appMenuInfo"]({ id: props.id });
|
|
|
|
|
form.setFieldsValue(data);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
useEffect(() => {
|
|
|
|
|
if (props.id) {
|
|
|
|
|
getData();
|
|
|
|
|
}
|
|
|
|
|
}, [props.id]);
|
|
|
|
|
|
|
|
|
|
const onSubmit = async (values) => {
|
|
|
|
|
const { success } = await props[props.id ? "appMenuUpdate" : "appMenuAdd"]({
|
|
|
|
|
...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}
|
|
|
|
|
labelCol={{ span: 6 }}
|
|
|
|
|
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>),
|
|
|
|
|
},
|
|
|
|
|
{ name: "menuType", label: "类型", render: FORM_ITEM_RENDER_ENUM.RADIO, items: MENU_TYPE_ENUM },
|
2026-02-09 10:30:25 +08:00
|
|
|
{ name: "menuName", label: "名称" },
|
|
|
|
|
{ name: "menuUrl", label: "路径", useConstraints: false },
|
|
|
|
|
{ name: "menuPerms", label: "标识", useConstraints: false },
|
2026-02-06 14:01:06 +08:00
|
|
|
{ name: "sort", label: "排序", onlyForLabel: true },
|
|
|
|
|
]}
|
|
|
|
|
/>
|
|
|
|
|
</Modal>
|
|
|
|
|
);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const RoleBindingModalComponent = (props) => {
|
|
|
|
|
const [selectedRowKeys, setSelectedRowKeys] = useState([]);
|
|
|
|
|
|
|
|
|
|
const selectedRowsRef = useRef([]);
|
|
|
|
|
|
|
|
|
|
const { tableProps } = useTable(props["systemPermsGroupsList"], {
|
|
|
|
|
useStorageQueryCriteria: false,
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
const getData = async () => {
|
|
|
|
|
const { data } = await props["appMenuGetMenuRoleByMenuAttribution"]({ menuAttribution: props.menuAttribution });
|
|
|
|
|
setSelectedRowKeys(data.map(item => item.roleId));
|
|
|
|
|
selectedRowsRef.current = data.map(item => ({ id: item.roleId, permsGroupName: item.roleName }));
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
useEffect(() => {
|
|
|
|
|
getData();
|
|
|
|
|
}, []);
|
|
|
|
|
|
|
|
|
|
const onSubmit = async () => {
|
|
|
|
|
const { success } = await props["appMenuGetMenuRoleByMenuAttributionSave"]({
|
|
|
|
|
menuAttribution: props.menuAttribution,
|
|
|
|
|
menuAttributionName: props.menuAttributionName,
|
|
|
|
|
roleList: selectedRowsRef.current.map(item => ({ roleId: item.id, roleName: item.permsGroupName })),
|
|
|
|
|
});
|
|
|
|
|
if (success) {
|
|
|
|
|
message.success("保存成功");
|
|
|
|
|
props.onCancel();
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
<Modal
|
|
|
|
|
open
|
|
|
|
|
title="角色绑定"
|
|
|
|
|
maskClosable={false}
|
|
|
|
|
width={800}
|
|
|
|
|
onCancel={props.onCancel}
|
|
|
|
|
onOk={onSubmit}
|
|
|
|
|
confirmLoading={props.appMenu.appMenuLoading}
|
|
|
|
|
>
|
|
|
|
|
<Table
|
|
|
|
|
rowSelection={{
|
|
|
|
|
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={[
|
|
|
|
|
{ title: "角色名称(权限组)", dataIndex: "permsGroupName" },
|
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);
|