import * as React from 'react'; import * as _ from 'lodash'; import { observer } from "mobx-react"; import { VBand } from './vBand'; import { BandsBuilder } from './bandsBuilder'; import { Field, ArrFields } from '../../entities'; import { computed, observable, IObservableObject, IObservableValue } from 'mobx'; import { VArr } from './vArr'; import { FormUI, FormUIBase, FormItems } from '../formUI'; import { VField } from './vField'; import { VSubmit } from './vSubmit'; import { IObservableArray } from 'mobx'; import { FA } from 'tonva-react-form'; export type FieldCall = (form:VForm, field:Field, values:any) => Promise; export interface FieldInput { select: FieldCall; content: React.StatelessComponent; placeHolder: string; } export interface FieldInputs { [fieldOrArr:string]: FieldInput | {[field:string]: FieldInput}; } export enum FormMode {new, edit, readonly} export interface FormOptions { fields: Field[]; arrs?: ArrFields[]; ui: FormUIBase; res: any; inputs: FieldInputs; submitCaption: string; arrNewCaption: string; arrEditCaption: string; arrTitleNewButton: JSX.Element; none: string; mode: FormMode; } export class VForm { protected fields: Field[]; protected arrs: ArrFields[]; protected bands: VBand[]; protected bandColl: {[key:string]: VBand}; protected onSubmit: ()=>Promise; constructor(options: FormOptions, onSubmit: ()=>Promise) { let {fields, arrs, ui, res, inputs, none, submitCaption, arrNewCaption, arrEditCaption, arrTitleNewButton, mode} = options; this.fields = fields; this.arrs = arrs; this.ui = ui; if (this.ui !== undefined) this.formItems = this.ui.items; //.compute = this.ui.compute; this.res = res; this.inputs = inputs; this.none = none; this.submitCaption = submitCaption; this.arrNewCaption = arrNewCaption; this.arrEditCaption = arrEditCaption; this.arrTitleNewButton = arrTitleNewButton || 新增; if (onSubmit === undefined) this.mode = FormMode.readonly; else this.mode = mode; this.buildFormValues(); this.buildBands(options, onSubmit); this.onSubmit = onSubmit; } ui: FormUI; res: any; values: any; errors: any; formItems: FormItems; mode: FormMode; vFields: {[name:string]:VField} = {}; vArrs: {[name:string]: VArr} = {}; vSubmit: VSubmit; inputs: FieldInputs; none: string; submitCaption: string; arrNewCaption: string; arrEditCaption: string; arrTitleNewButton: JSX.Element; private buildBands(options: FormOptions, onSubmit: (values:any)=>Promise) { this.bandColl = {}; let bandsBuilder = new BandsBuilder(this, options, onSubmit); this.bands = bandsBuilder.build(); for (let band of this.bands) { this.bandColl[band.key] = band; let vFields = band.getVFields(); if (vFields !== undefined) for (let f of vFields) this.vFields[f.name] = f; let vArr = band.getVArr(); if (vArr !== undefined) this.vArrs[vArr.name] = vArr; let vSubmit = band.getVSubmit(); if (vSubmit !== undefined) this.vSubmit = vSubmit; } } private onFormSubmit = (event:React.FormEvent) => { event.preventDefault(); return false; } protected view = observer(({className}:{className:string}) => { return
{this.bands.map(v => v.render())}
; }); getBand(name:string) { return this.bandColl[name]; } computeFields() { if (this.formItems === undefined) return; let values = this.values; for (let i in this.formItems) { let item = this.formItems[i]; if (typeof item !== 'function') continue; values[i] = item.call(this, values); } } async submit() { if (this.onSubmit === undefined) return; await this.onSubmit(); } getValues() { let ret:any = {}; let values = this.values; for (let f of this.fields) { let {name} = f; let v = values[name] ret[name] = v !== null && typeof v === 'object' ? v.id : v; } if (this.arrs !== undefined) { for (let arr of this.arrs) { let {name, fields, id, order} = arr; let list = ret[name] = []; let rows = this.vArrs[name].list; for (let row of rows) { let item = {} as any; if (id !== undefined) item[id] = row[id]; if (order !== undefined) item[order] = row[order]; for (let f of fields) { let {name:fn} = f; let v = row[fn] item[fn] = v !== null && typeof v === 'object' ? v.id : v; } list.push(item); } } } return ret; } get valueBoxs() { let ret:any = {}; let values = this.values; for (let f of this.fields) { let {name, _tuid} = f; let v = values[name] ret[name] = _tuid === undefined || typeof v === 'object' ? v : _tuid.boxId(v); } if (this.arrs === undefined) return ret; for (let arr of this.arrs) { let {name, fields, id, order} = arr; let list = ret[name] = this.vArrs[name].list.slice(); for (let row of list) { for (let f of fields) { let {name:fn, _tuid} = f; let v = row[fn] row[fn] = _tuid === undefined || typeof v === 'object' ? v : _tuid.boxId(v); } } } return ret; } setValues(initValues:any) { if (initValues === undefined) { this.reset(); return; } let values = this.values; let errors = this.errors; for (let f of this.fields) { let fn = f.name; errors[fn] = undefined; let v = initValues[fn]; values[fn] = v; } // 还要设置arrs的values for (let i in this.vArrs) { let list = initValues[i]; if (list === undefined) continue; let arrList = values[i] as IObservableArray; arrList.clear(); arrList.push(...list); } } @computed get isOk():boolean { for (let i in this.vFields) { if (this.vFields[i].isOk === false) return false; } return true; } reset() { let values = this.values; let errors = this.errors; for (let f of this.fields) { let fn = f.name; //if (this.compute !== undefined && this.compute[fn] !== undefined) continue; values[fn] = null; errors[fn] = undefined; } for (let i in this.vFields) { let ctrl = this.vFields[i]; let cn = ctrl.name; if (cn === undefined) continue; //if (this.compute !== undefined && this.compute[cn] !== undefined) continue; ctrl.setValue(null); } for (let i in this.vArrs) { let vArr = this.vArrs[i]; vArr.reset(); } } getValue(fieldName: string) { return this.values[fieldName]; } setValue(fieldName: string, value: any) { this.values[fieldName] = value } setError(fieldName:string, error:string) {this.errors[fieldName] = error} private buildFieldValues(fields: Field[]):any { let v: {[p:string]: any} = { valueFromFieldName: function(propName:string) { return this[propName]; } }; for (let f of fields) { let fn = f.name; v[fn] = null; } return v; } private buildObservableValues():IObservableObject { let v: {[p:string]: any} = this.buildFieldValues(this.fields); if (this.arrs !== undefined) { for (let arr of this.arrs) { v[arr.name] = observable.array([], {deep:true}); } } let ret = observable(v); return ret; } private buildFormValues() { this.values = this.buildObservableValues(); this.errors = observable(this.buildFieldValues(this.fields)); } render(className:string = "py-3"):JSX.Element { return } }