角色配置、单位类型配置

master
LiuJiaNan 2026-08-04 17:51:42 +08:00
parent 51a2fc1a17
commit 494e8947ef
6 changed files with 471 additions and 4 deletions

View File

@ -6,8 +6,8 @@
"license": "MIT", "license": "MIT",
"main": "index.js", "main": "index.js",
"scripts": { "scripts": {
"serve": "node node_modules/@cqsjjb/scripts/rspack.dev.server.js", "serve": "node node_modules/@cqsjjb/scripts/webpack.dev.server.js",
"build": "node node_modules/@cqsjjb/scripts/rspack.build.js", "build": "node node_modules/@cqsjjb/scripts/webpack.build.js",
"push": "jjb-cmd push java production", "push": "jjb-cmd push java production",
"clean-cache": "rimraf node_modules/.cache/webpack", "clean-cache": "rimraf node_modules/.cache/webpack",
"serve:development": "cross-env NODE_ENV=development npm run serve", "serve:development": "cross-env NODE_ENV=development npm run serve",
@ -31,12 +31,12 @@
"lodash-es": "^4.17.21", "lodash-es": "^4.17.21",
"react": "^18.2.0", "react": "^18.2.0",
"react-dom": "^18.2.0", "react-dom": "^18.2.0",
"zy-react-library": "^1.2.6" "zy-react-library": "^1.3.29"
}, },
"devDependencies": { "devDependencies": {
"@antfu/eslint-config": "^5.4.1", "@antfu/eslint-config": "^5.4.1",
"@babel/plugin-proposal-decorators": "^7.19.3", "@babel/plugin-proposal-decorators": "^7.19.3",
"@cqsjjb/scripts": "latest", "@cqsjjb/scripts": "2.0.0",
"@eslint-react/eslint-plugin": "^2.2.2", "@eslint-react/eslint-plugin": "^2.2.2",
"cross-env": "^7.0.3", "cross-env": "^7.0.3",
"eslint": "^9.37.0", "eslint": "^9.37.0",

14
src/api/role/index.js Normal file
View File

@ -0,0 +1,14 @@
import { declareRequest } from "@cqsjjb/jjb-dva-runtime";
export const getRoles = declareRequest(
"roleLoading",
"Get > /system/operation/roles",
);
export const getRoleUnits = declareRequest(
"roleLoading",
"Get > /appmenu/roleUnit/listAll",
);
export const updateRole = declareRequest(
"roleLoading",
"Put > @/appmenu/roleUnit/edit",
);

View File

@ -0,0 +1,34 @@
import { declareRequest } from "@cqsjjb/jjb-dva-runtime";
export const getUnitTypeConfigList = declareRequest(
"unitTypeConfigLoading",
"Post > @/appmenu/tenantTypeConfig/list",
);
export const saveUnitTypeConfig = declareRequest(
"unitTypeConfigLoading",
"Post > @/appmenu/tenantTypeConfig/save",
);
export const editUnitTypeConfig = declareRequest(
"unitTypeConfigLoading",
"Put > @/appmenu/tenantTypeConfig/edit",
);
export const getUnitTypeConfigDetail = declareRequest(
"unitTypeConfigLoading",
"Get > /appmenu/tenantTypeConfig/{id}",
);
export const deleteUnitTypeConfig = declareRequest(
"unitTypeConfigLoading",
"Delete > @/appmenu/tenantTypeConfig/{id}",
);
export const verifyUnitTypeConfig = declareRequest(
"unitTypeConfigLoading",
"Put > @/appmenu/tenantTypeConfig/verify",
);
export const getFullServiceMenu = declareRequest(
"unitTypeConfigLoading",
"Get > /base/menus/full-service",
);
export const getTenantTypes = declareRequest(
"unitTypeConfigLoading",
"Get > /system/operation/tenant-types",
);

View File

@ -10,3 +10,5 @@ export const NS_NOTICE = defineNamespace("Notice");
export const NS_NoticeReadRecord = defineNamespace("NoticeReadRecord"); export const NS_NoticeReadRecord = defineNamespace("NoticeReadRecord");
export const NS_CORPINFO = defineNamespace("corpInfo"); export const NS_CORPINFO = defineNamespace("corpInfo");
export const NS_TODO_LIST = defineNamespace("toDoList"); export const NS_TODO_LIST = defineNamespace("toDoList");
export const NS_ROLE = defineNamespace("role");
export const NS_UNIT_TYPE_CONFIG = defineNamespace("unitTypeConfig");

View File

@ -0,0 +1,61 @@
import { Connect } from "@cqsjjb/jjb-dva-runtime";
import { message } from "antd";
import { useEffect, useState } from "react";
import FormBuilder from "zy-react-library/components/FormBuilder";
import Page from "zy-react-library/components/Page";
import { FORM_ITEM_RENDER_ENUM } from "zy-react-library/enum/formItemRender";
import { NS_ROLE } from "~/enumerate/namespace";
function Role(props) {
const [roles, setRoles] = useState([]);
const [form] = FormBuilder.useForm();
const getRoles = async () => {
const { data } = await props.getRoles({ pageIndex: 1, pageSize: 1000 });
setRoles(data);
};
const getRoleUnits = async () => {
const { data } = await props.getRoleUnits();
form.setFieldValue("roleId", data.map(item => item.roleId));
};
useEffect(() => {
getRoles();
getRoleUnits();
}, []);
const onSubmit = async (values) => {
const { success } = await props.updateRole({
roles: roles.filter(item => values.roleId.includes(item.id)).map(item => ({
roleId: item.id,
roleName: item.roleName,
})),
});
if (success) {
message.success("保存成功");
getRoleUnits();
}
};
return (
<Page isShowAllAction={false}>
<FormBuilder
span={24}
options={[
{
label: "角色名称",
name: "roleId",
render: FORM_ITEM_RENDER_ENUM.CHECKBOX,
items: roles,
itemsField: { labelKey: "roleName", valueKey: "id" },
checkboxCol: 3,
},
]}
form={form}
onFinish={onSubmit}
/>
</Page>
);
}
export default Connect([NS_ROLE], true)(Role);

View File

@ -0,0 +1,356 @@
import useUrlState from "@ahooksjs/use-url-state";
import { Permission } from "@cqsjjb/jjb-common-decorator/permission";
import { Connect } from "@cqsjjb/jjb-dva-runtime";
import { Button, message, Modal, Space } from "antd";
import { useEffect, useState } from "react";
import FormBuilder from "zy-react-library/components/FormBuilder";
import AddIcon from "zy-react-library/components/Icon/AddIcon";
import BackIcon from "zy-react-library/components/Icon/BackIcon";
import Page from "zy-react-library/components/Page";
import DictionarySelect from "zy-react-library/components/Select/Dictionary";
import BasicSelectTree from "zy-react-library/components/SelectTree/Basic";
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 { STRONG_PASSWORD } from "zy-react-library/regular";
import { getLabelName } from "zy-react-library/utils";
import { NS_UNIT_TYPE_CONFIG } from "~/enumerate/namespace";
function List(props) {
const [addModalVisible, setAddModalVisible] = useState(false);
const [currentId, setCurrentId] = useState("");
const [urlState, setUrlState] = useUrlState({
parentId: "0",
parentName: "",
}, {
navigateMode: "replace",
});
const { tableProps, getData } = useTable(props["getUnitTypeConfigList"], {
params: () => ({ parentId: urlState.parentId }),
manual: true,
});
useEffect(() => {
getData();
}, [urlState.parentId]);
const onDelete = (record) => {
Modal.confirm({
title: "删除确认",
content: `确定要删除【${record.tenantTypeName}】吗`,
onOk: async () => {
const { success } = await props["deleteUnitTypeConfig"]({ id: record.id });
if (success) {
message.success("删除成功");
getData();
}
},
});
};
return (
<Page isShowAllAction={false}>
<Table
toolBarRender={() => (
<Space>
{
urlState.parentId !== "0" && (
<Button
icon={<BackIcon />}
onClick={() => {
setUrlState({
parentId: "0",
parentName: "",
});
}}
type="primary"
ghost
>
返回
</Button>
)
}
<Button
type="primary"
icon={(<AddIcon />)}
onClick={() => {
setAddModalVisible(true);
}}
>
新增
</Button>
</Space>
)}
columns={[
{
title: "单位类型",
dataIndex: "tenantTypeName",
render: (_, record) => (
urlState.parentId === "0"
? (
<Button
type="link"
onClick={() => {
setUrlState({
parentId: record.id,
parentName: record.tenantTypeName,
});
}}
>
{record.tenantTypeName}
</Button>
)
: record.tenantTypeName
),
},
{ title: "编码", dataIndex: "code" },
{
title: "操作",
width: 150,
fixed: "right",
render: (_, record) => (
<Space>
<Button
type="link"
onClick={() => {
setCurrentId(record.id);
setAddModalVisible(true);
}}
>
编辑
</Button>
<Button
type="link"
danger
onClick={() => {
onDelete(record);
}}
>
删除
</Button>
</Space>
),
},
]}
{...tableProps}
/>
{
addModalVisible && (
<AddModal
id={currentId}
parentId={urlState.parentId}
getData={getData}
onCancel={() => {
setAddModalVisible(false);
setCurrentId("");
}}
/>
)
}
</Page>
);
}
const AddModalComponent = (props) => {
const { parentId, id } = props;
const [tenantTypes, setTenantTypes] = useState([]);
const [fullServiceMenu, setFullServiceMenu] = useState([]);
const [form] = FormBuilder.useForm();
const getData = async () => {
if (id) {
const { data } = await props["getUnitTypeConfigDetail"]({ id });
form.setFieldsValue({
...data,
menuIds: data.menuIds?.split(",") || [],
});
}
};
const getTenantTypes = async () => {
if (parentId !== "0") {
const { data } = await props["getTenantTypes"]({ pageIndex: 1, pageSize: 1000 });
setTenantTypes(data);
}
};
const getFullServiceMenu = async () => {
if (parentId !== "0") {
const { data } = await props["getFullServiceMenu"]();
const appList = data[0].appList;
for (let i = 0; i < appList.length; i++) {
appList[i].menuName = appList[i].appName;
appList[i].children = appList[i].menuList;
}
setFullServiceMenu(appList);
}
};
useEffect(() => {
getData();
getTenantTypes();
getFullServiceMenu();
}, []);
const onActualSubmission = async (values) => {
const { success } = await props[id ? "editUnitTypeConfig" : "saveUnitTypeConfig"]({
...values,
id,
level: parentId === "0" ? 1 : 2,
parentId,
menuIds: values.menuIds?.join(","),
});
if (success) {
message.success(`${id ? "编辑" : "添加"}成功`);
props.onCancel();
props.getData();
}
};
const onSubmit = async (values) => {
if (parentId !== "0") {
const { data } = await props["verifyUnitTypeConfig"]({
defaultType: values.defaultType,
id,
});
if (!data.available) {
Modal.confirm({
title: "温馨提示",
content: data.msg,
onOk: async () => {
onActualSubmission(values);
},
});
return;
}
}
onActualSubmission(values);
};
return (
<Modal
open
title={id ? "编辑" : "添加"}
maskClosable={false}
width={600}
onCancel={props.onCancel}
onOk={form.submit}
confirmLoading={props.unitTypeConfig.unitTypeConfigLoading}
>
<FormBuilder
loading={props.unitTypeConfig.unitTypeConfigLoading}
options={parentId === "0"
? [
{ name: "tenantTypeName", label: "单位类型" },
{ name: "code", label: "编码", render: FORM_ITEM_RENDER_ENUM.INTEGER },
]
: [
{
name: "tenantTypeId",
label: "单位类型",
render: FORM_ITEM_RENDER_ENUM.SELECT,
items: tenantTypes,
itemsField: { labelKey: "tenantTypeName", valueKey: "id" },
rules: [
{
validator: async (_, value) => {
if (value) {
const { data } = await props["verifyUnitTypeConfig"]({
tenantTypeId: value,
id,
});
return data.available ? Promise.resolve() : Promise.reject(new Error(data.msg));
}
else {
Promise.resolve();
}
},
validateTrigger: "onChange",
},
],
formItemProps: { validateTrigger: ["onChange"] },
componentProps: {
onChange: (value) => {
form.setFieldValue("tenantTypeName", getLabelName({
list: tenantTypes,
status: value,
nameKey: "tenantTypeName",
idKey: "id",
}));
},
},
},
{ name: "tenantTypeName", label: "单位类型名称", onlyForLabel: true },
{
name: "code",
label: "编码",
render: FORM_ITEM_RENDER_ENUM.INTEGER,
rules: [
{
validator: async (_, value) => {
if (value) {
const { data } = await props["verifyUnitTypeConfig"]({
code: value,
id,
});
return data.available ? Promise.resolve() : Promise.reject(new Error(data.msg));
}
else {
Promise.resolve();
}
},
validateTrigger: "onBlur",
},
],
formItemProps: { validateTrigger: ["onChange", "onBlur"] },
},
{
name: "defaultType",
label: "默认单位类型",
required: false,
render: (
<DictionarySelect
dictValue="defaultType"
onGetLabel={(label) => {
form.setFieldValue("defaultTypeName", label);
}}
/>
),
},
{ name: "defaultTypeName", label: "默认单位类型名称", onlyForLabel: true },
{
name: "password",
label: "初始密码",
rules: [{ pattern: STRONG_PASSWORD, message: "密码至少8个字符包含大小写字母、数字和特殊字符" }],
},
{
name: "menuIds",
label: "关联菜单",
render: (
<BasicSelectTree
treeData={fullServiceMenu}
nameKey="menuName"
idKey="id"
childrenKey="children"
onlyLastLevel
treeCheckable={true}
showCheckedStrategy={undefined}
/>
),
},
]}
labelCol={{ span: 10 }}
span={24}
showActionButtons={false}
form={form}
onFinish={onSubmit}
/>
</Modal>
);
};
const AddModal = Connect([NS_UNIT_TYPE_CONFIG], true)(AddModalComponent);
export default Connect([NS_UNIT_TYPE_CONFIG], true)(Permission(List));