<template>
  <div ref="content">
    <!--
        @slot 顶部
    -->
    <slot name="top" :form="this" />
    <Form ref="form" :model="data" label-position="top" label-colon="：" class="ivu-mt" :rules="rules" @submit.prevent>
      <!-- <Tabs v-model="tabName" v-tab-hide="tabs.length == 1">
        <TabPane v-for="(tab, tabIndex) in tabs" :key="tabIndex" :label="tab" :name="tab"> -->
      <Row :gutter="24" type="flex">
        <template v-for="(column, index) in columns">
          <div :key="'newLine' + index" v-if="column.newLine" style="width: 100%"></div>
          <Col
            :key="index"
            v-if="column.isShow || column.controlType === 'Table' || column.controlType === 'ExcelTable' || column.controlType === 'List'"
            v-show="column.isShow"
            v-bind="getGrid(column.columnWidth)"
          >
            <div :key="column.code" v-if="column.controlType === 'Placeholder'" style="margin-bottom: 0px"></div>
            <div :key="column.code" v-if="column.controlType === 'Title'">
              <div class="form-title" :style="{ width: column.controlWidth == null ? null : column.controlWidth + 'px' }">
                {{ getNameI18n(column) }} {{ showData(data, column) }}
              </div>
            </div>
            <div v-if="column.controlType === 'Table'">
              <Divider :plain="true" dashed orientation="left" size="small">
                <span class="title">{{ getNameI18n(column) }}</span>
              </Divider>
              <view-table
                :ref="'table_' + column.code"
                :static="true"
                :view-code="column.source"
                :readonly="readonly || column.isReadonly"
                :embedded="true"
                :parent-data="data"
                @on-change="(row, sender, selected) => onDataChange(column, null, row, sender, selected)"
              >
                <template #filterCommand>
                  <!--
                      @slot 内嵌表格筛选栏按钮
                      @binding {object} table 表格对象
                      @binding {object} tableColumn 表格列对象
                      @binding {string} tableCode 表格列代码
                  -->
                  <slot name="tableFilterCommand" :tableColumn="column" :tableCode="column.code"></slot>
                </template>
                <template #column="scope">
                  <!--
                      @slot 内嵌表格自定义列
                      @binding {object} table 表格对象
                      @binding {object} tableColumn 表格列对象
                      @binding {string} tableCode 表格列代码
                      @binding {object} row 行对象
                      @binding {int} index 行序号
                      @binding {object} column 列对象
                      @binding {string} code 列代码
                  -->
                  <slot
                    name="tableColumn"
                    :table="$refs['table_' + column.code][0]"
                    :tableColumn="column"
                    :tableCode="column.code"
                    :row="scope.row"
                    :index="scope.index"
                    :column="scope.column"
                    :code="scope.code"
                  ></slot>
                </template>
                <template #command="scope">
                  <!--
                      @slot 内嵌表格工具栏
                      @binding {object} table 表格对象
                      @binding {object} tableColumn 表格列对象
                      @binding {string} tableCode 表格列代码
                      @binding {object} row 行对象
                      @binding {int} index 行序号
                  -->
                  <slot name="tableCommand" :table="$refs['table_' + column.code][0]" :tableColumn="column" :tableCode="column.code" :row="scope.row" :index="scope.index"></slot>
                </template>
              </view-table>
            </div>
            <div v-if="column.controlType === 'ExcelTable'">
              <Divider :plain="true" dashed orientation="left" size="small">
                <span class="title">{{ getNameI18n(column) }}</span>
              </Divider>
              <view-table-excel
                :ref="'table_' + column.code"
                :view-code="column.source"
                :readonly="readonly || column.isReadonly"
                :parent-data="data"
                @on-change="(row, sender, selected) => onDataChange(column, null, row, sender, selected)"
              >
                <template #top>
                  <!--
                      @slot 内嵌表格顶部
                      @binding {object} tableColumn 表格列对象
                      @binding {string} tableCode 表格列代码
                  -->
                  <slot name="excelTableTop" :tableColumn="column" :tableCode="column.code"></slot>
                </template>
              </view-table-excel>
            </div>
            <div v-if="column.controlType === 'List'">
              <Divider :plain="true" dashed orientation="left" size="small">
                <span class="title">{{ getNameI18n(column) }}</span>
              </Divider>
              <view-table :ref="'list_' + column.code" :view-code="column.source" :readonly="true" :auto-load="false"></view-table>
            </div>
            <FormItem
              :label="getNameI18n(column)"
              :prop="column.code"
              :key="column.code"
              :rules="getRules(column)"
              v-if="
                column.controlType !== 'Placeholder' &&
                column.controlType !== 'Title' &&
                column.controlType !== 'Table' &&
                column.controlType !== 'ExcelTable' &&
                column.controlType !== 'List'
              "
            >
              <template v-if="column.controlType === 'Custom'">
                <!--
                    @slot 自定义列
                    @binding {object} form 表单对象
                    @binding {object} data 数据对象
                    @binding {object} column 列对象
                    @binding {string} code 列代码
                -->
                <slot name="column" :form="this" :data="data" :column="column" :code="column.code"></slot>
              </template>
              <template v-else-if="column.controlType === 'Label'">
                <div class="label" :title="compareData == null ? null : showData(compareData, column)">
                  <div :class="{ error: compareData != null && parseData(data, column.code) != parseData(compareData, column.code) }" v-html="showData(data, column)"></div>
                </div>
              </template>
              <template v-else-if="column.controlType === 'Tag'">
                <Tag
                  v-if="parseData(data, column.code) != null"
                  :color="getTagColor(column, parseData(data, column.code))"
                  :type="column.source == 'default' ? null : column.source"
                >
                  {{ showData(data, column) }}
                </Tag>
              </template>
              <template v-else-if="column.controlType === 'Description'">
                <div v-html="showMultiLine(column.description)"></div>
              </template>
              <template v-if="column.controlType === 'Hyperlink'">
                <a :href="getTemplateReplace(data, column.hyperlink)" :target="column.isNewWindow ? '_blank' : ''">
                  <span v-html="showData(data, column)"></span>
                </a>
              </template>
              <template v-if="column.controlType === 'ModalForm'">
                <a href="#" @click="openModalForm($refs['modalForm_' + column.code][0], parseData(data, column.code))">
                  <span v-html="getTemplateReplace(data, column.description)"></span>
                </a>
                <modal-form :ref="'modalForm_' + column.code" :view-code="column.source" :readonly="true"></modal-form>
              </template>
              <template v-else-if="column.controlType === 'TextInput'">
                <Input
                  type="text"
                  :model-value="parseData(data, column.code)"
                  @update:model-value="$event => setData(data, column.code, $event)"
                  :readonly="readonly || column.isReadonly"
                  :clearable="!(readonly || column.isReadonly)"
                  :style="{ width: column.controlWidth == null ? null : column.controlWidth + 'px' }"
                  :maxlength="column.maxLength"
                  :placeholder="column.description"
                  @on-change="onDataChange(column)"
                  @on-blur="onBlur(column)"
                />
              </template>
              <template v-else-if="column.controlType === 'NumberInput'">
                <Input
                  type="number"
                  number
                  :model-value="parseData(data, column.code)"
                  @update:model-value="$event => setData(data, column.code, $event)"
                  :readonly="readonly || column.isReadonly"
                  :clearable="!(readonly || column.isReadonly)"
                  :style="{ width: column.controlWidth == null ? '100px' : column.controlWidth + 'px' }"
                  :placeholder="column.description"
                  :max="column.maxValue"
                  :min="column.minValue"
                  @on-change="onDataChange(column)"
                  @on-blur="onBlur(column)"
                />
              </template>
              <template v-else-if="column.controlType === 'Select'">
                <Select
                  :model-value="parseData(data, column.code) == null ? null : parseData(data, column.code).toString()"
                  @update:model-value="$event => setData(data, column.code, $event)"
                  :disabled="readonly || column.isReadonly"
                  :clearable="!(readonly || column.isReadonly)"
                  :style="{
                    width: column.controlWidth == null ? null : column.controlWidth + 'px',
                    'min-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
                  :model-value="parseArrayData(data, column.code)"
                  @update:model-value="$event => setArrayData(data, column.code, $event)"
                  :disabled="readonly || column.isReadonly"
                  :multiple="true"
                  :clearable="!(readonly || column.isReadonly)"
                  :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
                  :model-value="parseTreeData(data, column.code)"
                  @update:model-value="$event => setData(data, column.code, $event)"
                  :data="getDataSource(data, column)"
                  :disabled="readonly || column.isReadonly"
                  :clearable="!(readonly || column.isReadonly)"
                  :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
                  :model-value="parseArrayData(data, column.code)"
                  @update:model-value="$event => setArrayData(data, column.code, $event)"
                  :data="getDataSource(data, column)"
                  :disabled="readonly || column.isReadonly"
                  :multiple="true"
                  :show-checkbox="true"
                  :clearable="!(readonly || column.isReadonly)"
                  :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 === 'AutoComplete'">
                  <AutoComplete :value="parseData(data, column.code) ? parseData(data, column.code) : ''"
                      @update:model-value="$event => setData(data, column.code, $event)"
                      :disabled="readonly || column.isReadonly"
                      :clearable="true"
                      @on-search="search => loadOption(data, column, search)"
                      @on-clear="() => loadOption(data, column)"
                      :style="{ width: column.controlWidth == null ? null : column.controlWidth + 'px' }"
                      :placeholder="column.description"
                      :transfer="true"
                      @on-change="(selected) => onDataChange(column, selected)">
                      <Option v-for="item in getDataSource(data, column)"
                          :key="item.id"
                          :value="item.name">{{ item.name }}</Option>
                  </AutoComplete>
              </template> -->
              <template v-else-if="column.controlType === 'ComboSelect'">
                <combo-select
                  :model-value="parseData(data, column.code)"
                  @update:model-value="$event => setData(data, column.code, $event)"
                  :multi="false"
                  :readonly="readonly || column.isReadonly"
                  :remote-method="search => loadOption(data, column, search)"
                  :data="data"
                  :param="getParam(data, column)"
                  :column="column"
                  @on-change="selected => onSelectDataChange(column, selected)"
                ></combo-select>
              </template>
              <template v-else-if="column.controlType === 'MultiComboSelect'">
                <combo-select
                  :model-value="parseArrayData(data, column.code)"
                  @update:model-value="$event => setArrayData(data, column.code, $event)"
                  :multi="true"
                  :readonly="readonly || column.isReadonly"
                  :remote-method="search => loadOption(data, column, search)"
                  :data="data"
                  :param="getParam(data, column)"
                  :column="column"
                  @on-change="selected => onSelectDataChange(column, selected)"
                ></combo-select>
              </template>
              <template v-else-if="column.controlType === 'DialogSelect'">
                <dialog-select
                  :model-value="parseData(data, column.code)"
                  :raw-data="data"
                  :column-code="column.code"
                  @update:model-value="$event => setData(data, column.code, $event)"
                  :readonly="readonly || column.isReadonly"
                  :source="column.source"
                  :source-data-code="column.sourceDataCode"
                  :source-display-code="column.sourceDisplayCode"
                  :param="getParam(data, column)"
                  :control-width="column.controlWidth"
                  @on-change="selected => onSelectDataChange(column, selected)"
                ></dialog-select>
              </template>
              <template v-else-if="column.controlType === 'MultiDialogSelect'">
                <dialog-select
                  :model-value="parseData(data, column.code)"
                  @update:model-value="$event => setData(data, column.code, $event)"
                  :multi="true"
                  :readonly="readonly || column.isReadonly"
                  :source="column.source"
                  :source-data-code="column.sourceDataCode"
                  :source-display-code="column.sourceDisplayCode"
                  :param="getParam(data, column)"
                  :control-width="column.controlWidth"
                  @on-change="selected => onSelectDataChange(column, selected)"
                ></dialog-select>
              </template>
              <template v-else-if="column.controlType === 'SelectWithOther'">
                <Select
                  :model-value="parseDataWithOther(data, column)"
                  @update:model-value="$event => setDataWithOther(data, column.code, $event)"
                  :disabled="readonly || column.isReadonly"
                  :clearable="!(readonly || column.isReadonly)"
                  :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">{{ !!(column.pattern || '').trim() ? column.pattern : $t('Front_Label_Others') }}</Option>
                </Select>
                <Input
                  type="text"
                  v-show="parseDataWithOther(data, column) == '__Other'"
                  :model-value="parseData(data, column.code)"
                  @update:model-value="$event => setData(data, column.code, $event)"
                  :readonly="readonly || column.isReadonly"
                  :style="{ width: column.controlWidth == null ? '40%' : column.controlWidth + 'px' }"
                  style="margin-left: 4px"
                  :maxlength="column.maxLength"
                  :placeholder="column.description"
                  @on-change="selected => onDataChange(column, selected)"
                  @on-blur="onBlur(column)"
                />
              </template>
              <template v-else-if="column.controlType === 'Date' || column.controlType === 'DateTime' || column.controlType === 'Year' || column.controlType === 'Month'">
                <DatePicker
                  :type="column.controlType.toLowerCase()"
                  :model-value="parseDateTimeData(data, column.code)"
                  :readonly="readonly || column.isReadonly"
                  :editable="layout.dateEditable !== false"
                  :placeholder="column.description"
                  :transfer="true"
                  :style="{ width: column.controlWidth == null ? null : column.controlWidth + 'px' }"
                  @on-change="
                    time => {
                      setData(data, column.code, time);
                      onDataChange(column);
                    }
                  "
                ></DatePicker>
              </template>
              <template v-else-if="column.controlType === 'DateRange'">
                <DatePicker
                  :type="column.controlType.toLowerCase()"
                  :model-value="parseDateRangeData(data, column.code)"
                  @update:model-value="$event => setArrayData(data, column.code, $event)"
                  :readonly="readonly || column.isReadonly"
                  :editable="layout.dateEditable !== false"
                  :placeholder="column.description"
                  :transfer="true"
                  :style="{ width: column.controlWidth == null ? null : column.controlWidth + 'px' }"
                  @on-change="onDataChange(column)"
                ></DatePicker>
              </template>
              <template v-else-if="column.controlType === 'Time'">
                <TimePicker
                  type="time"
                  :model-value="parseData(data, column.code)"
                  :readonly="readonly || column.isReadonly"
                  :placeholder="column.description"
                  :transfer="true"
                  :style="{ width: column.controlWidth == null ? null : column.controlWidth + 'px' }"
                  @on-change="
                    time => {
                      setData(data, column.code, time);
                      onDataChange(column);
                    }
                  "
                ></TimePicker>
              </template>
              <template v-else-if="column.controlType === 'Check'">
                <Checkbox
                  :model-value="!!parseData(data, column.code)"
                  @update:model-value="$event => setData(data, column.code, $event)"
                  :disabled="readonly || column.isReadonly"
                  size="large"
                  @on-change="onDataChange(column)"
                />
              </template>
              <template v-else-if="column.controlType === 'Switch'">
                <Switch
                  :model-value="!!parseData(data, column.code)"
                  @update:model-value="$event => setData(data, column.code, $event)"
                  :disabled="readonly || column.isReadonly"
                  @on-change="onDataChange(column)"
                />
              </template>
              <template v-else-if="column.controlType === 'Radio'">
                <RadioGroup
                  :model-value="parseData(data, column.code)"
                  @update:model-value="$event => setData(data, column.code, $event)"
                  @on-change="selected => onSelectDataChange(column, selected)"
                >
                  <Radio v-for="item in getDataSource(data, column)" :key="item.id" :label="item.id" :disabled="readonly || column.isReadonly">
                    <span>{{ item.name }}</span>
                  </Radio>
                </RadioGroup>
              </template>
              <template v-else-if="column.controlType === 'CheckGroup'">
                <!-- <CheckboxGroup
                    :model-value="parseArrayData(data, column.code)"
                    @update:model-value="$event => setArrayData(data, column.code, $event)"
                    @on-change="selected => onSelectDataChange(column, selected)"
                  >
                    <Checkbox v-for="item in getDataSource(data, column)" :key="item.id" :label="item.name" :disabled="readonly || column.isReadonly">
                      <span>{{ item.name }}</span>
                    </Checkbox>
                  </CheckboxGroup> -->

                <check-group
                  :model-value="parseData(data, column.code)"
                  @update:model-value="$event => setData(data, column.code, $event)"
                  :dataSource="getDataSource(data, column)"
                  value-key="id"
                  label-key="name"
                  :readonly="readonly || column.isReadonly"
                  @on-change="() => onSelectDataChange(column)"
                ></check-group>
              </template>
              <template v-else-if="column.controlType === 'TextArea'">
                <Input
                  type="textarea"
                  :model-value="parseData(data, column.code)"
                  @update:model-value="$event => setData(data, column.code, $event)"
                  :readonly="readonly || column.isReadonly"
                  :style="{ width: column.controlWidth == null ? null : column.controlWidth + 'px' }"
                  :rows="column.controlHeight / 20"
                  :maxlength="column.maxLength"
                  :placeholder="column.description"
                />
              </template>
              <template v-else-if="column.controlType === 'RichEditor'">
                <rich-editor
                  :model-value="parseData(data, column.code)"
                  @update:model-value="$event => setData(data, column.code, $event)"
                  :readonly="readonly || column.isReadonly"
                  :height="column.controlHeight"
                  :width="column.controlWidth"
                />
              </template>
              <template v-else-if="column.controlType === 'Attachment'">
                <upload-attachment
                  v-if="!readonly && !column.isReadonly"
                  :ref="'attachment_' + column.code"
                  :model-value="parseData(data, column.code)"
                  @update:model-value="$event => setData(data, column.code, $event)"
                  :max-count="column.maxLength"
                  :max-size="column.maxValue"
                  :accept="column.pattern"
                  :draggable="column.mergeSame"
                />
                <template v-if="(readonly || column.isReadonly) && !!(parseData(data, column.code) || '').trim()">
                  <a
                    :href="getAttachmentUrl(attachment.file, attachment.name)"
                    :key="attachmentIndex"
                    target="_blank"
                    v-for="(attachment, attachmentIndex) in JSON.parse(parseData(data, column.code))"
                  >
                    <span>
                      <Icon type="ios-document" />
                      {{ attachment.name }}
                    </span>
                  </a>
                </template>
              </template>
              <template v-else-if="column.controlType === 'Image'">
                <upload-image
                  :model-value="parseData(data, column.code)"
                  @update:model-value="$event => setData(data, column.code, $event)"
                  :readonly="readonly || column.isReadonly"
                  :max-count="column.maxLength"
                  :max-size="column.maxValue"
                  :height="column.controlHeight"
                  :width="column.controlWidth"
                  :accept="column.pattern"
                />
              </template>
              <template v-else-if="column.controlType === 'Slider'">
                <Slider
                  v-if="!readonly && !column.isReadonly"
                  :model-value="parseData(data, column.code)"
                  @update:model-value="$event => setData(data, column.code, $event)"
                  show-input
                  :style="{ width: column.controlWidth == null ? null : column.controlWidth + 'px' }"
                  :max="column.maxValue"
                  :min="column.minValue"
                />
                <Input
                  v-if="readonly || column.isReadonly"
                  type="number"
                  number
                  readonly
                  :model-value="parseData(data, column.code)"
                  :style="{ width: column.controlWidth == null ? '100px' : column.controlWidth + 'px' }"
                  :placeholder="column.description"
                />
              </template>
              <Button type="primary" v-if="!!(column.tooltip || '').trim()" style="margin-left: 4px" size="small" :title="column.tooltip" shape="circle" icon="md-help"></Button>
            </FormItem>
          </Col>
        </template>
      </Row>
      <!-- </TabPane>
      </Tabs> -->
      <!--
          @slot 底部
          @binding {object} form 表单对象
      -->
      <slot name="bottom" :form="this" />
    </Form>
    <!-- <FooterToolbar>
            <Button type="primary" size="large">{{ $t('Front_Btn_Submit') }}</Button>
        </FooterToolbar>-->
  </div>
</template>
<script>
  import mixinPage from '../../mixins/page';
  import mixin from './mixin';
  import { mapActions } from 'vuex';
  import modelApi from '../../api/model';
  import customModelApi from '../../api/customModel';
  import richEditor from '../richEditor/index.vue';
  import uploadAttachment from '../upload/upload-attachment.vue';
  import uploadImage from '../upload/upload-image.vue';
  import CheckGroup from '../input/check-group.vue';
  // import lodop from '../../libs/lodop';

  /**
   * @displayName view-form 表单视图
   */
  export default {
    mixins: [mixin, mixinPage],
    components: { richEditor, uploadAttachment, uploadImage, CheckGroup },
    emits: ['on-blur', 'on-change', 'on-ready'],
    data() {
      return {
        formView: {},
        tabs: [],
        tabName: '',
        columns: [],
        rules: {},
        data: null,
        compareData: null,
        dataBefore: null,
        isReady: false,
        lazyloadFunc: null
      };
    },
    async created() {
      // 默认视图代码
      if (this.viewCode) {
        // 初始化
        await this.init(this.viewCode);
      }
    },
    props: {
      /**
       * 视图代码
       */
      viewCode: {
        type: String
      },
      /**
       * 只读
       */
      readonly: {
        type: Boolean,
        default: false
      },
      /**
       * 预设默认值
       */
      defaultData: {
        type: Object,
        default() {
          return {};
        }
      },
      /**
       * 显示工具栏
       */
      commandEnable: {
        type: Boolean,
        default: true
      },
      /**
       * 是否允许配置界面
       */
      settingEnable: {
        type: Boolean,
        default: true
      }
    },
    computed: {
      tables() {
        let tables = {};

        for (let column of this.columns) {
          if ((column.controlType == 'Table' || column.controlType == 'ExcelTable') && !column.isReadonly && column.isShow) {
            tables[column.code] = this.$refs['table_' + column.code][0];
          }
        }

        return tables;
      }
    },
    watch: {
      data() {
        if (this.data && Object.keys(this.data).length > 0) {
          this.columns.forEach(async column => {
            if ((column.controlType == 'Table' || column.controlType == 'ExcelTable') && this.$refs['table_' + column.code]) {
              this.reloadTable(column.code);
            } else if (column.controlType == 'Attachment' && this.$refs['attachment_' + column.code] && this.$refs['attachment_' + column.code].length > 0) {
              this.$refs['attachment_' + column.code][0].setData(this.parseData(this.data, column.code));
            }
          });
        }

        //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 && !view.isExist && viewCode.indexOf('_') >= 0) {
          view = await this.loadDataView(viewCode.split('_')[0]);
        }

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

        this.loadView(view);

        setTimeout(() => {
          this.isReady = true;

          if (typeof this.lazyloadFunc === 'function') {
            this.lazyloadFunc();
            this.lazyloadFunc = null;
          }

          if (typeof callback === 'function') {
            callback(view);
          }
        });
      },
      /**
       * 加载视图
       *
       * @param {object} view 视图
       * @public
       */
      loadView(view) {
        // 加载表格视图
        this.formView = view.dataView;
        this.formView.columns = view.viewColumns;

        /**
         * 视图获取完成事件
         * @property {object} formView 表单视图
         */
        this.$emit('on-ready', this.formView);
        this.columns = view.viewColumns;

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

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

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

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

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

          this.onDataChange();
        });
      },
      /**
       * 重置
       *
       * @public
       */
      reset() {
        // 清空表格控件数据;
        this.columns.forEach(column => {
          if (column.controlType == 'Table' || column.controlType == 'ExcelTable') {
            this.$refs['table_' + column.code][0].loadData([]);
          }
        });

        this.data = {};
        setTimeout(() => {
          this.clearValidate();
        });
      },
      /**
       * 重置表格页码
       *
       * @public
       */
      async resetTablePage() {
        this.columns.forEach(column => {
          if (column.controlType == 'Table') {
            //this.$refs['table_' + column.code][0].loadData([]);
          }
        });
      },
      /**
       * 清空验证信息
       *
       * @public
       */
      async clearValidate() {
        this.$refs.form.fields.forEach(field => {
          field.validateState = '';
          field.validateMessage = '';
        });
      },
      /**
       * 设为默认值
       *
       * @param {object} data 默认值
       * @public
       */
      setDefault(data) {
        //this.$refs.form.resetFields();

        // 清空表格控件数据
        // this.columns.forEach(column => {
        //     if (column.controlType == 'Table') {
        //         this.$refs['table_' + column.code][0].loadData([]);
        //     }
        // });

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

        // 表格默认行数
        let tables = this.columns.filter(item => item.controlType == 'Table' || item.controlType == 'ExcelTable');
        for (let column of tables) {
          if (column.digit) {
            for (let i = 0; i < column.digit; i++) {
              this.$refs['table_' + column.code][0].addNew();
            }
          }
        }

        this.clearValidate();
      },
      /**
       * 验证
       *
       * @public
       */
      async validate() {
        let isOk = await this.$refs.form.validate();

        for (let column of this.columns) {
          if (column.controlType == 'ExcelTable' && !column.isReadonly && column.isShow) {
            let tableOk = await this.$refs['table_' + column.code][0].validate();
            isOk = isOk && tableOk;
          }
        }

        return isOk;
      },
      /**
       * 获取完整数据
       *
       * @public
       */
      getFullData() {
        let data = this.copy(this.data);
        if (!data) {
          return null;
        }

        data.tableData = [];

        for (let column of this.columns) {
          if ((column.controlType == 'Table' || column.controlType == 'ExcelTable') && !column.isReadonly && column.isShow) {
            let tableData = this.$refs['table_' + column.code][0].getData();

            if (column.isRequired && tableData.length == 0) {
              this.error('Front_Msg_Row_Required|' + this.getNameI18n(column));
              return false;
            }

            if (column.controlType == 'Table') {
              let isOk = this.$refs['table_' + column.code][0].validate();

              if (!isOk) {
                return false;
              }
            }

            if (column.tableStoreType == 'Inner') {
              // 表内存储
              data[column.code] = JSON.stringify(tableData);
            } else {
              // 外部关联表
              data.tableData.push({
                model: column.sourceModel,
                sourceDataCode: column.sourceDataCode,
                filtering: this.$refs['table_' + column.code][0].tableView.filtering,
                data: tableData
              });
            }
          }
        }

        return data;
      },
      /**
       * 获取完整数据，跳过验证
       *
       * @public
       */
      getFullDataWithoutValidate() {
        let data = this.copy(this.data);
        if (!data) {
          return null;
        }

        data.tableData = [];

        for (let column of this.columns) {
          if ((column.controlType == 'Table' || column.controlType == 'ExcelTable') && !column.isReadonly && column.isShow) {
            let tableData = this.$refs['table_' + column.code][0].getData();

            if (column.tableStoreType == 'Inner') {
              // 表内存储
              data[column.code] = JSON.stringify(tableData);
            } else {
              // 外部关联表
              data.tableData.push({
                model: column.sourceModel,
                sourceDataCode: column.sourceDataCode,
                filtering: this.$refs['table_' + column.code][0].tableView.filtering,
                data: tableData
              });
            }
          }
        }

        return data;
      },
      /**
       * 设置表格字段内容
       *
       * @param {string} code 字段
       * @param {object} value 值
       * @public
       */
      setTableData(code, value) {
        let column = this.columns.find(x => x.code == code);

        if (value == null) {
          this.setData(this.data, column.code, null);
          value = [];
        } else {
          this.setData(this.data, column.code, JSON.stringify(value));
        }

        if ((column.controlType == 'Table' || column.controlType == 'ExcelTable') && this.$refs['table_' + column.code]) {
          this.$refs['table_' + column.code][0].loadData(value);
        }
      },
      /**
       * 刷新
       *
       * @public
       */
      refresh() {
        this.onDataChange();
      },
      // 根据选项卡序号返回列
      tabColumns(index) {
        return this.columns.filter(item => {
          return item.tabIndex === index || item.tabIndex == null;
        });
      },
      getRules(column) {
        if (!column.isShow) {
          return [];
        }

        let rules = [];

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

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

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

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

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

        return rules;
      },
      // 初始化校验规则
      // initRule() {
      //     // 重置验证信息
      //     setTimeout(() => {
      //         this.clearValidate();
      //     });
      // },
      // 初始化板块
      initTab() {
        if (!!(this.formView.tab || '').trim()) {
          this.tabs = this.formView.tab.split(',');
        } else {
          this.tabs = [this.formView.name];
        }

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

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

                    if (column.dataType == 'Integer' || column.dataType == 'BigInteger') {
                      column.dataSource.push({
                        id: parseInt(key),
                        name: value
                      });
                    } else if (column.dataType == 'Decimal' || column.dataType == 'Float' || column.dataType == 'Double') {
                      column.dataSource.push({
                        id: parseFloat(key),
                        name: value
                      });
                    } else if (column.dataType == 'Boolean' && column.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
                      });
                    }
                  }
                }
              });
            }

            // 默认第一项
            if (column.dataSource.length > 0 && column.isDefaultFirst) {
              this.setData(this.data, column.code, column.dataSource[0].id);
            }
          }
        });

        //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 || param[key].split('.')[0] + 'ID' == item.code;
                })
                .forEach(item => {
                  item.triggers.push(this.copy(column));
                });
            }
          });

        // 公式中包含变量需要刷新
        // this.columns
        //     .filter(column => {
        //         return !!(column.calculate || '').trim();
        //     })
        //     .forEach(column => {
        //         let triggers = this.getTriggers(column.calculate);

        //         this.columns
        //             .filter(item => {
        //                 return triggers.some(i => {
        //                     return i == item.code;
        //                 });
        //             })
        //             .forEach(item => {
        //                 item.triggers.push(column);
        //             });
        //     });
      },
      // 填充数据源
      async fillDataSource(data, column, param) {
        let value;
        if (column.controlType === 'TreeSelect' || column.controlType === 'MultiTreeSelect') {
          // 树选择框重新加载数据源时，需要先清空数据源，否则无法直接点击清空按钮清除数据。
          value = this.parseTreeData(data, column.code);
          column.dataSource = null;
        }

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

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

        column.rawData = res.data;

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

          column.dataSource = this.getTreeDataSource(treeData, column, null);
          this.setData(data, column.code, value);
        } else {
          column.dataSource = res.data.map(item => {
            return {
              id: !(column.sourceDataCode || '').trim() ? item.id : this.parseData(item, column.sourceDataCode),
              name: this.parseData(item, column.sourceDisplayCode)
            };
          });

          // 默认第一项
          if (data) {
            if (
              column.isDefaultFirst &&
              res.data.length > 0 &&
              (this.parseData(data, column.code) == null ||
                !res.data.some(item => {
                  return this.parseData(data, column.code) == this.parseData(item, column.sourceDataCode);
                }))
            ) {
              this.setData(data, column.code, this.parseData(res.data[0], column.sourceDataCode));
              /**
               * 数据变化事件
               * @property {object} sender 触发的列对象
               * @property {object} oldValue 原数据
               * @property {object} newValue 新数据
               * @property {object} selected 选中对象（弹出选择框等有效）
               */
              this.$emit('on-change', column, null, column.rawData[0], null);

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

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

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

            // 触发
            column.triggers.forEach(item => {
              item.needClear = true;
            });
          }
        }
      },
      // 获取树结构数据源
      getTreeDataSource(treeData, column, parentID) {
        let result = treeData
          .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(treeData, column, item.value);
          }
        }

        return result;
      },
      // 获取数据源
      getDataSource(data, column) {
        if (!column.isStaticItem && column.dataType && column.dataType.startsWith('Enum:')) {
          // 枚举
          return this.getEnumList(column.dataType.split(':')[1]);
        } else {
          return column.dataSource == null ? [] : column.dataSource;
        }
      },
      // 选项变化事件
      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.parseData(rawData, sender.sourceDataCode) == item;
                    })
                  );
                } else {
                  model.push(item);
                }
              }
            }
          } else {
            model = selected;
          }
        } else {
          if (sender.rawData) {
            model = sender.rawData.find(rawData => {
              return this.parseData(rawData, sender.sourceDataCode) == selected;
            });
          } else {
            model = selected;
          }
        }

        if (code) {
          let objModel = model;
          if (sender.sourceDataCode.endsWith('ID')) {
            objModel = this.parseData(model, sender.sourceDataCode.substr(0, sender.sourceDataCode.length - 2));
          }

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

        this.onDataChange(sender, model);
      },
      // 数据变化事件
      async onDataChange(sender, selected, tableRow, tableSender, tableSelected) {
        for (let column of this.columns) {
          // 判断是否需要显示
          if (!!(column.showJson || '').trim()) {
            let setting = JSON.parse(column.showJson);

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

          // 判断是否只读
          if (!!(column.readonlyJson || '').trim()) {
            let setting = JSON.parse(column.readonlyJson);

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

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

            if (setting.type == 'Condition' || setting.type == 'Expression') {
              let before = column.isRequired;
              column.isRequired = this.judgeCondition(setting, this.data);

              if (before != column.isRequired) {
                // 必填有变化
                let field = this.$refs.form.fields.find(field => {
                  return field.prop == column.code;
                });

                if (field != null) {
                  field.isRequired = column.isRequired;

                  if (!column.isRequired) {
                    field.validateState = '';
                    field.validateMessage = '';
                  }
                }
              }
            }
          }
        }

        if (sender != null && (sender.controlType == 'Table' || sender.controlType == 'ExcelTable')) {
          /**
           * 数据变化事件
           * @property {object} sender 触发的列对象
           * @property {object} oldValue 原数据
           * @property {object} newValue 新数据
           * @property {object} selected 选中对象（弹出选择框等有效）
           * @property {object} tableRow 表格行
           * @property {object} tableSender 表格中的控件
           * @property {object} tableSelected 表格中的选中项目
           */
          this.$emit('on-change', sender, null, null, this.$refs['table_' + sender.code][0].data, tableRow, tableSender, tableSelected);
        } else if (sender != null) {
          let oldValue = this.parseData(this.dataBefore, sender.code);
          let newValue = this.parseData(this.data, sender.code);
          if (oldValue !== newValue) {
            setTimeout(() => {
              this.$emit('on-change', sender, oldValue, newValue, selected);
            });
          }
        } else {
          this.$emit('on-change', sender, null, null, selected);
        }

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

        // 公式计算
        for (let column of this.columns) {
          if (!!(column.calculate || '').trim()) {
            let calculate = column.calculate;

            // 计算sum、min、max、avg等统计值
            calculate = this.calcStat('sum', calculate);
            calculate = this.calcStat('min', calculate);
            calculate = this.calcStat('max', calculate);
            calculate = this.calcStat('avg', calculate);

            let triggers = this.getTriggers(calculate);

            if (!sender || triggers.some(item => item == sender.code) || column.calculate != calculate) {
              // 包含在公式中，需要刷新
              setTimeout(() => {
                let result = this.calculate(calculate, this.data);

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

                let oldValue = this.parseData(this.data, column.code);

                this.setData(this.data, column.code, result);

                if (oldValue !== result) {
                  setTimeout(() => {
                    this.$emit('on-change', column, oldValue, result);
                  });
                }
              });
            }
          }
        }

        // 计算需要刷新的字段
        if (sender == null || (sender.triggers && sender.triggers !== [])) {
          this.columns.forEach(function (column) {
            if (
              !column.isStaticItem &&
              !!(column.source || '').trim() &&
              !(column.dataType && column.dataType.startsWith('Enum:')) &&
              (sender == null ||
                sender.triggers.some(item => {
                  return item.code == column.code;
                }))
            ) {
              column.needRefresh = true;
              // if (column.controlType == 'Table') {
              //     this.$refs['table_' + sender.code][0];
              // } else {
              // }
            }
          });
        }

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

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

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

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

                // 触发
                column.triggers.forEach(item => {
                  item.needClear = true;
                });
              }
            } else if (sender && (column.controlType === 'DialogSelect' || column.controlType === 'MultiDialogSelect')) {
              // 需要刷新，清空数据
              this.setData(this.data, column.code, null);
              // column.displayValue = null;

              // 触发
              column.triggers.forEach(item => {
                item.needClear = true;
              });
            } else if (column.controlType === 'List') {
              if (param != null) {
                // 参数完整，查询数据
                let res;

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

                let filtering = tableView.filtering;

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

                for (let key in param) {
                  this.$refs['list_' + column.code][0].filterData[key] = param[key];
                }

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

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

          column.needClear = false;
          column.needRefresh = false;
        }
      },
      // 输入框失去焦点事件
      onBlur(sender) {
        /**
         * 数据变化事件
         * @property {object} sender 触发的列对象
         */
        this.$emit('on-blur', sender);
      },
      // 获取数据类型
      getDataType(column) {
        if (!(column.dataType || '').trim()) {
          return null;
        }
        if (column.dataType.startsWith('Enum:')) {
          return 'string';
        }

        switch (column.dataType) {
          case 'String':
          case 'BigInteger':
            return 'string';
          case 'Boolean':
            return 'boolean';
          case 'DateTime':
            return 'date';
          case 'Float':
          case 'Double':
          case 'Decimal':
            return 'number';
          case 'Short':
          case 'Integer':
            return 'integer';
        }
      },
      // 根据表达式取值（带其他）
      parseDataWithOther(model, column) {
        let expression = column.code;
        let selectValue = this.parseData(model, expression + '_o');

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

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

        if (value == null) {
          return '';
        } else {
          return value;
        }
      },
      // 计算统计值
      calcStat(op, calculate) {
        let start = calculate.indexOf(op + '(');
        let end = calculate.indexOf(')', start);

        if (start == -1 || end == -1) {
          return calculate;
        }

        let property = calculate.substring(start + 4, end);

        if (property.indexOf('.') == -1) {
          return calculate;
        }

        let table = this.$refs['table_' + property.split('.')[0]];

        if (table == null || table.length == 0) {
          return calculate;
        }

        let tableData = table[0].getData();
        let result = null;
        let sum = null;
        let count = null;

        for (let item of tableData) {
          let value = this.parseData(item, property.substr(property.indexOf('.') + 1));

          if (value) {
            if (op == 'sum') {
              result = result == null ? value : result + value;
            } else if (op == 'min') {
              result = result == null ? value : value < result ? value : result;
            } else if (op == 'max') {
              result = result == null ? value : value > result ? value : result;
            } else if (op == 'avg') {
              sum = sum == null ? value : sum + value;
              count = count == null ? 1 : count + 1;
              result = count > 0 ? sum / count : null;
            }
          }
        }

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

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

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

          // 触发
          column.triggers.forEach(item => {
            item.needClear = true;
          });
        }
      },
      // 打开弹出表单
      async openModalForm(control, id) {
        let data;
        if (control.formView.isCustom) {
          data = await customModelApi.get(control.formView.model, id);
        } else {
          data = await modelApi.get(control.formView.model, id);
        }

        control.open(data);
      },
      // 重新加载内嵌表格数据
      reloadTable(tableCode) {
        let column = this.columns.find(item => item.code == tableCode);

        setTimeout(async () => {
          if (column.tableStoreType == 'Inner') {
            // 表内存储
            let json = this.parseData(this.data, column.code);

            if (json) {
              this.$refs['table_' + column.code][0].loadData(JSON.parse(json));
            }
          } else {
            // 关联表
            if (this.data.id) {
              // 参数完整，查询数据
              let res;
              let param = {};

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

              let filtering = tableView.filtering;

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

              param[column.sourceDataCode] = this.data.id;

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

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

          if (this.$refs['table_' + column.code][0].$refs.tableFilter) {
            this.$refs['table_' + column.code][0].$refs.tableFilter.onDataChange();
          }
        });
      }
      // // 打印
      // print() {
      //   const LODOP = lodop.getLodop();
      //   LODOP.PRINT_INIT('Print');

      //   console.log('print', this.$refs.content.outerHTML);

      //   LODOP.ADD_PRINT_TABLE('4%', '3%', '94%', '90%', result);
      //   LODOP.SET_PRINT_PAGESIZE(1, 0, 0, 'A4');

      //   LODOP.PRINTA();
      // }
    }
  };
</script>
