<template>
  <div>
    <Form ref="form" :model="data" label-position="top" label-colon="：" class="ivu-mt">
      <draggable
        v-model="columns"
        item-key="index"
        :animation="500"
        :scroll="true"
        group="sort"
        @start="start"
        @end="end"
        class="ivu-row ivu-row-flex"
        style="margin-left: -12px; margin-right: -12px"
      >
        <template #item="{ element: column, index }">
          <div
            :id="'col-' + index"
            :ref="'col-' + index"
            class="ivu-col"
            :class="getClass(column)"
            style="padding-left: 12px; padding-right: 12px"
            :style="column._actived ? 'border: dashed #ddd 1px; background-color: #ffefd5;' : ''"
            @mouseover="mouseover(column)"
            @mouseleave="mouseleave(column)"
          >
            <div style="position: absolute; z-index: 100; top: 4px; right: 4px">
              <Button size="small" v-if="column._editable" @click="edit(column, index)" icon="md-cog" type="primary" style="margin-right: 4px; width: 22px; height: 22px"></Button>
              <Button size="small" v-show="column._editable" @click="remove(column, index)" icon="md-close" type="warning" style="width: 22px; height: 22px"></Button>
            </div>
            <div :key="column.code" v-if="column.controlType === 'Placeholder'" style="margin-bottom: 0px"></div>
            <div :key="column.code" v-if="column.controlType === 'Title'">
              <div class="form-title" :style="{ width: column.controlWidth == null ? null : column.controlWidth + 'px' }">
                {{ getNameI18n(column) }} {{ showData(data, column) }}
              </div>
            </div>
            <div v-if="column.controlType === 'Table'">
              <Divider :plain="true" dashed orientation="left" size="small">
                <span class="title">{{ getNameI18n(column) }}</span>
              </Divider>
              <view-table :static="true" :view-code="column.source" :readonly="column.isReadonly" :embedded="true"></view-table>
            </div>
            <div v-if="column.controlType === 'ExcelTable'">
              <Divider :plain="true" dashed orientation="left" size="small">
                <span class="title">{{ getNameI18n(column) }}</span>
              </Divider>
              <view-table :static="true" :view-code="column.source" :readonly="column.isReadonly" :embedded="true"></view-table>
            </div>
            <div v-if="column.controlType === 'List'">
              <Divider :plain="true" dashed orientation="left" size="small">
                <span class="title">{{ getNameI18n(column) }}</span>
              </Divider>
              <view-table :static="true" :view-code="column.source" :readonly="true" :embedded="true"></view-table>
            </div>
            <FormItem
              :label="getNameI18n(column)"
              :prop="column.code"
              :key="column.code"
              :rules="getRules(column)"
              :error="column.code == null ? $t('Front_Label_Column_Not_Bind') : null"
              v-if="
                column.controlType !== 'Placeholder' &&
                column.controlType !== 'Title' &&
                column.controlType !== 'Table' &&
                column.controlType !== 'ExcelTable' &&
                column.controlType !== 'List'
              "
            >
              <template v-if="column.controlType === 'Custom'"></template>
              <template v-else-if="column.controlType === 'Label'">
                <div class="label" :title="compareData == null ? showData(data, column) : showData(compareData, column)">
                  <div :class="{ error: compareData != null && parseData(data, column.code) != parseData(compareData, column.code) }" v-html="showData(data, column)"></div>
                </div>
              </template>
              <template v-if="column.controlType === 'Hyperlink'">
                <a href="#" :target="column.isNewWindow ? '_blank' : ''">
                  <span v-html="showData(data, column)"></span>
                </a>
              </template>
              <template v-if="column.controlType === 'ModalForm'">
                <a href="#">
                  <span v-html="getTemplateReplace(data, column.description)"></span>
                </a>
              </template>
              <template v-else-if="column.controlType === 'TextInput'">
                <Input
                  type="text"
                  :model-value="parseData(data, column.code)"
                  @update:model-value="$event => setData(data, column.code, $event)"
                  :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
                  :model-value="parseData(data, column.code)"
                  @update:model-value="$event => setData(data, column.code, $event)"
                  :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
                  :model-value="parseData(data, column.code)"
                  @update:model-value="$event => setData(data, column.code, $event)"
                  :disabled="column.isReadonly"
                  :clearable="true"
                  :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 === 'MultiSelect'">
                <Select
                  :model-value="parseArrayData(data, column.code)"
                  @update:model-value="$event => setArrayData(data, column.code, $event)"
                  :disabled="column.isReadonly"
                  :multiple="true"
                  :clearable="true"
                  :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 === 'TreeSelect'">
                <TreeSelect
                  :model-value="parseTreeData(data, column.code)"
                  @update:model-value="$event => setData(data, column.code, $event)"
                  :data="getDataSource(data, column)"
                  :disabled="column.isReadonly"
                  :clearable="true"
                  :style="{ width: column.controlWidth == null ? null : column.controlWidth + 'px' }"
                  :placeholder="column.description"
                  :transfer="true"
                ></TreeSelect>
              </template>
              <template v-else-if="column.controlType === 'MultiTreeSelect'">
                <TreeSelect
                  :model-value="parseArrayData(data, column.code)"
                  @update:model-value="$event => setArrayData(data, column.code, $event)"
                  :data="getDataSource(data, column)"
                  :disabled="column.isReadonly"
                  :multiple="true"
                  :show-checkbox="true"
                  :clearable="true"
                  :style="{ width: column.controlWidth == null ? null : column.controlWidth + 'px' }"
                  :placeholder="column.description"
                  :transfer="true"
                ></TreeSelect>
              </template>
              <template v-else-if="column.controlType === 'SelectWithOther'">
                <Select
                  :model-value="parseDataWithOther(data, column)"
                  @update:model-value="$event => setDataWithOther(data, column.code, $event)"
                  :disabled="column.isReadonly"
                  :clearable="true"
                  :style="{ width: column.controlWidth == null ? '40%' : 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>
                  <Option key="__Other" value="__Other">{{ !!(column.pattern || '').trim() ? column.pattern : $t('Front_Label_Others') }}</Option>
                </Select>
                <Input
                  type="text"
                  v-show="parseDataWithOther(data, column) == '__Other'"
                  :model-value="parseData(data, column.code)"
                  @update:model-value="$event => setData(data, column.code, $event)"
                  :readonly="column.isReadonly"
                  :style="{ width: column.controlWidth == null ? '40%' : column.controlWidth + 'px' }"
                  style="margin-left: 4px"
                  :maxlength="column.maxLength"
                  :placeholder="column.description"
                  @on-change="onDataChange(column)"
                />
              </template>
              <template v-else-if="column.controlType === 'ComboSelect'">
                <combo-select
                  :model-value="parseData(data, column.code)"
                  @update:model-value="$event => setData(data, column.code, $event)"
                  :multi="false"
                  :readonly="column.isReadonly"
                  :remote-method="search => loadOption(data, column, search)"
                  :data="data"
                  :param="getParam(data, column)"
                  :column="column"
                  @on-change="selected => onSelectDataChange(column, selected)"
                ></combo-select>
              </template>
              <template v-else-if="column.controlType === 'MultiComboSelect'">
                <combo-select
                  :model-value="parseArrayData(data, column.code)"
                  @update:model-value="$event => setArrayData(data, column.code, $event)"
                  :multi="true"
                  :readonly="column.isReadonly"
                  :remote-method="search => loadOption(data, column, search)"
                  :data="data"
                  :param="getParam(data, column)"
                  :column="column"
                  @on-change="selected => onSelectDataChange(column, selected)"
                ></combo-select>
              </template>
              <template v-else-if="column.controlType === 'DialogSelect'">
                <dialog-select
                  :model-value="parseData(data, column.code)"
                  @update:model-value="$event => setData(data, column.code, $event)"
                  :readonly="column.isReadonly"
                  :source="column.source"
                  :source-data-code="column.sourceDataCode"
                  :source-display-code="column.sourceDisplayCode"
                  :param="getParam(data, column)"
                  :controlWidth="column.controlWidth"
                  @on-change="selected => onDataChange(column, selected)"
                ></dialog-select>
              </template>
              <template v-else-if="column.controlType === 'MultiDialogSelect'">
                <dialog-select
                  :model-value="parseData(data, column.code)"
                  @update:model-value="$event => setData(data, column.code, $event)"
                  :multi="true"
                  :readonly="column.isReadonly"
                  :source="column.source"
                  :source-data-code="column.sourceDataCode"
                  :source-display-code="column.sourceDisplayCode"
                  :param="getParam(data, column)"
                  :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'">
                <DatePicker
                  :type="column.controlType.toLowerCase()"
                  :model-value="parseData(data, column.code)"
                  :readonly="column.isReadonly"
                  :editable="layout.dateEditable !== false"
                  :placeholder="column.description"
                  :transfer="true"
                  :style="{ width: column.controlWidth == null ? null : column.controlWidth + 'px' }"
                  @on-change="
                    time => {
                      setData(data, column.code, time);
                      onDataChange(column);
                    }
                  "
                ></DatePicker>
              </template>
              <template v-else-if="column.controlType === 'DateRange'">
                <DatePicker
                  :type="column.controlType.toLowerCase()"
                  :model-value="parseDateRangeData(data, column.code)"
                  @update:model-value="$event => setArrayData(data, column.code, $event)"
                  :readonly="column.isReadonly"
                  :editable="layout.dateEditable !== false"
                  :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"
                  :model-value="parseData(data, column.code)"
                  @update:model-value="$event => setData(data, column.code, $event)"
                  :readonly="column.isReadonly"
                  :placeholder="column.description"
                  :transfer="true"
                  :style="{ width: column.controlWidth == null ? null : column.controlWidth + 'px' }"
                  @on-change="
                    time => {
                      setData(data, column.code, time);
                      onDataChange(column);
                    }
                  "
                ></TimePicker>
              </template>
              <template v-else-if="column.controlType === 'Check'">
                <Checkbox
                  :model-value="!!parseData(data, column.code)"
                  @update:model-value="$event => setData(data, column.code, $event)"
                  :disabled="column.isReadonly"
                  size="large"
                  @on-change="onDataChange(column)"
                />
              </template>
              <template v-else-if="column.controlType === 'Switch'">
                <Switch
                  :model-value="!!parseData(data, column.code)"
                  @update:model-value="$event => setData(data, column.code, $event)"
                  :disabled="column.isReadonly"
                  @on-change="onDataChange(column)"
                />
              </template>
              <template v-else-if="column.controlType === 'Radio'">
                <RadioGroup :model-value="parseData(data, column.code)" @update:model-value="$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="column.isReadonly">
                    <span>{{ item.name }}</span>
                  </Radio>
                </RadioGroup>
              </template>
              <template v-else-if="column.controlType === 'CheckGroup'">
                <CheckboxGroup
                  :model-value="parseArrayData(data, column.code)"
                  @update:model-value="$event => setArrayData(data, column.code, $event)"
                  @on-change="onDataChange(column)"
                >
                  <Checkbox v-for="item in getDataSource(data, column)" :key="item.id" :label="item.id" :disabled="column.isReadonly">
                    <span>{{ item.name }}</span>
                  </Checkbox>
                </CheckboxGroup>
              </template>
              <template v-else-if="column.controlType === 'TextArea'">
                <Input
                  type="textarea"
                  :model-value="parseData(data, column.code)"
                  @update:model-value="$event => setData(data, column.code, $event)"
                  :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
                  :model-value="parseData(data, column.code)"
                  @update:model-value="$event => setData(data, column.code, $event)"
                  :readonly="column.isReadonly"
                  :height="column.controlHeight"
                  :width="column.controlWidth"
                />
              </template>
              <template v-else-if="column.controlType === 'Attachment'">
                <upload-attachment
                  :model-value="parseData(data, column.code)"
                  @update:model-value="$event => setData(data, column.code, $event)"
                  :readonly="column.isReadonly"
                  :maxCount="column.maxLength"
                  :accept="column.pattern"
                  :draggable="column.mergeSame"
                />
              </template>
              <template v-else-if="column.controlType === 'Image'">
                <upload-image
                  :model-value="parseData(data, column.code)"
                  @update:model-value="$event => setData(data, column.code, $event)"
                  :readonly="column.isReadonly"
                  :maxCount="column.maxLength"
                  :height="column.controlHeight"
                  :width="column.controlWidth"
                />
              </template>
              <template v-else-if="column.controlType === 'Slider'">
                <Slider
                  v-if="!column.isReadonly"
                  :model-value="parseData(data, column.code)"
                  @update:model-value="$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="column.isReadonly"
                  type="number"
                  number
                  readonly
                  :model-value="parseData(data, column.code)"
                  :style="{ width: column.controlWidth == null ? '100px' : column.controlWidth + 'px' }"
                  :placeholder="column.description"
                />
              </template>
            </FormItem>
          </div>
        </template>
      </draggable>
    </Form>
    <!-- <FooterToolbar>
            <Button type="primary" size="large">{{ $t('Front_Btn_Submit') }}</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 richEditor from '../richEditor/index.vue';
  import uploadAttachment from '../upload/upload-attachment.vue';
  import uploadImage from '../upload/upload-image.vue';
  import draggable from 'vuedraggable';

  export default {
    mixins: [mixin, mixinPage],
    components: { richEditor, uploadAttachment, uploadImage, draggable },
    data() {
      return {
        formView: {},
        columns: [],
        tabs: [],
        tabName: '',
        rules: {},
        data: null,
        compareData: null,
        dragging: false,
        draggingColumn: null
      };
    },
    async created() {},
    props: {},
    computed: {},
    methods: {
      ...mapActions('admin/dataView', { loadDataView: 'load' }),
      getRules(column) {
        if (!column.isShow) {
          return [];
        }

        let rules = [];

        if (column.isRequired) {
          if (
            column.controlType == 'Date' ||
            column.controlType == 'DateTime' ||
            column.controlType == 'Year' ||
            column.controlType == 'Month' ||
            column.controlType == 'DateRange'
          ) {
            rules.push({
              pattern: /.+/,
              required: true,
              message: this.$t('Front_Msg_Please_Input'),
              trigger: 'blur,change'
            });
          } else {
            rules.push({
              type: this.getDataType(column),
              required: true,
              message: this.$t('Front_Msg_Please_Input'),
              trigger: 'blur,change'
            });
          }
        }

        if (column.pattern && column.controlType == 'TextInput') {
          rules.push({
            type: this.getDataType(column),
            pattern: column.pattern,
            message: this.$t('Front_Msg_Validation_Pattern'),
            trigger: 'blur,change'
          });
        }

        if (column.maxValue != null && (column.controlType == 'NumberInput' || column.controlType == 'Slider')) {
          rules.push({
            type: this.getDataType(column),
            max: column.maxValue,
            message: this.tParam('Front_Msg_Validation_Max_Value|' + column.maxValue),
            trigger: 'blur,change'
          });
        }

        if (column.minValue != null && (column.controlType == 'NumberInput' || column.controlType == 'Slider')) {
          rules.push({
            type: this.getDataType(column),
            min: column.minValue,
            message: this.tParam('Front_Msg_Validation_Min_Value|' + column.minValue),
            trigger: 'blur,change'
          });
        }

        if (column.maxLength != null && (column.controlType == 'TextInput' || column.controlType == 'TextArea')) {
          rules.push({
            type: this.getDataType(column),
            length: column.maxLength,
            message: this.tParam('Front_Msg_Validation_Max_Length|' + column.maxLength),
            trigger: 'blur,change'
          });
        }

        return rules;
      },
      // 获取数据类型
      getDataType(column) {
        if (!(column.dataType || '').trim()) {
          return null;
        }
        if (column.dataType.startsWith('Enum:')) {
          return 'string';
        }

        switch (column.dataType) {
          case 'String':
          case 'BigInteger':
            return 'string';
          case 'Boolean':
            return 'boolean';
          case 'DateTime':
            return 'date';
          case 'Float':
          case 'Double':
          case 'Decimal':
            return 'number';
          case 'Short':
          case 'Integer':
            return 'integer';
        }
      },
      // 根据选项卡序号返回列
      tabColumns(index) {
        return this.columns.filter(item => {
          return item.tabIndex === index || item.tabIndex == null;
        });
      },
      // 初始化
      init(formView, columns) {
        this.formView = formView;
        this.columns = columns;

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

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

          // 初始化静态选项
          this.initStaticItem();

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

          // 处理强制换行
          this.initNewLine();

          this.onDataChange();
        });
      },
      // 初始化板块
      initTab() {
        if (!!(this.formView.tab || '').trim()) {
          this.tabs = this.formView.tab.split(',');
        } else {
          this.tabs = [this.formView.name];
        }

        this.tabName = this.tabs[0];
      },
      // 初始化静态选项
      initStaticItem() {
        this.columns.forEach(column => {
          if (column.isStaticItem) {
            column.dataSource = [];

            if (!!(column.itemData || '').trim()) {
              column.itemData.split(/[\n]/).forEach(item => {
                if (!!(item || '').trim()) {
                  if (item.split(':').length > 1) {
                    let key = item.split(':')[0];
                    let value = item.split(':')[1];

                    if (column.dataType == 'Integer' || column.dataType == 'BigInteger') {
                      column.dataSource.push({
                        id: parseInt(key),
                        name: value
                      });
                    } else if (column.dataType == 'Decimal' || column.dataType == 'Float' || column.dataType == 'Double') {
                      column.dataSource.push({
                        id: parseFloat(key),
                        name: value
                      });
                    } else if (column.dataType == 'Boolean') {
                      column.dataSource.push({
                        id: key.toUpperCase() == 'TRUE',
                        name: value
                      });
                    } else {
                      column.dataSource.push({
                        id: key,
                        name: value
                      });
                    }
                  } else {
                    if (column.dataType == 'Integer' || column.dataType == 'BigInteger') {
                      column.dataSource.push({
                        id: parseInt(item),
                        name: item
                      });
                    } else if (column.dataType == 'Decimal' || column.dataType == 'Float' || column.dataType == 'Double') {
                      column.dataSource.push({
                        id: parseFloat(item),
                        name: item
                      });
                    } else if (column.dataType == 'Boolean') {
                      column.dataSource.push({
                        id: item.toUpperCase() == 'TRUE',
                        name: item
                      });
                    } else {
                      column.dataSource.push({
                        id: item,
                        name: item
                      });
                    }
                  }
                }
              });
            }
          }
        });
      },
      // 初始化触发规则
      initTrigger() {
        // 触发规则
        this.columns.forEach(column => {
          column.triggers = [];
        });

        // 数据源中包含变量需要刷新
        this.columns
          .filter(column => {
            return !!(column.source || '').trim() && !!(column.param || '').trim() && !(column.dataType && column.dataType.startsWith('Enum:'));
          })
          .forEach(column => {
            let param = JSON.parse(column.param);
            for (let key in param) {
              this.columns
                .filter(item => {
                  return param[key] == item.code || param[key].split('.')[0] + 'ID' == item.code;
                })
                .forEach(item => {
                  item.triggers.push(this.copy(column));
                });
            }
          });
      },
      // 填充数据源
      async fillDataSource(data, column, param) {
        let value;
        if (column.controlType === 'TreeSelect' || column.controlType === 'MultiTreeSelect') {
          // 树选择框重新加载数据源时，需要先清空数据源，否则无法直接点击清空按钮清除数据。
          value = this.parseTreeData(data, column.code);
          column.dataSource = null;
        }

        if (column.controlType === 'ComboSelect' || column.controlType === 'MultiComboSelect') {
          param.per = 20;
        }

        // 参数完整，查询数据
        this.disableLoader();
        let res;
        if (column.isSourceCustom) {
          res = await customModelApi.query(column.source, param); //, [column.sourceDataCode, column.sourceDisplayCode]);
        } else {
          res = await modelApi.query(column.source, param); //, [column.sourceDataCode, column.sourceDisplayCode]);
        }
        this.enableLoader();

        column.rawData = res.data;

        if (column.controlType === 'TreeSelect' || column.controlType === 'MultiTreeSelect') {
          let treeData = res.data.map(item => {
            return {
              id: !(column.sourceDataCode || '').trim() ? item.id : this.parseData(item, column.sourceDataCode),
              name: this.parseData(item, column.sourceDisplayCode),
              parentID: item.parentID
            };
          });

          column.dataSource = this.getTreeDataSource(treeData, column, null);
          this.setData(data, column.code, value);
        } else {
          column.dataSource = res.data.map(item => {
            return {
              id: !(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.data.length > 0) {
              this.setData(data, column.code, this.parseData(res.data[0], column.sourceDataCode));
              /**
               * 数据变化事件
               * @property {object} sender 触发的列对象
               * @property {object} oldValue 原数据
               * @property {object} newValue 新数据
               * @property {object} selected 选中对象（弹出选择框等有效）
               */
              this.$emit('on-change', column, null, column.rawData[0], null);

              if (column.sourceDataCode == 'id' && column.code.length > 2) {
                let code = column.code.substr(0, column.code.length - 2);
                let model = column.rawData.find(item => {
                  return item.id == this.parseData(data, column.code);
                });

                this.setData(data, code, model);
              }
            }
          }
        }

        // 级联更新时清空数据
        if (column.controlType == 'Select' || column.controlType == 'Radio') {
          if (
            !column.dataSource.some(item => {
              return item.id == this.parseData(data, column.code);
            })
          ) {
            // 数据不存在于此数据源，清空数据
            this.setData(data, column.code, null);

            // 触发
            column.triggers.forEach(item => {
              item.needClear = true;
            });
          }
        }
      },
      // 获取树结构数据源
      getTreeDataSource(data, column, parentID) {
        let result = data
          .filter(item => {
            return item.parentID == parentID;
          })
          .map(item => {
            return {
              value: !(column.sourceDataCode || '').trim() ? item.id : this.parseData(item, column.sourceDataCode),
              title: this.parseData(item, column.sourceDisplayCode),
              selected: false,
              checked: false
            };
          });

        if (result.length > 0) {
          for (let item of result) {
            item.expand = true;
            item.children = this.getTreeDataSource(data, column, item.value);
          }
        }

        return result;
      },
      // 获取数据源
      getDataSource(data, column) {
        if (!column.isStaticItem && column.dataType && column.dataType.startsWith('Enum:')) {
          // 枚举
          return this.getEnumList(column.dataType.split(':')[1]);
        } else {
          return column.dataSource == null ? [] : column.dataSource;
        }
      },
      // 数据变化事件
      async onDataChange(sender) {
        // 计算需要刷新的字段
        if (sender == null || (sender.triggers && sender.triggers !== [])) {
          this.columns.forEach(function (column) {
            if (
              !column.isStaticItem &&
              !!(column.source || '').trim() &&
              !(column.dataType && column.dataType.startsWith('Enum:')) &&
              (sender == null ||
                sender.triggers.some(item => {
                  return item.code == column.code;
                }))
            ) {
              column.needRefresh = true;
              // if (column.controlType == 'Table') {
              //     this.$refs['table_' + sender.code][0];
              // } else {
              // }
            }
          });
        }

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

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

          // 重新加载数据源
          if (column.needClear && this.parseData(this.data, column.code) != null) {
            this.setData(this.data, column.code, null);
            // 触发
            column.triggers.forEach(item => {
              item.needClear = true;
            });
          } else if (column.needRefresh && !!(column.source || '').trim() && !(column.dataType && column.dataType.startsWith('Enum:'))) {
            let param = this.getParam(this.data, column);

            if (
              column.controlType === 'Select' ||
              column.controlType === 'MultiSelect' ||
              column.controlType === 'TreeSelect' ||
              column.controlType === 'MultiTreeSelect' ||
              column.controlType === 'SelectWithOther' ||
              column.controlType === 'ComboSelect' ||
              column.controlType === 'MultiComboSelect' ||
              column.controlType === 'Radio' ||
              column.controlType === 'CheckGroup'
              // 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.needClear = true;
                });
              }
            } else if (column.controlType === 'List') {
              if (param != null) {
                // 参数完整，查询数据
                let res;

                let tableView = this.$refs['list_' + column.code][0].tableView;

                let filtering = tableView.filtering;

                if (!!(filtering || '').trim()) {
                  param = {
                    ...param,
                    ...JSON.parse(filtering)
                  };
                }

                if (column.isSourceCustom) {
                  res = await customModelApi.query(column.sourceModel, param, null, tableView.isReturnSimple ? tableView : null);
                } else {
                  res = await modelApi.query(column.sourceModel, param, null, tableView.isReturnSimple ? tableView : null, tableView.functionName, tableView.functionType);
                }

                this.$refs['list_' + column.code][0].loadData(res.data);
              }
            }
          }

          // 重新加载公式
          // if (!!(column.calculate || '').trim()) {
          //     let data = this.calculate(column.calculate, this.data);
          //     this.setData(this.data, column.code, data);
          // }

          column.needClear = false;
          column.needRefresh = false;
        }
      },
      // 编辑
      edit(column, index) {
        this.$emit('edit', { column, index });
      },
      // 删除
      remove(column, index) {
        this.$emit('remove', { column, index });
      },
      // 根据表达式取值（带其他）
      parseDataWithOther(model, column) {
        let expression = column.code;
        let selectValue = this.parseData(model, expression + '_o');

        let value = this.parseData(model, expression);
        let dataSource = this.getDataSource(model, column);

        if (selectValue != null) {
          return selectValue;
        } else if (value == null) {
          return null;
        } else if (
          dataSource &&
          dataSource.some(item => {
            return item.id == value;
          })
        ) {
          return value;
        } else {
          return '__Other';
        }
      },
      // 根据表达式赋值（带其他）
      setDataWithOther(model, expression, value) {
        this.setData(model, expression + '_o', value);
        if (value != '__Other') {
          this.setData(model, expression, value);
        } else {
          this.setData(model, expression, null);
        }
      },
      // 根据表达式取值（树）
      parseTreeData(data, code) {
        let value = this.parseData(data, code);

        if (value == null) {
          return '';
        } else {
          return value;
        }
      },
      // 获取多语言名称
      getNameI18n(column) {
        if (this.layout.showI18n) {
          if (column.code) {
            let key = 'DataView_' + this.formView.code + '_' + column.code;
            let text = this.$t(key);
            if (text == key) {
              return column.name;
            } else {
              return text;
            }
          } else {
            return column.name;
          }
        } else {
          return column.name;
        }
      },
      // 获取样式
      getClass(column) {
        const grid = this.getGrid(column.columnWidth);
        const classes = [];

        for (const key in grid) {
          classes.push('ivu-col-span-' + key + '-' + grid[key]);
        }

        return classes;
      },
      // 鼠标移入
      mouseover(column) {
        if (!this.dragging) {
          column._editable = true;
        }

        //this.$forceUpdate();
      },
      // 鼠标移出
      mouseleave(column) {
        if (!this.dragging) {
          column._editable = false;
        }
        //this.$forceUpdate();
      },
      start(evt) {
        this.draggingColumn = this.columns[evt.oldDraggableIndex];
        this.draggingColumn._actived = true;
        this.draggingColumn._editable = false;

        this.dragging = true;
      },
      end(evt) {
        this.draggingColumn._actived = false;

        this.dragging = false;

        this.initNewLine();
      },
      initNewLine() {
        this.columns.forEach((column, index) => {
          const line = document.getElementById('line-' + index);
          if (line) {
            line.parentNode.removeChild(line);
          }
        });

        this.columns.forEach((column, index) => {
          if (column.newLine) {
            const col = document.getElementById('col-' + index);
            const line = document.createElement('div');
            line.id = 'line-' + index;
            line.style.width = '100%';

            col.parentNode.insertBefore(line, col);
          }
        });
      },
      // 可筛选下拉框加载数据
      async loadOption(data, column, keyword) {
        if (column.isStaticItem || (column.dataType && column.dataType.startsWith('Enum:'))) {
          return;
        }

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

        if (param != null) {
          param[column.sourceDisplayCode + '_c'] = keyword;
          this.fillDataSource(data, column, param);
        } else {
          // 参数不完整，清空数据
          column.rawData = [];
          column.dataSource = [];
          this.setData(data, column.code, null);
          // column.displayValue = null;

          // 触发
          column.triggers.forEach(item => {
            item.needClear = true;
          });
        }
      }
    }
  };
</script>

<style>
  .draggable .ivu-form-item-content {
    margin-bottom: 8px;
  }
</style>
