feat: add field renderer
This commit is contained in:
parent
ab90b15ffc
commit
d45d37cabf
@ -4,6 +4,8 @@ import { Actions } from '@/components/actions';
|
|||||||
import api from '@/api-client';
|
import api from '@/api-client';
|
||||||
import { useRequest } from 'umi';
|
import { useRequest } from 'umi';
|
||||||
import { Spin } from '@nocobase/client';
|
import { Spin } from '@nocobase/client';
|
||||||
|
import Field from './Field';
|
||||||
|
import get from 'lodash/get';
|
||||||
|
|
||||||
export function Details(props: any) {
|
export function Details(props: any) {
|
||||||
const {
|
const {
|
||||||
@ -38,7 +40,9 @@ export function Details(props: any) {
|
|||||||
<Descriptions bordered column={1}>
|
<Descriptions bordered column={1}>
|
||||||
{fields.map((field: any) => {
|
{fields.map((field: any) => {
|
||||||
return (
|
return (
|
||||||
<Descriptions.Item label={field.title||field.name}>{JSON.stringify(data[field.name])}</Descriptions.Item>
|
<Descriptions.Item label={field.title||field.name}>
|
||||||
|
<Field schema={field} value={get(data, field.name)}/>
|
||||||
|
</Descriptions.Item>
|
||||||
)
|
)
|
||||||
})}
|
})}
|
||||||
</Descriptions>
|
</Descriptions>
|
||||||
|
134
packages/app/src/components/views/Field/index.tsx
Normal file
134
packages/app/src/components/views/Field/index.tsx
Normal file
@ -0,0 +1,134 @@
|
|||||||
|
|
||||||
|
import React, { useEffect, useState } from 'react';
|
||||||
|
import moment from 'moment';
|
||||||
|
import { Tag } from 'antd';
|
||||||
|
import Icon from '@/components/icons';
|
||||||
|
|
||||||
|
const InterfaceTypes = new Map<string, any>();
|
||||||
|
|
||||||
|
function registerFieldComponent(type, Component) {
|
||||||
|
InterfaceTypes.set(type, Component);
|
||||||
|
}
|
||||||
|
|
||||||
|
function registerFieldComponents(components) {
|
||||||
|
Object.keys(components).forEach(key => {
|
||||||
|
registerFieldComponent(key, components[key]);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function getFieldComponent(type) {
|
||||||
|
if (InterfaceTypes.has(type)) {
|
||||||
|
return InterfaceTypes.get(type);
|
||||||
|
}
|
||||||
|
return InterfaceTypes.get('string');
|
||||||
|
}
|
||||||
|
|
||||||
|
export function StringField(props: any) {
|
||||||
|
const { value } = props;
|
||||||
|
return (
|
||||||
|
<>{value}</>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function TextareaField(props: any) {
|
||||||
|
const { value } = props;
|
||||||
|
return (
|
||||||
|
<>{value}</>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function BooleanField(props: any) {
|
||||||
|
const { value } = props;
|
||||||
|
return (
|
||||||
|
<>{value ? '是' : '否'}</>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function NumberField(props: any) {
|
||||||
|
const { schema: { precision }, value } = props;
|
||||||
|
return (
|
||||||
|
<>{value}</>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function PercentField(props: any) {
|
||||||
|
const { schema: { precision }, value } = props;
|
||||||
|
return (
|
||||||
|
<>{value}%</>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function DateTimeField(props: any) {
|
||||||
|
const { schema: { dateFormat, showTime, timeFormat }, value } = props;
|
||||||
|
const m = moment(value);
|
||||||
|
if (!m.isValid()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
let format = dateFormat;
|
||||||
|
if (showTime) {
|
||||||
|
format += ` ${timeFormat}`;
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
<>{m.format(`${format}`)}</>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function IconField(props) {
|
||||||
|
const { value } = props;
|
||||||
|
return <Icon type={value}/>;
|
||||||
|
}
|
||||||
|
|
||||||
|
function toFlat(items = []): Array<any> {
|
||||||
|
let flat = [];
|
||||||
|
items.forEach(item => {
|
||||||
|
flat.push(item);
|
||||||
|
if (Array.isArray(item.children) && item.children.length) {
|
||||||
|
flat = flat.concat(toFlat(item.children));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return flat;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function DataSourceField(props: any) {
|
||||||
|
const { schema: { dataSource = [] }, value } = props;
|
||||||
|
const items = toFlat(dataSource);
|
||||||
|
console.log(items);
|
||||||
|
if (Array.isArray(value)) {
|
||||||
|
return value.map(val => {
|
||||||
|
const item = items.find(item => item.value === val);
|
||||||
|
return (
|
||||||
|
<Tag>
|
||||||
|
{item ? item.label : val}
|
||||||
|
</Tag>
|
||||||
|
)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
const item = items.find(item => item.value === value);
|
||||||
|
return (
|
||||||
|
<Tag>
|
||||||
|
{item ? item.label : value}
|
||||||
|
</Tag>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
registerFieldComponents({
|
||||||
|
string: StringField,
|
||||||
|
textarea: TextareaField,
|
||||||
|
boolean: BooleanField,
|
||||||
|
select: DataSourceField,
|
||||||
|
multipleSelect: DataSourceField,
|
||||||
|
radio: DataSourceField,
|
||||||
|
checkboxes: DataSourceField,
|
||||||
|
number: NumberField,
|
||||||
|
percent: PercentField,
|
||||||
|
datetime: DateTimeField,
|
||||||
|
createdAt: DateTimeField,
|
||||||
|
updatedAt: DateTimeField,
|
||||||
|
icon: IconField,
|
||||||
|
});
|
||||||
|
|
||||||
|
export default function Field(props: any) {
|
||||||
|
const { schema = {} } = props;
|
||||||
|
const Component = getFieldComponent(schema.interface);
|
||||||
|
return <Component {...props}/>;
|
||||||
|
}
|
@ -6,6 +6,7 @@ import arrayMove from 'array-move';
|
|||||||
import findIndex from 'lodash/findIndex';
|
import findIndex from 'lodash/findIndex';
|
||||||
import get from 'lodash/get';
|
import get from 'lodash/get';
|
||||||
import './style.less';
|
import './style.less';
|
||||||
|
import Field from '../Field';
|
||||||
|
|
||||||
export const SortableItem = sortableElement(props => <tr {...props} />);
|
export const SortableItem = sortableElement(props => <tr {...props} />);
|
||||||
export const SortableContainer = sortableContainer(props => <tbody {...props} />);
|
export const SortableContainer = sortableContainer(props => <tbody {...props} />);
|
||||||
@ -55,10 +56,7 @@ export const components = ({data = {}, rowKey, mutate, onMoved}: Props) => {
|
|||||||
|
|
||||||
export function fields2columns(fields) {
|
export function fields2columns(fields) {
|
||||||
const columns: any[] = fields.map(field => {
|
const columns: any[] = fields.map(field => {
|
||||||
const type = get(field, 'component.type');
|
field.render = (value) => field.interface === 'sort' ? <DragHandle/> : <Field schema={field} value={value}/>;
|
||||||
if (type === 'sort') {
|
|
||||||
field.render = () => <DragHandle/>;
|
|
||||||
}
|
|
||||||
return {
|
return {
|
||||||
...field,
|
...field,
|
||||||
...(field.component||{}),
|
...(field.component||{}),
|
||||||
|
@ -12,7 +12,7 @@ const transforms = {
|
|||||||
arr.push({
|
arr.push({
|
||||||
...field.get(),
|
...field.get(),
|
||||||
sorter: field.get('sortable'),
|
sorter: field.get('sortable'),
|
||||||
dataIndex: field.name,
|
dataIndex: field.name.split('.'),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
return arr;
|
return arr;
|
||||||
@ -72,6 +72,9 @@ const transforms = {
|
|||||||
set(prop, 'x-component-props.children', prop.title);
|
set(prop, 'x-component-props.children', prop.title);
|
||||||
delete prop.title;
|
delete prop.title;
|
||||||
}
|
}
|
||||||
|
if (interfaceType === 'multipleSelect') {
|
||||||
|
set(prop, 'x-component-props.mode', 'multiple');
|
||||||
|
}
|
||||||
if (['radio', 'select', 'multipleSelect', 'checkboxes'].includes(interfaceType)) {
|
if (['radio', 'select', 'multipleSelect', 'checkboxes'].includes(interfaceType)) {
|
||||||
prop.enum = get(field.options, 'dataSource', []);
|
prop.enum = get(field.options, 'dataSource', []);
|
||||||
}
|
}
|
||||||
@ -159,6 +162,9 @@ export default async (ctx, next) => {
|
|||||||
});
|
});
|
||||||
view.setDataValue('defaultTabName', get(defaultTabs, [0, 'name']));
|
view.setDataValue('defaultTabName', get(defaultTabs, [0, 'name']));
|
||||||
}
|
}
|
||||||
|
if (view.get('template') === 'SimpleTable') {
|
||||||
|
view.setDataValue('rowViewName', 'form');
|
||||||
|
}
|
||||||
if (view.get('updateViewName')) {
|
if (view.get('updateViewName')) {
|
||||||
view.setDataValue('rowViewName', view.get('updateViewName'));
|
view.setDataValue('rowViewName', view.get('updateViewName'));
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user