<template>
  <x-page-container class="common-page-container x-meta-query toolbar-page-container">
    <template v-slot:header>
      <x-table-filter
        ref="tableFilter"
        :field-list="fields"
        :api-list="apiConfig"
        :data-code="dataCode"
        :query-code="realQueryCode"
        :temp-condition-config="realConditionConfig"
        :get-temp-column-list="handleGetTempColumnList"
        @confirm="handleConfirm"
        :from-str="$attrs['from-str']"
        :sort-config-visible="sortConfigVisible"
        :column-config-visible="columnConfigVisible"
      ></x-table-filter>
      <!--查询方案下拉框结束-->
      <x-button-group :button-config="buttonConfig">
        <template v-for="(item) in buttonSlotArray" v-slot:[item.name]="scope">
          <slot :name="item.name" v-bind="scope"></slot>
        </template>
      </x-button-group>
      <vxe-toolbar ref="vxeToolbar" class="page-header-toolbar" :custom="custom"></vxe-toolbar>
    </template>
    <template v-slot:sub>
      <x-condition ref="xCondition" @resize="handleResize" :condition-config="realConditionConfig"
                   :drawer-config="{show: true}">
        <template v-for="(item) in conditionSlotArray" v-slot:[item.name]="scope">
          <slot :name="item.name" v-bind="scope"></slot>
        </template>
      </x-condition>
      <x-table-setting-dialog
        title="表格显示格式"
        :visible.sync="tableSettingDialogVisible"
        :mis-configure="tableSettingMisConfigure"
        :handle-select="handleTableSettingSelect"
      ></x-table-setting-dialog>
      <el-tabs v-if="showTab" v-model="realTabConfig.activeName" :type="realTabConfig.type || 'card'"
               @tab-click="handleTabClick">
        <el-tab-pane v-for="item in realTabConfig.list" :key="item.name" :label="item.label"
                     :name="item.name"></el-tab-pane>
      </el-tabs>
    </template>
    <template v-slot:main>
      <x-table
        v-on="$listeners"
        v-bind="$attrs"
        :id="realId"
        :column-cache="realColumnCache"
        ref="xTable"
        column-key
        border
        resizable
        height="100%"
        highlight-hover-row
        highlight-current-row
        :keyboard-config="{isEdit: true, isEnter: false, editMethod}"
        :sort-config="{remote: true, multiple: true}"
        :filter-config="{remote: true}"
        :mouse-config="{area: true, extension: true}"
        :seq-config="realSeqConfig"
        :columns="realColumns"
        :scroll-y="{gt: 60}"
        :menu-config="realMenuConfig"
        :clip-config="realClipConfig"
        :edit-config="realEditConfig"
        @menu-click="handleMenuClick"
        @sort-change="handleSortChange"
        @filter-change="handleFilterChange"
        :table-setting-config=tableSettingConfig
        @scroll="handleScroll"
        @cell-area-selection-end="handleCellAreaSelectionEnd"
        @keydown="$handleKeyDown"
        @keydown-capture="handleKeyDownCapture"
        :show-footer="realShowFooter"
        :footer-method="realFooterMethod"
        @mousedown-capture="handleMouseDownCapture"
      >
        <template v-for="item in slotArray" v-slot:[item]="scope">
          <slot :name="item" v-bind="scope"></slot>
        </template>
      </x-table>
    </template>
    <template v-slot:footer>
      <x-page-footer class="page-footer-dynamic-statistics" v-if="realDynamicStatisticsConfig.enabled"
                     :page-footer-config="dynamicStatisticsPageFooterConfig"></x-page-footer>
      <el-pagination
        v-if="realPageConfig.type === 'page' && realPageConfig.show"
        :small="realPageConfig.small"
        background
        @size-change="handleSizeChange"
        @current-change="handlePageCurrentChange"
        :current-page="currentPage"
        highlight-hover-row
        :page-size="pageSize"
        :page-sizes="realPageConfig.pageSizes"
        layout="total, sizes, prev, pager, next, jumper"
        :total="total"
      ></el-pagination>
      <x-page-footer class="page-footer-total" v-if="realPageConfig.type === 'scroll' && realPageConfig.show"
                     :page-footer-config="realPageFooterTotalConfig"></x-page-footer>
    </template>
  </x-page-container>
</template>

<script>
/**
 * @desc 从后端获取查询方案、查询条件和表格信息，前端组装和动态显示这些信息，配置化查询
 * @author LiangYongJia
 */
import {
  getConditionModel,
  arrayToMap,
  getColumnCacheName,
  getGroupColumnsAndLeafColumns,
  convertSortList,
  getStatisticsFlag,
  showInvalidFieldsMessage
} from '../../util/componentUtil';
import metaMixin from './meta-mixin';
import singleMetaMixin from './single-meta-mixin';
import metaQueryMixin from './meta-query-mixin';
import {convertCondition, getColumns, sortPlanList, getCoreQueryParams, getMetaDataDictQueryParams, getMetaDataDict, getFormRules} from '../../util/metaQueryUtil';
import tableSettingConfigMixin from '../../mixins/table-setting-config-mixin';
import tableOperateConfigMixin from '../../mixins/table-operate-config-mixin';
import tableOperateMixin from '../../mixins/table-operate-mixin';
import * as appUtils from '../../util/appUtils';
import { Tabs, TabPane, Pagination } from 'element-ui';
import { XButtonGroup, XTable, XPageContainer, XTableFilter, XPageFooter, XCondition } from '@newpearl/ui';
import { Toolbar } from 'vxe-table';
import {PAGE_CONFIG_TYPE_PAGE, PAGE_CONFIG_TYPE_SCROLL} from '../../mixins/page-mixin';

export default {
  inheritAttrs: false,
  name: 'XMetaQuery',
  components: {
    [Tabs.name]: Tabs,
    [TabPane.name]: TabPane,
    [Pagination.name]: Pagination,
    [Toolbar.name]: Toolbar,
    [XButtonGroup.name]: XButtonGroup,
    [XCondition.name]: XCondition,
    [XTable.name]: XTable,
    [XPageContainer.name]: XPageContainer,
    [XTableFilter.name]: XTableFilter,
    [XPageFooter.name]: XPageFooter
  },
  mixins: [tableSettingConfigMixin, tableOperateConfigMixin, tableOperateMixin, metaMixin, singleMetaMixin, metaQueryMixin],
  props: {
    // 查询编码，用于获取查询条件
    queryCode: {
      type: String,
      default: ''
    },
    // queryCode改变的回调事件
    handleCodeChange: Function
  },
  data() {
    return {
      // 用户选中查询方案
      selectedQueryCode: '',
      // 通过dataCode获得的表格的配置信息
      fields: [],
      // 用户的筛选操作
      filterList: [],
      // 缓存需要转成tab的查询条件
      tabCondition: null
    };
  },
  created() {
    this.sortList = [];
    // 记录从接口中返回的数据
    this.metaData = null;
    if (this.conditionConfig && this.conditionConfig.labelWidth) {
      this.realConditionConfig.labelWidth = this.conditionConfig.labelWidth;
    }
  },
  mounted() {
    this.getXTable().getGridInstance().connect(this.$refs.vxeToolbar);
  },
  methods: {
    handleTableSettingSelect({row}) {
      this.getXTable().setMisConfigure(row).then(() => {
        this.queryFirstPageData();
      });
    },
    $handleKeyDown(args) {
      if (this.$listeners.keydown) {
        return;
      }
      this.handleKeyDown(args);
    },
    handleGetTempColumnList() {
      return this.getXTable().getGridInstance().getTableColumn();
    },
    /**
     * @desc 处理tab点击的回调
     */
    handleTabClick() {
      this.queryFirstPageData();
    },
    /**
     * @desc 筛选的回调
     */
    handleFilterChange(args) {
      this.filterList = args.filterList;
      this.queryFirstPageData();
    },
    /**
     * @desc 排序的回调
     */
    handleSortChange({ sortList }) {
      this.sortList = sortList;
      this.queryFirstPageData();
    },
    async handleConfigQuery(args) {
      if (this.handleMetaQuery) {
        args = await this.handleMetaQuery(args);
      }
      const { conditions, sorts, lists, groupLists } = args;
      const conditionList = await convertCondition({
        conditions,
        fields: this.fields,
        presetConditionConfig: this.conditionConfig,
        event: {
          handleItemChange: this.handleItemChange,
          handleInputItemEnter: this.queryFirstPageData,
          handleSearchListSelect: this.queryFirstPageData
        }
      });
      this.convertTab(conditionList);
      this.realConditionConfig.model = getConditionModel({ list: conditionList });
      this.realConditionConfig.rules = await getFormRules({fields: conditions, presetRules: this.conditionConfig.rules, modelKey: 'uniqueField'});
      this.realConditionConfig.list = conditionList;
      // 通过queryCode或者高级查询获到的排序信息,缓存起来后面查询会用到
      this.sorts = sorts;
      // 生成列表的列信息
      const columns = await getColumns({
        lists,
        groupLists,
        fieldMap: this.fieldMap,
        presetColumns: this.columns,
        conditionConfig: this.realConditionConfig,
        tabConfig: this.realTabConfig,
        handleMouseDown: this.handleMouseDown,
        showSort: this.realQueryConfig.sort,
        showFilter: this.realQueryConfig.filter
      });
      // 判断是否需要显示底部统计行
      this.realColumns = columns;
      if (this.realShowFooter !== false) {
        this.realShowFooter = this.getStatisticsFlag({name: 'sumAll'}) || this.getStatisticsFlag({name: 'sumPage'});
      }
      if (this.handleInitializationComplete) {
        this.handleInitializationComplete({
          conditionConfig: this.realConditionConfig,
          columns: this.realColumns,
          sorts: this.sorts
        });
      }
      // 使用$nextTick只能获取第一层表头，有可能每层表头都是分别在微任务中渲染，所以使用setTimeout来获取
      setTimeout(() => {
        this.getXTable().initTableSetting().then(() => {
          if (this.realQueryConfig.autoQuery) {
            this.queryFirstPageData();
          }
        });
      }, 0);
    },
    convertTab(conditionList) {
      this.tabCondition = null;
      // 判断conditionList中是否有元素的fieldCode和tabConfig的field一样，如果有，就转成tab
      if (!this.tabConfig) {
        return;
      }
      for (let i = 0; i < conditionList.length; i++) {
        const item = conditionList[i];
        if (this.tabConfig.field === item.fieldCode) {
          this.tabCondition = item;
          conditionList.splice(i, 1);
          break;
        }
      }
    },
    /**
     * @desc 高级查询弹框确定或者保存的回调
     */
    handleConfirm({ data, queryCode, metaQueryList }) {
      // 由于排序可能已经合并到查询方案中，所以表中的排序要清除
      this.getXTable().getGridInstance().clearSort();
      // 如果不显示查询方案，就直接根据data来查询
      this.selectedQueryCode = queryCode;
      this.handleCodeChange && this.handleCodeChange({ queryCode, dataCode: this.dataCode });
      this.handleConfigQuery(data);
    },
    /**
     * @desc 获取基本信息和部分表格信息
     */
    getMetaDataDetail() {
      this.apiConfig.getMetaDataAndFieldsApi({ dataCode: this.dataCode }).then(({ data }) => {
        if (!data.isSuccess()) {
          this.$notify.error(data.msg);
          return;
        }
        data = data.data;
        if (!data) {
          this.$notify.error('配置信息为空');
          return;
        }
        if (this.handleMetaData) {
          this.handleMetaData(data);
        }
        this.metaData = data.metaData;
        if (!Array.isArray(data.fields) || data.fields.length < 1) {
          return;
        }
        this.fields = data.fields;
        if (this.queryCode) {
          this.handleQueryCodeChange(this.queryCode);
        } else {
          this.getQueryCodeList();
        }
      });
    },
    /**
     * @desc 获取查询方案列表
     */
    getQueryCodeList() {
      this.apiConfig.getMetaQueryPlanList(this.dataCode, { queryTypeArray: this.queryTypeArray }).then(({ data }) => {
        if (!data.isSuccess()) {
          this.$notify.error(data.msg);
          return;
        }
        data = data.data;
        if (!Array.isArray(data) || data.length < 1) {
          this.$notify.error('暂无查询方案，请新建查询方案');
          return;
        }
        sortPlanList(data);
        // 如果queryCode是空, 就从根据dataCode获取查询方案列表,并选中第一个
        // 如果queryCode不为空, 就从根据dataCode获取查询方案列表,并选中queryCode对应的查询方案
        if (this.queryCode) {
          this.selectedQueryCode = this.queryCode;
        } else {
          this.selectedQueryCode = data[0].queryCode;
        }
        this.handleQueryCodeChange(this.selectedQueryCode);
      });
    },
    /**
     * @desc 改变queryCode触发的回调
     */
    handleQueryCodeChange(queryCode) {
      this.handleCodeChange && this.handleCodeChange({ queryCode, dataCode: this.dataCode });
      this.apiConfig.getMetaQueryPlanDetail({ queryCode, dataCode: this.dataCode }).then(({ data }) => {
        if (!data.isSuccess()) {
          this.$notify.error(data.msg);
          return;
        }
        data = data.data;
        if (!Array.isArray(data.conditions)) {
          data.conditions = [];
        }
        // 需要将真实表头和分组表头分开
        const { groupColumns, leafColumns } = getGroupColumnsAndLeafColumns({ columns: data.lists });
        data.lists = leafColumns;
        data.groupLists = groupColumns;
        // 默认或者系统查询方案直接显示
        if (!data.metaQuery.baseId) {
          // 查询条件需要做转换处理
          this.handleConfigQuery(data);
          return;
        }
        // 用户自定义方案需要将基础方案查询出来并合并查询条件
        this.apiConfig.getMetaQueryAll(data.metaQuery.baseId).then((response) => {
          const res = response.data;
          if (!res.isSuccess()) {
            this.$notify.error(res.msg);
            return;
          }
          const result = res.data;
          if (!Array.isArray(result.conditions)) {
            this.handleConfigQuery(data);
            return;
          }
          data.conditions.unshift(...result.conditions);
          this.handleConfigQuery(data);
        });
      });
    },
    queryFirstPageData() {
      if (this.currentPage !== 1) {
        this.currentPage = 1;
      }
      if (this.realPageConfig.type === PAGE_CONFIG_TYPE_PAGE) {
        this.queryData();
      } else {
        // 加大每页数量
        // this.pageSize = 100;
        this.lastPage = false;
        this.getXTable().getGridInstance().loadData([]);
        this.scrollQueryData();
      }
    },
    async scrollQueryData({ validate = true } = {}) {
      if (this.loading) {
        return;
      }
      this.loading = true;
      try {
        const coreQueryParams = await this.getCoreQueryParamsAsync({validate, sumAll: this.getStatisticsFlag({name: 'sumAll'})});
        const {data} = await this.apiConfig.searchMetaDataReportList({jsonStr: JSON.stringify(coreQueryParams)});
        if (!data.isSuccess()) {
          this.$notify.error(data.msg);
          return;
        }
        this.currentPage += 1;
        let resData = data.data;
        if (this.handleQueryData) {
          const result = await this.handleQueryData({data: resData});
          resData = result.data;
        }
        if (resData.sumAll) {
          this.sumAllResult = resData.sumAll;
        }
        const pager = resData.pager;
        const list = pager.list;
        this.total = pager.totalRows;
        if (list.length < this.pageSize) {
          this.lastPage = true;
        }
        const grid = this.getXTable().getGridInstance();
        await getMetaDataDict({list, $grid: grid});
        const originData = grid.getTableData().fullData;
        if (originData.length > 0) {
          this.$lastRow = originData[originData.length - 1];
        }
        originData.push(...list);
        await grid.loadData(originData);
        if (this.$lastRow) {
          grid.scrollToRow(this.$lastRow);
        }
        this.handleLoadDataFinish && this.handleLoadDataFinish({$grid: grid, data: list});
      } finally {
        this.loading = false;
      }
    },
    async queryData({ validate = true } = {}) {
      const coreQueryParams = await this.getCoreQueryParamsAsync({validate, sumAll: this.getStatisticsFlag({name: 'sumAll'})});
      const { data } = await this.apiConfig.searchMetaDataReportList({ jsonStr: JSON.stringify(coreQueryParams) });
      if (!data.isSuccess()) {
        this.$notify.error(data.msg);
        this.getXTable().loadData([]);
        return;
      }
      let resData = data.data;
      if (this.handleQueryData) {
        const result = await this.handleQueryData({data: resData});
        resData = result.data;
      }
      if (resData.sumAll) {
        this.sumAllResult = resData.sumAll;
      }
      const pager = resData.pager;
      const list = pager.list;
      const grid = this.getXTable().getGridInstance();
      await getMetaDataDict({list, $grid: grid});
      this.total = pager.totalRows;
      await grid.loadData(list);
      this.handleLoadDataFinish && this.handleLoadDataFinish({$grid: grid, data: list});
    },
    /**
     * 获取查询参数
     * @param validate 是否对字段进行校验
     * @param page 页码
     * @param pageSize 每页数据大小
     * @param sumAll 是否统计
     * @return {object}
     */
    async getCoreQueryParamsAsync({validate = true, page, pageSize, sumAll} = {}) {
      if (!validate) {
        return this.getCoreQueryParams({page, pageSize, sumAll});
      }
      try {
        await this.$refs.xCondition.validate();
        return this.getCoreQueryParams({page, pageSize, sumAll});
      } catch (error) {
        if (error instanceof RuleError) {
          if (error.invalidFields) {
            showInvalidFieldsMessage({invalidFields: error.invalidFields});
            throw error;
          }
          this.$notify.error(error.message);
          throw error;
        }
        throw error;
      }
    },
    /**
     * 获取查询参数
     * @param page 页码
     * @param pageSize 每页数据大小
     * @param sumAll 是否统计
     * @return {object}
     */
    getCoreQueryParams({page, pageSize, sumAll} = {}) {
      return getCoreQueryParams({
        dataCode: this.dataCode,
        page: page === undefined ? this.currentPage : page,
        pageSize: pageSize === undefined ? this.pageSize : pageSize,
        sumAll,
        metaData: this.metaData,
        conditionConfig: this.realConditionConfig,
        sorts: this.sorts,
        sortList: this.sortList,
        filterList: this.filterList,
        tabConfig: this.realTabConfig,
        handleQueryParams: this.handleQueryParams
      });
    },
    /**
     * @desc 获取全部数据
     * @author liangyongjia
     * @param pageSize每页大小
     */
    async getFullTableData({pageSize = 250} = {}) {
      let page = 1;
      const $pageSize = pageSize === undefined ? this.pageSize : pageSize;
      const tableData = [];
      while (true) {
        const coreQueryParams = await this.getCoreQueryParamsAsync({validate: true, page, pageSize: $pageSize});
        const {data} = await this.apiConfig.searchMetaDataReportList({jsonStr: JSON.stringify(coreQueryParams)});
        if (!data.isSuccess()) {
          return Promise.reject(new Error(data.msg));
        }
        page += 1;
        const pager = data.data.pager;
        const list = pager.list;
        this.total = pager.totalRows;
        const grid = this.getGridInstance();
        const fullColumn = grid.getTableColumn().fullColumn;
        const dictObject = {};
        for (const column of fullColumn) {
          const property = column.property;
          // 配置了enumCode列直接用formatter来转换
          if (column.params && column.params.metaDataField && column.params.metaDataField.enumCode) {
            for (const item of list) {
              item[property] = column.formatter({ cellValue: item[property], column });
            }
            continue;
          }
          // 缓存字典
          if (!dictObject[property]) {
            dictObject[property] = {};
          }
          const queryParams = getMetaDataDictQueryParams({column, list, dict: dictObject[property]});
          if (!queryParams) {
            continue;
          }
          const { data } = await this.apiConfig.searchMetaDataReportList(queryParams);
          if (!data.isSuccess()) {
            return Promise.reject(new Error(data.msg));
          }
          const dictList = data.data.pager.list;
          if (!Array.isArray(dictList)) {
            return;
          }
          const metaDataField = column.params.metaDataField;
          const rowKey = metaDataField.refFieldCode;
          const rowName = metaDataField.refFieldName;
          const dict = dictObject[property];
          // 更新字典
          for (const item of dictList) {
            dict[item[rowKey]] = dict[item[rowName]];
          }
          // 转换数据
          for (const item of list) {
            const cellValue = item[property];
            if (appUtils.isEmpty(cellValue)) {
              continue;
            }
            item[property] = dict[cellValue];
          }
        }
        tableData.push(...list);
        if (list.length < $pageSize) {
          return tableData;
        }
      }
    },
    getRadioRecord() {
      return this.getGridInstance().getRadioRecord();
    },
    getCheckboxRecords() {
      return this.getGridInstance().getCheckboxRecords();
    },
    getTableData() {
      return this.getGridInstance().getTableData();
    },
    getStatisticsFlag({name}) {
      // 滚动加载不显示合计
      if (this.realPageConfig.type === PAGE_CONFIG_TYPE_SCROLL && name === 'sumPage') {
        return false;
      }
      // 这里做缓存，提高性能
      const cacheName = '$Statistics' + name;
      if (Object.prototype.hasOwnProperty.call(this, cacheName)) {
        return this[cacheName];
      }
      this[cacheName] = getStatisticsFlag({columns: this.realColumns, propertyArray: [name]});
      return this[cacheName];
    }
  },
  computed: {
    realColumnCache () {
      if (this.columnCache) {
        return this.columnCache;
      }
      return getColumnCacheName({ name: this.dataCode + '-' + this.realQueryCode });
    },
    // 将fields转成对象，方便根据fieldCode获取数组元素
    fieldMap() {
      return arrayToMap({ array: this.fields, keyProperty: 'fieldCode' });
    },
    realQueryCode() {
      return this.selectedQueryCode || this.queryCode;
    }
  }
};
</script>
