diff --git a/src/components/detail/common.tsx b/src/components/detail/common.tsx new file mode 100644 index 0000000000000000000000000000000000000000..a112c87a9771238a45317ead8be7b870f0963068 --- /dev/null +++ b/src/components/detail/common.tsx @@ -0,0 +1,182 @@ +import React from 'react' +import { ParamConfig } from '../../interface' + +import { DetailFieldConfigs as getFieldConfigs } from './' +import ParamHelper from '../../util/param' +/** + * 详情页表单项基类配置文件格式定义 + * - field: 表单项字段名 + * - label: 表单项名称 + * - defaultValue: 表单项默认值 + * - display: 是否可见 + * - - type: 默认值类型 + * - - * static: 固定值 + * - - * data: 上一步骤数据 + * - - * query: 页面GET方法传参 + * - - * hash: 页面HASH传参 + * - - * interface: 接口入参获取 + * - - value: 默认值(static类型使用) + * - - field: 字段名(data/query/hash类型使用)(hash类型选填) + */ +export interface DetailFieldConfig { + field: string + label: string + display?: 'none' + defaultValue?: ParamConfig, + condition?: DetailFieldConditionConfig + // styles?: object +} + +export interface DetailFieldConditionConfig { + statement?: string + params?: Array<{ + field?: string + data?: ParamConfig + }> + debug?: boolean +} + +/** + * 详情页表单项配置文件格式定义 - 枚举 + */ +export type DetailFieldConfigs = getFieldConfigs + +/** + * 详情页表单项子类需实现的方法 + * - reset: 表单项重置当前值 + * - set: 表单项设置当前值 + * - get: 表单项获取当前值 + * - validate: 表单项的值校验方法 + */ +export interface IDetailField { + reset: () => Promise + set: (value: T) => Promise + get: () => Promise + validate: (value: T) => Promise + fieldFormat: () => Promise<{}> +} + +/** + * 详情页表单项子类需要的入参 + * - ref: + * - formLayout: + * - value: + * - data: + * - step: + * - config: + * - onChange: + */ +export interface DetailFieldProps { + // 挂载事件 + ref: (instance: DetailField | null) => void + formLayout: 'horizontal' | 'vertical' | 'inline' + value: T, + record: { [field: string]: any }, + data: any[], + step: number, + config: C + // TODO 待删除 + onChange: (value: T) => Promise + // 事件:设置值 + onValueSet: (path: string, value: T, validation: true | DetailFieldError[]) => Promise + // // 事件:置空值 + onValueUnset: (path: string, validation: true | DetailFieldError[]) => Promise + // 事件:修改值 - 列表 - 追加 + onValueListAppend: (path: string, value: any, validation: true | DetailFieldError[]) => Promise + // 事件:修改值 - 列表 - 删除 + onValueListSplice: (path: string, index: number, count: number, validation: true | DetailFieldError[]) => Promise + loadDomain: (domain: string) => Promise +} + +/** + * 详情页配置接口获取数据需要的入参 +* - url: 请求地址 +* - method: 请求类型 +* - withCredentials?: 跨域是否提供凭据信息 +* - response: 返回值 +* - format?: 格式化返回值 +* - responseArrayKey?: format === 'array' 时配置 key 值 +* - responseArrayValue?: format === 'array' 时配置 value 值 + */ +export interface DetailFieldInterface { + interface?: { + url: string + method: 'GET' | 'POST' | 'get' | 'post' + withCredentials?: boolean + response: string + format?: 'array' | 'key' + responseArrayKey?: string + responseArrayValue?: string + } +} + +/** + * 详情项基类 + * - C: 表单项的配置文件类型 + * - E: 表单项的渲染方法入参 + * - T: 表单项的值类型 + * - S: 表单项的扩展状态 + */ +export class DetailField extends React.Component, S> implements IDetailField { + static defaultProps = { + config: {} + }; + + /** + * 获取默认值 + */ + defaultValue = async () => { + const { + config + } = this.props + if (config.defaultValue !== undefined) { + return ParamHelper(config.defaultValue, { record: this.props.record, data: this.props.data, step: this.props.step }) + } + + return undefined + } + + reset: () => Promise = async () => { + return this.defaultValue() + }; + + set: (value: T) => Promise = async (value) => { + const { + onChange + } = this.props + if (onChange) { + onChange(value) + } + }; + + get: () => Promise = async () => { + return this.props.value + } + + validate: (value: T) => Promise = async () => { + return true + }; + + fieldFormat: () => Promise<{}> = async () => { + return {} + } + + renderComponent = (props: E) => { + return + 当前UI库未实现该表单类型 + + } + + render = () => { + return ( + 当前UI库未实现该表单类型 + ) + } +} + +export class DetailFieldError { + message: string + constructor(message: string) { + this.message = message + } +} diff --git a/src/components/detail/group/index.tsx b/src/components/detail/group/index.tsx new file mode 100644 index 0000000000000000000000000000000000000000..5f3e745ff8bbb606f38e28fd78fa7f7bcae94edc --- /dev/null +++ b/src/components/detail/group/index.tsx @@ -0,0 +1,286 @@ +import React from 'react' +import { cloneDeep } from 'lodash' +import { setValue, getValue } from '../../../util/value' +import { DetailField, DetailFieldConfig, DetailFieldError, DetailFieldProps, IDetailField } from '../common' +import getALLComponents, { DetailFieldConfigs } from '../' +import { IDetailItem } from '../../../steps/detail' +import ConditionHelper from '../../../util/condition' + +export interface GroupFieldConfig extends DetailFieldConfig { + type: 'group' + fields: DetailFieldConfigs[] +} + +export interface IGroupField { + children: React.ReactNode[] +} + +interface IGroupFieldState { + detailData: { status: 'normal' | 'error' | 'loading', message?: string }[] +} + +export default class GroupField extends DetailField implements IDetailField { + // 各表单项对应的类型所使用的UI组件的类 + getALLComponents = (type: any): typeof DetailField => getALLComponents[type] + + detailFields: Array | null> = [] + detailFieldsMounted: Array = [] + + constructor (props: DetailFieldProps) { + super(props) + + this.state = { + detailData: [] + } + } + + get = async () => { + let data: any = {}; + + if (Array.isArray(this.props.config.fields)) { + for (const detailFieldIndex in this.props.config.fields) { + const detailFieldConfig = this.props.config.fields[detailFieldIndex] + if (!ConditionHelper(detailFieldConfig.condition, { record: this.props.value, data: this.props.data, step: this.props.step })) { + continue + } + const detailField = this.detailFields[detailFieldIndex] + if (detailField) { + const value = await detailField.get() + data = setValue(data, detailFieldConfig.field, value) + } + } + } + + return data + } + + handleMount = async (detailFieldIndex: number) => { + if (this.detailFieldsMounted[detailFieldIndex]) { + return true + } + + this.detailFieldsMounted[detailFieldIndex] = true + + if (this.detailFields[detailFieldIndex]) { + const detailField = this.detailFields[detailFieldIndex] + if (detailField) { + const detailFieldConfig = this.props.config.fields[detailFieldIndex] + + let value = getValue(this.props.value, detailFieldConfig.field) + if ((detailFieldConfig.defaultValue) && value === undefined) { + value = await detailField.reset() + this.props.onValueSet(detailFieldConfig.field, value, true) + } + + const validation = await detailField.validate(value) + if (value === undefined || validation === true) { + await this.setState(({ detailData }) => { + detailData[detailFieldIndex] = { status: 'normal' } + return { detailData: cloneDeep(detailData) } + }) + } else { + await this.setState(({ detailData }) => { + detailData[detailFieldIndex] = { status: 'error', message: validation[0].message } + return { detailData: cloneDeep(detailData) } + }) + } + } + } + } + + handleChange = async (formFieldIndex: number, value: any) => { + // const formField = this.formFields[formFieldIndex] + // const formFieldConfig = this.props.config.fields[formFieldIndex] + + // const formData = cloneDeep(this.state.formData) + + // if (formField && formFieldConfig) { + // if (this.props.onChange) { + // if (formFieldConfig.field === '') { + // await this.props.onChange(value) + // } else { + // const changeValue = setValue({}, formFieldConfig.field, value) + // await this.props.onChange(changeValue) + // } + // } + + // const validation = await formField.validate(value) + // if (validation === true) { + // formData[formFieldIndex] = { value, status: 'normal' } + // } else { + // formData[formFieldIndex] = { value, status: 'error', message: validation[0].message } + // } + + // await this.setState({ + // formData + // }) + // } + } + + handleValueSet = async (detailFieldIndex: number, path: string, value: any, validation: true | DetailFieldError[]) => { + const detailFieldConfig = (this.props.config.fields || [])[detailFieldIndex] + if (detailFieldConfig) { + const fullPath = detailFieldConfig.field === '' || path === '' ? `${detailFieldConfig.field}${path}` : `${detailFieldConfig.field}.${path}` + await this.props.onValueSet(fullPath, value, true) + + const detailData = cloneDeep(this.state.detailData) + if (validation === true) { + detailData[detailFieldIndex] = { status: 'normal' } + } else { + detailData[detailFieldIndex] = { status: 'error', message: validation[0].message } + } + + this.setState({ + detailData + }) + } + } + + handleValueUnset = async (detailFieldIndex: number, path: string, validation: true | DetailFieldError[]) => { + const detailFieldConfig = (this.props.config.fields || [])[detailFieldIndex] + if (detailFieldConfig) { + const fullPath = detailFieldConfig.field === '' || path === '' ? `${detailFieldConfig.field}${path}` : `${detailFieldConfig.field}.${path}` + await this.props.onValueUnset(fullPath, true) + + const detailData = cloneDeep(this.state.detailData) + if (validation === true) { + detailData[detailFieldIndex] = { status: 'normal' } + } else { + detailData[detailFieldIndex] = { status: 'error', message: validation[0].message } + } + + this.setState({ + detailData + }) + } + } + + handleValueListAppend = async (detailFieldIndex: number, path: string, value: any, validation: true | DetailFieldError[]) => { + const detailFieldConfig = (this.props.config.fields || [])[detailFieldIndex] + if (detailFieldConfig) { + const fullPath = detailFieldConfig.field === '' || path === '' ? `${detailFieldConfig.field}${path}` : `${detailFieldConfig.field}.${path}` + await this.props.onValueListAppend(fullPath, value, true) + + const detailData = cloneDeep(this.state.detailData) + if (validation === true) { + detailData[detailFieldIndex] = { status: 'normal' } + } else { + detailData[detailFieldIndex] = { status: 'error', message: validation[0].message } + } + + this.setState({ + detailData + }) + } + } + + handleValueListSplice = async (detailFieldIndex: number, path: string, index: number, count: number, validation: true | DetailFieldError[]) => { + const detailFieldConfig = (this.props.config.fields || [])[detailFieldIndex] + if (detailFieldConfig) { + const fullPath = detailFieldConfig.field === '' || path === '' ? `${detailFieldConfig.field}${path}` : `${detailFieldConfig.field}.${path}` + await this.props.onValueListSplice(fullPath, index, count, true) + + const detailData = cloneDeep(this.state.detailData) + if (validation === true) { + detailData[detailFieldIndex] = { status: 'normal' } + } else { + detailData[detailFieldIndex] = { status: 'error', message: validation[0].message } + } + + this.setState({ + detailData + }) + } + } + + renderComponent = (props: IGroupField) => { + return + 您当前使用的UI版本没有实现GroupField组件。 + + } + + /** + * 表单项组件 - UI渲染方法 + * 各UI库需重写该方法 + * @param props + */ + renderItemComponent = (props: IDetailItem) => { + return + 您当前使用的UI版本没有实现DetailItem组件。 + + } + + render = () => { + const { + config, + formLayout, + value, + record, + data, + step + } = this.props + + return ( + + {this.renderComponent({ + children: (this.props.config.fields || []).map((detailFieldConfig, detailFieldIndex) => { + if (!ConditionHelper(detailFieldConfig.condition, { record: value, data: this.props.data, step: this.props.step })) { + return null + } + let hidden: boolean = true + let display: boolean = true + + // if (detailFieldConfig.type === 'hidden') { + // hidden = true + // display = false + // } + + if (detailFieldConfig.display === 'none') { + hidden = true + display = false + } + + const DetailFieldComponent = this.getALLComponents(detailFieldConfig.type) || DetailField + + const renderData = { + key: detailFieldIndex, + label: detailFieldConfig.label, + layout: formLayout, + visitable: display, + fieldType: detailFieldConfig.type, + children: ( + | null) => { + if (detailFieldIndex !== null) { + this.detailFields[detailFieldIndex] = detailField + this.handleMount(detailFieldIndex) + } + }} + formLayout={formLayout} + value={getValue(value, detailFieldConfig.field)} + record={record} + data={cloneDeep(data)} + step={step} + config={detailFieldConfig} + onChange={async (value: any) => { await this.handleChange(detailFieldIndex, value) }} + onValueSet={async (path, value, validation) => this.handleValueSet(detailFieldIndex, path, value, validation)} + onValueUnset={async (path, validation) => this.handleValueUnset(detailFieldIndex, path, validation)} + onValueListAppend={async (path, value, validation) => this.handleValueListAppend(detailFieldIndex, path, value, validation)} + onValueListSplice={async (path, index, count, validation) => this.handleValueListSplice(detailFieldIndex, path, index, count, validation)} + loadDomain={async (domain: string) => await this.props.loadDomain(domain)} + /> + ) + } + // 渲染表单项容器 + return ( + hidden + ? this.renderItemComponent(renderData) + : + ) + }) + })} + + ) + } +} diff --git a/src/components/detail/index.tsx b/src/components/detail/index.tsx new file mode 100644 index 0000000000000000000000000000000000000000..66e8fb4e9037058f08dce593c0389b2f964b261d --- /dev/null +++ b/src/components/detail/index.tsx @@ -0,0 +1,22 @@ + +import TextField, { TextFieldConfig } from './text' + +import { DetailFieldConfig } from './common' +import GroupField, { GroupFieldConfig } from './group' + + +/** + * 详情步骤内详情项配置文件格式定义 - 枚举 + */ +export type DetailFieldConfigs = + TextFieldConfig | + GroupFieldConfig + +export type componentType = + 'text' | + 'group' + +export default { + group: GroupField, + text: TextField +} diff --git a/src/components/detail/text/index.tsx b/src/components/detail/text/index.tsx new file mode 100644 index 0000000000000000000000000000000000000000..886c4147c2e4777e81c1a2b48d67136c73023a1d --- /dev/null +++ b/src/components/detail/text/index.tsx @@ -0,0 +1,36 @@ +import React from 'react' +import { getBoolean } from '../../../util/value' +import { DetailField, DetailFieldConfig, DetailFieldError, IDetailField } from '../common' + +export interface TextFieldConfig extends DetailFieldConfig { + type: 'text' +} + +export interface ITextField { + value: string +} + +export default class TextField extends DetailField implements IDetailField { + + renderComponent = (props: ITextField) => { + return + 您当前使用的UI版本没有实现Text组件。 +
+
+
+ } + + render = () => { + const { + value + } = this.props + + return ( + + {this.renderComponent({ + value + })} + + ) + } +} diff --git a/src/components/formFields/group/index.tsx b/src/components/formFields/group/index.tsx index ebd9de72432e4a01559eeca6034ab9eff1539e7e..1826dcbbed806b702f780287526523070f2e8849 100644 --- a/src/components/formFields/group/index.tsx +++ b/src/components/formFields/group/index.tsx @@ -278,6 +278,7 @@ export default class GroupField extends Field Promise + backText?: string +} + +/** + * 详情项组件 - UI渲染方法 + * - key: react需要的unique key + * - label: 详情项名称 + * - layout: 详情项布局 + * - visitable: 详情项可见性 + * - * horizontal: 左侧文本、右侧输入框、纵向排列 + * - * vertical: 顶部文本、底部输入框、纵向排列 + * - * inline: 左侧文本、右侧输入框、横向排列 + * - children: 详情项内容 + */ +export interface IDetailItem { + key: string | number, + label: string + layout: 'horizontal' | 'vertical' | 'inline' + visitable: boolean + fieldType: string + children: React.ReactNode +} + +/** + * 详情步骤组件 - 状态 + * - formData: 表单的值 + */ +interface DetailState { + ready: boolean + detailValue: { [field: string]: any } + detailData: { status: 'normal' | 'error' | 'loading', message?: string, name: string }[] +} + +/** + * 表单步骤组件 + */ +export default class DetailStep extends Step { + // 各详情项对应的类型所使用的UI组件的类 + getALLComponents = (type: any): typeof DetailField => getALLComponents[type] + + // 各详情项所使用的UI组件的实例 + detailFields: Array | null> = [] + detailFieldsMounted: Array = [] + + detailValue: { [field: string]: any } = {} + detailData: { status: 'normal' | 'error' | 'loading', message?: string, name: string, hidden: boolean }[] = [] + + /** + * 初始化表单的值 + * @param props + */ + constructor(props: StepProps) { + super(props) + this.state = { + ready: false, + detailValue: {}, + detailData: [] + } + } + + /** + * 重写表单步骤装载事件 + */ + stepPush = async () => { + // 处理表单步骤配置文件的默认值 + const { + config: { + fields: detailFieldsConfig = [] + }, + data, + step, + onMount + } = this.props + + const detailData = cloneDeep(this.state.detailData) + + if (this.props.config.defaultValue) { + const detailDefault = ParamHelper(this.props.config.defaultValue, { data, step }) + for (const detailFieldIndex in detailFieldsConfig) { + const detailFieldConfig = detailFieldsConfig[detailFieldIndex] + const value = getValue(detailDefault, detailFieldConfig.field) + this.detailValue = setValue(this.detailValue, detailFieldConfig.field, value) + detailData[detailFieldIndex] = { status: 'normal', name: detailFieldConfig.label } + } + } + + await this.setState({ + ready: true, + detailValue: this.detailValue, + detailData: cloneDeep(detailData) + }) + + // 表单初始化结束,展示表单界面。 + onMount() + } + + handleDetailFieldMount = async (detailFieldIndex: number) => { + if (this.detailFieldsMounted[detailFieldIndex]) { + return true + } + this.detailFieldsMounted[detailFieldIndex] = true + + const detailData = cloneDeep(this.state.detailData) + + if (this.detailFields[detailFieldIndex]) { + const detailField = this.detailFields[detailFieldIndex] + if (detailField) { + const detailFieldConfig = (this.props.config.fields || [])[detailFieldIndex] + + let value = getValue(this.detailValue, detailFieldConfig.field) + if ((detailFieldConfig.defaultValue) && value === undefined) { + value = await detailField.reset() + } + this.detailValue = setValue(this.detailValue, detailFieldConfig.field, value) + + const validation = await detailField.validate(value) + if (validation === true) { + detailData[detailFieldIndex] = { status: 'normal', name: detailFieldConfig.label } + } else { + // 首次进入错误提示; + detailData[detailFieldIndex] = { status: 'error', message: validation[0].message, name: detailFieldConfig.label } + } + } + } + + await this.setState({ + detailValue: this.detailValue, + detailData: cloneDeep(detailData) + }) + } + + + /** + * 处理表单返回事件 + */ + handleCancel = async () => { + const { + onUnmount + } = this.props + + onUnmount() + } + + /** + * 处理详情项change事件 + * @param field 详情项配置 + * @param value 目标值 + */ + handleChange = async (detailFieldIndex: number, value: any) => { + const detailData = cloneDeep(this.state.detailData) + + const detailField = this.detailFields[detailFieldIndex] + const detailFieldConfig = (this.props.config.fields || [])[detailFieldIndex] + if (detailField && detailFieldConfig) { + this.detailValue = setValue(this.detailValue, detailFieldConfig.field, value) + + const validation = await detailField.validate(value) + if (validation === true) { + detailData[detailFieldIndex] = { status: 'normal', name: detailFieldConfig.label } + } else { + detailData[detailFieldIndex] = { status: 'error', message: validation[0].message, name: detailFieldConfig.label } + } + + await this.setState({ + detailValue: this.detailValue, + detailData + }) + if (this.props.onChange) { + this.props.onChange(this.detailValue) + } + } + } + + handleValueSet = async (detailFieldIndex: number, path: string, value: any, validation: true | DetailFieldError[]) => { + const detailFieldConfig = (this.props.config.fields || [])[detailFieldIndex] + if (detailFieldConfig) { + const fullPath = detailFieldConfig.field === '' || path === '' ? `${detailFieldConfig.field}${path}` : `${detailFieldConfig.field}.${path}` + + set(this.detailValue, fullPath, value) + this.setState({ + detailValue: this.detailValue + }) + if (this.props.onChange) { + this.props.onChange(this.detailValue) + } + + if (validation === true) { + this.detailData[detailFieldIndex] = { status: 'normal', name: detailFieldConfig.label, hidden: false } + } else { + this.detailData[detailFieldIndex] = { status: 'error', message: validation[0].message, name: detailFieldConfig.label, hidden: false } + } + await this.setState({ + detailData: this.detailData + }) + } + } + + handleValueUnset = async (detailFieldIndex: number, path: string, validation: true | DetailFieldError[]) => { + const detailFieldConfig = (this.props.config.fields || [])[detailFieldIndex] + if (detailFieldConfig) { + const fullPath = detailFieldConfig.field === '' || path === '' ? `${detailFieldConfig.field}${path}` : `${detailFieldConfig.field}.${path}` + + unset(this.detailValue, fullPath) + this.setState({ + detailValue: this.detailValue + }) + if (this.props.onChange) { + this.props.onChange(this.detailValue) + } + + if (validation === true) { + this.detailData[detailFieldIndex] = { status: 'normal', name: detailFieldConfig.label, hidden: false } + } else { + this.detailData[detailFieldIndex] = { status: 'error', message: validation[0].message, name: detailFieldConfig.label, hidden: false } + } + + await this.setState({ + detailData: this.detailData + }) + } + } + + handleValueListAppend = async (detailFieldIndex: number, path: string, value: any, validation: true | DetailFieldError[]) => { + const detailFieldConfig = (this.props.config.fields || [])[detailFieldIndex] + if (detailFieldConfig) { + const fullPath = detailFieldConfig.field === '' || path === '' ? `${detailFieldConfig.field}${path}` : `${detailFieldConfig.field}.${path}` + + const list = get(this.detailValue, fullPath, []) + list.push(value) + set(this.detailValue, fullPath, list) + this.setState({ + detailValue: this.detailValue + }) + if (this.props.onChange) { + this.props.onChange(this.detailValue) + } + + if (validation === true) { + this.detailData[detailFieldIndex] = { status: 'normal', name: detailFieldConfig.label, hidden: false } + } else { + this.detailData[detailFieldIndex] = { status: 'error', message: validation[0].message, name: detailFieldConfig.label, hidden: false } + } + + await this.setState({ + detailData: this.detailData + }) + } + } + + handleValueListSplice = async (detailFieldIndex: number, path: string, index: number, count: number, validation: true | DetailFieldError[]) => { + const detailFieldConfig = (this.props.config.fields || [])[detailFieldIndex] + if (detailFieldConfig) { + const fullPath = detailFieldConfig.field === '' || path === '' ? `${detailFieldConfig.field}${path}` : `${detailFieldConfig.field}.${path}` + + const list = get(this.detailValue, fullPath, []) + list.splice(index, count) + set(this.detailValue, fullPath, list) + this.setState({ + detailValue: this.detailValue + }) + if (this.props.onChange) { + this.props.onChange(this.detailValue) + } + + if (validation === true) { + this.detailData[detailFieldIndex] = { status: 'normal', name: detailFieldConfig.label, hidden: false } + } else { + this.detailData[detailFieldIndex] = { status: 'error', message: validation[0].message, name: detailFieldConfig.label, hidden: false } + } + + await this.setState({ + detailData: this.detailData + }) + } + } + + /** + * 详情步骤组件 - UI渲染方法 + * 各UI库需重写该方法 + * @param props + */ + renderComponent = (props: IDetail) => { + return + 您当前使用的UI版本没有实现Detail组件。 + + } + + /** + * 详情项组件 - UI渲染方法 + * 各UI库需重写该方法 + * @param props + */ + renderItemComponent = (props: IDetailItem) => { + return + 您当前使用的UI版本没有实现DetailItem组件。 + + } + + render () { + const { + data, + step + // config: { + // layout = 'horizontal', + // fields = [] + // } + } = this.props + + const layout = this.props.config?.layout || 'horizontal' + const fields = this.props.config?.fields || [] + + const { + ready, + detailValue, + detailData + } = this.state + + if (ready) { + return ( + + {/* 渲染表单 */} + {this.renderComponent({ + layout, + onBack: this.props.config.hiddenBack ? undefined : async () => this.handleCancel(), + backText: this.props.config?.backText?.replace(/(^\s*)|(\s*$)/g, ""), + children: fields.map((detailFieldConfig, detailFieldIndex) => { + if (!ConditionHelper(detailFieldConfig.condition, { record: detailValue, data, step })) { + return null + } + let hidden: boolean = true + let display: boolean = true + + // if (detailFieldConfig.type === 'hidden') { + // hidden = true + // display = false + // } + + if (detailFieldConfig.display === 'none') { + hidden = true + display = false + } + + // 隐藏项同时打标录入数据并清空填写项 + if (!hidden) { + this.detailData[detailFieldIndex] = { status: 'normal', name: detailFieldConfig.label, hidden } + } + + const DetailFieldComponent = this.getALLComponents(detailFieldConfig.type) || DetailField + + const renderData = { + key: detailFieldIndex, + label: detailFieldConfig.label, + // status: detailFieldConfig.field !== undefined ? getValue(detailData, detailFieldConfig.field, {}).status || 'normal' : 'normal', + // message: detailFieldConfig.field !== undefined ? getValue(detailData, detailFieldConfig.field, {}).message || '' : '', + layout, + visitable: display, + fieldType: detailFieldConfig.type, + children: ( + | null) => { + if (detailFieldIndex !== null) { + this.detailFields[detailFieldIndex] = detailField + this.handleDetailFieldMount(detailFieldIndex) + } + }} + formLayout={layout} + value={detailFieldConfig.field !== undefined ? getValue(detailValue, detailFieldConfig.field) : undefined} + record={detailValue} + data={cloneDeep(data)} + step={step} + config={detailFieldConfig} + onChange={async (value: any) => { await this.handleChange(detailFieldIndex, value) }} + onValueSet={async (path, value, validation) => await this.handleValueSet(detailFieldIndex, path, value, validation)} + onValueUnset={async (path, validation) => await this.handleValueUnset(detailFieldIndex, path, validation)} + onValueListAppend={async (path, value, validation) => await this.handleValueListAppend(detailFieldIndex, path, value, validation)} + onValueListSplice={async (path, index, count, validation) => await this.handleValueListSplice(detailFieldIndex, path, index, count, validation)} + loadDomain={async (domain: string) => await this.props.loadDomain(domain)} + /> + ) + } + // 渲染详情项容器 + return ( + hidden + ? this.renderItemComponent(renderData) + : + ) + }) + })} + + ) + } else { + return <> + } + } +} diff --git a/src/steps/form/index.tsx b/src/steps/form/index.tsx index 4a658bb4ceb5a100099548b70c293e99147b276d..8eeb22380f3b02df082f4ee49e77f7c60d834b5f 100644 --- a/src/steps/form/index.tsx +++ b/src/steps/form/index.tsx @@ -52,6 +52,7 @@ export interface IForm { /** * 表单项容器组件 - UI渲染方法 - 入参格式 + * - key: react需要的unique key * - label: 表单项名称 * - status: 表单项状态 * - * normal 默认状态 @@ -66,6 +67,7 @@ export interface IForm { * - children: 表单项内容 */ export interface IFormItem { + key: string | number, label: string status: 'normal' | 'error' | 'loading' description?: string @@ -441,6 +443,7 @@ export default class FormStep extends Step { const FormField = this.getALLComponents(formFieldConfig.type) || Field const renderData = { + key: formFieldIndex, label: formFieldConfig.label, status: formData[formFieldIndex]?.status || 'normal', message: formData[formFieldIndex]?.message || '', diff --git a/src/steps/index.tsx b/src/steps/index.tsx index 63fc5eaae8b63310af4a56a3fd94887872733d3e..99e62033a37499d6683ca879545b279b385b9cc5 100644 --- a/src/steps/index.tsx +++ b/src/steps/index.tsx @@ -3,13 +3,15 @@ import FilterStep, { FilterConfig } from './filter' import FormStep, { FormConfig } from './form' import SkipStep, { SkipConfig } from './skip' import TableStep, { TableConfig } from './table' +import DetailStep, { DetailConfig } from './detail' -export type StepConfigs = FetchConfig | FormConfig | SkipConfig | TableConfig | FilterConfig +export type StepConfigs = FetchConfig | FormConfig | SkipConfig | TableConfig | FilterConfig | DetailConfig export default { fetch: FetchStep, form: FormStep, skip: SkipStep, table: TableStep, - filter: FilterStep + filter: FilterStep, + detail: DetailStep }