mirror of
https://github.com/nocobase/nocobase
synced 2024-11-15 05:57:53 +00:00
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 { useRequest } from 'umi';
|
||||
import { Spin } from '@nocobase/client';
|
||||
import Field from './Field';
|
||||
import get from 'lodash/get';
|
||||
|
||||
export function Details(props: any) {
|
||||
const {
|
||||
@ -38,7 +40,9 @@ export function Details(props: any) {
|
||||
<Descriptions bordered column={1}>
|
||||
{fields.map((field: any) => {
|
||||
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>
|
||||
|
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 get from 'lodash/get';
|
||||
import './style.less';
|
||||
import Field from '../Field';
|
||||
|
||||
export const SortableItem = sortableElement(props => <tr {...props} />);
|
||||
export const SortableContainer = sortableContainer(props => <tbody {...props} />);
|
||||
@ -55,10 +56,7 @@ export const components = ({data = {}, rowKey, mutate, onMoved}: Props) => {
|
||||
|
||||
export function fields2columns(fields) {
|
||||
const columns: any[] = fields.map(field => {
|
||||
const type = get(field, 'component.type');
|
||||
if (type === 'sort') {
|
||||
field.render = () => <DragHandle/>;
|
||||
}
|
||||
field.render = (value) => field.interface === 'sort' ? <DragHandle/> : <Field schema={field} value={value}/>;
|
||||
return {
|
||||
...field,
|
||||
...(field.component||{}),
|
||||
|
@ -12,7 +12,7 @@ const transforms = {
|
||||
arr.push({
|
||||
...field.get(),
|
||||
sorter: field.get('sortable'),
|
||||
dataIndex: field.name,
|
||||
dataIndex: field.name.split('.'),
|
||||
});
|
||||
}
|
||||
return arr;
|
||||
@ -72,6 +72,9 @@ const transforms = {
|
||||
set(prop, 'x-component-props.children', prop.title);
|
||||
delete prop.title;
|
||||
}
|
||||
if (interfaceType === 'multipleSelect') {
|
||||
set(prop, 'x-component-props.mode', 'multiple');
|
||||
}
|
||||
if (['radio', 'select', 'multipleSelect', 'checkboxes'].includes(interfaceType)) {
|
||||
prop.enum = get(field.options, 'dataSource', []);
|
||||
}
|
||||
@ -159,6 +162,9 @@ export default async (ctx, next) => {
|
||||
});
|
||||
view.setDataValue('defaultTabName', get(defaultTabs, [0, 'name']));
|
||||
}
|
||||
if (view.get('template') === 'SimpleTable') {
|
||||
view.setDataValue('rowViewName', 'form');
|
||||
}
|
||||
if (view.get('updateViewName')) {
|
||||
view.setDataValue('rowViewName', view.get('updateViewName'));
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user