Commit c6b68f2b authored by chenos's avatar chenos
Browse files

feat: improve code

parent f300fd6a
Showing with 13 additions and 2918 deletions
+13 -2918
......@@ -8,10 +8,11 @@ export default defineConfig({
define: {
'process.env.API_URL': process.env.API_URL,
},
includes: ['docs'],
// mfsu: {},
// ssr: {},
// exportStatic: {},
mode: 'site',
mode: 'doc',
logo: 'https://www.nocobase.com/dist/images/logo.png',
navs: {
'en-US': [
......
......@@ -10,21 +10,15 @@ export default {
// 如使用代码作为 id 可能更节省,但由于代码数字最长为 12 字节,除非使用 bigint(64) 才够放置
{
name: 'code',
title: '代码',
interface: 'string',
type: 'string',
unique: true,
},
{
name: 'name',
title: '名称',
interface: 'string',
type: 'string',
},
{
name: 'parent',
title: '从属',
interface: 'linkTo',
type: 'belongsTo',
target: 'china_regions',
targetKey: 'code',
......@@ -32,8 +26,6 @@ export default {
},
{
name: 'children',
title: '下辖',
interface: 'linkTo',
type: 'hasMany',
target: 'china_regions',
sourceKey: 'code',
......@@ -41,7 +33,6 @@ export default {
},
{
name: 'level',
title: '层级',
type: 'integer'
}
]
......
import path from 'path';
import { registerModels } from '@nocobase/database';
import Database, { registerModels } from '@nocobase/database';
import { ChinaRegion } from './models/china-region';
import Application from '@nocobase/server';
export default async function (options = {}) {
registerModels({ ChinaRegion });
export default async function (this: Application, options = {}) {
const { database } = this;
registerModels({ ChinaRegion });
database.import({
directory: path.resolve(__dirname, 'collections'),
});
this.on('china-region.init', async () => {
const M = database.getModel('china_regions');
await M.importData();
});
}
{
"name": "@nocobase/plugin-collections-v04",
"version": "0.4.0-alpha.7",
"main": "lib/index.js",
"license": "MIT",
"dependencies": {
"@nocobase/database": "^0.4.0-alpha.7",
"@nocobase/resourcer": "^0.4.0-alpha.7",
"@nocobase/server": "^0.4.0-alpha.7",
"deepmerge": "^4.2.2"
},
"devDependencies": {
"@nocobase/actions": "^0.4.0-alpha.7"
},
"gitHead": "f0b335ac30f29f25c95d7d137655fa64d8d67f1e"
}
import { Agent, getAgent, getApp } from '..';
import { Application } from '@nocobase/server';
import { types } from '../../interfaces';
describe('collection hooks', () => {
let app: Application;
let agent: Agent;
beforeEach(async () => {
app = await getApp();
agent = getAgent(app);
});
afterEach(() => app.database.close());
it('create table', async () => {
const response = await agent.resource('collections').create({
values: {
name: 'tests',
title: 'tests',
},
});
const table = app.database.getTable('tests');
expect(table).toBeDefined();
});
it('create table without name', async () => {
const response = await agent.resource('collections').create({
values: {
title: 'tests',
},
});
const { name } = response.body;
const table = app.database.getTable(name);
expect(table).toBeDefined();
expect(table.getOptions().title).toBe('tests');
const list = await agent.resource('collections').list();
expect(list.body.rows.length).toBe(1);
await table.getModel().drop();
});
});
import qs from 'qs';
import plugin from '../server';
import supertest from 'supertest';
import bodyParser from 'koa-bodyparser';
import { Dialect } from 'sequelize';
import Database from '@nocobase/database';
import { actions, middlewares } from '@nocobase/actions';
import { Application, middleware } from '@nocobase/server';
function getTestKey() {
const { id } = require.main;
const key = id
.replace(`${process.env.PWD}/packages`, '')
.replace(/src\/__tests__/g, '')
.replace('.test.ts', '')
.replace(/[^\w]/g, '_')
.replace(/_+/g, '_');
return key
}
const config = {
username: process.env.DB_USER,
password: process.env.DB_PASSWORD,
database: process.env.DB_DATABASE,
host: process.env.DB_HOST,
port: Number.parseInt(process.env.DB_PORT, 10),
dialect: process.env.DB_DIALECT as Dialect,
define: {
hooks: {
beforeCreate(model, options) {
},
},
},
logging: false,
sync: {
force: true,
alter: {
drop: true,
},
},
};
export async function getApp() {
const app = new Application({
database: {
...config,
hooks: {
beforeDefine(columns, model) {
model.tableName = `${getTestKey()}_${model.tableName || model.name.plural}`;
}
},
},
resourcer: {
prefix: '/api',
},
});
app.resourcer.use(middlewares.associated);
app.resourcer.registerActionHandlers({ ...actions.associate, ...actions.common });
app.registerPlugin('collections', [plugin]);
await app.loadPlugins();
await app.database.sync();
// 表配置信息存到数据库里
// const tables = app.database.getTables([]);
// for (const table of tables) {
// const Collection = app.database.getModel('collections');
// await Collection.import(table.getOptions(), { hooks: false });
// }
app.use(async (ctx, next) => {
ctx.db = app.database;
await next();
});
app.use(bodyParser());
app.use(middleware({
prefix: '/api',
resourcer: app.resourcer,
database: app.database,
}));
return app;
}
interface ActionParams {
resourceKey?: string | number;
// resourceName?: string;
// associatedName?: string;
associatedKey?: string | number;
fields?: any;
filter?: any;
values?: any;
[key: string]: any;
}
interface Handler {
get: (params?: ActionParams) => Promise<supertest.Response>;
list: (params?: ActionParams) => Promise<supertest.Response>;
create: (params?: ActionParams) => Promise<supertest.Response>;
update: (params?: ActionParams) => Promise<supertest.Response>;
destroy: (params?: ActionParams) => Promise<supertest.Response>;
[name: string]: (params?: ActionParams) => Promise<supertest.Response>;
}
export interface Agent {
resource: (name: string) => Handler;
}
export function getAgent(app: Application): Agent {
const agent = supertest.agent(app.callback());
return {
resource(name: string): any {
return new Proxy({}, {
get(target, method, receiver) {
return (params: ActionParams = {}) => {
const { associatedKey, resourceKey, values = {}, ...restParams } = params;
let url = `/api/${name}`;
if (associatedKey) {
url = `/api/${name.split('.').join(`/${associatedKey}/`)}`;
}
url += `:${method as string}`;
if (resourceKey) {
url += `/${resourceKey}`;
}
console.log(url);
if (['list', 'get'].indexOf(method as string) !== -1) {
return agent.get(`${url}?${qs.stringify(restParams)}`);
} else {
return agent.post(`${url}?${qs.stringify(restParams)}`).send(values);
}
}
}
});
}
};
}
export function getDatabase() {
return new Database({
...config,
hooks: {
beforeDefine(columns, model) {
model.tableName = `${getTestKey()}_${model.tableName || model.name.plural}`;
}
}
});
};
import Database, { ModelCtor } from '@nocobase/database';
import { getDatabase } from '../';
import BaseModel from '../../models/base';
import _ from 'lodash';
describe('models.base', () => {
let database: Database;
let TestModel: ModelCtor<BaseModel>;
let test: BaseModel;
beforeEach(async () => {
database = getDatabase();
database.table({
name: 'tests',
model: BaseModel,
additionalAttribute: 'options',
fields: [
{
name: 'name',
type: 'string',
},
{
name: 'title',
type: 'virtual',
},
{
name: 'xyz',
type: 'virtual',
defaultValue: 'xyz1',
},
{
name: 'content',
type: 'virtual',
set(val) {
// 留空
}
},
{
name: 'key1',
type: 'virtual',
set(val) {
this.setDataValue('options.key1', `111${val}111`);
}
},
{
name: 'key2',
type: 'virtual',
get() {
return 'val2';
}
},
{
type: 'json',
name: 'component',
defaultValue: {},
},
{
type: 'json',
name: 'options',
defaultValue: {},
},
],
});
await database.sync();
TestModel = database.getModel('tests') as ModelCtor<BaseModel>;
test = await TestModel.create({
name: '123',
abc: { aa: 'aa' },
'abc.bb': 'bb',
component: {
a: 'a',
},
'component.b': 'b',
options: {
bcd: 'bbb',
},
arr: [{ a: 'a' }, { b: 'b' }],
});
});
afterEach(() => database.close());
it('get all attribute', async () => {
// 获取所有字段
expect(test.get()).toMatchObject({
abc: { aa: 'aa', bb: 'bb' },
bcd: 'bbb',
name: '123',
component: { a: 'a', b: 'b' },
arr: [{ a: 'a' }, { b: 'b' }],
});
});
it('get options attribute', async () => {
// 直接取 options 字段
expect(test.get('options')).toEqual({
abc: {
aa: 'aa',
bb: 'bb',
},
bcd: 'bbb',
xyz: "xyz1",
arr: [{ a: 'a' }, { b: 'b' }],
});
});
it('get component attribute', async () => {
expect(test.get('component')).toEqual({ a: 'a', b: 'b' });
});
it('set component attribute with dot key', async () => {
test.set('component.c', 'c');
await test.save();
expect(test.get()).toMatchObject({
abc: { aa: 'aa', bb: 'bb' },
bcd: 'bbb',
name: '123',
component: { a: 'a', b: 'b' },
arr: [{ a: 'a' }, { b: 'b' }],
});
expect(test.get('component')).toEqual({ a: 'a', b: 'b', c: 'c' });
});
it('set options attribute with dot key', async () => {
test.set('options.cccc', 'cccc');
await test.save();
expect(test.get()).toMatchObject({
abc: { aa: 'aa', bb: 'bb' },
bcd: 'bbb',
name: '123',
cccc: 'cccc',
component: { a: 'a', b: 'b' },
arr: [{ a: 'a' }, { b: 'b' }],
});
});
it('set options attribute without options prefix', async () => {
test.set('dddd', 'dddd');
await test.save();
expect(test.get()).toMatchObject({
abc: { aa: 'aa', bb: 'bb' },
bcd: 'bbb',
name: '123',
dddd: 'dddd',
component: { a: 'a', b: 'b' },
arr: [{ a: 'a' }, { b: 'b' }],
});
});
it('refind', async () => {
test.set('component.c', 'c');
await test.save();
// 重新查询
const test2 = await TestModel.findByPk(test.id);
expect(test2.get()).toMatchObject({
abc: { aa: 'aa', bb: 'bb' },
bcd: 'bbb',
name: '123',
component: { a: 'a', b: 'b', c: 'c' },
arr: [{ a: 'a' }, { b: 'b' }],
});
expect(test2.get('component')).toEqual({ a: 'a', b: 'b', c: 'c' });
});
it('update', async () => {
await test.update({
'name123': 'xxx',
'component.d': 'd',
});
expect(test.get()).toMatchObject({
abc: { aa: 'aa', bb: 'bb' },
bcd: 'bbb',
name: '123',
name123: 'xxx',
component: { a: 'a', b: 'b', d: 'd' },
arr: [{ a: 'a' }, { b: 'b' }],
});
});
it('update virtual attribute', async () => {
await test.update({
title: 'xxx', // 虚拟字段没 set 转存 options
content: 'content123', // set 留空,这个 key 什么也不做
key1: 'val1', // 走 set 方法
});
// 重新获取再验证
const test2 = await TestModel.findByPk(test.id);
expect(test2.get()).toMatchObject({
abc: { aa: 'aa', bb: 'bb' },
bcd: 'bbb',
name: '123',
component: { a: 'a', b: 'b' },
arr: [{ a: 'a' }, { b: 'b' }],
title: 'xxx',
key2: 'val2', // key2 为 get 方法取的
key1: '111val1111',
});
expect(test2.get('content')).toBeUndefined();
});
it('update', async () => {
const t = await TestModel.create({
name: 'name1',
// xyz: 'xyz',
});
await t.update({
abc: 'abc',
});
const t2 = await TestModel.findOne({
where: {
name: 'name1',
}
});
expect(t2.get()).toMatchObject({
xyz: 'xyz1',
abc: 'abc',
key2: 'val2',
id: 2,
name: 'name1',
});
await t2.update({
abc: 'abcdef',
});
const t3 = await TestModel.findOne({
where: {
name: 'name1',
}
});
// 查询之后更新再重新查询
expect(t3.get()).toMatchObject({
xyz: 'xyz1',
abc: 'abcdef',
key2: 'val2',
id: 2,
name: 'name1',
});
});
it('update', async () => {
const t = await TestModel.create({
name: 'name1',
xyz: 'xyz',
});
await t.update({
abc: 'abc',
});
const t2 = await TestModel.findOne({
where: {
name: 'name1',
}
});
expect(t2.get()).toMatchObject({
xyz: 'xyz',
abc: 'abc',
key2: 'val2',
id: 2,
name: 'name1',
});
});
it('component', async () => {
const t = await TestModel.create({
component: {
arr: [
{ a: 'a', aa: 'aa' },
{ b: 'b', bb: 'bb' },
{ c: 'c', cc: 'cc' },
],
},
});
t.set({
component: {
arr: [
{ a: 'aa' },
{ b: 'bb' },
],
}
});
await t.save();
expect(t.get('component')).toEqual({
arr: [
{ a: 'aa' },
{ b: 'bb' },
],
});
})
});
import { Agent, getAgent, getApp } from '../';
import { Application } from '@nocobase/server';
import * as types from '../../interfaces/types';
describe('models.collection', () => {
let app: Application;
let agent: Agent;
beforeEach(async () => {
app = await getApp();
agent = getAgent(app);
});
afterEach(() => app.database.close());
it('import all tables', async () => {
const tables = app.database.getTables([]);
for (const table of tables) {
const Collection = app.database.getModel('collections');
await Collection.import(table.getOptions(), { migrate: false });
}
});
it('import examples', async () => {
await app.database.getModel('collections').import({
title: '示例',
name: 'examples',
showInDataMenu: true,
statusable: false,
fields: [
{
interface: 'string',
title: '单行文本',
name: 'string',
component: {
showInTable: true,
showInDetail: true,
showInForm: true,
},
},
{
interface: 'textarea',
title: '多行文本',
name: 'textarea',
component: {
showInTable: true,
showInDetail: true,
showInForm: true,
},
},
],
}, {
// migrate: false,
});
const table = app.database.getTable('examples');
expect(table).toBeDefined();
expect(table.getFields().size).toBe(2);
await table.sync();
const Example = app.database.getModel('examples');
const example = await Example.create({
string: 'string1',
textarea: 'textarea1',
});
expect(example.toJSON()).toMatchObject({
string: 'string1',
textarea: 'textarea1',
});
});
});
import { Agent, getAgent, getApp } from '../';
import { Application } from '@nocobase/server';
import { types } from '../../interfaces';
describe('models.field', () => {
let app: Application;
let agent: Agent;
beforeEach(async () => {
app = await getApp();
agent = getAgent(app);
});
afterEach(() => app.database.close());
it('updatedAt', async () => {
const Field = app.database.getModel('fields');
const field = new Field();
field.setInterface('updatedAt');
expect(field.get()).toMatchObject(types.updatedAt.options)
});
it('dataSource', async () => {
const Collection = app.database.getModel('collections');
// @ts-ignore
const collection = await Collection.create({
title: 'tests',
});
await collection.updateAssociations({
fields: [
{
title: 'xx',
name: 'xx',
interface: 'select',
type: 'virtual',
dataSource: [
{ label: 'xx', value: 'xx' },
],
component: {
type: 'string',
showInDetail: true,
showInForm: true,
},
}
],
});
const fields = await collection.getFields();
expect(fields[0].get('dataSource')).toEqual([
{ label: 'xx', value: 'xx' },
]);
});
it.skip('sub table field', async () => {
const [Collection, Field] = app.database.getModels(['collections', 'fields']);
const options = {
title: 'tests',
name: 'tests',
fields: [
{
interface: 'subTable',
title: '子表格',
name: 'subs',
children: [
{
interface: 'string',
title: '名称',
name: 'name',
},
],
},
],
};
const collection = await Collection.create(options);
await collection.updateAssociations(options);
const field = await Field.findOne({
where: {
title: '子表格',
},
});
await field.createChild({
interface: 'string',
title: '名称',
name: 'title',
});
const Test = app.database.getModel('tests');
const Sub = app.database.getModel('subs');
// console.log(Test.associations);
// console.log(Sub.rawAttributes);
const test = await Test.create({});
const sub = await test.createSub({ name: 'name1', title: 'title1' });
expect(sub.toJSON()).toMatchObject({ name: 'name1', title: 'title1' })
});
it('sub table field', async () => {
const [Collection, Field] = app.database.getModels(['collections', 'fields']);
// @ts-ignore
const options = {
title: 'tests',
name: 'tests',
fields: [
{
interface: 'subTable',
title: '子表格',
// name: 'subs',
children: [
{
interface: 'string',
title: '名称',
// name: 'name',
},
],
},
],
};
const collection = await Collection.create(options);
await collection.updateAssociations(options);
const field = await Field.findOne({
where: {
title: '子表格',
},
});
await field.createChild({
interface: 'string',
title: '名称',
name: 'title',
});
});
});
import { Model, ModelCtor } from '@nocobase/database';
import { ResourceOptions } from '@nocobase/resourcer';
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<Model>[];
const collection = await Collection.findOne(Collection.parseApiJson({
filter: {
name: resourceName,
},
// fields: {
// // appends: ['tabs'],
// },
}));
const views = await collection.getViews({
where: {
default: true,
},
});
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 => ({
...tab.toJSON(),
...tab.options,
viewCollectionName: tab.type == 'association' ? tab.options.association : tab.collection_name,
})),
};
await next();
}
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 [View, Field, Action] = ctx.db.getModels(['views', 'fields', 'actions']) as ModelCtor<Model>[];
const view = await View.findOne(View.parseApiJson({
filter: {
collection_name: resourceName,
name: resourceKey,
},
fields: {
appends: ['actions', 'fields'],
},
}));
const collection = await view.getCollection();
const fields = await collection.getFields();
const actions = await collection.getActions();
const actionNames = view.options.actionNames || [];
// console.log(view.options);
if (view.type === 'table') {
const defaultTabs = await collection.getTabs({
where: {
default: true,
},
});
view.setDataValue('defaultTabName', get(defaultTabs, [0, 'name']));
}
if (view.options.updateViewId) {
view.setDataValue('rowViewName', view.options.updateViewName);
}
view.setDataValue('viewCollectionName', view.collection_name);
ctx.body = {
...view.toJSON(),
...(view.options || {}),
fields,
actions: actions.filter(action => actionNames.includes(action.name)).map(action => ({
...action.toJSON(),
...action.options,
viewCollectionName: action.collection_name,
})),
};
await next();
};
import { TableOptions } from '@nocobase/database';
export default {
name: 'actions',
title: '操作配置',
internal: true,
draggable: true,
model: 'ActionModel',
developerMode: true,
fields: [
{
interface: 'sort',
type: 'sort',
name: 'sort',
scope: ['collection'],
title: '排序',
component: {
type: 'sort',
className: 'drag-visible',
width: 60,
showInTable: true,
},
},
{
interface: 'string',
type: 'string',
name: 'title',
title: '名称',
component: {
type: 'string',
className: 'drag-visible',
showInForm: true,
showInTable: true,
showInDetail: true,
},
},
{
interface: 'string',
type: 'string',
name: 'name',
title: '标识',
component: {
type: 'string',
showInForm: true,
showInTable: true,
showInDetail: true,
},
},
{
interface: 'string',
type: 'string',
name: 'type',
title: '类型',
component: {
type: 'string',
showInForm: true,
showInTable: true,
showInDetail: true,
},
},
{
interface: 'boolean',
type: 'boolean',
name: 'developerMode',
title: '开发者模式',
defaultValue: false,
component: {
type: 'boolean',
},
},
{
interface: 'linkTo',
type: 'belongsTo',
name: 'collection',
title: '所属数据表',
target: 'collections',
targetKey: 'name',
component: {
type: 'drawerSelect',
},
},
{
interface: 'json',
type: 'json',
name: 'options',
title: '配置信息',
defaultValue: {},
component: {
type: 'hidden',
},
},
],
actions: [
{
type: 'list',
name: 'list',
title: '查看',
},
{
type: 'destroy',
name: 'destroy',
title: '删除',
},
{
type: 'create',
name: 'create',
title: '新增',
viewName: 'form',
},
{
type: 'update',
name: 'update',
title: '编辑',
viewName: 'form',
},
],
} as TableOptions;
import { TableOptions } from '@nocobase/database';
export default {
name: 'collections',
title: '数据表配置',
internal: true,
sortable: true,
draggable: true,
model: 'CollectionModel',
developerMode: true,
createdAt: 'createdTime',
updatedAt: 'updatedTime',
fields: [
// {
// interface: 'sort',
// type: 'sort',
// name: 'sort',
// title: '排序',
// component: {
// type: 'sort',
// className: 'drag-visible',
// width: 60,
// showInTable: true,
// },
// },
{
interface: 'string',
type: 'string',
name: 'title',
title: '数据表名称',
required: true,
component: {
type: 'string',
},
},
{
interface: 'string',
type: 'string',
name: 'name',
createOnly: true,
title: '标识',
unique: true,
required: true,
developerMode: true,
component: {
type: 'string',
},
},
{
interface: 'textarea',
type: 'text',
name: 'description',
title: '数据表描述',
component: {
type: 'textarea',
},
},
// {
// interface: 'boolean',
// type: 'virtual',
// name: 'createdAt',
// title: '记录创建时间',
// developerMode: true,
// defaultValue: true,
// component: {
// type: 'checkbox',
// default: true,
// showInForm: true,
// },
// },
// {
// interface: 'boolean',
// type: 'virtual',
// name: 'updatedAt',
// title: '记录修改时间',
// developerMode: true,
// defaultValue: true,
// component: {
// type: 'checkbox',
// default: true,
// showInForm: true,
// },
// },
{
interface: 'boolean',
type: 'virtual',
name: 'createdBy',
title: '记录创建人信息',
developerMode: true,
component: {
type: 'checkbox',
default: true,
showInForm: true,
},
},
{
interface: 'boolean',
type: 'virtual',
name: 'updatedBy',
title: '记录修改人信息',
developerMode: true,
component: {
type: 'checkbox',
default: true,
showInForm: true,
},
},
{
interface: 'boolean',
type: 'boolean',
name: 'developerMode',
title: '开发者模式',
developerMode: true,
defaultValue: false,
component: {
type: 'boolean',
},
},
{
interface: 'json',
type: 'json',
name: 'options',
title: '配置信息',
defaultValue: {},
component: {
type: 'hidden',
},
},
{
interface: 'boolean',
type: 'boolean',
name: 'internal',
title: '系统内置',
defaultValue: false,
developerMode: true,
component: {
type: 'boolean',
},
},
{
interface: 'linkTo',
type: 'hasMany',
name: 'fields',
title: '字段',
sourceKey: 'name',
draggable: true,
actions: {
list: {
sort: 'sort',
},
get: {
fields: {
appends: ['children'],
},
},
},
component: {
type: 'drawerSelect',
},
},
{
interface: 'linkTo',
type: 'hasMany',
name: 'actions',
title: '动作',
sourceKey: 'name',
draggable: true,
actions: {
list: {
sort: 'sort',
},
},
component: {
type: 'drawerSelect',
},
},
{
interface: 'linkTo',
type: 'hasMany',
name: 'views_v2',
target: 'views_v2',
title: '视图',
sourceKey: 'name',
draggable: true,
// actions: {
// list: {
// sort: 'sort',
// },
// destroy: {
// filter: {
// default: false
// }
// }
// },
component: {
type: 'drawerSelect',
},
},
{
interface: 'linkTo',
type: 'hasMany',
name: 'scopes',
target: 'scopes',
title: '数据范围',
sourceKey: 'name',
actions: {
list: {
sort: 'id',
},
update: {
filter: {
locked: false
}
},
destroy: {
filter: {
locked: false
}
}
},
component: {
type: 'drawerSelect',
},
},
],
actions: [
{
type: 'list',
name: 'list',
title: '查看',
},
{
type: 'destroy',
name: 'destroy',
title: '删除',
},
{
type: 'create',
name: 'create',
title: '新增',
viewName: 'form',
},
{
type: 'update',
name: 'update',
title: '编辑',
viewName: 'form',
},
],
views_v2: [
{
developerMode: true,
type: 'table',
name: 'table',
title: '全部数据',
labelField: 'title',
actions: [
{
name: 'create',
type: 'create',
title: '新增',
viewName: 'form',
},
{
name: 'destroy',
type: 'destroy',
title: '删除',
},
],
fields: ['title', 'description'],
detailsOpenMode: 'window', // window
details: ['descriptions', 'fields', 'views'],
sort: ['id'],
},
{
developerMode: true,
type: 'form',
name: 'form',
title: '表单',
fields: ['title', 'description'],
},
{
developerMode: true,
type: 'descriptions',
name: 'descriptions',
title: '详情',
fields: ['title', 'description'],
actions: [
{
name: 'update',
type: 'update',
title: '编辑',
viewName: 'form',
},
],
},
{
developerMode: true,
type: 'table',
name: 'permissions_table',
title: '权限表格',
labelField: 'title',
actions: [],
fields: ['title'],
detailsOpenMode: 'drawer', // window
details: ['permissions_form'],
sort: ['id'],
},
{
developerMode: true,
type: 'form',
name: 'permissions_form',
title: '权限表单',
fields: [
{
interface: 'json',
type: 'json',
title: '数据操作权限',
name: 'actions',
component: {
"type": "permissions.actions",
"title": "数据操作权限",
"x-linkages": [{
"type": "value:schema",
"target": "actions",
"schema": {
"x-component-props": {
"resourceKey": "{{ $form.values && $form.values.resourceKey }}"
}
}
}],
"x-component-props": {
"dataSource": []
}
},
},
{
interface: 'json',
type: 'json',
title: '字段权限',
name: 'fields',
component: {
"type": "permissions.fields",
"x-linkages": [{
"type": "value:schema",
"target": "fields",
"schema": {
"x-component-props": {
"resourceKey": "{{ $form.values && $form.values.resourceKey }}"
}
}
}],
"x-component-props": {
"dataSource": []
}
},
},
],
},
{
developerMode: true,
type: 'table',
dataSourceType: 'association',
name: 'fields',
title: '字段',
targetViewName: 'table2',
targetFieldName: 'fields',
},
{
developerMode: true,
type: 'table',
dataSourceType: 'association',
name: 'views',
title: '视图',
targetViewName: 'table',
targetFieldName: 'views_v2',
},
],
} as TableOptions;
import { TableOptions } from '@nocobase/database';
import { types, getOptions } from '../interfaces';
export default {
name: 'fields',
title: '字段配置',
internal: true,
draggable: true,
model: 'FieldModel',
developerMode: true,
fields: [
{
interface: 'sort',
type: 'sort',
name: 'sort',
scope: ['collection'],
title: '排序',
component: {
type: 'sort',
className: 'drag-visible',
width: 60,
showInTable: true,
},
},
{
interface: 'string',
type: 'string',
name: 'title',
title: '字段名称',
required: true,
component: {
type: 'string',
className: 'drag-visible',
showInTable: true,
showInDetail: true,
showInForm: true,
},
},
{
interface: 'string',
type: 'string',
name: 'name',
title: '标识',
required: true,
createOnly: true,
developerMode: true,
component: {
type: 'string',
showInTable: true,
showInDetail: true,
showInForm: true,
},
},
{
interface: 'select',
type: 'string',
name: 'interface',
title: '字段类型',
required: true,
dataSource: getOptions(),
createOnly: true,
component: {
type: 'select',
showInTable: true,
showInDetail: true,
showInForm: true,
"x-linkages": [
// TODO(draft): 统一解决字段类型和配置参数联动的一种方式
// {
// type: 'value:schema',
// target: 'options',
// schema: {
// 'x-component-props': {
// fields: '{{ $self.values[1].fields || [] }}'
// }
// },
// condition: '{{ !!$self.value }}'
// },
{
"type": "value:visible",
"target": "precision",
"condition": "{{ ['number', 'percent'].indexOf($self.value) !== -1 }}"
},
{
"type": "value:visible",
"target": "dataSource",
"condition": "{{ ['select', 'multipleSelect', 'radio', 'checkboxes'].indexOf($self.value) !== -1 }}"
},
{
"type": "value:visible",
"target": "dateFormat",
"condition": "{{ ['datetime', 'createdAt', 'updatedAt'].indexOf($self.value) !== -1 }}"
},
{
"type": "value:visible",
"target": "showTime",
"condition": "{{ ['datetime', 'createdAt', 'updatedAt'].indexOf($self.value) !== -1 }}"
},
{
"type": "value:visible",
"target": "timeFormat",
"condition": "{{ ['time'].indexOf($self.value) !== -1 }}"
},
{
"type": "value:visible",
"target": "multiple",
"condition": "{{ ['linkTo'].indexOf($self.value) !== -1 }}"
},
{
"type": "value:visible",
"target": "target",
"condition": "{{ ['linkTo'].indexOf($self.value) !== -1 }}"
},
// {
// "type": "value:visible",
// "target": "labelField",
// "condition": "{{ ['linkTo'].indexOf($self.value) !== -1 }}"
// },
{
"type": "value:visible",
"target": "createable",
"condition": "{{ ['linkTo'].indexOf($self.value) !== -1 }}"
},
{
"type": "value:visible",
"target": "children",
"condition": "{{ ['subTable'].indexOf($self.value) !== -1 }}"
},
{
"type": "value:visible",
"target": "component.showInTable",
"condition": "{{ ['subTable', 'description'].indexOf($self.value) === -1 }}"
},
{
"type": "value:visible",
"target": "component.showInForm",
"condition": "{{ ['createdAt', 'updatedAt', 'createdBy', 'updatedBy'].indexOf($self.value) === -1 }}"
},
{
"type": "value:visible",
"target": "required",
"condition": "{{ ['createdAt', 'updatedAt', 'createdBy', 'updatedBy'].indexOf($self.value) === -1 }}"
},
{
"type": "value:visible",
"target": "maxLevel",
"condition": "{{ ['chinaRegion'].includes($self.value) }}"
},
{
"type": "value:visible",
"target": "incompletely",
"condition": "{{ ['chinaRegion'].includes($self.value) }}"
},
],
},
},
// TODO(draft): 将 options 作为集合字段开放出来,可以动态的解决字段参数的配置表单联动问题
// {
// interface: 'json',
// type: 'json',
// name: 'options',
// title: '配置信息',
// defaultValue: {},
// component: {
// type: 'subFields',
// showInForm: true,
// },
// },
{
interface: 'subTable',
type: 'virtual',
name: 'dataSource',
title: '可选项',
component: {
type: 'table',
default: [{}],
// showInTable: true,
// showInDetail: true,
showInForm: true,
items: {
type: 'object',
properties: {
value: {
type: "string",
title: "",
required: true
},
label: {
type: "string",
title: "选项",
required: true
},
},
},
},
},
{
interface: 'string',
type: 'string',
name: 'type',
title: '数据类型',
developerMode: true,
component: {
type: 'string',
showInTable: true,
showInDetail: true,
showInForm: true,
},
},
{
interface: 'number',
type: 'integer',
name: 'parent_id',
title: '所属分组',
component: {
type: 'number',
},
},
{
interface: 'select',
type: 'virtual',
name: 'precision',
title: '精度',
dataSource: [
{ value: 0, label: '1' },
{ value: 1, label: '1.0' },
{ value: 2, label: '1.00' },
{ value: 3, label: '1.000' },
{ value: 4, label: '1.0000' },
],
component: {
type: 'number',
showInForm: true,
default: 0,
},
},
{
interface: 'select',
type: 'virtual',
name: 'dateFormat',
title: '日期格式',
dataSource: [
{ value: 'YYYY/MM/DD', label: '年/月/日' },
{ value: 'YYYY-MM-DD', label: '年-月-日' },
{ value: 'DD/MM/YYYY', label: '日/月/年' },
],
component: {
type: 'string',
showInForm: true,
default: 'YYYY-MM-DD',
},
},
{
interface: 'boolean',
type: 'virtual',
name: 'showTime',
title: '显示时间',
component: {
type: 'boolean',
showInForm: true,
default: false,
"x-linkages": [
{
"type": "value:visible",
"target": "timeFormat",
"condition": "{{ ($form.values && $form.values.interface === 'time') || $self.value === true }}"
},
],
},
},
{
interface: 'select',
type: 'virtual',
name: 'timeFormat',
title: '时间格式',
dataSource: [
{ value: 'HH:mm:ss', label: '24小时制' },
{ value: 'hh:mm:ss a', label: '12小时制' },
],
component: {
type: 'string',
showInForm: true,
default: 'HH:mm:ss',
},
},
// TODO(refactor): 此部分类型相关的参数,后期应拆分出去
{
name: 'maxLevel',
title: '可选层级',
interface: 'radio',
type: 'virtual',
dataSource: [
{ value: 1, label: '' },
{ value: 2, label: '' },
{ value: 3, label: '区/县' },
{ value: 4, label: '乡镇/街道' },
{ value: 5, label: '村/居委会' },
],
component: {
showInForm: true,
default: 3
}
},
{
name: 'incompletely',
title: '可部分选择',
interface: 'boolean',
type: 'virtual',
component: {
showInForm: true,
}
},
{
interface: 'linkTo',
multiple: false,
type: 'belongsTo',
name: 'parent',
title: '所属分组',
target: 'fields',
foreignKey: 'parent_id',
targetKey: 'id',
component: {
type: 'drawerSelect',
},
},
{
interface: 'string',
type: 'virtual',
name: 'target',
title: '要关联的数据表',
required: true,
createOnly: true,
component: {
type: 'remoteSelect',
showInDetail: true,
showInForm: true,
'x-component-props': {
mode: 'simple',
resourceName: 'collections',
labelField: 'title',
valueField: 'name',
},
"x-linkages": [
{
type: "value:state",
target: "labelField",
condition: "{{ $self.inputed }}",
state: {
value: null,
}
},
{
"type": "value:visible",
"target": "labelField",
"condition": "{{ !!$self.value }}"
},
{
type: "value:schema",
target: "labelField",
// condition: "{{ $self.value }}",
schema: {
"x-component-props": {
"associatedKey": "{{ $self.value }}"
},
},
},
{
type: 'value:visible',
target: 'component.x-component-props.filter',
condition: '{{ !!$self.value }}'
},
{
type: "value:schema",
target: "component.x-component-props.filter",
schema: {
"x-component-props": {
"associatedKey": "{{ $self.value }}"
},
},
},
],
},
},
{
interface: 'string',
type: 'virtual',
name: 'labelField',
title: '要显示的字段',
required: true,
component: {
type: 'remoteSelect',
'x-component-props': {
mode: 'simple',
resourceName: 'collections.fields',
labelField: 'title',
valueField: 'name',
},
showInDetail: true,
showInForm: true,
},
},
{
interface: 'boolean',
type: 'virtual',
name: 'multiple',
title: '允许添加多条记录',
component: {
type: 'checkbox',
showInDetail: true,
showInForm: true,
default: true,
},
},
{
name: 'component.x-component-props.filter',
interface: 'json',
type: 'virtual',
title: '数据范围',
component: {
type: 'filter',
'x-component-props': {
resourceName: 'collections.fields',
},
showInForm: true,
}
},
{
interface: 'boolean',
type: 'virtual',
name: 'createable',
title: '允许直接在关联的数据表内新建数据',
component: {
type: 'checkbox',
showInDetail: true,
showInForm: true,
},
},
{
interface: 'subTable',
type: 'hasMany',
name: 'children',
target: 'fields',
sourceKey: 'id',
foreignKey: 'parent_id',
title: '子表格字段',
viewName: 'table2',
// visible: true,
component: {
type: 'subTable',
default: [],
// showInTable: true,
// showInDetail: true,
showInForm: true,
'x-linkages': [
{
type: 'value:schema',
target: 'children',
schema: {
'x-component-props': {
associatedKey: "{{ $form.values && $form.values.id }}"
},
},
},
],
},
},
// {
// interface: 'linkTo',
// multiple: true,
// type: 'hasMany',
// name: 'children',
// title: '子字段',
// target: 'fields',
// foreignKey: 'parent_id',
// sourceKey: 'id',
// component: {
// type: 'drawerSelect',
// },
// },
{
interface: 'textarea',
type: 'virtual',
name: 'component.tooltip',
title: '提示信息',
component: {
type: 'textarea',
showInDetail: true,
showInForm: true,
},
},
{
interface: 'boolean',
type: 'boolean',
name: 'required',
title: '必填项',
component: {
type: 'checkbox',
showInTable: true,
showInDetail: true,
showInForm: true,
},
},
{
interface: 'boolean',
type: 'virtual',
name: 'component.showInTable',
title: '显示在表格中',
component: {
type: 'checkbox',
tooltip: '若勾选,该字段将作为一列显示在数据表里',
showInTable: true,
showInDetail: true,
showInForm: true,
default: true,
},
},
{
interface: 'boolean',
type: 'virtual',
name: 'component.showInForm',
title: '显示在表单中',
component: {
type: 'checkbox',
tooltip: '若勾选,该字段将出现在表单中',
showInTable: true,
showInDetail: true,
showInForm: true,
default: true,
},
},
{
interface: 'boolean',
type: 'virtual',
name: 'component.showInDetail',
title: '显示在详情中',
component: {
type: 'checkbox',
tooltip: '若勾选,该字段将出现在详情中',
showInTable: true,
showInDetail: true,
showInForm: true,
default: true,
},
},
{
interface: 'linkTo',
type: 'belongsTo',
name: 'collection',
title: '所属数据表',
target: 'collections',
targetKey: 'name',
labelField: 'title',
component: {
type: 'drawerSelect',
// showInTable: true,
'x-component-props': {
resourceName: 'collections.fields',
labelField: 'title',
valueField: 'name',
},
},
},
{
interface: 'boolean',
type: 'boolean',
name: 'developerMode',
title: '开发者模式',
defaultValue: false,
component: {
type: 'boolean',
},
},
{
interface: 'json',
type: 'json',
name: 'component',
title: '前端组件',
defaultValue: {},
component: {
type: 'hidden',
},
},
{
interface: 'json',
type: 'json',
name: 'options',
title: '配置信息',
defaultValue: {},
component: {
type: 'hidden',
},
},
],
actions: [
{
type: 'list',
name: 'list',
title: '查看',
},
{
type: 'destroy',
name: 'destroy',
title: '删除',
},
{
type: 'create',
name: 'create',
title: '新增',
viewName: 'form',
},
{
type: 'update',
name: 'update',
title: '编辑',
viewName: 'form',
},
],
views_v2: [
{
developerMode: true,
type: 'table',
name: 'table',
title: '关联的字段',
labelField: 'title',
actions: [
{
name: 'create',
type: 'create',
title: '新增',
viewName: 'form',
},
{
name: 'destroy',
type: 'destroy',
title: '删除',
},
],
fields: ['title', 'interface'],
detailsOpenMode: 'drawer', // window
details: ['form'],
sort: ['sort'],
},
{
developerMode: true,
type: 'table',
name: 'table2',
title: '表格',
labelField: 'title',
actions: [
{
name: 'create',
type: 'create',
title: '新增',
viewName: 'form',
},
{
name: 'destroy',
type: 'destroy',
title: '删除',
},
],
fields: ['sort', 'title', 'interface'],
detailsOpenMode: 'drawer', // window
details: ['form'],
sort: ['sort'],
},
{
developerMode: true,
type: 'form',
name: 'form',
title: '表单',
fields: [
'title',
'interface',
'dataSource',
'precision',
'dateFormat',
'showTime',
'timeFormat',
'maxLevel',
'incompletely',
'target',
'labelField',
'children',
'multiple',
// 'required',
],
},
],
} as TableOptions;
import { TableOptions } from '@nocobase/database';
export default {
name: 'scopes',
title: '表操作范围',
developerMode: true,
internal: true,
fields: [
{
comment: '范围名称',
type: 'string',
name: 'title',
title: '名称',
component: {
type: 'string',
showInTable: true,
showInForm: true,
},
},
{
interface: 'json',
type: 'jsonb',
name: 'filter',
title: '条件',
developerMode: false,
mode: 'replace',
defaultValue: {},
component: {
type: 'filter',
showInForm: true,
"x-linkages": [
{
type: "value:schema",
target: "filter",
schema: {
"x-component-props": {
associatedKey: "{{ $form.values && $form.values.associatedKey }}"
},
},
},
],
},
},
{
interface: 'boolean',
type: 'boolean',
name: 'locked',
title: '锁定',
defaultValue: false,
component: {
showInTable: true,
}
},
{
type: 'belongsTo',
name: 'collection',
targetKey: 'name',
onDelete: 'CASCADE'
}
],
views_v2: [
{
developerMode: true,
type: 'table',
name: 'table',
title: '全部数据',
labelField: 'title',
actions: [
{
name: 'create',
type: 'create',
title: '新增',
viewName: 'form',
},
{
name: 'destroy',
type: 'destroy',
title: '删除',
},
],
fields: ['title'],
detailsOpenMode: 'drawer', // window
details: ['form'],
sort: ['id'],
},
{
developerMode: true,
type: 'form',
name: 'form',
title: '表单',
fields: [
'title',
'filter',
],
},
],
} as TableOptions;
import { TableOptions } from '@nocobase/database';
export default {
name: 'tabs',
title: '标签配置',
internal: true,
sortable: true,
model: 'TabModel',
developerMode: true,
fields: [
{
interface: 'sort',
type: 'sort',
name: 'sort',
scope: ['collection'],
title: '排序',
component: {
type: 'sort',
className: 'drag-visible',
width: 60,
showInTable: true,
},
},
{
interface: 'string',
type: 'string',
name: 'title',
title: '名称',
required: true,
component: {
type: 'string',
className: 'drag-visible',
showInTable: true,
showInDetail: true,
showInForm: true,
},
},
{
interface: 'string',
type: 'string',
name: 'name',
title: '标识',
component: {
type: 'string',
showInTable: true,
showInDetail: true,
showInForm: true,
},
},
{
interface: 'radio',
type: 'string',
name: 'type',
title: '类型',
required: true,
dataSource: [
{ label: '详情数据', value: 'details' },
{ label: '相关数据', value: 'association' },
{ label: '模块组合', value: 'module', disabled: true },
],
component: {
type: 'radio',
showInTable: true,
showInDetail: true,
showInForm: true,
"x-linkages": [
// {
// "type": "value:visible",
// "target": "association",
// "condition": "{{ $self.value === 'association' }}"
// },
{
type: "value:visible",
target: "associationField",
condition: "{{ $self.value === 'association' }}"
},
{
type: "value:visible",
target: "displayFields",
condition: "{{ $self.value === 'details' }}",
},
{
type: "value:visible",
target: "displayFormFields",
condition: "{{ $self.value === 'details' }}",
},
// {
// type: "value:schema",
// target: "association",
// condition: "{{ $self.value === 'association' }}",
// schema: {
// "x-component-props": {
// "associatedKey": "{{ $form.values && $form.values.associatedKey }}"
// },
// },
// },
{
type: "value:schema",
target: "displayFields",
condition: "{{ $self.value === 'details' }}",
schema: {
"x-component-props": {
associatedKey: "{{ $form.values && $form.values.associatedKey }}"
},
},
},
{
type: "value:schema",
target: "displayFormFields",
condition: "{{ $self.value === 'details' }}",
schema: {
"x-component-props": {
associatedKey: "{{ $form.values && $form.values.associatedKey }}"
},
},
},
{
type: "value:schema",
target: "associationField",
condition: "{{ $self.value === 'association' }}",
schema: {
"x-component-props": {
associatedKey: "{{ $form.values && $form.values.associatedKey }}"
},
},
},
],
},
},
// {
// interface: 'string',
// type: 'string',
// name: 'association',
// title: '相关数据',
// component: {
// type: 'remoteSelect',
// showInDetail: true,
// showInForm: true,
// 'x-component-props': {
// resourceName: 'collections.fields',
// labelField: 'title',
// valueField: 'name',
// filter: {
// interface: 'linkTo',
// },
// },
// },
// },
{
interface: 'linkTo',
type: 'belongsTo',
name: 'associationField',
target: 'fields',
title: '相关数据表',
labelField: 'title',
required: true,
// valueField: 'name',
component: {
type: 'remoteSelect',
showInDetail: true,
showInForm: true,
'x-component-props': {
resourceName: 'collections.fields',
labelField: 'title',
// valueField: 'name',
objectValue: true,
filter: {
interface: 'linkTo',
},
},
"x-linkages": [
{
type: "value:visible",
target: "viewName",
condition: "{{ !!$self.value }}"
},
{
type: "value:schema",
target: "viewName",
condition: "{{ !!$self.value }}",
schema: {
"x-component-props": {
associatedKey: "{{ $self.value.target }}"
},
},
},
],
},
},
{
interface: 'json',
type: 'json',
name: 'displayFields',
title: '显示在详情中的字段',
labelField: 'title',
// valueField: 'name',
component: {
type: 'draggableTable',
showInDetail: true,
showInForm: true,
'x-component-props': {
resourceName: 'collections.fields',
labelField: 'title',
valueField: 'name',
mode: 'showInDetail',
fields: [
// {
// interface: 'sort',
// name: 'sort',
// title: '排序',
// type: 'sort',
// dataIndex: ['sort'],
// className: 'drag-visible',
// },
{
interface: 'string',
name: 'title',
title: '字段名称',
type: 'string',
className: 'drag-visible',
dataIndex: ['title'],
}
],
},
},
},
{
interface: 'json',
type: 'json',
name: 'displayFormFields',
title: '当前标签页可编辑字段',
labelField: 'title',
// valueField: 'name',
component: {
type: 'draggableTable',
showInDetail: true,
showInForm: true,
'x-component-props': {
resourceName: 'collections.fields',
labelField: 'title',
valueField: 'name',
mode: 'showInForm',
fields: [
// {
// interface: 'sort',
// name: 'sort',
// title: '排序',
// type: 'sort',
// dataIndex: ['sort'],
// className: 'drag-visible',
// },
{
interface: 'string',
name: 'title',
title: '字段名称',
type: 'string',
className: 'drag-visible',
dataIndex: ['title'],
}
],
},
},
},
{
interface: 'string',
type: 'string',
name: 'viewName',
title: '视图',
labelField: 'title',
required: true,
// valueField: 'name',
component: {
type: 'remoteSelect',
showInDetail: true,
showInForm: true,
'x-component-props': {
resourceName: 'collections.views',
labelField: 'title',
valueField: 'name',
},
},
},
{
interface: 'boolean',
type: 'radio',
name: 'default',
title: '作为默认标签页',
defaultValue: false,
scope: ['collection'],
component: {
type: 'checkbox',
showInTable: true,
showInDetail: true,
showInForm: true,
},
},
{
interface: 'boolean',
type: 'boolean',
name: 'enabled',
title: '启用',
defaultValue: true,
component: {
type: 'checkbox',
showInTable: true,
showInDetail: true,
showInForm: true,
},
},
{
interface: 'boolean',
type: 'boolean',
name: 'developerMode',
title: '开发者模式',
defaultValue: false,
component: {
type: 'boolean',
},
},
{
interface: 'linkTo',
type: 'belongsTo',
name: 'collection',
title: '所属数据表',
target: 'collections',
targetKey: 'name',
component: {
type: 'drawerSelect',
},
},
{
interface: 'json',
type: 'json',
name: 'options',
title: '配置信息',
defaultValue: {},
component: {
type: 'hidden',
},
},
],
actions: [
{
type: 'list',
name: 'list',
title: '查看',
},
{
type: 'destroy',
name: 'destroy',
title: '删除',
filter: {
default: false
}
},
{
type: 'create',
name: 'create',
title: '新增',
viewName: 'form',
},
{
type: 'update',
name: 'update',
title: '编辑',
viewName: 'form',
},
],
views: [
{
type: 'form',
name: 'form',
title: '表单',
template: 'DrawerForm',
developerMode: true,
},
{
type: 'details',
name: 'details',
title: '详情',
template: 'Details',
actionNames: ['update'],
developerMode: true,
},
{
type: 'table',
name: 'simple',
title: '简易模式',
template: 'Table',
mode: 'simple',
default: true,
actionNames: ['destroy', 'create'],
detailsViewName: 'details',
updateViewName: 'form',
paginated: false,
draggable: true,
},
],
} as TableOptions;
import { TableOptions } from '@nocobase/database';
export default {
name: 'views',
title: '视图配置',
internal: true,
sortable: true,
model: 'ViewModel',
developerMode: true,
fields: [
{
interface: 'sort',
type: 'sort',
name: 'sort',
scope: ['collection'],
title: '排序',
component: {
type: 'sort',
className: 'drag-visible',
width: 60,
showInTable: true,
},
},
{
interface: 'string',
type: 'string',
name: 'title',
title: '视图名称',
required: true,
component: {
type: 'string',
className: 'drag-visible',
showInTable: true,
showInDetail: true,
showInForm: true,
},
},
{
interface: 'string',
type: 'string',
name: 'name',
title: '标识',
component: {
type: 'string',
showInTable: true,
showInDetail: true,
showInForm: true,
},
},
{
interface: 'radio',
type: 'string',
name: 'type',
title: '视图类型',
required: true,
dataSource: [
{ label: '表格', value: 'table' },
{ label: '日历', value: 'calendar' },
// { label: '表单', value: 'form' },
{ label: '看板', value: 'kanban', disabled: true },
{ label: '地图', value: 'map', disabled: true },
],
component: {
type: 'radio',
showInTable: true,
showInDetail: true,
showInForm: true,
default: 'table',
"x-linkages": [
{
"type": "value:visible",
"target": "filter",
"condition": "{{ $self.value !== 'form' }}"
},
{
type: "value:schema",
target: "labelField",
"condition": "{{ $self.value === 'calendar' }}",
schema: {
"x-component-props": {
associatedKey: "{{ $form.values && $form.values.associatedKey }}"
},
},
},
{
type: "value:schema",
target: "startDateField",
"condition": "{{ $self.value === 'calendar' }}",
schema: {
"x-component-props": {
associatedKey: "{{ $form.values && $form.values.associatedKey }}"
},
},
},
{
type: "value:schema",
target: "endDateField",
"condition": "{{ $self.value === 'calendar' }}",
schema: {
"x-component-props": {
associatedKey: "{{ $form.values && $form.values.associatedKey }}"
},
},
},
{
"type": "value:visible",
"target": "labelField",
"condition": "{{ $self.value === 'calendar' }}",
},
{
"type": "value:visible",
"target": "startDateField",
"condition": "{{ $self.value === 'calendar' }}",
},
{
"type": "value:visible",
"target": "endDateField",
"condition": "{{ $self.value === 'calendar' }}",
},
],
},
},
{
interface: 'select',
type: 'virtual',
title: '标题字段',
name: 'labelField',
required: true,
component: {
type: 'remoteSelect',
showInDetail: true,
showInForm: true,
'x-component-props': {
mode: 'simple',
resourceName: 'collections.fields',
labelField: 'title',
valueField: 'name',
filter: {
type: 'string',
},
},
},
},
{
interface: 'select',
type: 'virtual',
title: '开始日期字段',
name: 'startDateField',
// required: true,
component: {
type: 'remoteSelect',
showInDetail: true,
showInForm: true,
'x-component-props': {
placeholder: '默认为创建时间字段',
mode: 'simple',
resourceName: 'collections.fields',
labelField: 'title',
valueField: 'name',
filter: {
type: 'date',
},
},
},
},
{
interface: 'select',
type: 'virtual',
title: '结束日期字段',
name: 'endDateField',
// required: true,
component: {
type: 'remoteSelect',
showInDetail: true,
showInForm: true,
'x-component-props': {
placeholder: '默认为创建时间字段',
mode: 'simple',
resourceName: 'collections.fields',
labelField: 'title',
valueField: 'name',
filter: {
type: 'date',
},
},
},
},
{
interface: 'json',
type: 'json',
name: 'filter',
title: '筛选数据',
developerMode: false,
mode: 'replace',
defaultValue: {},
component: {
type: 'filter',
showInForm: true,
},
},
{
interface: 'radio',
type: 'string',
name: 'mode',
title: '查看和编辑模式',
required: true,
dataSource: [
{ label: '常规模式', value: 'default' },
{ label: '快捷模式', value: 'simple' },
],
component: {
tooltip: "常规模式:点击数据进入查看界面,再次点击进入编辑界面<br/>快捷模式:点击数据直接打开编辑界面",
type: 'radio',
default: 'default',
showInTable: true,
showInDetail: true,
showInForm: true,
},
},
{
interface: 'select',
type: 'string',
name: 'template',
title: '模板',
required: true,
developerMode: true,
dataSource: [
{ label: '表单', value: 'DrawerForm' },
{ label: '常规表格', value: 'Table' },
{ label: '简易表格', value: 'SimpleTable' },
{ label: '日历模板', value: 'Calendar' },
],
component: {
type: 'select',
default: 'Table',
showInTable: true,
showInDetail: true,
showInForm: true,
},
},
{
interface: 'radio',
type: 'virtual',
name: 'defaultPerPage',
title: '默认每页显示几行数据',
defaultValue: 50,
dataSource: [
{ label: '10', value: 10 },
{ label: '20', value: 20 },
{ label: '50', value: 50 },
{ label: '100', value: 100 },
],
component: {
type: 'radio',
showInForm: true,
showInDetail: true,
},
},
{
interface: 'boolean',
type: 'virtual',
name: 'draggable',
title: '支持拖拽数据排序',
showInForm: true,
showInDetail: true,
component: {
type: 'checkbox',
showInForm: true,
showInDetail: true,
},
},
{
interface: 'boolean',
type: 'radio',
name: 'default',
title: '作为默认视图',
defaultValue: false,
scope: ['collection'],
component: {
type: 'checkbox',
showInTable: true,
showInDetail: true,
showInForm: true,
},
},
{
interface: 'boolean',
type: 'boolean',
name: 'showInDataMenu',
title: '作为数据表子菜单',
defaultValue: false,
component: {
type: 'checkbox',
showInTable: true,
showInDetail: true,
showInForm: true,
},
},
{
interface: 'boolean',
type: 'boolean',
name: 'developerMode',
title: '开发者模式',
defaultValue: false,
component: {
type: 'boolean',
},
},
{
interface: 'linkTo',
type: 'belongsTo',
name: 'collection',
title: '所属数据表',
target: 'collections',
targetKey: 'name',
component: {
type: 'drawerSelect',
},
},
{
interface: 'json',
type: 'json',
name: 'options',
title: '配置信息',
defaultValue: {},
component: {
type: 'hidden',
},
},
// 以下暂不考虑
// {
// type: 'belongsToMany',
// name: 'fields',
// component: {
// type: 'drawerSelect',
// },
// },
// {
// type: 'belongsToMany',
// name: 'actions',
// component: {
// type: 'drawerSelect',
// },
// },
],
actions: [
{
type: 'list',
name: 'list',
title: '查看',
},
{
type: 'destroy',
name: 'destroy',
title: '删除',
filter: {
default: false
}
},
{
type: 'create',
name: 'create',
title: '新增',
viewName: 'form',
},
{
type: 'update',
name: 'update',
title: '编辑',
viewName: 'form',
},
],
views: [
{
type: 'form',
name: 'form',
title: '表单',
template: 'DrawerForm',
developerMode: true,
},
{
type: 'details',
name: 'details',
title: '详情',
template: 'Details',
actionNames: ['update'],
developerMode: true,
},
{
type: 'table',
name: 'simple',
title: '简易模式',
template: 'SimpleTable',
mode: 'simple',
default: true,
actionNames: ['destroy', 'create'],
detailsViewName: 'details',
updateViewName: 'form',
paginated: false,
draggable: true,
},
],
} as TableOptions;
import CollectionModel from '../models/collection';
const defaultValues = {
actions: [
{
type: 'filter',
name: 'filter',
title: '筛选',
},
{
type: 'list',
name: 'list',
title: '查看',
},
{
type: 'destroy',
name: 'destroy',
title: '删除',
},
{
type: 'create',
name: 'create',
title: '新增',
viewName: 'form',
},
{
type: 'update',
name: 'update',
title: '编辑',
viewName: 'form',
},
],
};
export default async function (model: CollectionModel, options: any = {}) {
const { migrate = true } = options;
console.log('plugin-collections hook', { migrate })
if (migrate) {
await model.migrate({ ...options, isNewRecord: true });
}
await model.updateAssociations(defaultValues, options);
}
import CollectionModel from '../models/collection';
export default async function (model: CollectionModel, options: any = {}) {
const { migrate = true } = options;
if (migrate) {
await model.migrate(options);
}
}
import CollectionModel from '../models/collection';
export default async function (model: CollectionModel) {
model.generateNameIfNull();
}
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment