<template>
  <div :class="{ 'full-screen': isFullScreen }">
    <Divider :plain="true" v-if="title != null" dashed orientation="left" size="small">
      <span class="title">{{ title }}</span>
    </Divider>
    <!--
        @slot 顶部
    -->
    <slot name="top"></slot>
    <Form
      v-if="tableView.filterEnable && filterEnable"
      :model="filter"
      :label-width="tableView.filterTitleWidth ? tableView.filterTitleWidth : layout.filterWidth"
      label-colon="："
      label-position="right"
      class="filter"
      @submit.native.prevent
    >
      <div ref="filterCommand">
        <Row :gutter="24" type="flex" justify="end">
          <!--
            @slot 筛选栏
            @binding {object} table 表格对象
            @binding {object} filter 筛选对象
        -->
          <slot name="filter" :table="this" :filter="filter">
            <!--
              @slot 自定义筛选栏
          -->
            <slot name="customFilter"></slot>
            <table-filter ref="tableFilter" :data="filter" :columns="filterColumns" :table-view="tableView" @on-keyup="onKeyup">
              <template slot="column" slot-scope="{ filter, column }">
                <!--
                  @slot 筛选栏自定义列
                  @binding {object} filter 筛选条件对象
                  @binding {object} column 列对象
                  @binding {string} code 列代码
              -->
                <slot name="filterColumn" :filter="filter" :column="column" :code="column.code"></slot>
              </template>
            </table-filter>
            <Col v-bind="getGrid(tableView.filterWidth)" :style="{ 'text-align': tableView.filterAlign == null ? 'left' : tableView.filterAlign.toLowerCase() }">
              <FormItem :label-width="0">
                <Button type="info" v-if="tableView.keywordEnable || filterColumns.length > 0" custom-icon="fa fa-search" @click="search()" size="small">
                  {{ $t('Front_Btn_Search') }}
                </Button>
                <Button type="primary" v-if="tableView.createEnable && createEnable" custom-icon="fa fa-plus" @click="create()" size="small">{{ $t('Front_Btn_New') }}</Button>
                <!--
                  @slot 筛选栏按钮
              -->
                <slot name="filterCommand"></slot>
                <Dropdown v-if="tableView.exportEnable || tableView.exportPdfEnable || tableView.printEnable || tableView.batchEditEnable" @on-click="moreClick">
                  <Button type="info" size="small">
                    {{ $t('Front_Btn_More') }}
                    <Icon type="ios-arrow-down" />
                  </Button>
                  <DropdownMenu slot="list">
                    <DropdownItem v-if="tableView.exportEnable" name="exportExcel">{{ $t('Front_Btn_Export_Excel') }}</DropdownItem>
                    <DropdownItem v-if="tableView.exportPdfEnable" name="exportPdf">{{ $t('Front_Btn_Export_PDF') }}</DropdownItem>
                    <DropdownItem v-if="tableView.printEnable" name="print">{{ $t('Front_Btn_Print') }}</DropdownItem>
                    <DropdownItem v-if="tableView.batchEditEnable" name="batchEdit">{{ $t('Front_Btn_Batch_Edit') }}</DropdownItem>
                  </DropdownMenu>
                </Dropdown>
                <Button
                  type="error"
                  :title="$t('Front_Btn_Filter_Setting')"
                  custom-icon="fa fa-filter"
                  size="small"
                  v-if="settingEnable && allow('permission/tableView')"
                  @click="filterSettingOpen"
                />
                <Button v-if="tableView.fullEnable" type="info" title="全屏" custom-icon="fa fa-expand-arrows-alt" size="small" @click="isFullScreen = !isFullScreen" />
              </FormItem>
            </Col>
          </slot>
        </Row>
      </div>
    </Form>
    <!--
        @slot 中部
    -->
    <slot name="middle"></slot>
    <div :class="{ 'i-table-no-border': !tableView.borderEnable }">
      <Table
        class=""
        ref="table"
        size="small"
        stripe
        row-key="id"
        :indent-size="18"
        :update-show-children="treeEnable"
        :columns="columns"
        :data="data"
        :max-height="maxHeight"
        :load-data="onLoadData"
        :draggable="draggable"
        :sticky="true"
        :span-method="handleSpan"
        :border="tableView.borderEnable"
        :show-summary="tableView.showSummary"
        :summary-method="summaryMethod"
        :page-size-opts="pageSizeOpts"
        no-data-text="暂无数据..."
        @on-column-width-resize="columnWidthResize"
        @on-sort-change="sortChange"
        @on-selection-change="onSelectionChange"
        @on-drag-drop="dragDrop"
      >
        <template slot-scope="{ row, column, index }" slot="normal" v-if="isShow(rowData(row, index), column)">
          <template v-if="column.controlType === 'Custom'">
            <!--
                @slot 自定义列
                @binding {object} row 行对象
                @binding {int} index 行序号
                @binding {int} column 列对象
                @binding {string} code 列代码
            -->
            <slot name="column" :row="rowData(row, index)" :index="index" :column="column" :code="column.code"></slot>
          </template>
          <template v-else-if="column.controlType === 'Label'">
            <div v-html="showData(rowData(row, index), column)"></div>
          </template>
          <template v-else-if="column.controlType === 'Hyperlink'">
            <a :href="getHyperlink(rowData(row, index), column.hyperlink)" :target="column.isNewWindow ? '_blank' : ''">
              <span v-html="showData(rowData(row, index), column)"></span>
            </a>
          </template>
          <template v-else-if="column.controlType === 'TextInput'">
            <Input
              type="text"
              size="small"
              :value="parseData(rowData(row, index), column.code)"
              @input="$event => setData(rowData(row, index), column.code, $event)"
              :readonly="isReadonly(rowData(row, index), column)"
              :style="{ width: column.controlWidth == null ? null : column.controlWidth - 8 + 'px' }"
              :maxlength="column.maxLength"
              :pattern="column.pattern"
              :placeholder="column.description"
              @on-change="onDataChange(rowData(row, index), column)"
              @on-blur="onBlur(rowData(row, index), column)"
            />
          </template>
          <template v-else-if="column.controlType === 'TextArea'">
            <Input
              type="textarea"
              size="small"
              :value="parseData(rowData(row, index), column.code)"
              @input="$event => setData(rowData(row, index), column.code, $event)"
              :readonly="isReadonly(rowData(row, index), column)"
              :style="{ width: column.controlWidth == null ? null : column.controlWidth - 8 + 'px' }"
              :rows="column.controlHeight / 20"
              :maxlength="column.maxLength"
              :placeholder="column.description"
            />
          </template>
          <template v-else-if="column.controlType === 'NumberInput'">
            <Input
              type="number"
              size="small"
              number
              :value="parseData(rowData(row, index), column.code)"
              @input="$event => setData(rowData(row, index), column.code, $event)"
              :readonly="isReadonly(rowData(row, index), column)"
              :style="{ width: column.controlWidth == null ? null : column.controlWidth - 8 + 'px' }"
              :placeholder="column.description"
              @on-change="onDataChange(rowData(row, index), column)"
              @on-blur="onBlur(rowData(row, index), column)"
            />
          </template>
          <template v-else-if="column.controlType === 'Select'">
            <Select
              size="small"
              :value="parseData(rowData(row, index), column.code)"
              @input="$event => setData(rowData(row, index), column.code, $event)"
              :disabled="isReadonly(rowData(row, index), column)"
              clearable
              :style="{ width: column.controlWidth == null ? null : column.controlWidth - 8 + 'px' }"
              :placeholder="column.description"
              :transfer="true"
              @on-change="selected => onSelectDataChange(rowData(row, index), column, selected)"
            >
              <Option v-for="item in getDataSource(rowData(row, index), column)" :key="item.id" :value="item.id">{{ item.name }}</Option>
            </Select>
          </template>
          <template v-else-if="column.controlType === 'MultiSelect'">
            <Select
              size="small"
              :value="parseArrayData(rowData(row, index), column.code)"
              @input="$event => setArrayData(rowData(row, index), column.code, $event)"
              :disabled="isReadonly(rowData(row, index), column)"
              :multiple="true"
              clearable
              :style="{ width: column.controlWidth == null ? null : column.controlWidth - 8 + 'px' }"
              :placeholder="column.description"
              :transfer="true"
              @on-change="selected => onSelectDataChange(rowData(row, index), column, selected)"
            >
              <Option v-for="item in getDataSource(rowData(row, index), column)" :key="item.id" :value="item.id">{{ item.name }}</Option>
            </Select>
          </template>
          <template v-else-if="column.controlType === 'ComboSelect'">
            <Select
              size="small"
              :value="parseData(rowData(row, index), column.code)"
              @input="$event => setData(rowData(row, index), column.code, $event)"
              :disabled="isReadonly(rowData(row, index), column)"
              clearable
              filterable
              :style="{ width: column.controlWidth == null ? null : column.controlWidth - 8 + 'px' }"
              :placeholder="column.description"
              :transfer="true"
              @on-change="selected => onSelectDataChange(rowData(row, index), column, selected)"
            >
              <Option v-for="item in getDataSource(rowData(row, index), column)" :key="item.id" :value="item.id">{{ item.name }}</Option>
            </Select>
          </template>
          <template v-else-if="column.controlType === 'DialogSelect'">
            <dialog-select
              :value="parseData(rowData(row, index), column.code)"
              size="small"
              @input="$event => setData(rowData(row, index), column.code, $event)"
              :readonly="isReadonly(rowData(row, index), column)"
              :source="column.source"
              :source-data-code="column.sourceDataCode"
              :source-display-code="column.sourceDisplayCode"
              :param="getParam(rowData(row, index), column)"
              :controlWidth="column.controlWidth == null ? null : column.controlWidth - 8"
              @on-change="selected => onSelectDataChange(rowData(row, index), column, selected)"
            ></dialog-select>
          </template>
          <template v-else-if="column.controlType === 'MultiDialogSelect'">
            <dialog-select
              :value="parseData(rowData(row, index), column.code)"
              size="small"
              @input="$event => setData(rowData(row, index), column.code, $event)"
              :multi="true"
              :readonly="isReadonly(rowData(row, index), column)"
              :source="column.source"
              :source-data-code="column.sourceDataCode"
              :source-display-code="column.sourceDisplayCode"
              :param="getParam(rowData(row, index), column)"
              :controlWidth="column.controlWidth == null ? null : column.controlWidth - 8"
              @on-change="selected => onSelectDataChange(rowData(row, index), column, selected)"
            ></dialog-select>
          </template>
          <template v-else-if="column.controlType === 'Date' || column.controlType === 'DateTime' || column.controlType === 'Year' || column.controlType === 'Month'">
            <DatePicker
              size="small"
              :type="column.controlType.toLowerCase()"
              :value="parseDateTimeData(rowData(row, index), column.code)"
              @input="$event => setData(rowData(row, index), column.code, $event)"
              :readonly="isReadonly(rowData(row, index), column)"
              :placeholder="column.description"
              :style="{ width: column.controlWidth == null ? null : column.controlWidth - 8 + 'px' }"
              :transfer="true"
              @on-change="
                time => {
                  setData(rowData(row, index), column.code, time);
                  onDataChange(rowData(row, index), column);
                }
              "
            ></DatePicker>
          </template>
          <template v-else-if="column.controlType === 'DateRange'">
            <DatePicker
              size="small"
              :type="column.controlType.toLowerCase()"
              :value="parseDateRangeData(rowData(row, index), column.code)"
              @input="$event => setArrayData(rowData(row, index), column.code, $event)"
              :readonly="isReadonly(rowData(row, index), column)"
              :placeholder="column.description"
              :style="{ width: column.controlWidth == null ? null : column.controlWidth - 8 + 'px' }"
              :transfer="true"
              @on-change="onDataChange(rowData(row, index), column)"
            ></DatePicker>
          </template>
          <template v-else-if="column.controlType === 'Time'">
            <TimePicker
              size="small"
              type="time"
              :value="parseDateTimeData(rowData(row, index), column.code)"
              @input="$event => setData(rowData(row, index), column.code, $event)"
              :readonly="isReadonly(rowData(row, index), column)"
              :placeholder="column.description"
              :style="{ width: column.controlWidth == null ? null : column.controlWidth - 8 + 'px' }"
              :transfer="true"
              @on-change="onDataChange(rowData(row, index), column)"
            ></TimePicker>
          </template>
          <template v-else-if="column.controlType === 'Check'">
            <Checkbox
              :value="!!parseData(rowData(row, index), column.code)"
              @input="$event => setData(rowData(row, index), column.code, $event)"
              :disabled="isReadonly(rowData(row, index), column)"
              @on-change="onDataChange(rowData(row, index), column)"
            />
          </template>
          <template v-else-if="column.controlType === 'Switch'">
            <Switch
              :value="!!parseData(rowData(row, index), column.code)"
              @input="$event => setData(rowData(row, index), column.code, $event)"
              :disabled="isReadonly(rowData(row, index), column)"
              @on-change="onDataChange(rowData(row, index), column)"
            />
          </template>
          <template v-else-if="column.controlType === 'Radio'">
            <RadioGroup
              :value="parseData(rowData(row, index), column.code)"
              @input="$event => setData(rowData(row, index), column.code, $event)"
              @on-change="selected => onSelectDataChange(rowData(row, index), column, selected)"
            >
              <Radio v-for="item in getDataSource(rowData(row, index), column)" :key="item.id" :label="item.id" :disabled="isReadonly(rowData(row, index), column)">
                <span>{{ item.name }}</span>
              </Radio>
            </RadioGroup>
          </template>
          <template v-else-if="column.controlType === 'CheckGroup'">
            <CheckboxGroup
              :value="parseArrayData(rowData(row, index), column.code)"
              @input="$event => setArrayData(rowData(row, index), column.code, $event)"
              @on-change="onDataChange(rowData(row, index), column)"
            >
              <Checkbox v-for="item in getDataSource(rowData(row, index), column)" :key="item.id" :label="item.id" :disabled="isReadonly(rowData(row, index), column)">
                <span>{{ item.name }}</span>
              </Checkbox>
            </CheckboxGroup>
          </template>
          <template v-else-if="column.controlType === 'Attachment'">
            <!-- <upload-attachment
              v-if="!readonly && !column.isReadonly"
              size="small"
              :value="parseData(rowData(row, index), column.code)"
              @input="$event => setData(rowData(row, index), column.code, $event)"
              :maxCount="column.maxLength"
              :accept="column.pattern"
            /> -->
            <template v-if="!!(parseData(rowData(row, index), column.code) || '').trim()">
              <a :href="getAttachmentUrl(attachment.file, attachment.name)" :key="attachmentIndex" v-for="(attachment, attachmentIndex) in JSON.parse(parseData(row, column.code))">
                <span style="margin: auto 4px">
                  <Icon type="ios-document" />
                  {{ attachment.name }}
                </span>
              </a>
            </template>
          </template>
          <template v-else-if="column.controlType === 'Image'">
            <div class="image-group" :style="{ 'justify-content': column.align ? column.align.toLowerCase() : 'center' }">
              <div class="image" v-for="(item, index) in parseData(row, column.code).split(',')" :key="index">
                <img v-if="item" @click="previewImage(item)" :src="getImgUrl(item)" />
              </div>
            </div>
          </template>
          <template v-else-if="column.controlType === 'Slider'">
            <Slider
              :value="parseData(rowData(row, index), column.code)"
              @input="$event => setData(rowData(row, index), column.code, $event)"
              show-input
              :style="{ width: column.controlWidth == null ? null : column.controlWidth - 8 + 'px' }"
              :max="column.MaxValue"
              :min="column.MinValue"
            />
            <Slider
              v-if="!readonly && !column.isReadonly"
              :value="parseData(rowData(row, index), column.code)"
              @input="$event => setData(rowData(row, index), column.code, $event)"
              show-input
              :style="{ width: column.controlWidth == null ? null : column.controlWidth - 8 + 'px' }"
              :max="column.maxValue"
              :min="column.minValue"
            />
            <Input
              v-if="isReadonly(rowData(row, index), column)"
              type="number"
              number
              readonly
              :value="parseData(rowData(row, index), column.code)"
              :style="{ width: column.controlWidth == null ? '100px' : column.controlWidth + 'px' }"
              :placeholder="column.description"
            />
          </template>
          <template v-else-if="column.controlType === 'Placeholder'"></template>
          <template v-else>{{ $t('Front_Label_Control_Type_Not_Supported') }} {{ column.controlType }}</template>
        </template>
        <div slot-scope="{ row, index }" slot="command">
          <!--
              @slot 工具栏（编辑按钮前）
              @binding {object} row 行对象
              @binding {int} index 行序号
          -->
          <slot name="commandBefore" :row="rowData(row, index)" :index="index"></slot>
          <Button
            v-if="judge(tableView.editEnable, tableView.editEnableJson, rowData(row, index)) && editEnable && !readonly"
            size="small"
            :title="$t('Front_Btn_Edit')"
            type="primary"
            custom-icon="fa fa-edit"
            @click="edit(rowData(row, index), index)"
          ></Button>
          <Button
            v-if="judge(tableView.removeEnable, tableView.removeEnableJson, rowData(row, index)) && removeEnable && !readonly"
            size="small"
            :title="$t('Front_Btn_Remove')"
            type="warning"
            custom-icon="fa fa-trash-alt"
            @click="remove(rowData(row, index), index)"
          ></Button>
          <Button
            v-if="static && tableView.adjustEnable && !readonly"
            size="small"
            :title="$t('Front_Btn_Up')"
            type="primary"
            custom-icon="fa fa-chevron-up"
            @click="up(rowData(row, index), index)"
          ></Button>
          <Button
            v-if="static && tableView.adjustEnable && !readonly"
            size="small"
            :title="$t('Front_Btn_Down')"
            type="primary"
            custom-icon="fa fa-chevron-down"
            @click="down(rowData(row, index), index)"
          ></Button>
          <Button
            v-for="(item, index) in commandButtons"
            :key="index"
            size="small"
            :title="item.title"
            type="info"
            :custom-icon="item.icon"
            @click="clickCommandButton(row, item)"
          ></Button>
          <!--
              @slot 工具栏
              @binding {object} row 行对象
              @binding {int} index 行序号
          -->
          <slot name="command" :row="rowData(row, index)" :index="index"></slot>
        </div>
        <div slot-scope="{ index }" slot="sn">
          {{ size * (current - 1) + index + 1 }}
        </div>
      </Table>
      <div class="ivu-mt ivu-text-right">
        <Button
          class="ivu-fr"
          type="error"
          :title="$t('Front_Btn_Setting')"
          custom-icon="fa fa-cog"
          v-if="settingEnable && allow('permission/tableView')"
          @click="tableSettingOpen"
        ></Button>
        <Page
          show-sizer
          show-total
          :current.sync="current"
          :page-size="size"
          :page-size-opts="pageSizeOpts == null ? [10, 20, 50, 100] : pageSizeOpts"
          :total="total"
          v-if="tableView.pageEnable && pageEnable"
          @on-change="loadData()"
          @on-page-size-change="pageSizeChange"
        />
      </div>
      <modal-table ref="dialogTable" v-if="dialogActive">
        <template slot-scope="{ row }" slot="command">
          <Button size="small" :title="$t('Front_Btn_Select')" type="primary" custom-icon="fa fa-check-square-o" @click="dialogCheck(row)"></Button>
        </template>
      </modal-table>
      <table-setting ref="tableSetting" v-if="tableSettingActive" :is-setting="true" @on-change="viewCode => init(viewCode)" />
      <filter-setting ref="filterSetting" v-if="filterSettingActive" @on-change="viewCode => init(viewCode)" />
      <item-select ref="itemSelect" v-if="itemSelectActive" @save="saveItemSelect"></item-select>
      <modal-table ref="modalTable" v-if="inited"></modal-table>
      <modal-form ref="modalForm" :saveEnable="false" v-if="inited"></modal-form>
      <modal-table ref="batchEditTable" :embedded="true" :static="true" :footerEnable="true" v-if="inited">
        <template slot="footer">
          <Button type="primary" custom-icon="fa fa-save" @click="batchSave()">{{ $t('Front_Btn_Save') }}</Button>
          <Button type="default" custom-icon="fa fa-times" @click="$refs.batchEditTable.close()">{{ $t('Front_Btn_Close') }}</Button>
        </template>
      </modal-table>
      <Modal
        :title="$t('Front_Label_Preview')"
        v-model="preview"
        scrollable
        :mask-closable="layout.maskClosable"
        :draggable="layout.draggable"
        :sticky="true"
        :reset-drag-position="true"
        width="70%"
      >
        <div style="text-align: center">
          <a href="#" :download="imageUrl" onClick="return false;">
            <img :src="getImgUrl(imageUrl)" v-if="preview" style="max-width: 100%" />
          </a>
        </div>
        <template slot="footer">
          <Button type="default" custom-icon="fa fa-times" @click="preview = false">{{ $t('Front_Btn_Close') }}</Button>
        </template>
      </Modal>
    </div>
  </div>
</template>
<script>
  import { mapActions } from 'vuex';
  import modelApi from '../../api/model';
  import customModelApi from '../../api/customModel';
  import dataSourceApi from '../../api/dataSource';
  import dataViewApi from '../../api/dataView';
  import mixinPage from '../../mixins/page';
  import mixin from './mixin';
  import tableSetting from './table-setting';
  import filterSetting from './filter-setting';
  import tableFilter from './table-filter';
  import dateFormat from 'date-fns/format';

  var getColumns = (view, item) => {
    let children = view.viewColumns.filter(i => {
      return i.parentCode == item.code;
    });

    if (children.length > 0) {
      // 合并单元格表头
      return {
        ...item,
        title: item.name,
        renderHeader: (h, params) => {
          return h('span', {
            domProps: {
              innerHTML: params.column.name.replace('|', '<br/>')
            }
          });
        },
        key: item.code,
        align: item.align ? item.align.toLowerCase() : 'center',
        children:
          children.length > 0
            ? children.map(item => {
                return getColumns(view, item);
              })
            : null
      };
    } else {
      // 普通单元格
      return {
        ...item,
        title: item.name,
        renderHeader: (h, params) => {
          return h('span', {
            domProps: {
              innerHTML: params.column.name.replace('|', '<br/>')
            }
          });
        },
        // tree: this.treeEnable && index == 0, // 需要树展开，给第一列添加展开按钮
        key: item.code,
        dataType: item.dataType,
        format: item.displayFormat,
        width: item.controlWidth,
        minWidth: 100,
        align: item.align ? item.align.toLowerCase() : 'center',
        sortable: !view.dataView.sortDisable && !item.sortDisable ? 'custom' : false,
        resizable: true,
        slot: 'normal'
      };
    }
  };

  /**
   * @displayName view-table 表格视图
   */
  export default {
    mixins: [mixin, mixinPage],
    components: { tableFilter, tableSetting, filterSetting },
    data() {
      return {
        inited: false,
        size: 10,
        orderBy: null,
        tableView: {},
        columns: [],
        viewFilter: {},
        filterColumns: [],
        data: [],
        staticData: [],
        selectedData: [],
        current: 1,
        total: 0,
        //setting: false,
        dialogActive: false,
        tableSettingActive: false,
        filterSettingActive: false,
        itemSelectActive: false,
        commandButtons: [],
        preview: false,
        imageUrl: null,
        isFullScreen: false
      };
    },
    async created() {
      // 默认视图代码
      if (this.viewCode) {
        // 初始化
        setTimeout(async () => {
          await this.init(this.viewCode);
          /**
           * 初始化完成事件
           */
          this.$emit('after-init');
        });
      }

      if (this.viewCode && this.autoLoad) {
        this.loadData();
      }
    },
    activated() {
      if (this.viewCode && this.autoLoad) {
        this.loadData();
      }
    },
    props: {
      /**
       * 标题
       */
      title: {
        type: String
      },
      /**
       * 视图代码
       */
      viewCode: {
        type: String
      },
      /**
       * 只读
       */
      readonly: {
        type: Boolean,
        default: false
      },
      /**
       * 是否内嵌表格
       */
      embedded: {
        type: Boolean,
        default: false
      },
      /**
       * 内嵌表格的父对象
       */
      parentData: {
        type: Object,
        default() {
          return {};
        }
      },
      /**
       * 是否静态数据
       */
      static: {
        type: Boolean,
        default: false
      },
      /**
       * 筛选
       */
      filter: {
        type: Object,
        default() {
          return {};
        }
      },
      /**
       * 是否允许配置界面
       */
      settingEnable: {
        type: Boolean,
        default: true
      },
      /**
       * 自动加载
       */
      autoLoad: {
        type: Boolean,
        default: true
      },
      /**
       * 是否允许选择
       */
      selectEnable: {
        type: Boolean,
        default: false
      },
      /**
       * 是否跨页选择
       */
      checkCrossPage: {
        type: Boolean,
        default: false
      },
      /**
       * 是否允许树展开
       */
      treeEnable: {
        type: Boolean,
        default: false
      },
      /**
       * 树展开动作
       */
      treeLoad: {
        type: Function
      },
      /**
       * 树包含子项
       */
      hasChildren: {
        type: Function
      },
      /**
       * 高度
       */
      height: {
        type: Number,
        default: null
      },
      /**
       * 允许创建
       */
      createEnable: {
        type: Boolean,
        default: true
      },
      /**
       * 允许编辑
       */
      editEnable: {
        type: Boolean,
        default: true
      },
      /**
       * 允许删除
       */
      removeEnable: {
        type: Boolean,
        default: true
      },
      /**
       * 允许拖动
       */
      draggable: {
        type: Boolean,
        default: false
      },
      /**
       * 允许筛选栏
       */
      filterEnable: {
        type: Boolean,
        default: true
      },
      /**
       * 允许分页
       */
      pageEnable: {
        type: Boolean,
        default: true
      },
      /**
       * 禁用筛选
       */
      filterDisable: {
        type: Boolean,
        default: false
      },
      /**
       * 加载数据前
       */
      beforeLoadData: {
        type: Function
      },
      /**
       * 查询方法
       */
      onSearch: {
        type: Function
      },
      /**
       * 合计方法
       */
      summaryMethod: {
        type: Function
      },
      /**
       * 每页条数切换的配置
       */
      pageSizeOpts: {
        type: Array
      },
      /**
       * 合并单元格的配置
       */
      spanMethod: {
        type: Function
      }
    },
    computed: {
      // 表格最大高度，固定表头
      maxHeight() {
        if (this.height == null) {
          if (this.isFullScreen) {
            return document.body.offsetHeight - 100 - this.$refs.filterCommand.offsetHeight;
          } else {
            return document.body.offsetHeight - 300;
          }
        } else {
          return this.height;
        }
      }
    },
    watch: {
      // value() {
      //     if (this.embedded) {
      //         this.loadData(this.value);
      //     }
      //     //this.changed = false;
      // }
      // staticData() {
      //     // 设置选中项
      //     if (typeof this.selectFunc === 'function') {
      //         let selected = this.staticData.filter(this.selectFunc);
      //         this.setSelected(selected);
      //     }
      // }
    },
    methods: {
      ...mapActions('admin/dataView', { loadDataView: 'load' }),
      /**
       * 初始化
       *
       * @param {string} viewCode 视图代码
       * @param {function} callback 完成后回调方法
       * @param {function} onFail 失败后回调方法
       * @public
       */
      async init(viewCode, callback, onFail) {
        // 加载表格视图

        let view = await this.loadDataView(viewCode);

        if (view == null && viewCode.indexOf('_') >= 0) {
          view = await this.loadDataView(viewCode.split('_')[0]);
        }

        if (view == null) {
          if (typeof onFail === 'function') {
            onFail();
          } else {
            this.error('Front_Msg_View_Code_Not_Exist|' + viewCode);
          }
          return;
        }

        this.tableView = view.dataView;
        this.tableView.columns = view.viewColumns;
        this.tableView.filterColumns = view.filterColumns;
        this.filterColumns = view.filterColumns;

        // 操作栏按钮
        if (!!(this.tableView.commandButton || '').trim()) {
          this.commandButtons = JSON.parse(this.tableView.commandButton);
        } else {
          this.commandButtons = [];
        }

        /**
         * 视图获取完成事件
         * @property {object} tableView 表格视图
         */
        this.$emit('on-ready', this.tableView);

        this.columns = view.viewColumns
          .filter(item => {
            return !(item.parentCode || '').trim();
          })
          .map(item => {
            return getColumns(view, item);
          });

        this.columns.forEach(column => {
          column.name = this.getNameI18n(column);
        });

        if (this.tableView.snEnable) {
          this.columns.unshift({
            title: this.$t('Front_Label_Sn'),
            slot: 'sn',
            align: 'center',
            width: 60
          });
        }

        if (this.tableView.commandEnable) {
          let column = {
            title: ' ',
            slot: 'command',
            align: 'center',
            width: this.embedded && !this.tableView.commandWidth ? 60 : this.tableView.commandWidth == null ? 90 : (this.tableView.commandWidth + 1) * 30,
            fixed: 'right'
          };

          if (this.embedded && this.tableView.batchSelectEnable && this.createEnable && !this.readonly) {
            column.renderHeader = h => {
              return h('div', [
                h('Button', {
                  style: {
                    height: '20px',
                    width: '20px'
                  },
                  props: {
                    type: 'primary',
                    shape: 'circle',
                    icon: 'md-checkmark-circle-outline',
                    size: 'small'
                  },
                  on: {
                    click: () => {
                      this.openSelectItem();
                    }
                  }
                })
              ]);
            };

            this.itemSelectActive = true;

            setTimeout(() => {
              this.$refs.itemSelect.init(this.tableView.batchSelectDataModel + 'Source', this.tableView.batchSelectDataModel + 'Target');
            });
          } else if (this.embedded && this.tableView.createEnable && this.createEnable && !this.readonly) {
            column.renderHeader = h => {
              return h('div', [
                h('Button', {
                  style: {
                    height: '20px',
                    width: '20px'
                  },
                  props: {
                    type: 'primary',
                    shape: 'circle',
                    icon: 'md-add',
                    size: 'small'
                  },
                  on: {
                    click: () => {
                      this.addNew();
                    }
                  }
                })
              ]);
            };
          }

          this.columns.push(column);
        }

        if (this.selectEnable || this.tableView.checkEnable) {
          this.columns.unshift({
            type: 'selection',
            align: 'center',
            width: 60
          });
        }
        if (this.treeEnable) {
          this.columns.unshift({
            tree: true,
            display: 'inline',
            align: 'left',
            width: 100
          });
        }

        // 默认每页数据量
        if (this.tableView.size) {
          this.size = this.tableView.size;
        } else if (this.tableView.pageEnable && this.pageEnable) {
          this.size = 10;
        } else {
          this.size = 1000;
        }

        if (this.tableView.sorting) {
          // 排序
          let obj = JSON.parse(this.tableView.sorting);
          let arr = [];
          for (let key in obj) {
            if (obj[key] === 'desc') {
              arr.push('-' + key);
            } else {
              arr.push('+' + key);
            }
          }

          this.orderBy = arr.join(',');
        } else {
          this.orderBy = null;
        }

        if (this.tableView.filtering) {
          // 排序
          let obj = JSON.parse(this.tableView.filtering);
          for (let key in obj) {
            this.viewFilter[key] = obj[key];
          }
        } else {
          this.viewFilter = {};
        }

        if (this.tableView.keywordEnable && !!(this.tableView.keywordColumn || '').trim()) {
          this.viewFilter['keywordColumns'] = this.tableView.keywordColumn;
        } else {
          this.viewFilter['keywordColumns'] = null;
        }

        // 清空数据
        // if (this.static) {
        //     this.staticData = [];
        //     this.data = [];
        // }

        // 清空选择项
        this.selectedData = [];

        this.inited = true;

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

        setTimeout(() => {
          if (typeof callback === 'function') {
            callback();
          }
        });
      },
      /**
       * 加载数据
       *
       * @param {array} staticData 静态数据
       * @public
       */
      async loadData(staticData) {
        if (!this.inited) {
          await this.init(this.viewCode);

          if (!this.inited) {
            return;
          }
        }

        // 加载前动作
        if (typeof this.beforeLoadData == 'function') {
          this.beforeLoadData();
        }

        if (staticData) {
          this.staticData = this.copy(staticData);
        }

        if (this.static) {
          // 筛选和排序
          let data = this.getFilterResult();

          this.total = data.length;

          let offset = (this.current - 1) * this.size;
          this.data = offset + this.size >= data.length ? data.slice(offset, data.length) : data.slice(offset, offset + this.size);
        } else {
          let data = {
            ...this.getAllFilter(),
            page: this.current,
            per: this.size,
            orderBy: this.orderBy
          };

          if (this.tableView.isGroupBy) {
            data.isGroupBy = true;
            data.groupColumn = JSON.parse(this.tableView.groupColumn);
            data.groupMethod = JSON.parse(this.tableView.groupMethod);
          }

          if (this.tableView.isCustom) {
            let res = await customModelApi.query(this.tableView.model, data);

            this.total = res.totalCount;
            this.data = res.data;
          } else if (this.tableView.isDataSource) {
            let res = await dataSourceApi.query(this.tableView.dataSource, data);

            this.total = res.totalCount;
            this.data = res.table;
          } else {
            let res = await modelApi.query(this.tableView.model, data, this.tableView.functionName, this.tableView.functionType);

            this.total = res.totalCount;
            this.data = res.data;
          }

          // 如果超出页码，设为最后一页
          if (this.current > Math.ceil(this.total / this.size)) {
            this.current = Math.ceil(this.total / this.size);
          }

          // 最小为第一页
          if (this.current <= 0) {
            this.current = 1;
          }

          if (this.checkCrossPage || this.tableView.checkCrossPage) {
            // 跨页选择，设置选中项
            this.data.forEach(item => {
              item._checked = this.selectedData.some(i => {
                return item.id === i.id;
              });
            });
          } else {
            // 非跨页选择，清空选择项
            this.selectedData = [];
          }

          // if (typeof this.selectFunc === 'function') {
          //     let selected = this.data.filter(this.selectFunc);
          //     this.setSelected(selected);
          // }
        }

        // 设置数据的可见性和只读属性
        this.data.forEach(item => {
          this.setShowStatus(item);
        });

        // 如果这行数据有子集，需要添加展开加载方法
        if (this.treeEnable) {
          this.data.forEach(item => {
            if (this.hasChildren == null || this.hasChildren(item)) {
              item._loading = false;
              item.children = [];
            }
          });

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

        // 加载数据源
        this.initDataSource();

        // 重新计算公式
        for (let i = 0; i < this.data.length; i++) {
          this.calc(this.data[i]);
        }

        /**
         * 数据加载事件
         */
        this.$emit('on-load-data');

        // 刷新表头控件
        if (this.$refs.tableFilter) {
          this.$refs.tableFilter.$forceUpdate();
        }
      },
      /**
       * 创建新项
       *
       * @public
       */
      create() {
        /**
         * 创建事件
         */
        this.$emit('create');
      },
      /**
       * 编辑项
       *
       * @param {object} row 行对象
       * @param {int} index 行序号
       * @public
       */
      edit(row, index) {
        /**
         * 编辑事件
         * @property {object} args { row 行对象, index 行序号 }
         */
        this.$emit('edit', { row, index });
      },
      /**
       * 删除项
       *
       * @param {object} row 行对象
       * @param {int} index 行序号
       * @public
       */
      remove(row, index) {
        this.confirm('Front_Msg_Sure_To_Delete_Item', async () => {
          if (this.embedded) {
            this.staticData.splice((this.current - 1) * this.size + index, 1);
            if (row.id) {
              let i = this.selectedData.findIndex(item => item.id == row.id);
              this.selectedData.splice(i, 1);
            }

            this.loadData();

            /**
             * 数据变化事件
             * @property {object} data 行对象
             */
            this.$emit('on-change', row);
          } else {
            if (this.tableView.isCustom) {
              await customModelApi.remove(this.tableView.model, row.id);
            } else {
              await modelApi.remove(this.tableView.model, row.id);
            }

            this.success('Front_Msg_Success', () => {
              if (row.id) {
                let i = this.selectedData.findIndex(item => item.id == row.id);
                this.selectedData.splice(i, 1);
              }
              this.loadData();
            });
          }
        });
      },
      /**
       * 获取默认值
       *
       * @public
       */
      getDefaultData() {
        let data = {};
        this.columns.forEach(item => {
          if (item.defaultValue) {
            if (item.defaultValue == '{today}') {
              // 当前日期
              let date = new Date();
              let value = date.toISOString().replace(/T.*/, '');
              this.setData(data, item.code, new Date(value));
            } else if (item.defaultValue.startsWith('{today(') && item.defaultValue.endsWith(')}')) {
              // 当前时间转字符串
              let format = item.defaultValue.substr(7, item.defaultValue.length - 9);
              this.setData(data, item.code, dateFormat(new Date(), format));
            } else if (item.defaultValue == '{currentUserID}') {
              // 当前用户编号
              this.setData(data, item.code, this.info.id);
            } else if (item.defaultValue == '{currentUser}') {
              // 当前用户姓名
              this.setData(data, item.code, this.info.name);
            } else {
              if (item.dataType === 'Integer') {
                this.setData(data, item.code, parseInt(item.defaultValue));
              } else if (item.dataType === 'Decimal') {
                this.setData(data, item.code, parseFloat(item.defaultValue));
              } else if (item.dataType === 'Boolean' && item.defaultValue.toUpperCase == 'TRUE') {
                this.setData(data, item.code, true);
              } else if (item.dataType === 'Boolean' && item.defaultValue.toUpperCase == 'FALSE') {
                this.setData(data, item.code, false);
              } else {
                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);
            }
          }
        });

        return data;
      },
      /**
       * 添加新行
       *
       * @public
       */
      addNew() {
        this.staticData.push(this.getDefaultData());
        this.loadData();
      },
      /**
       * 获取选中项
       *
       * @public
       */
      getSelected() {
        return this.selectedData;
      },
      /**
       * 设置选中项
       *
       * @param {object} selected 选中项
       * @public
       */
      setSelected(selected) {
        this.selectedData = [];
        selected.forEach(item => {
          this.selectedData.push(item);
        });

        if (this.static) {
          this.staticData.forEach(item => {
            item._checked = this.selectedData.some(i => {
              return item.id === i.id;
            });
          });

          this.loadData();
        } else {
          this.data.forEach(item => {
            item._checked = this.selectedData.some(i => {
              return item.id === i.id;
            });
          });
        }

        //this.$forceUpdate();

        this.data = this.copy(this.data);
      },
      /**
       * 必填验证
       *
       * @public
       */
      validate() {
        for (let i = 0; i < this.staticData.length; i++) {
          let row = this.staticData[i];

          for (let j = 0; j < this.columns.length; j++) {
            let column = this.columns[j];

            // 不显示的不验证
            if (row._isShow && row._isShow[column.code] == false) {
              continue;
            } else if (!column.isShow) {
              continue;
            }

            let isRequired = column.isRequired;

            // 动态判断是否必填
            if (!!(column.requiredJson || '').trim()) {
              let setting = JSON.parse(column.requiredJson);

              if (setting.type == 'Condition' || setting.type == 'Expression') {
                isRequired = this.judgeCondition(setting, row);
              }
            }

            if (isRequired) {
              let value = this.parseData(row, column.code);

              if (value == null || !(String(value) || '').trim()) {
                this.error('Front_Msg_Row_Column_Required|' + (i + 1) + '|' + column.name);
                return false;
              }
            }
          }
        }

        return true;
      },
      /**
       * 获取数据
       *
       * @public
       */
      getData() {
        let data = null;
        if (this.static) {
          data = this.copy(this.staticData);
        } else {
          data = this.copy(this.data);
        }

        data.forEach(item => {
          delete item._checked;
          delete item._dataSource;
          delete item._needRefresh;
          delete item._needClear;
          delete item._rawData;
        });

        return data;
      },
      /**
       * 重置筛选
       *
       * @public
       */
      resetFilter() {
        for (let key in this.filter) {
          delete this.filter[key];
        }

        this.$forceUpdate();
      },
      // 查询
      search() {
        if (typeof this.onSearch == 'function') {
          this.onSearch();
        } else {
          this.loadData();
        }
      },
      // 点击更多按钮
      async moreClick(name) {
        if (!this.inited) {
          await this.init(this.viewCode);

          if (!this.inited) {
            return;
          }
        }

        if (this.static) {
          if (name === 'exportExcel') {
            dataViewApi.exportExcel(
              this.tableView,
              this.staticData,
              this.columns.filter(item => {
                return item.slot == 'normal';
              })
            );
          } else if (name === 'exportPdf') {
            dataViewApi.exportPdf(
              this.tableView,
              this.staticData,
              this.columns.filter(item => {
                return item.slot == 'normal';
              })
            );
          } else if (name === 'print') {
            dataViewApi.print(
              this.tableView,
              this.staticData,
              this.columns.filter(item => {
                return item.slot == 'normal';
              })
            );
          } else if (name === 'batchEdit') {
            this.error('Front_Msg_Not_Supported');
          }
        } else {
          if (name === 'exportExcel') {
            this.exportExcel();
          } else if (name === 'exportPdf') {
            this.exportPdf();
          } else if (name === 'print') {
            this.print();
          } else if (name === 'batchEdit') {
            this.$refs.batchEditTable.init(this.tableView.batchEditView, async () => {
              let res;
              if (this.tableView.isCustom) {
                res = await customModelApi.query(this.tableView.model, {});
              } else {
                res = await modelApi.query(this.tableView.model, {});
              }
              this.$refs.batchEditTable.loadData(res.data);
              this.$refs.batchEditTable.open();
            });
          }
        }
      },
      // 导出Excel
      exportExcel() {
        let data = {
          ...this.getAllFilter(),
          orderBy: this.orderBy
        };

        if (this.tableView.isCustom) {
          customModelApi.exportExcel(this.tableView, data);
        } else if (this.tableView.isDataSource) {
          dataSourceApi.exportExcel(this.tableView, data);
        } else {
          modelApi.exportExcel(this.tableView, data);
        }
      },
      // 导出PDF
      exportPdf() {
        let data = {
          ...this.getAllFilter(),
          orderBy: this.orderBy
        };

        if (this.tableView.isCustom) {
          customModelApi.exportExcel(this.tableView, data);
        } else if (this.tableView.isDataSource) {
          dataSourceApi.exportPdf(this.tableView, data);
        } else {
          modelApi.exportPdf(this.tableView, data);
        }
      },
      // 打印
      print() {
        let data = {
          ...this.getAllFilter(),
          orderBy: this.orderBy
        };

        if (this.tableView.isCustom) {
          customModelApi.exportExcel(this.tableView, data);
        } else if (this.tableView.isDataSource) {
          dataSourceApi.printList(this.tableView, data);
        } else {
          modelApi.printList(this.tableView, data);
        }
      },
      // 加载数据源
      initDataSource() {
        this.columns.forEach(column => {
          if (
            column.controlType == 'Select' ||
            column.controlType == 'SelectWithOther' ||
            column.controlType == 'ComboSelect' ||
            column.controlType == 'MultiSelect' ||
            column.controlType == 'Radio' ||
            column.controlType == 'CheckGroup'
          ) {
            if (column.isStaticItem) {
              // 固定数据源
              this.data.forEach(row => {
                if (!row._dataSource) {
                  row._dataSource = {};
                  row._rawData = {};
                  row._needRefresh = {};
                  row._needClear = {};
                } else if (row._dataSource[column.code]) {
                  return;
                }

                row._dataSource[column.code] = [];
                row._rawData[column.code] = [];

                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];
                        row._dataSource[column.code].push({
                          id: key,
                          name: value
                        });
                      } else {
                        row._dataSource[column.code].push({
                          id: item,
                          name: item
                        });
                      }
                    }
                  });
                }
              });

              this.$forceUpdate();
            } else {
              if (!!(column.source || '').trim()) {
                this.data.forEach(row => {
                  if (row._dataSource && row._dataSource[column.code]) {
                    return;
                  }

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

                  // 选择框、单选框组
                  if (param != null) {
                    this.fillDataSource(row, column, param);
                  }
                });
              }
            }
          }
        });
      },
      // 初始化触发规则
      initTrigger() {
        // 触发规则
        this.columns.forEach(column => {
          column.triggers = [];
        });

        // 数据源中包含变量需要刷新
        this.columns
          .filter(column => {
            return !column.isStaticItem && !!(column.source || '').trim() && !!(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 || param[key].split('.')[0] + 'ID' == item.code;
                })
                .forEach(item => {
                  item.triggers.push(this.copy(column));
                });
            }
          });
      },
      // 填充数据源
      async fillDataSource(data, column, param) {
        if (!data._dataSource) {
          data._dataSource = {};
          data._rawData = {};
          data._needRefresh = {};
          data._needClear = {};
        }

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

        data._rawData[column.code] = res.data;

        data._dataSource[column.code] = 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));

            if (column.sourceDataCode == 'id' && column.code.length > 2) {
              let code = column.code.substr(0, column.code.length - 2);

              if (data._rawData && data._rawData[column.code]) {
                let model = data._rawData[column.code].find(item => {
                  return item.id == this.parseData(data, column.code);
                });

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

        // 更新data触发刷新
        this.data = this.data.map(item => {
          return item;
        });

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

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

      //     if (param != null) {
      //         if (!(keyword || '').trim() && this.parseData(data, column.code) != null) {
      //             param.id = this.parseData(data, column.code);
      //         } else {
      //             param.keyword = keyword;
      //         }
      //         param.per = 20;

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

      //         // 触发
      //         column.triggers.forEach(item => {
      //             item.needRefresh = true;
      //         });
      //     }
      // },
      // 每页数量切换
      pageSizeChange(size) {
        this.size = size;
        this.loadData();
      },
      // 排序切换
      sortChange({ key, order }) {
        let orderColumns = [];
        if (this.orderBy) {
          orderColumns = this.orderBy.split(',');
        }

        orderColumns = orderColumns.filter(item => {
          return item.substring(1) !== key;
        });

        // 添加排序字段
        if (order === 'asc') {
          orderColumns.unshift('+' + key);
        } else if (order === 'desc') {
          orderColumns.unshift('-' + key);
        }

        this.orderBy = orderColumns.join(',');

        this.loadData();
      },
      columnWidthResize(newWidth, oldWidth, column, event) {
        console.log('columnWidthResize', newWidth, oldWidth, column, event);
      },
      onSelectDataChange(data, 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 (data._rawData && data._rawData[sender.code]) {
                  model.push(
                    data._rawData[sender.code].find(rawData => {
                      return this.parseData(rawData, sender.sourceDataCode) == item;
                    })
                  );
                } else {
                  model.push(item);
                }
              }
            }
          } else {
            model = selected;
          }
        } else {
          if (data._rawData && data._rawData[sender.code]) {
            model = data._rawData[sender.code].find(rawData => {
              return this.parseData(rawData, sender.sourceDataCode) == selected;
            });
          } else {
            model = selected;
          }
        }

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

        this.onDataChange(data, sender, model);
      },
      // 数据变化事件
      onDataChange(data, sender, selected) {
        this.setShowStatus(data);

        this.$forceUpdate();

        /**
         * 数据变化事件
         * @property {object} data 行对象
         * @property {object} sender 触发的列对象
         * @property {object} selected 选中对象（弹出选择框等有效）
         */
        this.$emit('on-change', data, sender, selected);

        // 公式计算
        this.calc(data, sender);

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

        // 刷新数据源
        while (true) {
          let column = this.columns.filter(item => {
            return (data._needRefresh && data._needRefresh[item.code] == true) || (data._needClear && data._needClear[item.code] == true);
          })[0];

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

          // 重新加载数据源
          if (data._needClear[column.code] && this.parseData(data, column.code) != null) {
            this.setData(data, column.code, null);
            // 触发
            column.triggers.forEach(item => {
              data._needClear[item.code] = true;
            });
          } else if (data._needRefresh[column.code] && !!(column.source || '').trim()) {
            let param = this.getParam(data, column, this.parentData);

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

                // 触发
                column.triggers.forEach(item => {
                  data._needClear[item.code] = true;
                });
              }
            }
          }

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

          data._needClear[column.code] = false;
          data._needRefresh[column.code] = false;
        }
      },
      // 公式计算
      calc(data, sender) {
        for (let i = 0; i < this.columns.length; i++) {
          let column = this.columns[i];
          if (!!(column.calculate || '').trim()) {
            let triggers = this.getTriggers(column.calculate);
            if (!sender || triggers.some(item => item == sender.code)) {
              // 包含在公式中，需要刷新
              let result = this.calculate(column.calculate, data);

              // 保留小数
              if (column.digit != null) {
                result = this.keepDecimal(result, column.digit, column.fixedDigit);
              }

              this.setData(data, column.code, result);
            }
          }
        }
      },
      // 输入框失去焦点事件
      onBlur(data, sender) {
        /**
         * 数据变化事件
         * @property {object} data 行对象
         * @property {object} sender 触发的列对象
         */
        this.$emit('on-blur', data, sender);
      },
      // 打开表格设置界面
      tableSettingOpen() {
        this.tableSettingActive = true;

        setTimeout(() => {
          this.$refs.tableSetting.open(this.tableView, this.copy(this.tableView.columns));
        });
      },
      // 打开筛选设置界面
      filterSettingOpen() {
        this.filterSettingActive = true;

        setTimeout(() => {
          this.$refs.filterSetting.open(this.tableView, this.copy(this.tableView.filterColumns));
        });
      },
      // 选中变化
      onSelectionChange(selection) {
        // 当页所有数据
        let allData = this.getDataWithChildren(this.data);

        allData.forEach(item => {
          const index = this.selectedData.findIndex(i => {
            return i.id == item.id;
          });

          if (selection.some(i => i.id == item.id)) {
            // 选中
            if (index == -1) {
              this.selectedData.push(item);
            }
          } else {
            // 未选中， 剔除

            if (index != -1) {
              this.selectedData.splice(index, 1);
            }
          }
        });

        /**
         * 选中项变化事件
         */
        this.$emit('on-select-change');
      },
      // 键盘事件
      onKeyup(e) {
        if (e) {
          var keycode = window.event ? e.keyCode : e.which;

          if (!keycode) {
            return;
          }

          if (keycode !== 0 && keycode !== 1 && keycode !== 13) {
            return;
          }
        }

        this.search();
      },
      // 合并后最终的筛选项
      getAllFilter() {
        let filter = {
          ...this.viewFilter,
          ...this.filter
        };

        for (let key in filter) {
          if (typeof filter[key] == 'object' && !(filter[key] instanceof Date)) {
            delete filter[key];
          }
        }

        return filter;
      },
      // 静态数据筛选
      getFilterResult() {
        let data = this.staticData;

        if (!this.filterDisable) {
          let filter = this.filter;

          for (let key in filter) {
            let column = key;
            let value = filter[key];
            if (value == null || value == '') {
              continue;
            }

            if (column == 'keywordColumns') {
              continue;
            }

            data = data.filter(item => {
              if (column.startsWith('d_')) {
                column = column.substr(2);
              } else if (column.startsWith('m_')) {
                column = column.substr(2);
              } else if (column.startsWith('y_')) {
                column = column.substr(2);
              }

              if (column == 'keyword') {
                // 关键词
                let columns = filter['keywordColumns'].split(',');

                for (let i = 0; i < columns.length; i++) {
                  let c = columns[i];

                  if (this.parseData(item, c) != null && this.parseData(item, c).indexOf(value) >= 0) {
                    return true;
                  }
                }

                return false;
              } else if (column.endsWith('_g')) {
                // 大于
                let c = column.substr(0, column.length - 2);
                if (value instanceof Date) {
                  return new Date(this.parseData(item, c)) > value;
                } else {
                  return this.parseData(item, c) > value;
                }
              } else if (column.endsWith('_l')) {
                // 小于
                let c = column.substr(0, column.length - 2);
                if (value instanceof Date) {
                  return new Date(this.parseData(item, c)) < value;
                } else {
                  return this.parseData(item, c) < value;
                }
              } else if (column.endsWith('_ge')) {
                // 大于等于
                let c = column.substr(0, column.length - 3);
                if (value instanceof Date) {
                  return new Date(this.parseData(item, c)) >= value;
                } else {
                  return this.parseData(item, c) >= value;
                }
              } else if (column.endsWith('_le')) {
                // 小于等于
                let c = column.substr(0, column.length - 3);
                if (value instanceof Date) {
                  return new Date(this.parseData(item, c)) <= value;
                } else {
                  return this.parseData(item, c) <= value;
                }
              } else if (column.endsWith('_n')) {
                // 不等于
                let c = column.substr(0, column.length - 2);
                if (typeof value == 'string') {
                  for (let i = 0; i < value.split(',').length; i++) {
                    if (this.parseData(item, c) != value.split(',')[i]) {
                      return true;
                    }
                  }

                  return false;
                } else if (value instanceof Date) {
                  return new Date(this.parseData(item, c)) != value;
                } else {
                  return this.parseData(item, c) != value;
                }
              } else if (column.endsWith('_c')) {
                // 文字包含
                let c = column.substr(0, column.length - 2);
                return this.parseData(item, c) != null && this.parseData(item, c).indexOf(value) >= 0;
              } else {
                // 相等
                let c = column;
                if (typeof value == 'string') {
                  for (let i = 0; i < value.split(',').length; i++) {
                    if (this.parseData(item, c) == value.split(',')[i]) {
                      return true;
                    }
                  }
                  return false;
                } else if (value instanceof Date) {
                  return new Date(this.parseData(item, c)) == value;
                } else {
                  return this.parseData(item, c) == value;
                }
              }
            });
          }
        }

        if (!!(this.orderBy || '').trim()) {
          // 需要排序
          let orderBy = this.orderBy.split(',')[0];

          let type = orderBy.substr(0, 1);
          let column = orderBy.substr(1);

          data.sort((a, b) => {
            let dataA = this.parseData(a, column);
            let dataB = this.parseData(b, column);

            if (dataA == dataB) {
              return 0;
            } else if (dataA > dataB || dataB == null) {
              return type == '+' ? 1 : -1;
            } else {
              return type == '+' ? -1 : 1;
            }
          });
        }

        return data;
      },
      // 树展开动态查询
      async onLoadData(item, callback) {
        if (this.treeLoad != null) {
          let data = await this.treeLoad(item);
          data.forEach(item => {
            if (this.hasChildren == null || this.hasChildren(item)) {
              item._loading = false;
              item.children = [];
            }
          });

          callback(data);
        }
      },
      // 拖动事件
      dragDrop(index1, index2) {
        /**
         * 拖动完成事件
         * @property {object} args { index1 来源行序号, index2 目标行序号 }
         */
        this.$emit('on-drag-drop', { index1, index2 });
      },
      // // 转换为日期类型
      // parseDateTime(value) {
      //     if (value && typeof value === 'string') {
      //         return new Date(value);
      //     } else {
      //         return value;
      //     }
      // },
      // 打开选择内容
      openSelectItem() {
        let selected = [];
        let batchSelectDataCode = this.tableView.batchSelectDataCode;
        let key = batchSelectDataCode.substr(0, batchSelectDataCode.length - 2);

        for (let i = 0; i < this.staticData.length; i++) {
          selected.push(this.staticData[i][key]);
        }

        this.$refs.itemSelect.setSelected(selected);

        this.$refs.itemSelect.open();
      },
      // 保存选择内容
      saveItemSelect() {
        let selected = this.$refs.itemSelect.getSelected();
        let batchSelectDataCode = this.tableView.batchSelectDataCode;
        let key = batchSelectDataCode.substr(0, batchSelectDataCode.length - 2);

        this.staticData = this.staticData.filter(item => {
          return selected.some(i => {
            return i.id == item[batchSelectDataCode];
          });
        });

        for (let i = 0; i < selected.length; i++) {
          if (
            !this.staticData.some(item => {
              return item[batchSelectDataCode] == selected[i].id;
            })
          ) {
            let item = {};
            item[batchSelectDataCode] = selected[i].id;
            item[key] = selected[i];

            this.staticData.push(item);
          }
        }

        this.loadData(this.staticData);
        this.$refs.itemSelect.close();

        //this.$forceUpdate();
      },
      // 操作栏按钮
      clickCommandButton(row, commandButton) {
        if (commandButton.viewType == 'TableView') {
          // 打开表格
          this.$refs.modalTable.init(commandButton.viewCode, async () => {
            let params = {};

            if (!!(commandButton.params || '').trim()) {
              let commandButtonParams = JSON.parse(commandButton.params);

              for (let i = 0; i < commandButtonParams.length; i++) {
                let value = this.parseData(row, commandButtonParams[i].value);
                params[commandButtonParams[i].param] = value;
              }
            }

            this.$refs.modalTable.open(params);
          });
        } else {
          // 打开表单
          this.$refs.modalForm.init(commandButton.viewCode, async () => {
            this.$refs.modalForm.open(row);
          });
        }
      },
      // 预览
      previewImage(item) {
        this.imageUrl = item;
        this.preview = true;
      },
      // 合并单元格方法
      handleSpan({ row, column, rowIndex, columnIndex }) {
        if (this.spanMethod != null) {
          return this.spanMethod(row, column, rowIndex, columnIndex);
        }

        if (column.mergeSame) {
          if (rowIndex != 0 && this.parseData(row, column.code) == this.parseData(this.data[rowIndex - 1], column.code)) {
            return [0, 0];
          }

          let span = 0;
          for (let i = rowIndex; i < this.data.length; i++) {
            if (this.parseData(row, column.code) == this.parseData(this.data[i], column.code)) {
              span++;
            } else {
              return [span, 1];
            }
          }

          return [span, 1];
        }
      },
      // 根据条件判断
      judge(enable, json, data) {
        // 判断是否只读
        if (!!(json || '').trim()) {
          let setting = JSON.parse(json);

          if (setting.type == 'Condition' || setting.type == 'Expression') {
            return this.judgeCondition(setting, data);
          }
        }

        return enable;
      },
      // 是否显示
      isShow(data, column) {
        if (data._isShow != null && data._isShow[column.code] != null) {
          return data._isShow[column.code];
        } else {
          return column.isShow;
        }
      },
      // 是否只读
      isReadonly(data, column) {
        if (this.readonly == true) {
          return true;
        } else if (data._isReadonly != null && data._isReadonly[column.code] != null) {
          return data._isReadonly[column.code];
        } else {
          return column.isReadonly;
        }
      },
      // 批量保存
      batchSave() {
        if (!this.$refs.batchEditTable.validate()) {
          return;
        }

        this.confirm('Front_Msg_Sure_To_Save', async () => {
          let data = this.$refs.batchEditTable.getData();

          if (this.tableView.isCustom) {
            await customModelApi.batchSave(this.tableView.model, data);
          } else {
            await modelApi.batchSave(this.tableView.model, data);
          }

          this.success('Front_Msg_Success', () => {
            this.$refs.batchEditTable.close();
            this.loadData();
          });
        });
      },
      // 行数据
      rowData(row, index) {
        if (this.treeEnable) {
          return row;
        } else {
          return this.data[index];
        }
      },
      // 所有数据，包括子数据
      getDataWithChildren(data) {
        let result = [];
        data.forEach(item => {
          result.push(item);
          if (item.children) {
            result = result.concat(this.getDataWithChildren(item.children));
          }
        });

        return result;
      },
      // 设置可见性和只读
      setShowStatus(data) {
        for (let column of this.columns) {
          // 判断是否需要显示
          if (!!(column.showJson || '').trim()) {
            if (data._isShow == null) {
              data._isShow = {};
            }

            let setting = JSON.parse(column.showJson);

            if (setting.type == 'Condition' || setting.type == 'Expression') {
              data._isShow[column.code] = this.judgeCondition(setting, data);
            }
          }

          // 判断是否只读
          if (!!(column.readonlyJson || '').trim()) {
            if (data._isReadonly == null) {
              data._isReadonly = {};
            }

            let setting = JSON.parse(column.readonlyJson);

            if (setting.type == 'Condition' || setting.type == 'Expression') {
              data._isReadonly[column.code] = this.judgeCondition(setting, data);
            }
          }
        }
      },
      // 获取多语言名称
      getNameI18n(column) {
        if (column) {
          if (this.layout.showI18n) {
            if (column.code) {
              let key = 'DataView_' + this.tableView.code + '_' + column.code;
              let text = this.$t(key);
              if (text == key) {
                return column.name;
              } else {
                return text;
              }
            }
          } else {
            return column.name;
          }
        }
      },
      // 上移
      up(row, index) {
        let data = this.staticData;
        if (index > 0) {
          data.splice(index, 1);
          data.splice(index - 1, 0, row);

          for (let item of data) {
            delete item.id;
          }

          this.loadData(data);
        }
      },
      // 下移
      down(row, index) {
        let data = this.staticData;
        if (index < data.length - 1) {
          data.splice(index, 1);
          data.splice(index + 1, 0, row);

          for (let item of data) {
            delete item.id;
          }

          this.loadData(data);
        }
      }
    }
  };
</script>

<style scoped>
  /* 图片 */
  .image-group {
    display: flex;
  }

  .image-group .image {
    border: solid 1px #ccc;
    width: 75px;
    height: 75px;
    margin: 2px 1px 2px 1px;
    cursor: pointer;
  }

  .image-group .image img {
    width: 75px;
    height: 75px;
  }
</style>
