* refactor: fields/views/pages... * update * update * update * updates * updates * add yarn.lock * updates * updates * updates * updates * updates * updates * updates * updates * updates * developerMode * 一大波更新 * bugfix * fix: hide the sorting settings * fix: reload menu when menu is updated * 页面重构 * modify text * 补充细节 * system settings * 继续更新补充 * fix: 多级菜单支持 * 无限嵌套 * fix: icon * 省市区参数调整 * 表单描述、文案调整 * 支持草稿 * 邮箱登录 * 细节补充 * 菜单页面权限初步 * 详情页打开方式 * 菜单父级、草稿问题 * 描述文字 * 详情分组显示 * 状态改为 radio * 菜单权限 * 跳过省市区 api * 修复权限数据范围 * onDraft * 页面跳转 * 修改文案 * 注册、登录 * fix: 权限过滤问题 * 微调上传组件样式 * 0.4.0-alpha.0 * father-build * remove father-build * 细节调整
382 lines
10 KiB
TypeScript
382 lines
10 KiB
TypeScript
import { ResourceOptions } from '@nocobase/resourcer';
|
|
import { Model, ModelCtor } from '@nocobase/database';
|
|
import actions from '@nocobase/actions';
|
|
import { merge } from '../utils';
|
|
import _ from 'lodash';
|
|
import { getViewTypeLinkages } from '../views';
|
|
|
|
export const getInfo = async (ctx: actions.Context, next) => {
|
|
const { resourceKey } = ctx.action.params;
|
|
const View = ctx.db.getModel('views_v2') as ModelCtor<Model>;
|
|
const Field = ctx.db.getModel('fields') as ModelCtor<Model>;
|
|
let primaryKey: string;
|
|
let viewName: string;
|
|
let collectionName: string;
|
|
let associatedName: string;
|
|
let resourceName: string;
|
|
let associationField: any;
|
|
|
|
if (!resourceKey.includes('.')) {
|
|
const view = await View.findOne({
|
|
where: {
|
|
name: resourceKey,
|
|
},
|
|
});
|
|
const viewData: any = view.toJSON();
|
|
for (const [key, value] of Object.entries(viewData[`x-${viewData.type}-props`]||{})) {
|
|
if (_.get(viewData, key) === null || _.get(viewData, key) === undefined) {
|
|
_.set(viewData, key, value);
|
|
}
|
|
}
|
|
ctx.body = viewData;
|
|
return next();
|
|
}
|
|
|
|
if (resourceKey.includes('.')) {
|
|
const keys = resourceKey.split('.');
|
|
viewName = keys.pop();
|
|
const key1 = keys.shift();
|
|
const key2 = keys.join('.');
|
|
// const [key1, key2] = keys;
|
|
if (key2) {
|
|
const field = ctx.db.getTable(key1).getField(key2);
|
|
associationField = await Field.findOne({
|
|
where: {
|
|
collection_name: key1,
|
|
name: key2,
|
|
},
|
|
});
|
|
collectionName = field.options.target;
|
|
associatedName = key1;
|
|
resourceName = key2;
|
|
} else {
|
|
collectionName = key1;
|
|
}
|
|
}
|
|
// console.log({viewName, collectionName, associatedName})
|
|
let view = await View.findOne({
|
|
where: {
|
|
name: viewName,
|
|
collection_name: collectionName
|
|
},
|
|
});
|
|
|
|
if (view && view.type === 'form') {
|
|
const statusable = !!ctx.db.getTable(view.collection_name).getField('status');
|
|
if (statusable) {
|
|
view.setDataValue('statusable', statusable);
|
|
}
|
|
}
|
|
|
|
const Collection = ctx.db.getModel('collections') as ModelCtor<Model>;
|
|
const M = ctx.db.getModel(collectionName) as ModelCtor<Model>;
|
|
|
|
// if (!view && viewName === 'descriptions') {
|
|
// view = await View.findOne({
|
|
// where: {
|
|
// name: 'form',
|
|
// collection_name: collectionName
|
|
// },
|
|
// });
|
|
// view.type = 'descriptions';
|
|
// }
|
|
let viewData: any = view ? view.toJSON() : {};
|
|
|
|
if (view) {
|
|
viewData.fields = view.get(`x-${view.type}-props.fields`) || view.get('fields') || [];
|
|
viewData.actions = view.get(`x-${view.type}-props.actions`) || view.get('actions') || [];
|
|
viewData.details = view.get(`x-${view.type}-props.details`) || view.get('details') || [];
|
|
}
|
|
|
|
if (!view) {
|
|
const collection = await Collection.findOne({
|
|
where: {
|
|
name: collectionName,
|
|
}
|
|
});
|
|
const fields = await collection.getFields({
|
|
order: [['sort', 'asc']],
|
|
});
|
|
if (viewName === 'table') {
|
|
viewData = {
|
|
collection_name: collectionName,
|
|
type: 'table',
|
|
name: 'table',
|
|
title: '全部数据',
|
|
actions: [
|
|
{
|
|
name: 'create',
|
|
type: 'create',
|
|
title: '新增',
|
|
viewName: 'form',
|
|
},
|
|
{
|
|
name: 'destroy',
|
|
type: 'destroy',
|
|
title: '删除',
|
|
},
|
|
],
|
|
// labelField: 'title',
|
|
fields: fields.filter(field => {
|
|
return field.name !== 'action_logs';
|
|
}).map(field => field.name),
|
|
detailsOpenMode: 'drawer', // window
|
|
details: ['form'],
|
|
sort: ['id'],
|
|
};
|
|
} else if (viewName === 'form') {
|
|
viewData = {
|
|
collection_name: collectionName,
|
|
type: 'form',
|
|
name: 'form',
|
|
title: '表单',
|
|
actions: [
|
|
{
|
|
type: 'update',
|
|
name: 'update',
|
|
title: '编辑',
|
|
viewName: 'form',
|
|
}
|
|
],
|
|
// labelField: 'title',
|
|
fields: fields.filter(field => {
|
|
return field.name !== 'action_logs';
|
|
}).map(field => field.name),
|
|
};
|
|
} else if (viewName === 'descriptions') {
|
|
viewData = {
|
|
collection_name: collectionName,
|
|
type: 'descriptions',
|
|
name: 'descriptions',
|
|
title: '详情',
|
|
// labelField: 'title',
|
|
actions: [],
|
|
fields: fields.filter(field => {
|
|
return field.name !== 'action_logs';
|
|
}).map(field => field.name),
|
|
};
|
|
}
|
|
}
|
|
|
|
// ctx.body = {};
|
|
// return next();
|
|
|
|
const fields = [];
|
|
for (const field of viewData.fields||[]) {
|
|
let fieldName: any;
|
|
let json: any;
|
|
if (typeof field === 'string') {
|
|
fieldName = field;
|
|
} else if (typeof field === 'object') {
|
|
// console.log({field});
|
|
if (field.field) {
|
|
const { field: f, ...others } = field;
|
|
fieldName = f.name;
|
|
json = {...others};
|
|
} else if (field.name) {
|
|
fieldName = field.name;
|
|
json = field;
|
|
}
|
|
}
|
|
const model = await Field.findOne({
|
|
where: {
|
|
collection_name: viewData.collection_name,
|
|
name: fieldName,
|
|
},
|
|
});
|
|
if (model) {
|
|
const target = model.get('target');
|
|
if (target && model.get('interface') === 'subTable') {
|
|
const children = await Field.findAll(Field.parseApiJson({
|
|
filter: {
|
|
collection_name: target,
|
|
'name.ne': 'action_logs',
|
|
},
|
|
sort: 'sort',
|
|
}));
|
|
if (children.length) {
|
|
model.setDataValue('children', children);
|
|
}
|
|
}
|
|
model.setDataValue('dataIndex', model.name.split('.'));
|
|
if (typeof field === 'object') {
|
|
json = merge(model.toJSON(), json);
|
|
} else {
|
|
json = model.toJSON();
|
|
}
|
|
}
|
|
if (!json.name) {
|
|
continue;
|
|
}
|
|
// console.log({field, json})
|
|
if (json.name === 'type' && json.collection_name === 'views_v2') {
|
|
json.linkages = getViewTypeLinkages();
|
|
}
|
|
json && fields.push(json);
|
|
}
|
|
|
|
const actions = [];
|
|
const toFields = async (values = []) => {
|
|
const fields = [];
|
|
for (const value of values) {
|
|
if (typeof value === 'string') {
|
|
const model = await Field.findOne({
|
|
where: {
|
|
collection_name: viewData.collection_name,
|
|
name: value,
|
|
},
|
|
});
|
|
if (model) {
|
|
fields.push(model);
|
|
}
|
|
}
|
|
}
|
|
return fields;
|
|
}
|
|
if (viewData.actions) {
|
|
const parts = resourceKey.split('.');
|
|
parts.pop();
|
|
for (const action of viewData.actions || []) {
|
|
if (action.viewName) {
|
|
if (!action.viewName.includes('.')) {
|
|
action.viewName = `${parts.join('.')}.${action.viewName}`;
|
|
}
|
|
}
|
|
if (action.view && action.view.name) {
|
|
action.viewName = `${parts.join('.')}.${action.view.name}`;
|
|
}
|
|
if (action.fields) {
|
|
action.fields = await toFields(action.fields);
|
|
}
|
|
actions.push({
|
|
...action,
|
|
})
|
|
}
|
|
}
|
|
const details = [];
|
|
for (const item of viewData.details || []) {
|
|
let vName: string;
|
|
if (typeof item === 'string') {
|
|
vName = item;
|
|
const sView = await View.findOne({
|
|
where: {
|
|
collection_name: viewData.collection_name,
|
|
name: vName,
|
|
}
|
|
});
|
|
if (sView) {
|
|
details.push({
|
|
title: sView.title,
|
|
views: [sView],
|
|
});
|
|
} else {
|
|
details.push({
|
|
title: '表单',
|
|
views: [{
|
|
name: item,
|
|
width: '50%',
|
|
}],
|
|
});
|
|
}
|
|
} else if (typeof item === 'object') {
|
|
if (item.views) {
|
|
// TODO 标签页多视图支持
|
|
} else if (item.view) {
|
|
const { view: v, ...others } = item;
|
|
vName = v.name;
|
|
const sView = await View.findOne({
|
|
where: {
|
|
collection_name: viewData.collection_name,
|
|
name: vName,
|
|
}
|
|
});
|
|
sView && details.push({
|
|
...others,
|
|
views: [sView],
|
|
});
|
|
}
|
|
}
|
|
}
|
|
const data: any = {
|
|
...viewData,
|
|
details,
|
|
actions,
|
|
fields,
|
|
};
|
|
if (data.target_field_id) {
|
|
const targetField = await Field.findByPk(data.target_field_id);
|
|
data.targetFieldName = targetField.name;
|
|
}
|
|
if (data.target_view_id) {
|
|
const targetView = await View.findByPk(data.target_view_id);
|
|
data.targetViewName = targetView.name;
|
|
}
|
|
if (associationField) {
|
|
data.associationField = associationField;
|
|
}
|
|
if (data.dataSourceType === 'association') {
|
|
const field = await Field.findOne({
|
|
where: {
|
|
name: data.targetFieldName,
|
|
collection_name: collectionName,
|
|
}
|
|
});
|
|
// console.log(field, data.targetFieldName, collectionName)
|
|
const targetViewName = `${field.get('target')}.${data.targetViewName}`;
|
|
const resourceName = `${collectionName}.${data.targetFieldName}`;
|
|
ctx.action.mergeParams({
|
|
resourceKey: targetViewName,
|
|
});
|
|
await getInfo(ctx, async () => {});
|
|
const body = ctx.body as any;
|
|
const actions = body.actions.map(action => {
|
|
if (action.viewName) {
|
|
const names= action.viewName.split('.');
|
|
action.viewName = `${resourceName}.${names.pop()}`;
|
|
}
|
|
return action;
|
|
});
|
|
const item = {
|
|
...body,
|
|
associationField: field,
|
|
resourceName,
|
|
actions,
|
|
rowKey: resourceKey === 'roles.collections' ? 'name' : body.rowKey,
|
|
}
|
|
ctx.body = item;
|
|
return next();
|
|
} else {
|
|
data.rowKey = data.rowKey || M.primaryKeyAttribute;
|
|
if (associatedName) {
|
|
data.resourceName = `${associatedName}.${resourceName}`;
|
|
} else {
|
|
data.resourceName = collectionName;
|
|
}
|
|
data.appends = data.fields.filter(field => {
|
|
return ['hasMany', 'hasOne', 'belongsToMany', 'belongsTo'].includes(field.type);
|
|
}).map(field => field.name);
|
|
|
|
for (const field of data.fields) {
|
|
if (field.interface === 'attachment') {
|
|
data.appends.push(`${field.name}.storage`);
|
|
}
|
|
}
|
|
}
|
|
delete data['resourceKey'];
|
|
delete data['associatedKey'];
|
|
for (const [key, value] of Object.entries(viewData[`x-${viewData.type}-props`]||{})) {
|
|
if (_.get(data, key) === null || _.get(data, key) === undefined) {
|
|
_.set(data, key, value);
|
|
}
|
|
}
|
|
|
|
if (_.isEmpty(data.sort)) {
|
|
data.sort = [];
|
|
}
|
|
|
|
ctx.body = data;
|
|
await next();
|
|
};
|
|
|
|
export default getInfo;
|