<template>
  <div class="head-list">
    <avue-form
      ref="form"
      v-if="isSetConfigForm"
      v-model="obj"
      v-on="$listeners"
      :option.sync="finalOption"
    >
      <!-- 自定义 slot, 只输出 slot, 具体内容在不在组件内部定义
      例如:
      customSlots: [ { "prop": "subject", "slotName": "subjectSlot" } ]
      输出的 slot 如下
      <template slot="subject" slot-scope="{ row }">
        <slot :slot-scope="row" name="subjectSlot" />
      </template>
      -->
      <template v-for="item in customSlots" :slot="item.prop" slot-scope="{ row }">
        <slot :slot-scope="row" :name="item.slotName" />
      </template>

      <template v-for="item in itemLinkList" :slot="item.prop">
        <span v-if="getReadOnly(item.prop)" :key="item.prop">
          <span v-if="obj[item.prop]">
            {{ obj[item.prop] }}
          </span>
          <!-- 禁用预定义 slot 点击跳转, 将来根据业务需要处理 -->
          <!-- <span v-if="obj[item.prop]" @click.stop="go(item, obj)">
            {{ obj[item.prop] }}
          </span> -->
        </span>
        <component
          v-else
          :api="listApi[item.prop]"
          :is="item.component"
          :key="item.prop"
          :list-params="listParams[item.prop]"
          :option="popupOption"
          :selected.sync="obj[item.prop]"
          @selectDone="doSelect(item.func, obj, $event, item.option || item.params, item)"
        />
      </template>
      <template v-for="item in itemUploadList" :slot="item.prop">
        <span :key="item.prop">
          <span v-if="obj[item.prop]">
            <img v-if="item.datatype === 'uploadImg'" width="200px" :src="obj[item.prop]" />
            <el-link v-else target="_blank" :href="obj[item.prop]"
              >{{ $ft('i18n_common_download', '下载') }}
            </el-link>
          </span>
          <fast2-upload
            v-if="!readOnly"
            @click="setUploadField(item.prop)"
            @file-error="onFileError"
            @file-progress="onFileProgress"
            @file-success="fileSuccess"
        /></span>
      </template>
    </avue-form>
  </div>
</template>
<script>
import cloneDeep from 'lodash/cloneDeep';

import { isNotEmptyPureObject } from '../../../lib/validate';
import {
  ft,
  generateDictURLWithLang,
  getBusinessAccount,
  getObjType,
  getRatio,
  isDictURL
} from '../../../lib/utils.js';
import { checkDataType, getFilePath, handlerSystemFiled, setRequired } from '../core/utils.js';
import { ElsPageConfigService } from '../../../lib/api/materials';
import popList from '../../../lib/popList';
import materialsFix from '../../../lib/materials-fix';
import { i18nConfig } from '../../../mixins/i18n';

const LABELS = {
  receipt: ft('i18n_common_receipt', '单据'),
  cancel: ft('i18n_common_cancel', '取消'),
  configuration: ft('i18n_common_configuration', '配置'),
  confirm: ft('i18n_common_confirm', '确定'),
  failedToQueryData: ft('i18n_common_failed_to_query_specified_data', '查询?数据失败'),
  uploading: ft('i18n_common_uploading', '上传中...')
};

export default {
  name: 'HeadPageProvider',
  mixins: [i18nConfig],
  props: {
    businessElsAccount: {
      type: String,
      default: null
    },

    col: {
      type: Number,
      default: 0
    },

    // customSlots: 自定义 slots, 只输出 slot name, 具体内容由使用都定义(不在组件内部定义)
    customSlots: {
      type: Array,
      default: function () {
        return [];
      }
    },

    data: {
      type: Object,
      default: function () {
        return { data: {} };
      }
    },

    // enAbleI18n: 是否支持多语言
    enAbleI18n: {
      type: Boolean,
      default: true
    },

    // excludePreSlots: 排除组件内置的预定义的字段(属性)Slot, 例如 :excludePreSlots=['materialNumber']
    excludePreSlots: {
      type: Array,
      default: function () {
        return [];
      }
    },

    extendDic: {
      type: Array,
      default: function () {
        return [];
      }
    },

    // itemLinkList: 组件内置的预定义的字段(属性)Slot
    itemLinkList: {
      type: Array,
      default: function () {
        return cloneDeep(popList);
      }
    },

    itemUploadList: {
      type: Array,
      default: function () {
        return [];
      }
    },

    // isCreate: 表示用于新建单据的操作
    isCreate: {
      type: Boolean,
      default: false
    },

    // pageCode: 远程获取 表格字段数据配置- 后续扩充 from 类型
    pageCode: {
      type: String,
      default: ''
    },

    // primaryKey: 单据对应的 key
    primaryKey: {
      type: String,
      default: 'new'
    },

    popupOption: {
      type: Object,
      default: function () {
        return {};
      }
    },

    // readOnly:  只读模式
    readOnly: {
      type: Boolean,
      default: false
    },

    // status: 组件编辑状态
    status: {
      type: String,
      default: 'new'
    },

    listApi: {
      type: Object,
      default: function () {
        return {};
      }
    },

    listParams: {
      type: Object,
      default: function () {
        return {};
      }
    },

    option: {
      type: Object,
      default: function () {
        return { column: [] };
      }
    },

    propMatch: {
      type: Array,
      default: function () {
        return [
          {
            from: 'subElsAccount',
            to: 'purchasePlaner',
            ref: 'purchasePlaner'
          }
        ];
      }
    },

    v2api: {
      type: Boolean,
      default: false
    },

    /**
     * @property {Function} handleMetadataFn - 设置表单元数据属性的方法
     */
    handleMetadataFn: {
      type: Function,
      default: null
    },

    /**
     * @property {Function} handleMetadataBeforeFn - 设置表单属性定义之前修改元数据
     */
    handleMetadataBeforeFn: {
      type: Function,
      default: null
    },

    /**
     * 打开弹窗选择一个数据并确定后, 对选取的数据进行处理
     * @example
     *  selectedItemProcFn(row, item) {
     *   row.queryUuid = row.uuid,
     * }
     */
    selectedItemProcFn: {
      type: Function,
      default: null
    }
  },
  data() {
    return {
      isSetConfigForm: false,
      rowPermission: [],

      finalOption: {
        menuBtn: false,
        submitBtn: false,
        clearBtn: false,
        column: []
      },

      defaultValues: {},
      obj: {},
      reload: false,
      formSlots: [],
      optionHash: '',
      typeData: [],
      selected: {},
      configurations: {},
      uploadField: ''
    };
  },

  computed: {
    innerBusinessElsAccount() {
      return getBusinessAccount();
    }
  },

  watch: {
    'data.data': {
      // 老的嵌套赋值
      handler: function (newVal, oldVar) {
        this.obj = newVal;
      },
      immediate: true,
      deep: true
    },
    data: {
      // 新的直接赋值
      handler: function (newVal, oldVar) {
        if (!newVal.data) {
          this.obj = newVal;
        }
      },
      immediate: true,
      deep: true
    },
    obj: {
      handler: function (newVal, oldVar) {
        if (this.data.data) {
          this.$emit('update:data.data', newVal);
        } else {
          this.$emit('update:data', newVal);
        }

        this.$emit('on-update', newVal);
        if (this.data.data) {
          // 老的嵌套数据方式
          this.data.data = newVal;
        } else {
          // 新的直接赋值方式
          this.data = newVal;
        }
      },
      immediate: true,
      deep: true
    }
  },
  async created() {
    if (this.readOnly) {
      this.finalOption.detail = true;
    }

    this.loadConfigurations();
  },
  methods: {
    checkForm(callback, failback) {
      this.$refs.form.validate((valid, done) => {
        if (valid) {
          callback && callback(done);
        } else {
          failback && failback();
          return false;
        }
      });
    },

    checkSlot(item) {
      this.itemLinkList.map((linkItem) => {
        // 非只读元素 可以弹窗
        if (item.prop === linkItem.prop && item.isReadOnly !== 'Y') {
          item.formslot = true;
          item.slot = true;
        }
      });

      if (item.datatype === 'uploadImg' || item.prop === 'picture') {
        this.itemUploadList.push(item);
      }

      if (item.datatype === 'uploadFile' || item.prop === 'url') {
        this.itemUploadList.push(item);
      }

      // 非只读元素 可以上传
      this.itemUploadList.map((linkItem) => {
        if (item.prop === linkItem.prop && item.isReadOnly === 'N') {
          linkItem.open = true;
          item.formslot = true;
          item.slot = true;
        }
      });
    },

    doSelect(func, row, event, params = []) {
      const type = getObjType(this[func]);

      if (type === 'function') {
        this[func](row, event, params);
      }
      const field = params[0] || 'materialNumber';

      this.$emit('on-select', field, row);

      this.$forceUpdate();
    },

    fileSuccess(req, req1, res) {
      const data = JSON.parse(res).data;
      const prop = this.uploadField || this.itemUploadList[0].prop;

      if (prop) {
        this.obj[prop] = getFilePath() + data.url;
      }
      this.$forceUpdate();
    },

    async filterColum(columns) {
      if (!columns || columns.length < 1) {
        return [];
      }

      const customSlotPropItems = {};

      const customSlots = this.customSlots || [];

      customSlots.forEach((item) => {
        if (item.prop) {
          customSlotPropItems[item.prop] = 1;
        }
      });

      for (const item of columns) {
        if (customSlotPropItems[item.prop] && item.formslot !== true) {
          item.formslot = true;
        }

        delete item.readonly;

        // 如果配置了国际化标签并启用了国际化
        if (this.enAbleI18n) {
          this.setI18n(item);
        } else {
          this.setDisplayName(item);
        }

        // 显示元素 并设置宽度为6
        item.display = true;
        item.span = 6;

        // 检查数据类型配置
        await checkDataType(item);

        if (typeof item.value !== 'undefined') {
          this.defaultValues[item.prop] = item.value;
          delete item.value;
        } else if (item.type === 'radio' && item.dicData && item.dicData.length > 0) {
          if (item.dicData[0] && typeof item.dicData[0].value !== 'undefined') {
            this.defaultValues[item.prop] = item.dicData[0].value;
          }
        }

        const isSystem = item.isSystem === 'Y';
        const isRequired = item.isRequired === 'Y' || item.isRequired === true;
        const isReadOnly = item.isReadOnly === 'Y';

        if (isSystem || isReadOnly) {
          handlerSystemFiled(item);
          continue;
        }
        // 检查是否 slot 元素
        this.checkSlot(item);

        // 检查必填设置
        if (isRequired) {
          delete item.readonly;
          delete item.disabled;

          setRequired(item);
        } else if (item.isDisabled || item.ref) {
          item.disabled = true;
          item.rules = [];
        }
      }

      return columns;
    },

    filterPreSlots() {
      const excludePreSlots = this.excludePreSlots;

      if (excludePreSlots.length > 0) {
        const itemLinks = this.itemLinkList;

        const len = itemLinks.length;

        for (let i = len - 1; i >= 0; i--) {
          const item = itemLinks[i];
          if (excludePreSlots.includes(item.prop)) {
            itemLinks.splice(i, 1);
          }
        }
      }
    },

    getData() {
      return this.obj;
    },

    getMaterialsRefs() {
      const refs = [];
      materialsFix.map((item) => {
        if (item.ref) {
          refs.push(item.prop);
        }
      });

      return refs;
    },

    getReadOnly(prop) {
      if (this.readOnly) {
        return true;
      }
      const item = this.findObject(this.finalOption.column, prop);
      if (item.isReadOnly === 'Y') {
        return true;
      }
    },

    getSelectRefs(type) {
      const refs = [];
      if (!type) {
        return refs;
      }
      this.finalOption.column.map((item) => {
        if (item.ref && item.ref.includes(type)) {
          refs.push(item.prop);
        }
      });

      return refs;
    },

    go(item, row) {
      if (window.parent) {
        const router = {
          name: item.label,
          src: item.url + row[item.prop]
        };

        const event = {
          name: 'openNewTag',
          props: router
        };

        window.parent.postMessage(event, '*');
      } else {
        window.location.href = item.url;
      }
    },

    handleConfigData(item = {}) {
      const fieldPermission = {};
      const tablePermission = {};

      const configJson = item.outputJson || '{}';

      const json = JSON.parse(configJson);

      const fields = json.field || [];
      const table = json.table || [];

      // 新建单据时, 单据 key 或 编号 由应用生成, 不需要在表单中展现
      if (this.primaryKey && (this.isCreate === true || this.isCreate === 'true')) {
        const primaryIndex = fields.findIndex((item) => {
          return item.prop === this.primaryKey;
        });

        if (primaryIndex > -1) {
          fields.splice(primaryIndex, 1);
        }
      }

      const configurations = {
        fieldColumns: fields,
        fieldJson: fieldPermission,
        tableColumns: table,
        tableJson: tablePermission,
        templateVersion: item.version
      };

      this.configurations = configurations;
    },

    initData() {
      const data = this.data.data || this.data;

      if (isNotEmptyPureObject(data)) {
        this.obj = data;
      } else {
        this.obj = this.defaultValues;
      }
    },

    loadConfigurations() {
      let api;
      let requestArguments;

      if (!this.v2api) {
        // V1
        api = ElsPageConfigService.list;

        requestArguments = [
          {
            elsAccount: this.innerBusinessElsAccount,
            code: this.pageCode
          }
        ];
      } else {
        // V2
        api = ElsPageConfigService.config;
        requestArguments = [this.pageCode, this.businessElsAccount || this.innerBusinessElsAccount];
      }

      api
        .apply(this, requestArguments)
        .then((res) => {
          const code = res.data.statusCode || res.data.code;
          if (res.data && code === '200' && res.data.data) {
            this.handleConfigData(res.data.data);
          } else {
            console.log('Failed to detail business type configuration.', res.data);
            this.$message.error(
              res.data.message ||
                LABELS.failedToQueryData.replace(
                  '?',
                  `${LABELS.receipt.toLowerCase()} ${LABELS.configuration.toLowerCase()}`
                )
            );
          }

          this.setHeadColumns();
          this.setTableColumns();
        })
        .catch((err) => {
          console.log('Error Failed to detail business type configuration.', err);
          this.$message.error(
            LABELS.failedToQueryData.replace(
              '?',
              `${LABELS.receipt.toLowerCase()} ${LABELS.configuration.toLowerCase()}`
            )
          );
        });
    },

    onFileProgress() {
      console.log(LABELS.uploading);
    },

    replaceWithExtendDic(item) {
      const extendList = this.extendDic || [];

      const extendDicFn = extendList.find((exitItem) => exitItem.prop === item.prop);

      if (extendDicFn) {
        Object.assign(item, extendDicFn);
        delete item.dicUrl;
        delete item.bizDic;
        delete item.datatype;
      }
    },

    saveSelected(row, list, option) {
      const item = list[0];
      const matchProps = this.propMatch;
      const columns = this.finalOption.column;

      let ref = '';

      this.$emit('on-select-head', row, item, list, option);

      if (option.isOption === true) {
        const valueProp = option.valueProp;
        ref = valueProp;

        const dataValue = item[option.dataValueProp];
        const dataName = item[option.dataNameProp];

        if (typeof dataValue !== 'undefined') {
          row[valueProp] = '';
          if (
            typeof row[valueProp] !== 'undefined' ||
            typeof this.findObject(columns, valueProp) === 'object'
          ) {
            row[valueProp] = dataValue;
          }
        }

        if (typeof dataName !== 'undefined') {
          const nameProp = option.nameProp;
          row[nameProp] = '';
          if (
            nameProp &&
            (typeof row[nameProp] !== 'undefined' ||
              typeof this.findObject(columns, nameProp) === 'object')
          ) {
            row[nameProp] = dataName;
          }

          const aliasProps = option.aliasProps || [];
          for (const aliasProp of aliasProps) {
            row[aliasProp] = '';
            if (
              typeof row[aliasProp] !== 'undefined' ||
              typeof this.findObject(columns, aliasProp) === 'object'
            ) {
              row[aliasProp] = dataName;
              break;
            }
          }
        }
      } else {
        const params = option;

        ref = params[0];

        row[params[0]] = item[params[2]];
        item[params[0]] = item[params[2]];
        row[params[1]] = item[params[3]];
        item[params[1]] = item[params[3]];
      }

      if (this.selectedItemProcFn && typeof this.selectedItemProcFn === 'function') {
        this.selectedItemProcFn(row, item, option);
      }

      // 价格信息记录号弹窗选择赋值使用
      if (item.toElsAccountName) {
        item.supplierName = item.toElsAccountName;
      }

      if (ref) {
        const refs = this.getSelectRefs(ref);

        if (refs && refs.length) {
          refs.map((prop) => {
            if (item[prop]) {
              row[prop] = item[prop];
            }
          });
        }

        if (matchProps && matchProps.length) {
          matchProps.map((matchProp) => {
            if (matchProp.ref === ref) {
              row[matchProp.to] = item[matchProp.from];
            }
          });
        }
        // 手动触发验证
        this.$refs.form.validateField(ref);
      }
    },

    saveSelectedAll(row, list, params) {
      const item = list[0];
      Object.assign(row, item);
    },

    selectedRowMaterails(row, materialList) {
      const refs = this.getMaterialsRefs();
      const material = materialList[0];

      refs.map((prop) => {
        row[prop] = material[prop] || '';
      });

      // 创建. 修改采购申请(新增的行将物料的uuid放入queryUuid字段), 重新选择了物料也要更新 queryUuid
      row.queryUuid = material.uuid;
      row.materialNumber = material.materialNumber;

      const materialObject = row;
      Object.assign(materialObject, material);
    },

    setHeadColumns(val) {
      const selected = this.configurations;
      if (selected) {
        this.selected = selected;

        this.updateColumn(selected);
      }
    },

    setTableColumns(val) {
      const selected = this.configurations;
      this.$emit('updateTableColumn', selected);
      this.$emit('updateTable', selected.tableColumns);
    },

    setUploadField(prop) {
      this.uploadField = prop;
    },

    async updateColumn(selected) {
      this.finalOption.column = [];
      const columns = this.finalOption.column;

      if (typeof this.handleMetadataBeforeFn === 'function') {
        this.handleMetadataBeforeFn(selected.fieldColumns, selected);
      }

      this.filterPreSlots();

      const newColumn = await this.filterColum(selected.fieldColumns);

      const waitUpdateDic = [];

      if (newColumn && newColumn.length > 0) {
        newColumn.map((item) => {
          this.replaceWithExtendDic(item);

          // 根据浏览器比例设置span
          const ratio = getRatio();
          if (ratio >= 150) {
            item.span = 8;
          }

          columns.push(item);

          if (item.dicUrl) {
            if (isDictURL(item.dicUrl)) {
              item.dicUrl = generateDictURLWithLang(item.dicUrl, true);
            }

            waitUpdateDic.push(item.prop);
          }
        });

        this.updateDic(waitUpdateDic);

        if (typeof this.handleMetadataFn === 'function') {
          this.handleMetadataFn(this.finalOption.column, this.finalOption);
        }

        this.initData();

        this.isSetConfigForm = true;
      }
    },

    updateFormDict(dicts) {
      const form = this.$refs.form;

      if (form && form.updateDic) {
        dicts.map((prop) => {
          form.updateDic(prop);
        });
      }
    },

    updateDic(list) {
      const form = this.$refs.form;
      if (form) {
        list.map((prop) => {
          form.updateDic(prop);
        });
      } else {
        setTimeout(() => {
          this.updateDic(list);
        }, 1000);
      }
    }
  }
};
</script>
<style lang="scss">
@import './list.scss';
</style>
