diff --git a/packages/app/src/api-client.ts b/packages/app/src/api-client.ts new file mode 100644 index 0000000000..d1672b5131 --- /dev/null +++ b/packages/app/src/api-client.ts @@ -0,0 +1,56 @@ +import { request } from 'umi'; + +interface ResourceProxyConstructor { + new (target: T, handler: ProxyHandler): H +} + +const ResourceProxy = Proxy as ResourceProxyConstructor; + +interface Params { + resourceKey?: string | number; + // resourceName?: string; + // associatedName?: string; + associatedKey?: string | number; + fields?: any; + filter?: any; +} + +interface Handler { + [name: string]: (params?: Params) => Promise; +} + +class APIClient { + resource(name: string) { + return new ResourceProxy({}, { + get(target, method, receiver) { + return (params: Params = {}) => { + console.log(params); + const { associatedKey, resourceKey, ...restParams } = params; + let url = `/${name}`; + let options: any = {}; + if (['list', 'get'].indexOf(method as string) !== -1) { + options.method = 'get'; + options.params = restParams; + } else { + options.method = 'post'; + options.data = restParams; + } + if (associatedKey) { + url = `/${name.split('.').join(`/${associatedKey}/`)}`; + } + url += `:${method as string}`; + // console.log(name, name.split('.'), associatedKey, name.split('.').join(`/${associatedKey}/`)); + if (resourceKey) { + url += `/${resourceKey}`; + } + console.log({url, params}); + return request(url, options); + }; + } + }); + } +} + +const api = new APIClient(); + +export default api; diff --git a/packages/app/src/api/index.ts b/packages/app/src/api/index.ts index 5adcad2c1d..dc343b2b42 100644 --- a/packages/app/src/api/index.ts +++ b/packages/app/src/api/index.ts @@ -2,7 +2,8 @@ import Api from '../../../server/src'; import dotenv from 'dotenv'; import path from 'path'; import Database, { Model } from '@nocobase/database'; -import { get } from 'lodash'; +import actions from '../../../actions/src'; +import associated from '../../../actions/src/middlewares/associated'; const sync = { force: true, @@ -34,6 +35,9 @@ const api = Api.create({ }, }); +api.resourcer.use(associated); +api.resourcer.registerHandlers(actions.associate); + const data = { title: '后台应用', path: '/', diff --git a/packages/app/src/components/pages/CollectionLoader/CollectionSingle.tsx b/packages/app/src/components/pages/CollectionLoader/CollectionSingle.tsx index 6e3b7d46ab..ebf8caad45 100644 --- a/packages/app/src/components/pages/CollectionLoader/CollectionSingle.tsx +++ b/packages/app/src/components/pages/CollectionLoader/CollectionSingle.tsx @@ -2,12 +2,19 @@ import React from 'react'; import { PageHeader, Tabs, Button, Statistic, Descriptions } from 'antd'; import { CollectionTabPane } from './CollectionTabPane'; import { getPathName, redirectTo } from './utils'; +import api from '@/api-client'; +import { useRequest } from 'umi'; export function CollectionSingle(props) { console.log(props); const { item = {} } = props; const { tabs = [] } = props.collection; const activeTab = tabs.find(tab => tab.name == item.tabName)||{}; + console.log(activeTab); + const { data = {} } = useRequest(() => activeTab && api.resource(activeTab.collection_name).getPageInfo({ + resourceKey: item.itemId, + })); + console.log(data); if (!activeTab) { return null; } @@ -21,7 +28,7 @@ export function CollectionSingle(props) { removeLastItem: true, }); }} - title={'企业信息库'} + title={data.pageTitle} // subTitle="This is a subtitle" extra={[ // , @@ -47,7 +54,7 @@ export function CollectionSingle(props) { } />
- +
); diff --git a/packages/app/src/components/pages/CollectionLoader/CollectionTabPane.tsx b/packages/app/src/components/pages/CollectionLoader/CollectionTabPane.tsx index 5d48fbc89c..d7d4da9572 100644 --- a/packages/app/src/components/pages/CollectionLoader/CollectionTabPane.tsx +++ b/packages/app/src/components/pages/CollectionLoader/CollectionTabPane.tsx @@ -4,23 +4,27 @@ import { PageHeader, Tabs, Button, Statistic, Descriptions } from 'antd'; import { useRequest, request, Spin } from '@nocobase/client'; export function CollectionTabPane(props) { - const { activeTab = {}, item = {} } = props; - const { viewCollectionName, viewName, association, collection_name } = activeTab; + const { pageInfo = {}, activeTab = {}, item = {} } = props; + const { viewCollectionName, viewName, association, collection_name, field = {} } = activeTab; + const { sourceKey = 'id' } = field; const params = {}; if (association) { params['resourceName'] = association; params['associatedName'] = collection_name; - params['associatedKey'] = item.itemId; + params['associatedKey'] = pageInfo[sourceKey] || item.itemId; } else { params['resourceName'] = collection_name; params['resourceKey'] = item.itemId; } + console.log(activeTab); + return (
- request(`/${collection}:getCollection`)); + const { data = {}, error, loading, run } = useRequest(() => api.resource(collection).getCollection()); if (loading) { return ; diff --git a/packages/app/src/components/pages/PageLoader.tsx b/packages/app/src/components/pages/PageLoader.tsx index 897ba1b166..76fb8bb7f3 100644 --- a/packages/app/src/components/pages/PageLoader.tsx +++ b/packages/app/src/components/pages/PageLoader.tsx @@ -3,10 +3,11 @@ import React, { useState } from 'react'; import { TemplateLoader } from './TemplateLoader'; import { useRequest, request } from '@nocobase/client'; import templates from '@/templates'; +import api from '@/api-client'; export function PageLoader(props: any) { const { path } = props.match.params; - const { data = {}, error, loading, run } = useRequest(() => request('/pages:getRoutes')); + const { data = {}, error, loading, run } = useRequest(() => api.resource('pages').getRoutes()); const [first, setFirst] = useState(true); (window as any).routesReload = async () => { setFirst(false); diff --git a/packages/app/src/components/views/SimpleTable.tsx b/packages/app/src/components/views/SimpleTable.tsx index 3798d661fe..5931275f86 100644 --- a/packages/app/src/components/views/SimpleTable.tsx +++ b/packages/app/src/components/views/SimpleTable.tsx @@ -1,8 +1,10 @@ -import React, { useRef } from 'react'; +import React, { useEffect, useRef } from 'react'; import { Table as AntdTable, Card } from 'antd'; import { redirectTo } from '@/components/pages/CollectionLoader/utils'; import { Actions } from '@/components/actions'; import ViewFactory from '@/components/views'; +import { request, useRequest } from 'umi'; +import api from '@/api-client'; const dataSource = []; for (let i = 0; i < 46; i++) { @@ -32,20 +34,42 @@ const columns = [ }, ]; -export function SimpleTable(props: any) { +export interface SimpleTableProps { + schema?: any; + activeTab?: any; + resourceName: string; + associatedName?: string; + associatedKey?: string; + [key: string]: any; +} + +export function SimpleTable(props: SimpleTableProps) { console.log(props); - const { activeTab, schema } = props; - const { viewCollectionName, rowViewName, actions = [] } = schema; + const { + activeTab = {}, + pageInfo = {}, + schema, + resourceName, + associatedName, + associatedKey, + } = props; + const { fields, viewCollectionName, rowViewName, actions = [] } = schema; + const { sourceKey = 'id' } = activeTab.field||{}; const drawerRef = useRef(); + const name = associatedName ? `${associatedName}.${resourceName}` : resourceName; + const { data } = useRequest(() => api.resource(name).list({ + associatedKey, + })); + console.log(activeTab); return ( - ({ + ({ onClick: () => { drawerRef.current.setVisible(true); }, - })} columns={columns} /> + })} columns={fields} /> ); } diff --git a/packages/app/src/components/views/index.tsx b/packages/app/src/components/views/index.tsx index 6b28bb62dc..f389d3e8db 100644 --- a/packages/app/src/components/views/index.tsx +++ b/packages/app/src/components/views/index.tsx @@ -5,6 +5,7 @@ import { Table } from './Table'; import { Details } from './Details'; import { useRequest, request, Spin } from '@nocobase/client'; import { SimpleTable } from './SimpleTable'; +import api from '@/api-client'; const TEMPLATES = new Map(); @@ -24,10 +25,14 @@ registerView('SimpleTable', SimpleTable); registerView('Details', Details); export default function ViewFactory(props) { - const { viewCollectionName, viewName, reference } = props; - const { data = {}, error, loading, run } = useRequest(() => request(`/${viewCollectionName}:getView/${viewName}`), { + const { activeTab, viewCollectionName, viewName, reference } = props; + console.log({viewCollectionName, viewName}); + const { data = {}, error, loading, run } = useRequest(() => api.resource(viewCollectionName).getView({ + resourceKey: viewName, + }), { refreshDeps: [viewCollectionName, viewName], }); + console.log(activeTab); if (loading) { return ; } diff --git a/packages/app/src/components/views/table.tsx b/packages/app/src/components/views/table.tsx index 73c2ade44e..e14789d9df 100644 --- a/packages/app/src/components/views/table.tsx +++ b/packages/app/src/components/views/table.tsx @@ -3,16 +3,7 @@ import { Table as AntdTable, Card } from 'antd'; import { redirectTo } from '@/components/pages/CollectionLoader/utils'; import { Actions } from '@/components/actions'; import { request, useRequest } from 'umi'; - -const dataSource = []; -for (let i = 0; i < 46; i++) { - dataSource.push({ - id: i, - name: `Edward King ${i}`, - age: 32, - address: `London, Park Lane no. ${i}`, - }); -} +import api from '@/api-client'; const columns = [ { @@ -32,12 +23,31 @@ const columns = [ }, ]; -export function Table(props: any) { - console.log(props); - const { activeTab, schema } = props; - const { defaultTabId, defaultTabName, actions = [] } = schema; - const { data } = useRequest(() => request('/collections')); +export interface TableProps { + schema?: any; + activeTab?: any; + resourceName: string; + associatedName?: string; + associatedKey?: string; + [key: string]: any; +} + +export function Table(props: TableProps) { + const { + activeTab = {}, + schema, + resourceName, + associatedName, + associatedKey, + } = props; + const { defaultTabId, fields, defaultTabName, rowKey = 'id', actions = [] } = schema; + const name = associatedName ? `${associatedName}.${resourceName}` : resourceName; + const { data } = useRequest(() => api.resource(name).list({ + associatedKey, + })); + const { sourceKey = 'id' } = activeTab.field||{}; console.log(data); + console.log(activeTab); return ( @@ -46,12 +56,12 @@ export function Table(props: any) { redirectTo({ ...props.match.params, [activeTab ? 'newItem' : 'lastItem']: { - itemId: data.id, + itemId: data[rowKey]||data.id, tabName: defaultTabName, }, }); }, - })} columns={columns} /> + })} columns={fields} /> ); } diff --git a/packages/plugin-collections/src/collections/actions.ts b/packages/plugin-collections/src/collections/actions.ts index b07dd4dd65..593a583790 100644 --- a/packages/plugin-collections/src/collections/actions.ts +++ b/packages/plugin-collections/src/collections/actions.ts @@ -69,7 +69,7 @@ export default { actionNames: ['update'], }, { - type: 'simple', + type: 'table', name: 'simple', title: '简易模式', template: 'SimpleTable', diff --git a/packages/plugin-collections/src/collections/collections.ts b/packages/plugin-collections/src/collections/collections.ts index 578e3c6e5c..de00b278de 100644 --- a/packages/plugin-collections/src/collections/collections.ts +++ b/packages/plugin-collections/src/collections/collections.ts @@ -104,7 +104,7 @@ export default { actionNames: ['update'], }, { - type: 'simple', + type: 'table', name: 'simple', title: '简易模式', template: 'SimpleTable', diff --git a/packages/plugin-collections/src/collections/fields.ts b/packages/plugin-collections/src/collections/fields.ts index c9a3acaac2..0a2bfeb110 100644 --- a/packages/plugin-collections/src/collections/fields.ts +++ b/packages/plugin-collections/src/collections/fields.ts @@ -69,7 +69,7 @@ export default { actionNames: ['update'], }, { - type: 'simple', + type: 'table', name: 'simple', title: '简易模式', template: 'SimpleTable', diff --git a/packages/plugin-collections/src/collections/tabs.ts b/packages/plugin-collections/src/collections/tabs.ts index eb43c37a44..b1827a6d5e 100644 --- a/packages/plugin-collections/src/collections/tabs.ts +++ b/packages/plugin-collections/src/collections/tabs.ts @@ -75,7 +75,7 @@ export default { actionNames: ['update'], }, { - type: 'simple', + type: 'table', name: 'simple', title: '简易模式', template: 'SimpleTable', diff --git a/packages/plugin-collections/src/collections/views.ts b/packages/plugin-collections/src/collections/views.ts index a6e0cc7b87..15a03985a4 100644 --- a/packages/plugin-collections/src/collections/views.ts +++ b/packages/plugin-collections/src/collections/views.ts @@ -88,7 +88,7 @@ export default { actionNames: ['update'], }, { - type: 'simple', + type: 'table', name: 'simple', title: '简易模式', template: 'SimpleTable', diff --git a/packages/plugin-collections/src/resources/actions.ts b/packages/plugin-collections/src/resources/actions.ts deleted file mode 100644 index df9bc5fa0d..0000000000 --- a/packages/plugin-collections/src/resources/actions.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { ResourceOptions } from '@nocobase/resourcer'; - -export default { - name: 'actions', -} as ResourceOptions; diff --git a/packages/plugin-collections/src/resources/collections.ts b/packages/plugin-collections/src/resources/collections.ts deleted file mode 100644 index a85ce0af68..0000000000 --- a/packages/plugin-collections/src/resources/collections.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { ResourceOptions } from '@nocobase/resourcer'; - -export default { - name: 'collections', - actions: { - list: { - fields: { - appends: ['fields'], - } - }, - get: { - fields: { - appends: ['fields'], - } - }, - // get: { - // handler: async (ctx, next) => { - // ctx.body = { - // get: {} - // } - // await next(); - // } - // }, - }, -} as ResourceOptions; diff --git a/packages/plugin-collections/src/resources/fields.ts b/packages/plugin-collections/src/resources/fields.ts deleted file mode 100644 index 53f66ff799..0000000000 --- a/packages/plugin-collections/src/resources/fields.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { ResourceOptions } from '@nocobase/resourcer'; - -export default { - name: 'fields', -} as ResourceOptions; diff --git a/packages/plugin-collections/src/resources/tabs.ts b/packages/plugin-collections/src/resources/tabs.ts deleted file mode 100644 index 964d6d780f..0000000000 --- a/packages/plugin-collections/src/resources/tabs.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { ResourceOptions } from '@nocobase/resourcer'; - -export default { - name: 'tabs', -} as ResourceOptions; diff --git a/packages/plugin-collections/src/resources/views.ts b/packages/plugin-collections/src/resources/views.ts deleted file mode 100644 index dc492ce851..0000000000 --- a/packages/plugin-collections/src/resources/views.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { ResourceOptions } from '@nocobase/resourcer'; - -export default { - name: 'views', -} as ResourceOptions; diff --git a/packages/plugin-collections/src/server.ts b/packages/plugin-collections/src/server.ts index 2e0684f07c..830e2ab302 100644 --- a/packages/plugin-collections/src/server.ts +++ b/packages/plugin-collections/src/server.ts @@ -9,8 +9,4 @@ export default async function (this: any, options = {}) { database.import({ directory: path.resolve(__dirname, 'collections'), }); - - resourcer.import({ - directory: path.resolve(__dirname, 'resources'), - }); } diff --git a/packages/plugin-file-manager/src/server.ts b/packages/plugin-file-manager/src/server.ts index fa3521dd40..16e788eff7 100644 --- a/packages/plugin-file-manager/src/server.ts +++ b/packages/plugin-file-manager/src/server.ts @@ -9,8 +9,4 @@ export default async function (options = {}) { database.import({ directory: path.resolve(__dirname, 'collections'), }); - - resourcer.import({ - directory: path.resolve(__dirname, 'resources'), - }); } diff --git a/packages/plugin-pages/src/actions/getCollection.ts b/packages/plugin-pages/src/actions/getCollection.ts index 380df51c75..394f998b93 100644 --- a/packages/plugin-pages/src/actions/getCollection.ts +++ b/packages/plugin-pages/src/actions/getCollection.ts @@ -4,7 +4,7 @@ import { get } from 'lodash'; export default async (ctx, next) => { const { resourceName, resourceKey } = ctx.action.params; - const [Collection, Tab, View] = ctx.db.getModels(['collections', 'tabs', 'views']) as ModelCtor[]; + const [Collection, Field, Tab, View] = ctx.db.getModels(['collections', 'fields', 'tabs', 'views']) as ModelCtor[]; const collection = await Collection.findOne(Collection.parseApiJson({ filter: { name: resourceName, @@ -20,14 +20,33 @@ export default async (ctx, next) => { }); collection.setDataValue('defaultViewId', get(views, [0, 'id'])); collection.setDataValue('defaultViewName', get(views, [0, 'name'])); - const tabs = await collection.getTabs(); - ctx.body = { - ...collection.toJSON(), - tabs: tabs.map(tab => ({ + const tabs = await collection.getTabs() as Model[]; + const tabItems = []; + for (const tab of tabs) { + const itemTab = { ...tab.toJSON(), ...tab.options, - viewCollectionName: tab.type == 'association' ? tab.options.association : tab.collection_name, - })), + }; + if (itemTab.type == 'association') { + const field = await Field.findOne({ + where: { + collection_name: itemTab.collection_name, + name: itemTab.association, + }, + }); + itemTab.field = field ? { + ...field.toJSON(), + ...field.options, + } : {}; + itemTab.viewCollectionName = itemTab.association; + } else { + itemTab.viewCollectionName = itemTab.collection_name; + } + tabItems.push(itemTab); + } + ctx.body = { + ...collection.toJSON(), + tabs: tabItems, }; await next(); } diff --git a/packages/plugin-pages/src/actions/getPageInfo.ts b/packages/plugin-pages/src/actions/getPageInfo.ts new file mode 100644 index 0000000000..b994ba62fe --- /dev/null +++ b/packages/plugin-pages/src/actions/getPageInfo.ts @@ -0,0 +1,14 @@ +import { ResourceOptions } from '@nocobase/resourcer'; +import { Model, ModelCtor } from '@nocobase/database'; +import { get } from 'lodash'; + +export default async (ctx, next) => { + const { resourceName, resourceKey } = ctx.action.params; + const M = ctx.db.getModel(resourceName) as ModelCtor; + const model = await M.findByPk(resourceKey); + ctx.body = { + pageTitle: model.title, + ...model.toJSON(), + }; + await next(); +}; diff --git a/packages/plugin-pages/src/actions/getView.ts b/packages/plugin-pages/src/actions/getView.ts index 76cb5d788e..38339b5f86 100644 --- a/packages/plugin-pages/src/actions/getView.ts +++ b/packages/plugin-pages/src/actions/getView.ts @@ -2,6 +2,41 @@ import { ResourceOptions } from '@nocobase/resourcer'; import { Model, ModelCtor } from '@nocobase/database'; import { get } from 'lodash'; +const transforms = { + table: async (fields: Model[]) => { + const arr = []; + for (const field of fields) { + arr.push({ + ...field.toJSON(), + ...field.options, + dataIndex: field.name, + }); + } + return arr; + }, + form: async (fields: Model[]) => { + const arr = []; + for (const field of fields) { + arr.push({ + ...field.toJSON(), + ...field.options, + dataIndex: field.name, + }); + } + return arr; + }, + details: async (fields: Model[]) => { + const arr = []; + for (const field of fields) { + arr.push({ + ...field.toJSON(), + ...field.options, + }); + } + return arr; + }, +}; + export default async (ctx, next) => { const { resourceName, resourceKey } = ctx.action.params; const [View, Field, Action] = ctx.db.getModels(['views', 'fields', 'actions']) as ModelCtor[]; @@ -10,9 +45,9 @@ export default async (ctx, next) => { collection_name: resourceName, name: resourceKey, }, - fields: { - appends: ['actions', 'fields'], - }, + // fields: { + // appends: ['actions', 'fields'], + // }, })); const collection = await view.getCollection(); const fields = await collection.getFields(); @@ -27,14 +62,14 @@ export default async (ctx, next) => { }); view.setDataValue('defaultTabName', get(defaultTabs, [0, 'name'])); } - if (view.options.updateViewId) { + if (view.options.updateViewName) { view.setDataValue('rowViewName', view.options.updateViewName); } view.setDataValue('viewCollectionName', view.collection_name); ctx.body = { ...view.toJSON(), ...(view.options||{}), - fields, + fields: await (transforms[view.type]||transforms.table)(fields), actions: actions.filter(action => actionNames.includes(action.name)).map(action => ({ ...action.toJSON(), ...action.options, diff --git a/packages/plugin-pages/src/resources/pages.ts b/packages/plugin-pages/src/resources/pages.ts deleted file mode 100644 index 4258854006..0000000000 --- a/packages/plugin-pages/src/resources/pages.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { ResourceOptions } from '@nocobase/resourcer'; -import getRoutes from '../actions/getRoutes'; - -export default { - name: 'pages', - actions: { - getRoutes, - }, -} as ResourceOptions; diff --git a/packages/plugin-pages/src/server.ts b/packages/plugin-pages/src/server.ts index 1a09d941df..c39fac0b05 100644 --- a/packages/plugin-pages/src/server.ts +++ b/packages/plugin-pages/src/server.ts @@ -3,6 +3,8 @@ import Database from '@nocobase/database'; import Resourcer from '@nocobase/resourcer'; import getCollection from './actions/getCollection'; import getView from './actions/getView'; +import getRoutes from './actions/getRoutes'; +import getPageInfo from './actions/getPageInfo'; export default async function (options = {}) { const database: Database = this.database; @@ -14,8 +16,6 @@ export default async function (options = {}) { resourcer.registerHandler('getCollection', getCollection); resourcer.registerHandler('getView', getView); - - resourcer.import({ - directory: path.resolve(__dirname, 'resources'), - }); + resourcer.registerHandler('getPageInfo', getPageInfo); + resourcer.registerHandler('pages:getRoutes', getRoutes); } diff --git a/packages/plugin-permissions/src/resources/roles.ts b/packages/plugin-permissions/src/resources/roles.ts deleted file mode 100644 index 9dc1e2013b..0000000000 --- a/packages/plugin-permissions/src/resources/roles.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { ResourceOptions } from '@nocobase/resourcer'; - -export default { - name: 'roles', -} as ResourceOptions; diff --git a/packages/plugin-permissions/src/server.ts b/packages/plugin-permissions/src/server.ts index fa3521dd40..16e788eff7 100644 --- a/packages/plugin-permissions/src/server.ts +++ b/packages/plugin-permissions/src/server.ts @@ -9,8 +9,4 @@ export default async function (options = {}) { database.import({ directory: path.resolve(__dirname, 'collections'), }); - - resourcer.import({ - directory: path.resolve(__dirname, 'resources'), - }); } diff --git a/packages/plugin-users/src/resources/users.ts b/packages/plugin-users/src/resources/users.ts deleted file mode 100644 index c9202f652a..0000000000 --- a/packages/plugin-users/src/resources/users.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { ResourceOptions } from '@nocobase/resourcer'; - -export default { - name: 'users', -} as ResourceOptions; diff --git a/packages/plugin-users/src/server.ts b/packages/plugin-users/src/server.ts index fa3521dd40..16e788eff7 100644 --- a/packages/plugin-users/src/server.ts +++ b/packages/plugin-users/src/server.ts @@ -9,8 +9,4 @@ export default async function (options = {}) { database.import({ directory: path.resolve(__dirname, 'collections'), }); - - resourcer.import({ - directory: path.resolve(__dirname, 'resources'), - }); }