<template>
    <div>
        <slot name="top"
            :form="this" />
        <Form ref="form"
            :model="data"
            label-position="top"
            label-colon="："
            class="ivu-mt"
            :rules="rules"
            @submit.native.prevent>
            <Tabs v-tab-hide="tabs.length == 1">
                <TabPane v-for="(tab, tabIndex) in tabs"
                    :key="tabIndex"
                    :label="tab"
                    :name="tab">
                    <Row :gutter="24"
                        type="flex">
                        <template v-for="(column, index) in tabColumns(tabIndex)">
                            <Col :key="index"
                                v-if="column.isShow"
                                v-bind="getGrid(column)">
                            <div :key="column.code"
                                style="height: 82px;"
                                v-if="column.controlType === 'Placeholder'">
                            </div>
                            <FormItem :label="column.name"
                                :prop="column.code"
                                :key="column.code"
                                v-if="column.controlType !== 'Placeholder'">
                                <template v-if="column.controlType === 'Custom'">
                                    <slot name="column"
                                        :form="this"
                                        :code="column.code"></slot>
                                </template>
                                <template v-else-if="column.controlType === 'Label'">
                                    <div class="label"
                                        :title="compareData == null ? showData(data,column.code, column.dataType, column.displayFormat) : showData(compareData,column.code, column.dataType, column.displayFormat)">
                                        <div :class="{ 'error': compareData != null && parseData(data, column.code) != parseData(compareData, column.code) }"
                                            v-html="showData(data,column.code, column.dataType, column.displayFormat)"></div>
                                    </div>
                                </template>
                                <template v-else-if="column.controlType === 'TextInput'">
                                    <Input type="text"
                                        :value="parseData(data, column.code)"
                                        @input="$event => setData(data, column.code, $event)"
                                        :readonly="readonly || column.isReadonly"
                                        :style="{ width: column.controlWidth == null ? null : column.controlWidth + 'px' }"
                                        :maxlength="column.maxLength"
                                        :placeholder="column.description"
                                        @on-change="onDataChange(column)" />
                                </template>
                                <template v-else-if="column.controlType === 'NumberInput'">
                                    <Input type="number"
                                        number
                                        :value="parseData(data, column.code)"
                                        @input="$event => setData(data, column.code, $event)"
                                        :readonly="readonly || column.isReadonly"
                                        :style="{ width: column.controlWidth == null ? '100px' : column.controlWidth + 'px' }"
                                        :placeholder="column.description"
                                        @on-change="onDataChange(column)" />
                                </template>
                                <template v-else-if="column.controlType === 'Select'">
                                    <Select :value="parseData(data, column.code)"
                                        @input="$event => setData(data, column.code, $event)"
                                        :disabled="readonly || column.isReadonly"
                                        clearable
                                        :style="{ width: column.controlWidth == null ? null : column.controlWidth + 'px' }"
                                        :placeholder="column.description"
                                        :transfer="true"
                                        @on-change="onDataChange(column)">
                                        <Option v-for="item in getDataSource(data, column)"
                                            :key="item.id"
                                            :value="item.id">{{ item.name }}
                                        </Option>
                                    </Select>
                                </template>
                                <template v-else-if="column.controlType === 'AutoComplete'">
                                    <AutoComplete :value="parseData(data, column.code) ? parseData(data, column.code) : ''"
                                        @input="$event => setData(data, column.code, $event)"
                                        :disabled="readonly || column.isReadonly"
                                        clearable
                                        @on-search="search => loadOption(data, column, search)"
                                        @on-clear="() => loadOption(data, column)"
                                        :style="{ width: column.controlWidth == null ? null : column.controlWidth + 'px' }"
                                        :placeholder="column.description"
                                        :transfer="true"
                                        @on-change="selected => onDataChange(column, selected)">
                                        <Option v-for="item in getDataSource(data, column)"
                                            :key="item.id"
                                            :value="item.name">{{ item.name }}</Option>
                                    </AutoComplete>
                                </template>
                                <template v-else-if="column.controlType === 'ComboSelect'">
                                    <Select :value="parseData(data, column.code)"
                                        @input="$event => setData(data, column.code, $event)"
                                        :disabled="readonly || column.isReadonly"
                                        clearable
                                        filterable
                                        remote
                                        :remote-method="search => loadOption(data, column, search)"
                                        :style="{ width: column.controlWidth == null ? null : column.controlWidth + 'px' }"
                                        :placeholder="column.description"
                                        :transfer="true">
                                        <Option v-for="item in getDataSource(data, column)"
                                            :key="item.id"
                                            :value="item.id">{{ item.name }}</Option>
                                    </Select>
                                </template>
                                <template v-else-if="column.controlType === 'DialogSelect'">
                                    <dialog-select :value="parseData(data, column.code)"
                                        @input="$event => setData(data, column.code, $event)"
                                        :source="column.source"
                                        :source-data-code="column.sourceDataCode"
                                        :source-display-code="column.sourceDisplayCode"
                                        :param="getParam(data, column)"
                                        :readonly="readonly"
                                        :controlWidth="column.controlWidth"
                                        @on-change="selected => onDataChange(column, selected)"></dialog-select>
                                </template>
                                <template v-else-if="
                                            column.controlType === 'Date' ||
                                            column.controlType === 'DateTime' ||
                                            column.controlType === 'Year' ||
                                            column.controlType === 'Month' ||
                                            column.controlType === 'DateRange'
                                        ">
                                    <DatePicker :type="column.controlType.toLowerCase()"
                                        :value="parseData(data, column.code)"
                                        @input="$event => setData(data, column.code, $event)"
                                        :readonly="readonly || column.isReadonly"
                                        :placeholder="column.description"
                                        :transfer="true"
                                        :style="{ width: column.controlWidth == null ? null : column.controlWidth + 'px' }"
                                        @on-change="onDataChange(column)"></DatePicker>
                                </template>
                                <template v-else-if="column.controlType === 'Time'">
                                    <TimePicker type="time"
                                        :value="parseData(data, column.code)"
                                        @input="$event => setData(data, column.code, $event)"
                                        :readonly="readonly || column.isReadonly"
                                        :placeholder="column.description"
                                        :transfer="true"
                                        :style="{ width: column.controlWidth == null ? null : column.controlWidth + 'px' }"
                                        @on-change="onDataChange(column)"></TimePicker>
                                </template>
                                <template v-else-if="column.controlType === 'Check'">
                                    <Checkbox :value="!!parseData(data, column.code)"
                                        @input="$event => setData(data, column.code, $event)"
                                        :disabled="readonly || column.isReadonly"
                                        size="large"
                                        @on-change="onDataChange(column)" />
                                </template>
                                <template v-else-if="column.controlType === 'Switch'">
                                    <Switch :value="!!parseData(data, column.code)"
                                        @input="$event => setData(data, column.code, $event)"
                                        :disabled="readonly || column.isReadonly"
                                        @on-change="onDataChange(column)" />
                                </template>
                                <template v-else-if="column.controlType === 'Radio'">
                                    <RadioGroup :value="parseData(data, column.code)"
                                        @input="$event => setData(data, column.code, $event)"
                                        @on-change="onDataChange(column)">
                                        <Radio v-for="item in getDataSource(data, column)"
                                            :key="item.id"
                                            :label="item.id"
                                            :disabled="readonly || column.isReadonly">
                                            <span>{{ item.name }}</span>
                                        </Radio>
                                    </RadioGroup>
                                </template>
                                <template v-else-if="column.controlType === 'CheckGroup'">
                                    <CheckboxGroup :value="parseData(data, column.code)"
                                        @input="$event => setData(data, column.code, $event)"
                                        @on-change="onDataChange(column)">
                                        <Checkbox v-for="item in getDataSource(data, column)"
                                            :key="item.id"
                                            :label="item.id"
                                            :disabled="readonly || column.isReadonly">
                                            <span>{{ item.name }}</span>
                                        </Checkbox>
                                    </CheckboxGroup>
                                </template>
                                <template v-else-if="column.controlType === 'TextArea'">
                                    <Input type="textarea"
                                        :value="parseData(data, column.code)"
                                        @input="$event => setData(data, column.code, $event)"
                                        :readonly="readonly || column.isReadonly"
                                        :style="{ width: column.controlWidth == null ? null : column.controlWidth + 'px' }"
                                        :rows="column.controlHeight / 20"
                                        :maxlength="column.maxLength"
                                        :placeholder="column.description" />
                                </template>
                                <template v-else-if="column.controlType === 'RichEditor'">
                                    <rich-editor :value="parseData(data, column.code)"
                                        @input="$event => setData(data, column.code, $event)"
                                        :readonly="readonly || column.isReadonly"
                                        :height="column.controlHeight"
                                        :width="column.controlWidth" />
                                </template>
                                <template v-else-if="column.controlType === 'Attachment'">
                                    <upload-attachment :value="parseData(data, column.code)"
                                        @input="$event => setData(data, column.code, $event)"
                                        :readonly="readonly || column.isReadonly"
                                        :maxCount="column.maxLength" />
                                </template>
                                <template v-else-if="column.controlType === 'Image'">
                                    <upload-image :value="parseData(data, column.code)"
                                        @input="$event => setData(data, column.code, $event)"
                                        :readonly="readonly || column.isReadonly"
                                        :maxCount="column.maxLength"
                                        :height="column.controlHeight"
                                        :width="column.controlWidth" />
                                </template>
                                <template v-else-if="column.controlType === 'Slider'">
                                    <Slider v-if="!readonly"
                                        :value="parseData(data, column.code)"
                                        @input="$event => setData(data, column.code, $event)"
                                        show-input
                                        :style="{ width: column.controlWidth == null ? null : column.controlWidth + 'px' }"
                                        :max="column.maxValue"
                                        :min="column.minValue" />
                                    <Input v-if="readonly || column.isReadonly"
                                        type="number"
                                        number
                                        readonly
                                        :value="parseData(data, column.code)"
                                        :style="{ width: column.controlWidth == null ? '100px' : column.controlWidth + 'px' }"
                                        :placeholder="column.description" />
                                </template>
                            </FormItem>
                            </Col>
                        </template>
                    </Row>
                </TabPane>
            </Tabs>
        </Form>
        <slot name="bottom"
            :form="this" />
        <!-- <FooterToolbar>
            <Button type="primary" size="large">提交</Button>
        </FooterToolbar>-->
    </div>
</template>
<script>
    import mixinPage from '../../mixins/page';
    import mixin from './mixin';
    import { mapActions } from 'vuex';
    import modelApi from '../../api/model';
    import customModelApi from '../../api/customModel';
    import dialogSelect from '../select/dialogSelect';
    import richEditor from '../richEditor';
    import uploadAttachment from '../upload/attachment';
    import uploadImage from '../upload/image';

    export default {
        mixins: [mixin, mixinPage],
        components: { dialogSelect, richEditor, uploadAttachment, uploadImage },
        data() {
            return {
                formView: {},
                tabs: [],
                columns: [],
                rules: {},
                data: null,
                compareData: null,
                dataBefore: null
            };
        },
        async created() {
            // 默认视图代码
            if (this.viewCode) {
                // 初始化
                await this.init(this.viewCode);
            }
        },
        props: {
            // 视图代码
            viewCode: {
                type: String
            },
            // 只读
            readonly: {
                type: Boolean,
                default: false
            },
            // 预设默认值
            defaultData: {
                type: Object,
                default() {
                    return {};
                }
            },
            // 显示工具栏
            commandEnable: {
                type: Boolean,
                default: true
            },
            // 是否允许配置界面
            settingEnable: {
                type: Boolean,
                default: true
            }
        },
        computed: {},
        methods: {
            ...mapActions('admin/dataView', { loadDataView: 'load' }),
            // 根据选项卡序号返回列
            tabColumns(index) {
                return this.columns.filter(item => {
                    return item.tabIndex === index || item.tabIndex == null;
                });
            },
            // 初始化
            async init(viewCode, callback) {
                // 加载表格视图
                let view = await this.loadDataView(viewCode);
                this.loadView(view);

                if (typeof callback === 'function') {
                    callback();
                }
            },
            loadView(view) {
                // 加载表格视图
                this.formView = view.dataView;
                this.formView.columns = view.viewColumns;
                this.$emit('on-ready', this.formView);
                this.columns = view.viewColumns;

                // 设置初始值
                this.data = this.getDefaultData();

                // 初始化校验规则
                this.initRule();

                setTimeout(() => {
                    // 初始化板块
                    this.initTab();

                    // 初始化触发规则
                    this.initTrigger();

                    this.onDataChange();
                });
            },
            // 初始化校验规则
            initRule() {
                this.columns.forEach(column => {
                    let rules = [];

                    if (column.isRequired) {
                        rules.push({
                            type: this.getDataType(column),
                            required: true,
                            message: '请输入' + column.name,
                            trigger: this.getTrigger(column)
                        });
                    }

                    if (column.pattern) {
                        rules.push({
                            type: this.getDataType(column),
                            pattern: column.pattern,
                            message: column.name + '不符合要求',
                            trigger: this.getTrigger(column)
                        });
                    }

                    if (column.maxValue != null) {
                        rules.push({
                            type: this.getDataType(column),
                            max: column.maxValue,
                            message: column.name + '不能大于' + column.maxValue,
                            trigger: this.getTrigger(column)
                        });
                    }

                    if (column.minValue != null) {
                        rules.push({
                            type: this.getDataType(column),
                            min: column.minValue,
                            message: column.name + '不能小于' + column.minValue,
                            trigger: this.getTrigger(column)
                        });
                    }

                    if (column.maxLength != null) {
                        rules.push({
                            type: this.getDataType(column),
                            length: column.maxLength,
                            message: column.name + '不能超过' + column.maxLength + '个字符',
                            trigger: this.getTrigger(column)
                        });
                    }

                    // this.setData(this.rules, column.code, rules);
                    if (rules.length > 0) {
                        this.rules[column.code] = rules;
                    }
                });
            },
            // 初始化板块
            initTab() {
                if (this.formView.tab != null && this.formView.tab.trim() !== '') {
                    this.tabs = this.formView.tab.split(',');
                } else {
                    this.tabs = [this.formView.name];
                }
            },
            // 初始化触发规则
            initTrigger() {
                // 触发规则
                this.columns.forEach(column => {
                    column.triggers = [];
                });

                this.columns
                    .filter(column => {
                        return column.source != null && column.source.trim() !== '' && column.param != null && column.param.trim() !== '';
                    })
                    .forEach(column => {
                        let param = JSON.parse(column.param);
                        for (let key in param) {
                            this.columns
                                .filter(item => {
                                    return param[key] === item.code;
                                })
                                .forEach(item => {
                                    item.triggers.push(column);
                                });
                        }
                    });
            },
            // 填充数据源
            async fillDataSource(data, column, param) {
                // 参数完整，查询数据
                let res;
                if (column.isSourceCustom) {
                    res = await customModelApi.query(column.source, param);
                } else {
                    res = await modelApi.query(column.source, param);
                }

                column.rawData = res.data;
                column.dataSource = res.data.map(item => {
                    return {
                        id: column.sourceDataCode == null || column.sourceDataCode.trim() === '' ? item.id : this.parseData(item, column.sourceDataCode),
                        name: this.parseData(item, column.sourceDisplayCode)
                    };
                });

                // 默认第一项
                if (data) {
                    if (this.parseData(data, column.code) == null && column.isDefaultFirst && res.length > 0) {
                        this.setData(data, column.code, this.parseData(res[0], column.sourceDataCode));
                    }
                }

                this.$forceUpdate();

                // 更新data触发刷新
                // this.data = { ...this.data };

                // 触发
                this.onDataChange(column);
            },
            // 获取数据源
            getDataSource(data, column) {
                if (column.dataType.indexOf('Enum:') === 0) {
                    // 枚举
                    return this.getEnumList(column.dataType.split(':')[1]);
                } else {
                    return column.dataSource;
                }
            },
            // 可筛选下拉框加载数据
            loadOption(data, column, keyword) {
                let param = this.getParam(data, column);

                if (param != null) {
                    if ((keyword == null || keyword.trim() === '') && this.parseData(data, column.code) != null && column.controlType !== 'AutoComplete') {
                        param[column.sourceDataCode] = this.parseData(data, column.code);
                    } else {
                        param.keyword = keyword;
                    }
                    param.per = 20;

                    this.fillDataSource(data, column, param);
                } else {
                    // 参数不完整，清空数据
                    column.dataSource = [];
                    this.setData(data, column.code, null);
                    // column.displayValue = null;

                    // 触发
                    column.triggers.forEach(item => {
                        item.needRefresh = true;
                    });
                }
            },
            // 数据变化事件
            onDataChange(sender, selected) {
                if (sender != null) {
                    let oldValue = this.parseData(this.dataBefore, sender.code);
                    let newValue = this.parseData(this.data, sender.code);
                    if (oldValue !== newValue) {
                        setTimeout(() => {
                            this.$emit('on-change', sender, oldValue, newValue, selected);
                        });
                    }
                } else {
                    this.$emit('on-change', sender, null, null, selected);
                }

                this.dataBefore = this.copy(this.data);

                // 计算需要刷新的字段
                if (sender == null || sender.triggers !== []) {
                    this.columns.forEach(function (column) {
                        if (
                            column.source != null &&
                            column.source.trim() !== '' &&
                            (sender == null ||
                                sender.triggers.some(item => {
                                    return item.id === column.id;
                                }))
                        ) {
                            column.needRefresh = true;
                        }
                    });
                }

                // 刷新数据源
                while (true) {
                    let column = this.columns.filter(item => {
                        return item.needRefresh === true;
                    })[0];

                    if (column == null) {
                        // 没有需要刷新的字段
                        break;
                    }

                    let param = this.getParam(this.data, column);

                    if (column.controlType === 'Select' || column.controlType === 'Radio' || column.controlType === 'AutoComplete') {
                        // 选择框、单选框组
                        if (param != null) {
                            this.fillDataSource(this.data, column, param);
                        } else {
                            // 参数不完整，清空数据
                            column.dataSource = [];
                            this.setData(this.data, column.code, null);
                            // column.displayValue = null;

                            // 触发
                            column.triggers.forEach(item => {
                                item.needRefresh = true;
                            });
                        }
                    } else if (column.controlType === 'ComboSelect') {
                        // 可筛选选择框
                        this.loadOption(this.data, column);
                    }

                    column.needRefresh = false;
                }
            },
            // 获取默认值
            getDefaultData() {
                let data = {};
                this.columns.forEach(item => {
                    if (item.defaultValue) {
                        this.setData(data, item.code, item.defaultValue);
                    } else {
                        if (item.dataType === 'Boolean') {
                            this.setData(data, item.code, false);
                        } else {
                            this.setData(data, item.code, null);
                        }
                    }
                });

                for (let key in this.defaultData) {
                    this.setData(data, key, this.defaultData[key]);
                }

                return data;
            },
            getDataType(column) {
                if (column.dataType.indexOf('Enum:') === 0) {
                    return 'string';
                }

                switch (column.dataType) {
                    case 'String':
                    case 'Boolean':
                        return 'boolean';
                    case 'DateTime':
                        return 'date';
                    case 'Float':
                    case 'Double':
                    case 'Decimal':
                        return 'number';
                    case 'Short':
                    case 'Integer':
                    case 'BigInteger':
                        return 'integer';
                }
            },
            // 重置
            reset() {
                this.$refs.form.resetFields();
            },
            // 设为默认值
            setDefault(data) {
                this.$refs.form.resetFields();

                this.data = this.getDefaultData();
                if (data) {
                    for (let key in data) {
                        this.data[key] = data[key];
                    }
                }
            },
            // 验证
            validate() {
                return this.$refs.form.validate();
            },
            // 获取触发器
            getTrigger(column) {
                if (column.controlType === 'TextInput' || column.controlType === 'NumberInput') {
                    return 'blur,change';
                } else {
                    return 'blur,change';
                }
            }
        }
    };
</script>
