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); + } }