master
LiuJiaNan 2026-02-06 14:01:06 +08:00
parent 7ce56deefe
commit 8f947d9f49
4 changed files with 325 additions and 39 deletions

View File

@ -21,6 +21,10 @@ export const appMenuInfo = declareRequest(
`Get > /appmenu/appMenu/{id}`, `Get > /appmenu/appMenu/{id}`,
); );
export const appMenuPermsGroupsList = declareRequest( export const appMenuPermsGroupsList = declareRequest(
"appMenuDistributionMenuLoading",
`Get > /appmenu/menuRoleRelational/list`,
);
export const systemPermsGroupsList = declareRequest(
"appMenuDistributionMenuLoading", "appMenuDistributionMenuLoading",
`Get > /system/operation/perms-groups`, `Get > /system/operation/perms-groups`,
); );
@ -32,3 +36,31 @@ export const appMenuGetAlreadyDistributionMenu = declareRequest(
"appMenuDistributionMenuLoading", "appMenuDistributionMenuLoading",
`Get > /appmenu/roleMenu/listAllByRoleIdByPc`, `Get > /appmenu/roleMenu/listAllByRoleIdByPc`,
); );
export const appMenuGetAppTenant = declareRequest(
"appMenuDistributionMenuLoading",
`Get > /appmenu/tenantAppRelational/getAppTenant`,
);
export const systemTenantsList = declareRequest(
"appMenuDistributionMenuLoading",
`Get > /system/tenants`,
);
export const appMenuGetTenantAppByMenuAttribution = declareRequest(
"appMenuDistributionMenuLoading",
`Get > /appmenu/tenantAppRelational/getTenantAppByMenuAttribution/{menuAttribution}`,
);
export const appMenuTenantAppRelationalSave = declareRequest(
"appMenuDistributionMenuLoading",
`Post > @/appmenu/tenantAppRelational/tenantAppRelationalSave`,
);
export const appMenuGetMenuAppByTenantId = declareRequest(
"appMenuDistributionMenuLoading",
`Get > /appmenu/tenantAppRelational/getMenuAppByTenantId`,
);
export const appMenuGetMenuRoleByMenuAttribution = declareRequest(
"appMenuDistributionMenuLoading",
`Get > /appmenu/menuRoleRelational/getMenuRoleByMenuAttribution/{menuAttribution}`,
);
export const appMenuGetMenuRoleByMenuAttributionSave = declareRequest(
"appMenuDistributionMenuLoading",
`Post > @/appmenu/menuRoleRelational/menuRoleRelationalSave`,
);

View File

@ -0,0 +1,142 @@
import { Connect } from "@cqsjjb/jjb-dva-runtime";
import { Button, message, Modal } from "antd";
import { useEffect, useRef, useState } from "react";
import Page from "zy-react-library/components/Page";
import Table from "zy-react-library/components/Table";
import useDictionary from "zy-react-library/hooks/useDictionary";
import useTable from "zy-react-library/hooks/useTable";
import { NS_APP_MENU } from "~/enumerate/namespace";
function App(props) {
const [list, setList] = useState([]);
const [configModalVisible, setConfigModalVisible] = useState(false);
const [currentInfo, setCurrentInfo] = useState({});
const { getDictionary } = useDictionary();
const getData = async () => {
const dictionary = await getDictionary({ dictValue: "APP_TYPE_ZC" });
const { data } = await props["appMenuGetAppTenant"]();
const corpMap = data.reduce((map, item) => {
map[item.menuAttribution] = item.corpList;
return map;
}, {});
const updatedDictionary = dictionary.map(item => ({
...item,
tenantName: corpMap[item.dictValue]?.map(item => item.corpName)?.join(",") || null,
}));
setList(updatedDictionary);
};
useEffect(() => {
getData();
}, []);
return (
<Page isShowAllAction={false}>
<Table
columns={[
{ title: "APP名称", dataIndex: "dictLabel" },
{ title: "所属租户", dataIndex: "tenantName" },
{
title: "操作",
width: 100,
fixed: "right",
render: (_, record) => (
<Button
type="link"
onClick={() => {
setCurrentInfo(record);
setConfigModalVisible(true);
}}
>
租户配置
</Button>
),
},
]}
dataSource={list}
pagination={false}
/>
{
configModalVisible && (
<ConfigModal
onCancel={() => {
setConfigModalVisible(false);
setCurrentInfo({});
}}
info={currentInfo}
getData={getData}
/>
)
}
</Page>
);
}
const ConfigModalComponent = (props) => {
const [selectedRowKeys, setSelectedRowKeys] = useState([]);
const selectedRowsRef = useRef([]);
const { tableProps } = useTable(props["systemTenantsList"], {
useStorageQueryCriteria: false,
});
const getTenantAppByMenuAttribution = async () => {
const { data } = await props["appMenuGetTenantAppByMenuAttribution"]({ menuAttribution: props.info.dictValue });
setSelectedRowKeys(data.map(item => item.corpId));
selectedRowsRef.current = data.map(item => ({ id: item.corpId, tenantName: item.corpName }));
};
useEffect(() => {
getTenantAppByMenuAttribution();
}, []);
const onSubmit = async () => {
const { success } = await props["appMenuTenantAppRelationalSave"]({
menuAttribution: props.info.dictValue,
menuAttributionName: props.info.dictLabel,
corpList: selectedRowsRef.current.map(item => ({ corpId: item.id, corpName: item.tenantName })),
});
if (success) {
message.success("保存成功");
props.onCancel();
props.getData();
}
};
return (
<Modal
open
title="租户配置"
maskClosable={false}
onCancel={props.onCancel}
onOk={onSubmit}
width={800}
confirmLoading={props.appMenu.appMenuDistributionMenuLoading}
>
<Table
headerTitle={<span style={{ color: "red", fontSize: 14 }}>取消勾选会清空租户下已有角色的APP使用权限请谨慎操作</span>}
rowSelection={{
selectedRowKeys,
onChange: (selectedRowKeys, selectedRows) => {
setSelectedRowKeys(selectedRowKeys);
selectedRowsRef.current = selectedRows;
},
}}
options={false}
disabledResizer={true}
columns={[{ title: "租户名称", dataIndex: "tenantName" }]}
{...tableProps}
/>
</Modal>
);
};
const ConfigModal = Connect([NS_APP_MENU], true)(ConfigModalComponent);
export default Connect([NS_APP_MENU], true)(App);

View File

@ -1,24 +1,36 @@
import { Connect } from "@cqsjjb/jjb-dva-runtime"; import { Connect } from "@cqsjjb/jjb-dva-runtime";
import { Button, message, Modal, Space, Tree } from "antd"; import { Button, Form, message, Modal, Space, Tree } from "antd";
import { useEffect, useRef, useState } from "react"; import { useEffect, useRef, useState } from "react";
import Page from "zy-react-library/components/Page"; import Page from "zy-react-library/components/Page";
import Search from "zy-react-library/components/Search";
import Table from "zy-react-library/components/Table"; import Table from "zy-react-library/components/Table";
import useTable from "zy-react-library/hooks/useTable"; import useTable from "zy-react-library/hooks/useTable";
import { NS_APP_MENU } from "~/enumerate/namespace"; import { NS_APP_MENU } from "~/enumerate/namespace";
function DistributionMenu(props) { function DistributionMenu(props) {
const [currentId, setCurrentId] = useState(""); const [currentInfo, setCurrentInfo] = useState({});
const [distributionMenuModalVisible, setDistributionMenuModalVisible] = useState(false); const [distributionMenuModalVisible, setDistributionMenuModalVisible] = useState(false);
const { tableProps, getData } = useTable(props["appMenuPermsGroupsList"]); const [form] = Form.useForm();
const { tableProps, getData } = useTable(props["appMenuPermsGroupsList"], {
form,
});
return ( return (
<Page isShowAllAction={false}> <Page isShowAllAction={false}>
<Search
labelCol={{ span: 7 }}
options={[
{ name: "likeRoleName", label: "角色名称(权限组)" },
]}
form={form}
onFinish={getData}
/>
<Table <Table
columns={[ columns={[
{ title: "权限组名称", dataIndex: "permsGroupName" }, { title: "角色名称(权限组)", dataIndex: "roleName" },
{ title: "权限类型", dataIndex: ["groupTypeEnum", "label"] }, { title: "所属APP", dataIndex: "menuAttributionName" },
{ title: "启用状态", dataIndex: ["statusEnum", "label"] },
{ {
title: "操作", title: "操作",
width: 200, width: 200,
@ -28,11 +40,11 @@ function DistributionMenu(props) {
<Button <Button
type="link" type="link"
onClick={() => { onClick={() => {
setCurrentId(record.id); setCurrentInfo(record);
setDistributionMenuModalVisible(true); setDistributionMenuModalVisible(true);
}} }}
> >
分配菜单 权限配置
</Button> </Button>
</Space> </Space>
), ),
@ -43,10 +55,10 @@ function DistributionMenu(props) {
{ {
distributionMenuModalVisible && ( distributionMenuModalVisible && (
<DistributionMenuModal <DistributionMenuModal
id={currentId} info={currentInfo}
onCancel={() => { onCancel={() => {
setDistributionMenuModalVisible(false); setDistributionMenuModalVisible(false);
setCurrentId(""); setCurrentInfo({});
}} }}
getData={getData} getData={getData}
/> />
@ -65,10 +77,10 @@ const DistributionMenuModalComponent = (props) => {
const halfCheckedKeys = useRef([]); const halfCheckedKeys = useRef([]);
const getData = async () => { const getData = async () => {
const { data: menuListTree } = await props["appMenuListTree"]({ eqMenuAttribution: "gwjapp" }); const { data: menuListTree } = await props["appMenuListTree"]({ eqMenuAttribution: props.info.menuAttribution });
setMenuListTree(menuListTree); setMenuListTree(menuListTree);
const { data } = await props["appMenuGetAlreadyDistributionMenu"]({ roleId: props.id }); const { data } = await props["appMenuGetAlreadyDistributionMenu"]({ roleId: props.info.roleId });
setCheckedKeys(data.map(item => item.menuId)); setCheckedKeys(data.map(item => item.menuId));
}; };
@ -78,7 +90,7 @@ const DistributionMenuModalComponent = (props) => {
const onSubmit = async () => { const onSubmit = async () => {
const { success } = await props["appMenuDistributionMenu"]({ const { success } = await props["appMenuDistributionMenu"]({
roleId: props.id, roleId: props.info.roleId,
menuIdList: checkedKeys, menuIdList: checkedKeys,
halfCheckMenuIdList: halfCheckedKeys.current, halfCheckMenuIdList: halfCheckedKeys.current,
}); });

View File

@ -1,7 +1,8 @@
import useUrlState from "@ahooksjs/use-url-state"; import useUrlState from "@ahooksjs/use-url-state";
import { ApiOutlined } from "@ant-design/icons";
import { Connect } from "@cqsjjb/jjb-dva-runtime"; import { Connect } from "@cqsjjb/jjb-dva-runtime";
import { Button, Form, message, Modal, Space, Tabs, Tag } from "antd"; import { Button, Form, message, Modal, Space, Tabs, Tag } from "antd";
import { useEffect, useState } from "react"; import { useEffect, useRef, useState } from "react";
import FormBuilder from "zy-react-library/components/FormBuilder"; import FormBuilder from "zy-react-library/components/FormBuilder";
import AddIcon from "zy-react-library/components/Icon/AddIcon"; import AddIcon from "zy-react-library/components/Icon/AddIcon";
import Page from "zy-react-library/components/Page"; import Page from "zy-react-library/components/Page";
@ -15,27 +16,41 @@ const MENU_TYPE_ENUM = [
{ bianma: 1, name: "菜单" }, { bianma: 1, name: "菜单" },
{ bianma: 2, name: "按钮" }, { bianma: 2, name: "按钮" },
]; ];
const MENU_ATTRIBUTION_ENUM = [
{ bianma: "gwjapp", name: "港务局app" },
];
function Menu(props) { function Menu(props) {
const [currentId, setCurrentId] = useState(""); const [currentId, setCurrentId] = useState("");
const [currentSort, setCurrentSort] = useState(0); const [currentSort, setCurrentSort] = useState(0);
const [addModalVisible, setAddModalVisible] = useState(false); const [addModalVisible, setAddModalVisible] = useState(false);
const [roleBindingModalVisible, setRoleBindingModalVisible] = useState(false);
const [parentId, setParentId] = useState(0); const [parentId, setParentId] = useState(0);
const [parentName, setParentName] = useState(""); const [parentName, setParentName] = useState("");
const [menuAttribution, setMenuAttribution] = useState([]);
const [urlState, setUrlState] = useUrlState({ const [urlState, setUrlState] = useUrlState({
menuAttribution: MENU_ATTRIBUTION_ENUM[0].bianma, menuAttribution: "",
menuAttributionName: "",
}, { }, {
navigateMode: "replace", navigateMode: "replace",
}); });
const { tableProps, getData } = useTable(props["appMenuListTree"], { const { tableProps, getData } = useTable(props["appMenuListTree"], {
params: { eqMenuAttribution: urlState.menuAttribution }, params: { eqMenuAttribution: urlState.menuAttribution },
usePagination: false, usePagination: false,
manual: true,
}); });
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();
}, []);
const onDelete = (id) => { const onDelete = (id) => {
Modal.confirm({ Modal.confirm({
title: "删除", title: "删除",
@ -58,6 +73,9 @@ function Menu(props) {
showIndexColumn={false} showIndexColumn={false}
toolBarRender={() => ( toolBarRender={() => (
<Space> <Space>
{urlState.menuAttribution
&& (
<>
<Button <Button
type="primary" type="primary"
icon={(<AddIcon />)} icon={(<AddIcon />)}
@ -70,14 +88,29 @@ function Menu(props) {
> >
新增一级菜单 新增一级菜单
</Button> </Button>
<Button
type="primary"
ghost
icon={(<ApiOutlined />)}
onClick={() => {
setRoleBindingModalVisible(true);
}}
>
角色绑定
</Button>
</>
)}
</Space> </Space>
)} )}
headerTitle={( headerTitle={(
<Tabs <Tabs
activeKey={urlState.menuAttribution} activeKey={urlState.menuAttribution}
items={MENU_ATTRIBUTION_ENUM.map(item => ({ key: item.bianma, label: item.name }))} items={menuAttribution.map(item => ({ key: item.menuAttribution, label: item.menuAttributionName }))}
onChange={(event) => { onChange={(event) => {
setUrlState({ menuAttribution: event }); setUrlState({
menuAttribution: event,
menuAttributionName: menuAttribution.find(item => item.menuAttribution === event)?.menuAttributionName,
});
getData(); getData();
}} }}
/> />
@ -105,7 +138,7 @@ function Menu(props) {
setAddModalVisible(true); setAddModalVisible(true);
setParentId(record.id); setParentId(record.id);
setParentName(record.menuName); setParentName(record.menuName);
setCurrentSort(record.children.length + 1); setCurrentSort((record.children?.length || 0) + 1);
}} }}
> >
新增子级 新增子级
@ -155,6 +188,17 @@ function Menu(props) {
/> />
) )
} }
{
roleBindingModalVisible && (
<RoleBindingModal
onCancel={() => {
setRoleBindingModalVisible(false);
}}
menuAttribution={urlState.menuAttribution}
menuAttributionName={urlState.menuAttributionName}
/>
)
}
</Page> </Page>
); );
} }
@ -219,18 +263,74 @@ const AddModalComponent = (props) => {
{ name: "menuUrl", label: "路径" }, { name: "menuUrl", label: "路径" },
{ name: "menuPerms", label: "标识" }, { name: "menuPerms", label: "标识" },
{ name: "menuType", label: "类型", render: FORM_ITEM_RENDER_ENUM.RADIO, items: MENU_TYPE_ENUM }, { name: "menuType", label: "类型", render: FORM_ITEM_RENDER_ENUM.RADIO, items: MENU_TYPE_ENUM },
{ { name: "sort", label: "排序", onlyForLabel: true },
name: "sort",
label: "排序",
render: FORM_ITEM_RENDER_ENUM.NUMBER,
rules: [{ pattern: /^\d*$/, message: "请输入整数" }],
},
]} ]}
/> />
</Modal> </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;
},
}}
options={false}
disabledResizer={true}
columns={[
{ title: "角色名称(权限组)", dataIndex: "permsGroupName" },
]}
{...tableProps}
/>
</Modal>
);
};
const AddModal = Connect([NS_APP_MENU], true)(AddModalComponent); const AddModal = Connect([NS_APP_MENU], true)(AddModalComponent);
const RoleBindingModal = Connect([NS_APP_MENU], true)(RoleBindingModalComponent);
export default Connect([NS_APP_MENU], true)(Menu); export default Connect([NS_APP_MENU], true)(Menu);