<template>
  <div style="display: contents">
    <Col v-for="(column, index) in columns" :key="index" v-bind="getGrid(column.columnWidth)">
      <template v-if="column.isShow">
        <div :key="column.code" v-if="column.controlType === 'Placeholder'"></div>
        <FormItem :label="getNameI18n(column)" :key="column.code" v-if="column.controlType !== 'Placeholder'">
          <template v-if="column.controlType === 'Custom'">
            <!--
                  @slot 自定义列
                  @binding {object} filter 数据对象
                  @binding {object} column 列对象
                  @binding {string} code 列代码
              -->
            <slot name="column" :filter="data" :column="column" :code="column.code"></slot>
          </template>
          <template v-else>
            <div style="display: flex; white-space: nowrap">
              <template v-if="!column._queryNull">
                <template v-if="column.controlType === 'Label'">
                  <div class="label">
                    <div>{{ showData(data, column) }}</div>
                  </div>
                </template>
                <template v-else-if="column.controlType === 'TextInput'">
                  <Input
                    size="small"
                    type="text"
                    :model-value="parseFilterData(data, column)"
                    @update:model-value="$event => setFilterData(data, column, $event)"
                    @on-keyup="$event => onKeyup($event)"
                    :clearable="true"
                    :style="{ width: column.controlWidth == null ? null : column.controlWidth + 'px' }"
                    :placeholder="column.description"
                  />
                </template>
                <template v-else-if="column.controlType === 'NumberInput'">
                  <Input
                    size="small"
                    type="number"
                    number
                    :model-value="parseFilterData(data, column)"
                    @update:model-value="$event => setFilterData(data, column, $event)"
                    @on-keyup="$event => onKeyup($event)"
                    :clearable="true"
                    :style="{ width: column.controlWidth == null ? '100px' : column.controlWidth + 'px' }"
                    :placeholder="column.description"
                  />
                </template>
                <template v-else-if="column.controlType === 'Select'">
                  <Select
                    size="small"
                    :model-value="parseFilterData(data, column)"
                    @update:model-value="$event => setFilterData(data, column, $event)"
                    :clearable="true"
                    :style="{ width: column.controlWidth == null ? null : column.controlWidth + 'px' }"
                    :placeholder="column.description"
                    :transfer="true"
                    @on-change="selected => onSelectDataChange(column, selected)"
                  >
                    <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
                    size="small"
                    :model-value="parseArrayFilterData(data, column)"
                    :multiple="true"
                    :clearable="true"
                    @update:model-value="$event => setArrayFilterData(data, column, $event)"
                    :style="{ width: column.controlWidth == null ? null : column.controlWidth + 'px' }"
                    :placeholder="column.description"
                    :transfer="true"
                    @on-change="selected => onSelectDataChange(column, selected)"
                  >
                    <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
                    size="small"
                    :model-value="parseTreeFilterData(data, column)"
                    @update:model-value="$event => setFilterData(data, column, $event)"
                    :data="getDataSource(data, column)"
                    :clearable="true"
                    :style="{ width: column.controlWidth == null ? null : column.controlWidth + 'px' }"
                    :placeholder="column.description"
                    :transfer="true"
                    @on-change="selected => onSelectDataChange(column, selected)"
                  ></TreeSelect>
                </template>
                <template v-else-if="column.controlType === 'MultiTreeSelect'">
                  <TreeSelect
                    size="small"
                    :model-value="parseArrayFilterData(data, column)"
                    @update:model-value="$event => setArrayFilterData(data, column, $event)"
                    :data="getDataSource(data, column)"
                    :multiple="true"
                    :show-checkbox="true"
                    :clearable="true"
                    :style="{ width: column.controlWidth == null ? null : column.controlWidth + 'px' }"
                    :placeholder="column.description"
                    :transfer="true"
                    @on-change="selected => onSelectDataChange(column, selected)"
                  ></TreeSelect>
                </template>
                <template v-else-if="column.controlType === 'SelectWithOther'">
                  <Select
                    size="small"
                    :model-value="parseFilterDataWithOther(data, column)"
                    @update:model-value="$event => setFilterDataWithOther(data, column, $event)"
                    :clearable="true"
                    :style="{ width: column.controlWidth == null ? '40%' : column.controlWidth + 'px' }"
                    :placeholder="column.description"
                    :transfer="true"
                    @on-change="selected => onSelectDataChange(column, selected)"
                  >
                    <Option v-for="item in getDataSource(data, column)" :key="item.id" :value="item.id">{{ item.name }}</Option>
                    <Option key="__Other" value="__Other">{{ $t('Front_Label_Others') }}</Option>
                  </Select>
                  <Input
                    type="text"
                    size="small"
                    v-show="parseFilterDataWithOther(data, column) == '__Other'"
                    :model-value="parseFilterData(data, column)"
                    @update:model-value="$event => setFilterData(data, column, $event)"
                    :style="{ width: column.controlWidth == null ? '40%' : column.controlWidth + 'px' }"
                    style="margin-left: 4px"
                    :placeholder="column.description"
                    @on-change="onDataChange(column)"
                  />
                </template>
                <template v-else-if="column.controlType === 'ComboSelect'">
                  <combo-select
                    size="small"
                    :model-value="parseFilterData(data, column)"
                    @update:model-value="$event => setFilterData(data, column, $event)"
                    :multi="false"
                    :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
                    size="small"
                    :model-value="parseArrayFilterData(data, column)"
                    @update:model-value="$event => setArrayFilterData(data, column, $event)"
                    :multi="true"
                    :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
                    size="small"
                    :model-value="parseFilterData(data, column)"
                    @update:model-value="$event => setFilterData(data, column, $event)"
                    :source="column.source"
                    :source-data-code="column.sourceDataCode"
                    :source-display-code="column.sourceDisplayCode"
                    :param="getParam(data, column, parentData)"
                    :controlWidth="column.controlWidth"
                    @on-change="selected => onSelectDataChange(column, selected)"
                  ></dialog-select>
                </template>
                <template v-else-if="column.controlType === 'MultiDialogSelect'">
                  <dialog-select
                    size="small"
                    :model-value="parseFilterData(data, column)"
                    @update:model-value="$event => setFilterData(data, column, $event)"
                    :multi="true"
                    :source="column.source"
                    :source-data-code="column.sourceDataCode"
                    :source-display-code="column.sourceDisplayCode"
                    :param="getParam(data, column, parentData)"
                    :controlWidth="column.controlWidth"
                    @on-change="selected => onSelectDataChange(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
                    size="small"
                    :type="column.controlType.toLowerCase()"
                    :model-value="parseFilterData(data, column)"
                    :editable="layout.dateEditable !== false"
                    :placeholder="column.description"
                    :transfer="true"
                    :style="{ width: column.controlWidth == null ? null : column.controlWidth + 'px' }"
                    @on-change="
                      time => {
                        if (column.controlType === 'DateRange' && time.length == 2 && time[0] == '') {
                          setFilterData(data, column, null);
                        } else {
                          setFilterData(data, column, time);
                        }

                        onDataChange(column);
                      }
                    "
                  ></DatePicker>
                </template>
                <template v-else-if="column.controlType === 'Time'">
                  <TimePicker
                    size="small"
                    type="time"
                    :model-value="parseFilterData(data, column)"
                    @update:model-value="$event => setFilterData(data, column, $event)"
                    :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
                    size="small"
                    style="line-height: 26px"
                    :model-value="!!parseFilterData(data, column)"
                    @update:model-value="$event => setFilterData(data, column, $event)"
                    @on-change="onDataChange(column)"
                  />
                </template>
                <template v-else-if="column.controlType === 'Switch'">
                  <div style="line-height: 24px">
                    <Switch
                      size="small"
                      :model-value="!!parseFilterData(data, column)"
                      @update:model-value="$event => setFilterData(data, column, $event)"
                      @on-change="onDataChange(column)"
                    />
                  </div>
                </template>
                <template v-else-if="column.controlType === 'Radio'">
                  <RadioGroup
                    size="small"
                    style="line-height: 22px"
                    :model-value="parseFilterData(data, column)"
                    @update:model-value="$event => setFilterData(data, column, $event)"
                    @on-change="selected => onSelectDataChange(column, selected)"
                  >
                    <Radio v-for="item in getDataSource(data, column)" :key="item.id" :label="item.id">
                      <span>{{ item.name }}</span>
                    </Radio>
                  </RadioGroup>
                </template>
                <template v-else-if="column.controlType === 'TextArea'">
                  <Input
                    type="textarea"
                    :model-value="parseFilterData(data, column)"
                    @update:model-value="$event => setFilterData(data, column, $event)"
                    :style="{ width: column.controlWidth == null ? null : column.controlWidth + 'px' }"
                    :rows="column.controlHeight / 20"
                    :placeholder="column.description"
                  />
                </template>
                <template v-else>{{ $t('Front_Label_Control_Type_Not_Supported') }} {{ column.controlType }}</template>
              </template>
              <span v-if="column.isQueryNull" style="margin-left: 5px">
                空
                <Checkbox
                  size="small"
                  style="line-height: 26px"
                  :model-value="!!column._queryNull"
                  @update:model-value="$event => setQueryNull(column, $event)"
                  @on-change="onDataChange(column)"
                />
              </span>
            </div>
          </template>
        </FormItem>
      </template>
    </Col>
    <Col v-if="tableView.keywordEnable" v-bind="grid6">
      <FormItem :label="$t('Front_Label_Keyword')">
        <Input v-model="data.keyword" v-focus @on-keyup="$event => onKeyup($event)" size="small" />
      </FormItem>
    </Col>
  </div>
</template>
<script>
  import mixinPage from '../../mixins/page';
  import mixin from './mixin';
  import modelApi from '../../api/model';
  import customModelApi from '../../api/customModel';
  import DialogSelect from '../input/dialog-select.vue';

  export default {
    mixins: [mixin, mixinPage],
    components: { DialogSelect },
    data() {
      return {
        data: {}
      };
    },
    async created() {
      this.init();
    },
    props: {
      // 表格视图
      tableView: {
        type: Object
      },
      // 字段
      columns: {
        type: Array
      },
      /**
       * 内嵌表格的父对象
       */
      parentData: {
        type: Object,
        default() {
          return {};
        }
      }
    },
    watch: {
      columns() {
        this.init();
      }
    },
    computed: {},
    methods: {
      init() {
        // 设置默认值
        let defaultData = this.getDefaultData(this.setFilterData, this.setArrayFilterData);

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

        // 初始化触发规则
        setTimeout(() => {
          // 初始化静态选项
          this.initStaticItem();

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

          this.onDataChange();
        });
      },
      // 初始化静态选项
      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.controlType != 'Select') {
                      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
                      });
                    }
                  }
                }
              });
            }
          }
        });

        //this.$forceUpdate();
      },
      // 初始化触发规则
      initTrigger() {
        // 触发规则
        this.columns.forEach(column => {
          column.triggers = [];
        });

        this.columns
          .filter(column => {
            return !column.isStaticItem && !!(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;
                })
                .forEach(item => {
                  item.triggers.push(column);
                });
            }
          });
      },
      // 填充数据源
      async fillDataSource(data, column, param) {
        let value;
        if (column.controlType === 'TreeSelect' || column.controlType === 'MultiTreeSelect') {
          // 树选择框重新加载数据源时，需要先清空数据源，否则无法直接点击清空按钮清除数据。
          value = this.parseTreeFilterData(data, column);
          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.setFilterData(data, column, 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.parseFilterData(data, column) == null && column.isDefaultFirst && res.length > 0) {
              this.setData(data, column.code, this.parseData(res[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.startsWith('Enum:')) {
          // 枚举
          return this.getEnumList(column.dataType.split(':')[1]);
        } else {
          return column.dataSource == null ? [] : column.dataSource;
        }
      },
      // 选项变化事件
      onSelectDataChange(sender, selected) {
        let code;
        if (sender.code.endsWith('ID')) {
          code = sender.code.substr(0, sender.code.length - 2);
        }
        let model = null;
        if (typeof selected == 'object') {
          if (selected instanceof Array) {
            model = [];

            for (let item of selected) {
              if (typeof item == 'object') {
                model.push(item);
              } else {
                if (sender.rawData) {
                  model.push(
                    sender.rawData.find(rawData => {
                      return this.parseFilterData(rawData, sender.sourceDataCode) == item;
                    })
                  );
                } else {
                  model.push(item);
                }
              }
            }
          } else {
            model = selected;
          }
        } else {
          if (sender.rawData) {
            model = sender.rawData.find(rawData => {
              return this.parseFilterData(rawData, sender.sourceDataCode) == selected;
            });
          } else {
            model = selected;
          }
        }

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

        this.onDataChange(sender, model);
      },
      // 数据变化事件
      onDataChange(sender, selected) {
        setTimeout(() => {
          this.$emit('on-change', sender, selected);
        });

        // 计算需要刷新的字段
        if (sender == null || 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.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, this.parentData);

          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'
          ) {
            // 选择框、单选框组
            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;
              });
            }
          }

          column.needRefresh = false;
        }

        //this.$forceUpdate();
      },
      // 筛选项取值
      parseFilterData(model, column) {
        return model[this.getFilterKey(column)];
      },
      // 筛选项赋值
      setFilterData(model, column, value) {
        model[this.getFilterKey(column)] = value;

        if (column.code.indexOf('.') >= 0) {
          this.setData(model, column.code, value);
        }
      },
      // 筛选项取值(数组)
      parseArrayFilterData(model, column) {
        let data = [];
        let value = this.parseFilterData(model, column);
        if (this.isJSON(value)) {
          data = JSON.parse(value);
        }

        return data;
      },
      // 筛选项赋值(数组)
      setArrayFilterData(model, column, value) {
        let data = '';
        if (value != null) {
          data = JSON.stringify(value);
        }

        this.setFilterData(model, column, data);
      },
      // 根据表达式取值（带其他）
      parseFilterDataWithOther(model, column) {
        let expression = column.code;
        let selectValue = this.parseData(model, expression + '_o');

        let value = this.parseFilterData(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';
        }
      },
      // 根据表达式赋值（带其他）
      setFilterDataWithOther(model, column, value) {
        this.setData(model, column.code + '_o', value);
        if (value != '__Other') {
          this.setFilterData(model, column, value);
        } else {
          this.setFilterData(model, column, null);
        }
      },
      // 获取筛选项Key
      getFilterKey(column) {
        let key = column.code;

        //if (!this.isDataSource) {
        switch (column.controlType) {
          case 'Date':
            key = 'd_' + key; // 日
            break;
          case 'Month':
            key = 'm_' + key; // 月
            break;
          case 'Year':
            key = 'y_' + key; // 年
            break;
          case 'DateRange':
            key = key + '_c'; // 日期范围
            return key;
        }
        //}

        switch (column.operator) {
          case 'GreaterThan':
            key = key + '_g'; // 大于
            break;
          case 'LessThan':
            key = key + '_l'; // 小于
            break;
          case 'GreaterThanOrEqual':
            key = key + '_ge'; // 大于等于
            break;
          case 'LessThanOrEqual':
            key = key + '_le'; // 小于等于
            break;
          case 'NotEqual':
            key = key + '_n'; // 不等于
            break;
          case 'Contains':
            key = key + '_c'; // 文字包含
            break;
        }

        return key;
      },
      // 键盘事件
      onKeyup(e) {
        this.$emit('on-keyup', e);
      },
      // 根据表达式取值（树）
      parseTreeFilterData(data, column) {
        let value = this.parseFilterData(data, column);

        if (value == null) {
          return '';
        } else {
          return value;
        }
      },
      // 获取多语言名称
      getNameI18n(column) {
        if (this.layout.showI18n) {
          if (column.code) {
            let key = 'DataView_' + this.tableView.code + '_Filter_' + column.code + '_' + column.operator;
            let text = this.$t(key);
            if (text == key) {
              return column.name;
            } else {
              return text;
            }
          }
        } else {
          return column.name;
        }
      },
      // 可筛选下拉框加载数据
      async loadOption(data, column, keyword) {
        if (column.isStaticItem || (column.dataType && column.dataType.startsWith('Enum:'))) {
          return;
        }

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

        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;
          });
        }
      },
      // 设置查询空值
      setQueryNull(column, e) {
        column._queryNull = e;
        if (column._queryNull) {
          this.setFilterData(this.data, column, 'null');
        } else {
          this.setFilterData(this.data, column, null);
        }
      }
    }
  };
</script>
