<template>
  <div class="history-table">
    <BasicTable ref="historyTable" @register="register" :data-source="data" :scroll="scroll" @change="search">
      <template #bodyCell="{ column, record }">
        <a-tag v-if="column.dataIndex === 'warnFlag'" :color="record.warnFlag == '0' ? 'green' : 'red'">
          {{ record.warnFlag == '0' ? '正常' : '报警' }}
        </a-tag>
        <a-tag v-if="column.dataIndex === 'netStatus'" :color="record.netStatus == '0' ? '#f00' : 'green'">
          {{ record.netStatus == '0' ? '断开' : '连接' }}
        </a-tag>
      </template>
      <template #form-submitBefore>
        <a-button type="primary" preIcon="ant-design:search-outlined" @click="search">查询</a-button>
      </template>
    </BasicTable>
  </div>
</template>

<script lang="ts" setup>
  // 场景类历史数据公共组件！
  // 用于服务场景类历史数据业务，这类数据通常由一条数据返回多个子设备的信息，例如：{ forcFan1Temp, forcFan2Temp }；
  // 而此组件可以将这些数据分类，例如：表格只有 温度 一列，但可以根据所选的子设备展示不同的数据；
  // 综上所述，此组件在基础的历史数据组件上添加了子设备下拉框（由字典驱动），用户选择子设备后表头将动态调整以适配数据展示；
  //
  // 使用方法如下：
  // 设有历史数据2条，[{ name, forcFan1Temp, forcFan2Temp }, { name, forcFan1Temp, forcFan2Temp }]。
  //
  // 1、配置设备字段（参考公司端综合设备管理-设备字段管理）
  // 以压风机为例，设压风机设备的历史数据编码为forcFan_history。
  // 那么字段code中需要把所有字段悉数配置，例子如下：
  //  显示字段    字段code
  //   温度     forcFanTemp
  //  安装位置      name
  //
  // 2、配置数据字典（参考系统管理-数据字典），为上述设备配置子设备
  // 同以压风机为例，设压风机子设备字典编码为forcFan_dict，且已经新增到系统中。
  // 则字典配置的例子如下：
  //  名称    数据值
  // 压风机1 forcFan1
  // 压风机2 forcFan2
  //
  // 3、运维人员应配合前端开发人员，使用指定的编码配置内容。
  // 同以压风机为例，需使用device-code（forcFan）、dict-code（forcFan_dict）。
  //
  // 4、其他内容说明
  // 同以压风机为例，当子设备没有数据时，不进行过滤，此时展示的数据是：
  //      温度    安装位置
  // 取forcFanTemp    取name
  // 同以压风机为例，当子设备选择压风机1时，过滤压风机1相关的表头，此时展示的数据是：
  //      温度        安装位置
  // 取forcFan1Temp    取name
  // 当设备字段不含数据字典关键词（forcFan）时不做处理，当设备字段包含关键词但已指定编号（即字段包含数字）时不做处理
  import { onMounted, ref, shallowRef } from 'vue';
  import { BasicColumn, PaginationProps, BasicTable } from '/@/components/Table';
  import { getTableHeaderColumns } from '/@/hooks/web/useWebColumns';
  import { defaultFormProps, defaultPaginationProps, getDefaultSchemas, defaultTableProps } from './history.data';
  import { getDeviceList, list } from './history.api';
  import { useListPage } from '/@/hooks/system/useListPage';
  import { initDictOptions } from '/@/utils/dict';

  const props = withDefaults(
    defineProps<{
      /** 表格项配置，默认由deviceCode获取且联动dictCode，可以覆写，覆写后将不支持联动，参考BaiscTable */
      // columns?: BasicColumn[];
      /** 表格操作项配置，默认为空，可以覆写 */
      // actionColumns?: BasicColumn;
      /** 查询表单项配置，默认联动dictCode，可以覆写，覆写后将不支持联动，提供formProps时此项无效，参考BaiscTable */
      // schemas?: FormSchema[];
      /** 表格分页配置，可以覆写，参考BaiscTable */
      pagination?: PaginationProps;
      /** 设备编码，该编码用于请求设备信息，示例：forcFan */
      deviceCode: string;
      /** 字典编码，该编码用于从字典配置中读出设备项，示例：forcFan_dict */
      dictCode: string;
      /** 字段编码，该编码用于从设备字段配置中读取默认表头信息，示例：forcFan_history */
      columnsCode: string;

      scroll: { x: number | true; y: number };
      /** 表格配置，参考BaiscTable，该值会与默认的配置进行浅合并，这里提供的任何配置都是优先的 */
      // tableProps?: BasicTableProps;
      /** 查询表单配置，参考BaiscTable */
      // formProps?: FormProps;
    }>(),
    {
      deviceCode: '',
      dictCode: '',
    }
  );

  // 创建表格，此表格目前不具备常用功能，需要初始化后使用（props指定表格配置时除外）
  let originColumns: BasicColumn[] = [];
  const { tableContext } = useListPage({ tableProps: defaultTableProps });
  const [register, { getForm, setLoading, getPaginationRef, setPagination, setProps, setColumns }] = tableContext;

  /**
   * 初始化表格，该方法将根据参数设定新的表头、表单，如果提供了自定义的表头、表单配置则不作操作。
   *
   * 之所以将设备相关的信息作参数传入，是因为这样可以确认依赖关系，即需要有设备信息之后再初始化表格。
   *
   * @param deviceCodes 获取表头所用的编码，从左到右依次尝试，直到找到第一个有表头信息的为止
   * @param deviceOptions 设备下拉框对应的选项
   */
  function initTable(deviceCodes: string[], deviceOptions: any[], dictOptions: any[]) {
    const defaultSchemas = getDefaultSchemas(dictOptions, deviceOptions);
    for (const code of deviceCodes) {
      const cols = getTableHeaderColumns(code);
      if (cols.length) {
        originColumns = cols;
        break;
      }
    }
    setProps({
      formConfig: {
        ...defaultFormProps,
        schemas: defaultSchemas,
      },
      pagination: props.pagination || defaultPaginationProps,
    });
  }

  /**
   * 更新表头，表头默认情况下需要和子设备联动
   * @param prefix 子设备的值，即为表头取数据时字段的前缀
   */
  function updateColumns(prefix?: string) {
    if (!prefix) return setColumns(originColumns);
    // 如果有子设备信息，筛选符合规范的表头
    const cols = originColumns.map((col) => {
      const dataIndex = col.dataIndex as string;
      // 获取到子设备编码的前缀及编码，正则例子：forcFan1 => [forcFan1, forcFan, 1]
      const [_, pfx] = prefix.match(/([A-Za-z]+)([0-9]+)/) || [];
      // 同时，如若已经在前缀后配置了编号则不要更改
      const reg = new RegExp(`${pfx}[0-9]`);
      if (dataIndex.search(reg) !== -1) return col;
      if (dataIndex.includes(pfx)) {
        return {
          ...col,
          dataIndex: dataIndex.replace(pfx, prefix),
        };
      }
      // 默认直接放行
      return col;
    });
    setColumns(cols);
  }

  // 表格数据相关的字段
  const data = shallowRef([]);

  /**
   * 获取列表的数据
   *
   * 这些参数确认了依赖关系，即需要有表单数据、设备信息之后再尝试获取表格数据。
   *
   * @param formData 表格上方的表单数据
   * @param deviceCode 设备编码
   * @param deviceInfo 设备信息
   */
  function fetchData(formData: Record<string, unknown>, deviceCode: string, deviceInfo: any) {
    setLoading(true);
    const pagination = getPaginationRef() as PaginationProps;
    return list(deviceCode, deviceInfo, formData, pagination)
      .then(({ records, total, current }) => {
        setPagination({
          current,
          total,
        });
        records.forEach((item) => {
          Object.assign(item, item.readData);
        });
        data.value = records;
      })
      .finally(() => {
        setLoading(false);
      });
  }

  // 设备信息相关的字段
  const deviceInfo = ref<Record<string, unknown>>({});
  const deviceOptions = ref<Record<string, unknown>[]>([]);
  const dictOptions = ref<Record<string, unknown>[]>([]); // 子设备下拉框选项

  /**
   * 获取设备信息列表，初始化设备信息及设备可选项
   */
  async function fetchDevice() {
    const results = await getDeviceList({ devicetype: props.deviceCode, pageSize: 10000 });
    const dicts = await initDictOptions(props.dictCode);

    const options = results.map((item) => {
      return {
        label: item.strinstallpos,
        value: item.id || item.deviceID,
        deviceType: item.strtype || item.deviceType,
        devicekind: item.devicekind,
        stationtype: item.stationtype,
      };
    });
    deviceOptions.value = options;
    deviceInfo.value = results[0];
    dictOptions.value = dicts;
  }

  /**
   * 搜索，核心方法
   *
   * 该方法获取表单、处理表单数据后尝试获取数据并设置表头
   */
  async function search() {
    const form = getForm();
    await form.validate();
    const formData = form.getFieldsValue();
    deviceInfo.value = deviceOptions.value.find((opt) => {
      return opt.value === formData.gdeviceid;
    }) as Record<string, unknown>;
    const code = (deviceInfo.value.deviceType || props.deviceCode.concat('*')) as string;
    await fetchData(formData, code, deviceInfo.value);
    updateColumns(formData.deviceNum);
  }

  onMounted(async () => {
    await fetchDevice();
    // 生成所有需要查询的表头编码，例如 forcFan_auto 对应 forcFan_auto_history、forcFan_history 这两个
    const codes: string[] = [];
    if (deviceInfo.value.deviceType) {
      const arr = (deviceInfo.value.deviceType as string).split('_');
      while (arr.length) {
        codes.push(arr.join('_').concat('_history'));
        arr.pop();
      }
    }
    // 如此，例如deviceType为forcFan_auto， 则查询表头按 forcFan_auto_history、forcFan_history、columnsCode 为顺序
    initTable(codes.concat(props.columnsCode), deviceOptions.value, dictOptions.value);
    search();
  });
</script>

<style scoped lang="less">
  @import '/@/design/theme.less';

  :deep(.@{ventSpace}-table-body) {
    height: auto !important;
  }
  :deep(.zxm-picker) {
    height: 30px !important;
  }
  :deep(.zxm-table) {
    .zxm-table-title {
      display: none !important;
    }
  }
  .history-table {
    width: 100%;
    :deep(.jeecg-basic-table-form-container) {
      .@{ventSpace}-form {
        padding: 0 !important;
        border: none !important;
        margin-bottom: 0 !important;
        .@{ventSpace}-picker,
        .@{ventSpace}-select-selector {
          width: 100% !important;
          background: #00000017;
          border: 1px solid #b7b7b7;
          input,
          .@{ventSpace}-select-selection-item,
          .@{ventSpace}-picker-suffix {
            color: #fff;
          }
          .@{ventSpace}-select-selection-placeholder {
            color: #ffffffaa;
          }
        }
      }
      .@{ventSpace}-table-title {
        min-height: 0 !important;
      }
    }
    .pagination-box {
      display: flex;
      justify-content: flex-end;
      align-items: center;
      .page-num {
        border: 1px solid #0090d8;
        padding: 4px 8px;
        margin-right: 5px;
        color: #0090d8;
      }
      .btn {
        margin-right: 10px;
      }
    }
  }
</style>
