diff --git a/packages/client/src/components/admin-layout/Permissions/MenuPermissionTable.tsx b/packages/client/src/components/admin-layout/Permissions/MenuPermissionTable.tsx
new file mode 100644
index 000000000..cfaf83ac6
--- /dev/null
+++ b/packages/client/src/components/admin-layout/Permissions/MenuPermissionTable.tsx
@@ -0,0 +1,121 @@
+import React from 'react';
+import { observer } from '@formily/react';
+import { Table, Checkbox, Spin } from 'antd';
+import { useRequest } from 'ahooks';
+import { request } from '../../../schemas';
+import { Resource } from '@nocobase/client/src/resource';
+import { useContext } from 'react';
+import { RoleContext } from '.';
+import { useState } from 'react';
+
+const getKeys = (items: any[]) => {
+ const keys = [];
+ for (const item of items) {
+ keys.push(item.key);
+ const children = getKeys(item.children || []);
+ keys.push(...children);
+ }
+ return keys;
+};
+
+export const MenuPermissionTable = observer((props) => {
+ const role = useContext(RoleContext);
+ const [allUiSchemaKyes, setAllUiSchemaKyes] = useState([]);
+ const [uiSchemaKyes, setUiSchemaKeys] = useState([]);
+ const { data, loading } = useRequest(
+ () => request('ui_schemas:getMenuItems'),
+ {
+ formatResult: (data) => data?.data,
+ onSuccess(data) {
+ setAllUiSchemaKyes(getKeys(data));
+ },
+ },
+ );
+ console.log('allUiSchemaKyes', allUiSchemaKyes);
+ const resource = Resource.make({
+ associatedName: 'roles',
+ associatedKey: role.name,
+ resourceName: 'ui_schemas',
+ });
+ useRequest(() => resource.list(), {
+ formatResult: (data) => data?.data,
+ onSuccess(data) {
+ setUiSchemaKeys(getKeys(data));
+ },
+ });
+ if (loading) {
+ return ;
+ }
+ return (
+
+
+ 0 &&
+ allUiSchemaKyes.length === uiSchemaKyes.length
+ }
+ onChange={async (e) => {
+ const resource = Resource.make({
+ resourceName: 'roles',
+ resourceKey: role.name,
+ });
+ if (e.target.checked) {
+ await resource.save({
+ ui_schemas: allUiSchemaKyes,
+ });
+ setUiSchemaKeys(allUiSchemaKyes);
+ } else {
+ await resource.save({
+ ui_schemas: [],
+ });
+ setUiSchemaKeys([]);
+ }
+ }}
+ />{' '}
+ 允许访问
+
+ ),
+ dataIndex: 'key',
+ render: (value) => {
+ return (
+ {
+ setUiSchemaKeys((prevUiSchemaKeys) => {
+ if (e.target.checked) {
+ prevUiSchemaKeys.push(value);
+ } else {
+ const index = prevUiSchemaKeys.findIndex(
+ (key) => key === value,
+ );
+ prevUiSchemaKeys.splice(index, 1);
+ }
+ return [...prevUiSchemaKeys];
+ });
+ await resource.toggle({
+ resourceKey: value,
+ });
+ }}
+ />
+ );
+ },
+ },
+ ]}
+ />
+
+ );
+});
diff --git a/packages/client/src/components/admin-layout/Permissions/index.tsx b/packages/client/src/components/admin-layout/Permissions/index.tsx
index cb4ee9be1..dd0544207 100644
--- a/packages/client/src/components/admin-layout/Permissions/index.tsx
+++ b/packages/client/src/components/admin-layout/Permissions/index.tsx
@@ -15,6 +15,7 @@ import { connect, ISchema, observer, useForm } from '@formily/react';
import { DescriptionsContext } from '../../../schemas/form';
import { createContext } from 'react';
import { ActionPermissionField } from './ActionPermissionField';
+import { MenuPermissionTable } from './MenuPermissionTable';
export const RoleContext = createContext(null);
@@ -246,96 +247,7 @@ const collectionSchema: ISchema = {
const menuSchema: ISchema = {
type: 'array',
- // 'x-decorator': 'CardItem',
- 'x-component': 'Table',
- default: [],
- 'x-component-props': {
- rowKey: 'name',
- showIndex: true,
- refreshRequestOnChange: true,
- pagination: {
- pageSize: 10,
- },
- useResource: useCollectionsResource,
- collectionName: 'collections',
- },
- properties: {
- [uid()]: {
- type: 'void',
- title: '操作',
- 'x-component': 'Table.Operation',
- 'x-component-props': {
- className: 'nb-table-operation',
- },
- properties: {
- [uid()]: {
- type: 'void',
- 'x-component': 'Action',
- 'x-component-props': {
- icon: 'EllipsisOutlined',
- },
- properties: {
- [uid()]: {
- type: 'void',
- 'x-component': 'Action.Dropdown',
- 'x-component-props': {},
- properties: {
- [uid()]: {
- type: 'void',
- title: '配置',
- 'x-component': 'Menu.Action',
- 'x-component-props': {
- style: {
- minWidth: 150,
- },
- },
- 'x-action-type': 'view',
- properties: {
- [uid()]: {
- type: 'void',
- title: '权限配置',
- 'x-component': 'Action.Drawer',
- 'x-component-props': {
- bodyStyle: {
- background: '#f0f2f5',
- paddingTop: 0,
- },
- },
- properties: {},
- },
- },
- },
- },
- },
- },
- },
- },
- },
- column1: {
- type: 'void',
- title: '权限名称',
- 'x-component': 'Table.Column',
- properties: {
- title: {
- type: 'string',
- 'x-component': 'Input',
- 'x-read-pretty': true,
- },
- },
- },
- column2: {
- type: 'void',
- title: '权限标识',
- 'x-component': 'Table.Column',
- properties: {
- name: {
- type: 'string',
- 'x-component': 'Input',
- 'x-read-pretty': true,
- },
- },
- },
- },
+ 'x-component': 'MenuPermissionTable',
};
const schema: ISchema = {
@@ -488,7 +400,7 @@ const schema: ISchema = {
},
[uid()]: {
type: 'void',
- title: '菜单权限',
+ title: '菜单访问权限',
'x-component': 'Tabs.TabPane',
'x-component-props': {},
properties: {
@@ -579,7 +491,7 @@ const schema: ISchema = {
export const Permissions = () => {
return (
);
diff --git a/packages/client/src/resource.ts b/packages/client/src/resource.ts
index 4da25cfb5..eef38dcf2 100644
--- a/packages/client/src/resource.ts
+++ b/packages/client/src/resource.ts
@@ -110,6 +110,15 @@ export class Resource {
});
}
+ toggle(options?: any) {
+ const { associatedKey, associatedName, resourceName } = this.options;
+ const { resourceKey } = options;
+ let url = `${associatedName}/${associatedKey}/${resourceName}:toggle/${resourceKey}`;
+ return request(url, {
+ method: 'post',
+ });
+ }
+
static make(options: null | string | Resource | ResourceOptions): Resource | null {
if (typeof options === 'string') {
return new Resource({ resourceName: options });
diff --git a/packages/plugin-permissions/src/collections/roles.ts b/packages/plugin-permissions/src/collections/roles.ts
index 2db67150c..f4d59e46c 100644
--- a/packages/plugin-permissions/src/collections/roles.ts
+++ b/packages/plugin-permissions/src/collections/roles.ts
@@ -25,5 +25,11 @@ export default {
target: 'users',
through: 'roles_users'
},
+ {
+ type: 'belongsToMany',
+ name: 'ui_schemas',
+ target: 'ui_schemas',
+ through: 'roles_ui_schemas'
+ },
],
} as TableOptions;
diff --git a/packages/plugin-ui-schema/src/actions/index.ts b/packages/plugin-ui-schema/src/actions/index.ts
index 9efc1c671..c976b412a 100644
--- a/packages/plugin-ui-schema/src/actions/index.ts
+++ b/packages/plugin-ui-schema/src/actions/index.ts
@@ -135,3 +135,14 @@ export const getTree = async (ctx: actions.Context, next: actions.Next) => {
await next();
};
+
+export const getMenuItems = async (ctx: actions.Context, next: actions.Next) => {
+ const UISchema = ctx.db.getModel('ui_schemas');
+ const schema = await UISchema.findOne({
+ where: {
+ 'x-component': 'Menu',
+ }
+ });
+ ctx.body = await schema.getHierarchy();
+ await next();
+};
diff --git a/packages/plugin-ui-schema/src/collections/ui_schemas.ts b/packages/plugin-ui-schema/src/collections/ui_schemas.ts
index 6d5047417..3f56c7ce6 100644
--- a/packages/plugin-ui-schema/src/collections/ui_schemas.ts
+++ b/packages/plugin-ui-schema/src/collections/ui_schemas.ts
@@ -32,6 +32,10 @@ export default {
type: 'string',
name: 'type',
},
+ {
+ type: 'string',
+ name: 'x-component',
+ },
{
type: 'json',
name: 'options',
diff --git a/packages/plugin-ui-schema/src/models/ui-schema.ts b/packages/plugin-ui-schema/src/models/ui-schema.ts
index 0c95ea631..4c5bdd997 100644
--- a/packages/plugin-ui-schema/src/models/ui-schema.ts
+++ b/packages/plugin-ui-schema/src/models/ui-schema.ts
@@ -86,4 +86,23 @@ export class UISchema extends Model {
}
return properties;
}
+
+ async getHierarchy() {
+ const data = [];
+ const children: UISchema[] = await this.getChildren({
+ where: {
+ async: false,
+ },
+ order: [['sort', 'asc']],
+ });
+ for (const child of children) {
+ const item: any = child.toJSON();
+ const nested = await child.getHierarchy();
+ if (nested.length) {
+ item.children = nested;
+ }
+ data.push(item);
+ }
+ return data;
+ }
}
diff --git a/packages/plugin-ui-schema/src/server.ts b/packages/plugin-ui-schema/src/server.ts
index f89a534dd..436e8c3e6 100644
--- a/packages/plugin-ui-schema/src/server.ts
+++ b/packages/plugin-ui-schema/src/server.ts
@@ -2,7 +2,7 @@ import path from 'path';
import { Application } from '@nocobase/server';
import { registerModels, Table } from '@nocobase/database';
import * as models from './models';
-import { create, update, getTree } from './actions';
+import * as actions from './actions';
export default async function (this: Application, options = {}) {
const database = this.database;
@@ -12,7 +12,7 @@ export default async function (this: Application, options = {}) {
directory: path.resolve(__dirname, 'collections'),
});
- this.resourcer.registerActionHandler('ui_schemas:create', create);
- this.resourcer.registerActionHandler('ui_schemas:update', update);
- this.resourcer.registerActionHandler('ui_schemas:getTree', getTree);
+ for (const [name, action] of Object.entries(actions)) {
+ this.resourcer.registerActionHandler(`ui_schemas:${name}`, action);
+ }
}