Source: widget/JsonForm.js

/**
 * 根据JsonSchema 绘制json 表单
 * 对于不要显示但需要保存但数据(如:主键)的数据建议使用隐藏控件,有利于数据专递。
 *
 * redmicro all Copyright (c)
 * Created by seeker910 on 2023/3/18.
 */
Rsd.define('Rsd.widget.JsonForm', {
    extend: 'Rsd.container.Form',
    requires: [
        'Rsd.form.Text',
        'Rsd.form.TextArea',
        'Rsd.form.TextFK',
        'Rsd.form.Date',
        'Rsd.form.Time',
        'Rsd.form.Timestamp',
        'Rsd.form.Number',
        'Rsd.form.Hidden',
        'Rsd.form.Json',
        'Rsd.form.CheckBox',
        'Rsd.form.ComboBox',
        'Rsd.form.ComboBoxEx',
        'Rsd.form.ComboBoxEnum',
        'Rsd.form.Picker',
        'Rsd.form.Image',
        'Rsd.form.Images',
        'Rsd.control.Grid',
        'Rsd.control.GridToolBar'
    ],
    xtype: 'json-form',
    layout: 'fit',
    height: 'auto',
    //fields 已加载
    //isLoaded:false,
    readOnly: true,
    errorList: [],
    /*
    * 对于不要显示但需要保存但数据(如:主键)的数据建议使用隐藏控件,有利于数据专递。
    * */
    schema: null,
    /**
     * 
     */
    fieldWidth: '45%',
    //最后一次加载的数据对象
    //data:{}, 
    items: [],
    /**
     * 
     */
    bgColors:['rgba(172, 207, 238, 0.35)','rgb(240, 248, 255)','rgb(250, 235, 215)'],
    /*
     * */
    constructor: function JsonForm(config) {
        config = config || {};
        this.apply(config);
    },
    /*
    * */
    onAfterRender: function onAfterRender() {

        var me = this;

        setTimeout(function () {

            me.loadFields(me.schema);//render 之后会执行doLayout

            //出现滚动条 重新设置 该控件高度,不让该控件出现滚动条,让滚动条出现在该控件父控件中
            if (me.body.scrollHeight > me.body.clientHeight) {
                var _scrollHeight = me.body.scrollHeight + 45;

                me.height = _scrollHeight;
            }

        }, 50);

        me.callParent();
    },
    /** 
    {
        a: {
            $id: a,
            title: ,
            description: ,
            required: true,
            type: string,
            minLength: 0,
            maxLength: 0,
            pattern: ,
            format: ,
            $ref: ,
            dependencies: null,
            minProperties: 0,
            maxProperties: 0,
            additionalProperties: false,
            enum: null,
            default: null,
            examples: [123],
            allOf: [],
            anyOf: [],
            oneOf: [],
            not: []
        }
    }
    * */
    loadFields: function loadFields(schema,callback) {

        //debugger;
        var me = this; 
        //console.log(schema);
        var _readOnly = me.readOnly;
        var _schema = schema || {};
        var _fields = _schema.properties;
        if (Rsd.isEmpty(_fields)) {
            return;
        }

        var _w = 0;
        var _width = me.getWidth() || me.parent.getWidth();
        var _index = 0;
        var _last_type = "";
        this.setElStyle('dom',{ backgroundColor:me.bgColors[_index%me.bgColors.length]});
 
        for (var p in _fields) {
            //debugger;
            var f = _fields[p];
            //console.log(p,f); 
            _index++;
            try {

                switch (f.type) {
                    case 'array': {
                        var _cols = f.items.map(function(item){
                            return {name:item.$id,dataIndex:item.$id,text:item.title || item.$id,xtype:item.type};
                        });
                        _cols.push({
                            text:'操 作',
                            align:'center',
                            schema:f,
                            width:70,
                            format:function(row,parent){
                              
                                var _f = this.schema;
                                return [
                                    Rsd.button('修 改',function(evt){
                                         
                                        Rsd.create('Rsd.tool.PageEditor',{
                                            width:_f.itemWidth||'60%',
                                            height:_f.itemHeight||'50%',
                                            title:(_f.itemTitle||'子项信息')+'编辑',
                                            dsName:_f.$id,
                                            dsSchema:{
                                                title:_f.itemTitle||'子项信息',
                                                properties:_f.items
                                            },
                                            data:row
                                        }).showDialog(); 
                                       
                                    }),
                                    Rsd.blankspace(2),
                                    Rsd.button('删 除',function(evt){
                                        console.log('del',row);
                                    })
                                ];
                            }
                        });
                        //console.log('this are cols:',_cols);
                        //console.log('rows',f.examples);
                       
                        var _grid = {
                            xtype: 'grid',
                            id: f.id || f.name,
                            dataIndex: f.dataIndex || f.dataindex || f.name || f.$id, 
                            height: f.height || 100 + f.examples.length *41,
                            name: f.$id,
                            style:{
                                backgroundColor:me.bgColors[_index%me.bgColors.length],
                            },
                            label: {
                                position:'top',
                                align:'left',
                                content: '  ' + (f.title || f.$id),
                                space:0,
                                style: {   
                                    fontSize:'150%', 
                                    lineHeight: f.height || 40 
                                }
                            },
                            margin:'0 0 0 2%',
                            width: '96%',
                            columns: _cols,
                            readOnly: true,
                            border: true,
                            tabIndex: _index,
                            dataSource: f.examples
                        };
                        me.add({xtype:'component-x',height:10});
                        me.add(_grid);
                        break;
                    }
                    case 'object':
                        {
                            //console.log('is object', f);
                            var form = {
                                xtype: 'json-form',
                                id: f.id || f.name,
                                dataIndex: f.dataIndex || f.dataindex || f.name || f.$id,
                                height: f.height || 60 + (f.properties.length/2+ f.properties.length%2) * 45,
                                width: '96%',
                                style:{
                                    backgroundColor:me.bgColors[_index%me.bgColors.length],
                                },
                                margin:'0 0 0 2%',
                                readOnly:me.readOnly,
                                schema:f,
                                header: {
                                    position:'top',
                                    align:'left',
                                    content: '  ' + (f.title || f.$id), 
                                    space:0,
                                    style: {  
                                            fontSize:'150%', 
                                            lineHeight: f.height || 40 
                                        }
                                },
                            }
                            me.add({xtype:'component-x',height:10});
                            me.add(form);
                            break;
                    }
                    case 'string':
                    default: {
                        
                            if(_last_type == "array" || _last_type == "object")
                            {
                                me.add({xtype:'component-x',height:10});
                            }
                            //console.log(f.examples);
                            var _value = f.examples.length > 0?f.examples[0]:'';
                            var _field = {
                                xtype: f.type == 'string'? 'text':f.type,
                                id: f.id || f.name,
                                dataIndex: f.dataIndex || f.dataindex || f.name || f.$id,
                                tabIndex: _index,
                                placeholder:_value,
                                //margin: '4 0 4 0',
                                width: f.width || me.fieldWidth,
                                height: f.height || 40,
                                name: f.$id,
                                title: f.description,
                                required: f.required,
                                minLength: f.minLength,
                                maxLength: f.maxLength,
                                pattern: f.pattern,
                                format: f.format,
                                enum: f.enum,
                                //value:_value,
                                default: f.default,
                                label: {
                                    content: f.title || f.$id,
                                    width:90,
                                    style: { lineHeight: f.height || 40 }
                                },

                            };
                            //console.log(_field);
                            if (f.labelStyle) {
                                _field.label.style = Rsd.apply(_field.label.style, f.labelStyle);
                                delete _field.label.text;
                            }
                            if (f.hasOwnProperty('readOnly')) {
                                _field.readOnly = (_readOnly ? true : f.readOnly);
                            }
                            else {
                                _field.readOnly = _readOnly;
                            }
                            var _h = 0;
                            if (_field.xtype != 'hidden') {
                                _h = _field.height || 40;
                            }
                            _w += _field.width || 0;
                            if (_field.width && _width && _w < _width) {
                            }
                            else {
                                _w = _field.width || 0;
                            }
                            me.add(_field);
                            break;
                    }
                }

            }
            catch (ex) {
                console.error('JsonFrom loadFields occured exception',ex);
            }

            _last_type = f.type;
        }
        //
        me.add({xtype:'component-x',height:10});
        //
        if(callback)
        {
            this.funApplyByIOC(callback,[]);
        }
      
        return this;
    }, 
     /**
     *@description 
     * */
    loadData: function loadData(data) {

        var _data = data || this.data || {};
        this.data = _data;

        var me = this;
       
        var id = setInterval (function(){

            if(!me.isLayout)
            {
                return;
            }
            clearInterval(id);

            //console.log(me.dataIndex,me.items.length);
            var _item = null;
            var _dataIndex = null;
            var _value = null;
    
            for (var i = 0; i < me.items.length; i++) {

                _item = me.items[i];
                if(_item.$className === 'Rsd.common.ComponentX')
                {
                    continue;
                }
                _dataIndex = _item.dataIndex || _item.dataindex || '';
    
               if(_dataIndex==undefined 
                ||_dataIndex == null 
                || _dataIndex=='')
               {
                    continue;
               }
                //获取值
                try {
                  
                    if (_data[_dataIndex] !== undefined) 
                    {
                        _value = _data[_dataIndex];
                    }
                    else
                    {
                        var list = _dataIndex.split('.');
                        var j = 0;
                        var _p = _data;
                        while (list.length > 1 && j < list.length && Rsd.hasProperty(_p, list[j])) {
                            _p = _p[list[j]];
                            j++;
                        }
                        if (j == list.length) {
                            _value = _p;
                        }
                    }
                }
                catch (e) {
                    console.error('JsonForm LoadData Occured Exception',e);
                }
     
                //设置值
                if(Rsd.isFunction(_item.setValue))
                {
                    _item.setValue(_value);
                }  
                 
                //加载值
                if(Rsd.isFunction(_item.loadData))
                {
                    _item.loadData(_value);
                }
            }
            me.isLoaded = true;

            },100);

        return this;
    },

    /**
     * @description 验证控件输入值 是否有效
     *  */
    checkRecord: function checkRecord() {

        var _item = null;
        var _form = this;
        this.errorList = [];
        for (var i = 0; i < _form.items.length; i++) {
            _item = _form.items[i];

            if (!Rsd.isFunction(_item.checkValue)) {
                if(_item.xtype !=='component-x'  || _item.xtype !=='container' )
                {
                    continue;
                }
                console.warn();('Control [' + _item.$className + '('+_item.xtype+')] has no function \'checkValue\'.');
                continue;
            }

            try {
                if (!_item.checkValue()) {
                    this.errorList.push(_item.getError());
                }
            }
            catch (err) {
                console.error(err);
            }

        }

        return this.errorList.length == 0;
    },
    /**
    * @description 错误消息处理
    * @description handler:方法注入
    * */
    showError: function showError(handler) {

        if (this.errorList.length > 0) {
            if (handler) {
                handler.call(this, [this.errorList]);
            }
            else {
                Rsd.alert('错误提示', this.errorList);
            }
        }

    },
    /** 
    * @description 将控件获取到到数据合并到 参数obj 或data 中返回;
    * @description 在获取前,应先验证form的数据是否全部有效,
    *
    * */
    getRecord: function getRecord(obj) {

        var _obj = obj || this.data || {};
        var me = this;
        var _item = null;
        var _form = me;

        for (var i = 0; i < _form.items.length; i++) {
            _item = _form.items[i];

            if (_item.readOnly) {
                //continue;
            }
            var _dataIndex = _item.dataIndex || _item.dataindex || _item.name;
            if (Rsd.isEmpty(_dataIndex)) {
                continue;
            }
            _obj[_dataIndex] = _item.getValue();
        }

        return _obj;

    },
    /**
    *
    * @description 获取字段值
    * */
    getFieldValue: function getFieldValue(name) {
        var _obj = this.data || {};
        var me = this;
        var _item = null;
        var _form = me;

        for (var i = 0; i < _form.items.length; i++) {
            _item = _form.items[i];
            if (_item.readOnly) {
                continue;
            }
            _obj[_item.dataIndex || _item.dataindex] = _item.getValue();
        }

        return _obj[name];
    },

   
    /*
    *@param key:index or name or id  or xtype
    * */
    getFieldControl: function getFieldControl(key) {
        if (Rsd.isNumber(key)) {
            return this.items[key];
        }
        return this.getItemByName(key) || this.getItemById(key) || this.getItemByXtype(key);
    },
    /**
     * 
     */
    getScrollHeight: function getScrollHeight() {
        return this.body.scrollHeight;
    }


}, function (type) {

    var _dataGetter = function () {

        if (!this.hasOwnProperty('__data')) {
            this.__data = {};
        }
        return this.__data;
    };
    var _dataSetter = function (value) {

        this.__data = value;
        return;

    };
    this.defineProperty(type, "data", _dataGetter, _dataSetter, true);

    //
    this.defineProperty(type, "isLoaded", function () {

        if (!this.hasOwnProperty('__isLoaded')) {
            this.__isLoaded = false;
        }
        return this.__isLoaded;

    }, function (value) {
        this.__isLoaded = value;
    } , false);

});