<template>
  <basic-container class="cargo-type-page">
    <avue-crud
      :option="option"
      :table-loading="loading"
      :data="data"
      v-model:page="page"
      v-model="form"
      ref="crud"
      :permission="permissionList"
      :before-open="beforeOpen"
      @row-save="rowSave"
      @row-update="rowUpdate"
      @row-del="rowDel"
      @search-change="searchChange"
      @search-reset="searchReset"
      @selection-change="selectionChange"
      @current-change="currentChange"
      @size-change="sizeChange"
      @refresh-change="refreshChange"
      @on-load="onLoad"
    >
      <template #menu-left>
        <el-button type="primary" v-if="permission.cargo_type_add" @click="$refs.crud.rowAdd()">
          <el-icon class="el-icon--left"><Plus /></el-icon>新建货物类型
        </el-button>
        <el-button type="primary" plain v-if="permission.cargo_type_import" @click="handleImport"
          ><el-icon class="el-icon--left"><Upload /></el-icon>批量导入</el-button
        >
        <el-button
          type="primary"
          plain
          v-if="permission.cargo_type_template"
          @click="handleTemplate"
          ><el-icon class="el-icon--left"><Download /></el-icon>下载模板</el-button
        >
        <el-button type="primary" plain v-if="permission.cargo_type_export" @click="handleExport"
          ><el-icon class="el-icon--left"><Download /></el-icon>批量导出</el-button
        >
        <el-button type="danger" plain v-if="permission.cargo_type_delete" @click="handleDelete"
          ><el-icon class="el-icon--left"><Delete /></el-icon>批量删除</el-button
        >
      </template>

      <template #typeLevel-header>
        <span>货物类型</span>
      </template>
      <template #parentCargoName="{ row }">
        {{ row.typeLevel === 1 ? '/' : row.parentCargoName || '/' }}
      </template>
      <template #parentCargoCode-header>
        <span>上级货物类型编码</span>
      </template>
      <template #parentCargoCode="{ row }">
        {{ row.typeLevel === 1 ? '/' : row.parentCargoCode || '/' }}
      </template>
      <template #createUserName="{ row }">
        {{ row.createUserName || row.createUser || '' }}
      </template>

      <template #parentId-form>
        <el-select
          v-model="form.parentId"
          filterable
          remote
          clearable
          :remote-method="loadParentOptions"
          :loading="parentLoading"
          :disabled="dialogType === 'view' || form.typeLevel !== 2"
          placeholder="请输入"
          style="width: 100%"
          @change="handleParentChange"
        >
          <el-option
            v-for="item in parentOptions"
            :key="item.id"
            :label="`${item.cargoName}（${item.cargoCode}）`"
            :value="item.id"
          />
        </el-select>
      </template>

      <template #menu="{ row, index }">
        <el-link
          type="primary"
          v-if="permission.cargo_type_view"
          @click="$refs.crud.rowView(row, index)"
        >
          查看
        </el-link>
        <el-link
          type="primary"
          v-if="permission.cargo_type_edit"
          @click="$refs.crud.rowEdit(row, index)"
        >
          编辑
        </el-link>
        <el-link type="primary" v-if="permission.cargo_type_delete" @click="rowDel(row)">
          删除
        </el-link>
      </template>
    </avue-crud>

    <empty-pagination
      :page="page"
      @size-change="sizeChange"
      @current-change="currentChange"
      @load="onLoad(page, query)"
    />

    <el-dialog title="货物类型导入" append-to-body v-model="excelBox" width="555px">
      <avue-form :option="excelOption" v-model="excelForm">
        <template #excelTemplate>
          <el-button type="primary" @click="handleTemplate">
            点击下载<i class="el-icon-download el-icon--right"></i>
          </el-button>
        </template>
      </avue-form>
    </el-dialog>
  </basic-container>
</template>

<script>
import { getList, getNextCode, getParentOptions, remove, submit } from '@/api/base/cargo-type';
import { getCargoTypeOption } from '@/option/base/cargo-type';
import { exportBlob } from '@/api/common';
import { mapGetters } from 'vuex';
import { downloadXls } from '@/utils/util';
import { openImportDialog } from '@/utils/import-excel';
import { getUploadHeaders } from '@/utils/upload';
import NProgress from 'nprogress';
import 'nprogress/nprogress.css';
import { Plus, Upload, Download, Delete } from '@element-plus/icons-vue';

// 导入失败明细中，每个错误文本对应的「字段列」与「规则说明」
const CARGO_TYPE_FAIL_RULES = [
  { match: '请选择货物类型级别', col: '类型', rule: '仅允许：一级货物类型/二级货物类型' },
  { match: '货物类型编码格式不正确', col: '货物类型编码', rule: '一级2位数字，二级4位数字' },
  { match: '该货物类型编码已存在', col: '货物类型编码', rule: '请更换唯一编码' },
  { match: '请选择上级货物类型', col: '上级货物类型', rule: '二级货物类型必须选择上级' },
  {
    match: '二级编码前2位必须与上级货物类型编码一致',
    col: '货物类型编码',
    rule: '二级编码前2位必须与上级货物类型编码一致',
  },
  { match: '货物类型名称不能超过50字符', col: '货物类型', rule: '货物类型名称不能超过50字符' },
  { match: '备注不能超过200字', col: '备注', rule: '备注不能超过200字' },
];

// 失败明细各列目标宽度（Excel 字符数），key 与后端 CargoTypeImportFailureExcel 表头完全一致
const CARGO_TYPE_FAIL_COL_WIDTH = {
  '*类型': 16,
  '上级货物类型（如为一级则不需填写）': 22,
  '上级货物类型编码（如为一级则不需填写）': 26,
  '*货物类型': 18,
  '*货物类型编码': 18,
  备注: 24,
  导入失败原因: 70,
};

/**
 * 加工后端返回的导入失败明细 Excel：
 * - 「导入失败原因」列按 1. 2. 3. 编号列出，多条以分号隔开
 * - 每个错误后追加对应规则说明，仅失败原因列标红
 * - 适当加宽各列、原因列自动换行，避免内容拥挤
 */
export const decorateCargoTypeFailDetail = async workbook => {
  const ws = workbook.worksheets[0];
  if (!ws) return;
  const headerRow = ws.getRow(1);
  const colMap = {};
  headerRow.eachCell((cell, colNumber) => {
    const name = String(cell.value == null ? '' : cell.value).trim();
    if (name) colMap[name] = colNumber;
  });
  const reasonCol = colMap['导入失败原因'];
  if (!reasonCol) return;
  ws.eachRow((row, rowNumber) => {
    if (rowNumber === 1) return; // 跳过表头
    // 仅「导入失败原因」列允许红色，其他列红色字体统一清除
    row.eachCell((cell, colNumber) => {
      if (colNumber === reasonCol) return;
      if (cell.font && cell.font.color) {
        const font = { ...cell.font };
        delete font.color;
        cell.font = font;
      }
    });
    const reasonCell = row.getCell(reasonCol);
    let raw = String(reasonCell.value == null ? '' : reasonCell.value).trim();
    if (!raw) return;
    // 去掉后端可能已经存在的「第N行：」前缀，避免重复
    raw = raw.replace(/^第\s*\d+\s*行[：:]\s*/, '');
    const parts = raw
      .split(/[；;\n\r]+/)
      .map(s => s.trim().replace(/^第\s*\d+\s*行[：:]\s*/, ''))
      .filter(Boolean);
    if (parts.length === 0) return;
    const decorated = parts.map((part, index) => {
      const label = `${index + 1}.`; // 1. 2. 3.
      const rule = CARGO_TYPE_FAIL_RULES.find(r => part.includes(r.match));
      if (rule) {
        // 规则说明若已包含在错误文本中则不再重复拼接
        return part.includes(rule.rule) ? `${label}${part}` : `${label}${part}，${rule.rule}`;
      }
      return `${label}${part}`;
    });
    // 兜底：失败行的备注列超长（>200字）时，补充备注超长提示
    const remarkCol = colMap['备注'];
    if (remarkCol) {
      const remarkVal = String(
        row.getCell(remarkCol).value == null ? '' : row.getCell(remarkCol).value
      ).trim();
      if (remarkVal.length > 200 && !decorated.some(d => d.includes('备注不能超过200字'))) {
        decorated.push(`${decorated.length + 1}.备注不能超过200字`);
      }
    }
    reasonCell.value = decorated.join('；');
    // 仅操作 G 列：黑色字体、无背景填充，其余列保持后端原样
    reasonCell.fill = { type: 'pattern', pattern: 'none' };
    reasonCell.font = { color: { argb: 'FF000000' } };
    reasonCell.alignment = { wrapText: true, vertical: 'top' };
  });
  // 加宽各列，避免内容拥挤（仅改列宽，不改动单元格样式）
  Object.keys(colMap).forEach(name => {
    const col = ws.getColumn(colMap[name]);
    col.width = CARGO_TYPE_FAIL_COL_WIDTH[name] || 20;
  });
};

export default {
  components: { Plus, Upload, Download, Delete },
  data() {
    return {
      form: {},
      query: {},
      loading: true,
      data: [],
      excelBox: false,
      excelForm: {},
      parentOptions: [],
      parentLoading: false,
      dialogType: 'add',
      page: {
        pageSize: 10,
        pageSizes: [10, 20, 50, 100],
        currentPage: 1,
        total: 0,
      },
      selectionList: [],
      option: getCargoTypeOption(this),
      excelOption: {
        submitBtn: false,
        emptyBtn: false,
        column: [
          {
            label: '模板上传',
            prop: 'excelFile',
            type: 'upload',
            drag: true,
            loadText: '模板上传中，请稍等',
            span: 24,
            propsHttp: {
              res: 'data',
            },
            headers: getUploadHeaders(),
            tip: '请上传 .xls,.xlsx 标准格式文件',
            action: '/blade-system/cargo-type/import-cargo-type',
          },
          {
            label: '模板下载',
            prop: 'excelTemplate',
            formslot: true,
            span: 24,
          },
        ],
      },
    };
  },
  computed: {
    ...mapGetters(['permission']),
    permissionList() {
      return {
        addBtn: false,
      };
    },
    ids() {
      return this.selectionList.map(ele => ele.id).join(',');
    },
  },
  methods: {
    findCargoColumn(prop) {
      return this.option.column.find(item => item.prop === prop) || {};
    },
    syncColumnDisplay() {
      const isChild = this.form.typeLevel === 2;
      this.findCargoColumn('parentId').display = isChild;
      this.findCargoColumn('parentCargoCode').display = isChild;
      this.findCargoColumn('parentCargoCode').addDisplay = isChild;
      this.findCargoColumn('parentCargoCode').editDisplay = isChild;
    },
    handleTypeLevelChange(value) {
      this.form.typeLevel = value;
      if (value === 1) {
        this.form.parentId = undefined;
        this.form.parentCargoName = '';
        this.form.parentCargoCode = '';
        this.form.cargoCode = String(this.form.cargoCode || '')
          .replace(/\D/g, '')
          .slice(0, 2);
      } else {
        this.form.cargoCode = String(this.form.cargoCode || '')
          .replace(/\D/g, '')
          .slice(0, 4);
      }
      this.syncColumnDisplay();
    },
    handleCargoCodeChange(value) {
      const maxLength = this.form.typeLevel === 1 ? 2 : 4;
      this.form.cargoCode = String(value || '')
        .replace(/\D/g, '')
        .slice(0, maxLength);
    },
    loadParentOptions(keyword = '') {
      this.parentLoading = true;
      return getParentOptions(keyword)
        .then(res => {
          this.parentOptions = res.data.data || [];
        })
        .finally(() => {
          this.parentLoading = false;
        });
    },
    ensureParentOption(row) {
      if (!row.parentId || !row.parentCargoName) return;
      const exists = this.parentOptions.some(item => String(item.id) === String(row.parentId));
      if (exists) return;
      this.parentOptions = [
        ...this.parentOptions,
        {
          id: row.parentId,
          cargoName: row.parentCargoName,
          cargoCode: row.parentCargoCode,
        },
      ];
    },
    handleParentChange(value) {
      const parent = this.parentOptions.find(item => String(item.id) === String(value));
      this.form.parentCargoName = parent ? parent.cargoName : '';
      this.form.parentCargoCode = parent ? parent.cargoCode || parent.code || '' : '';
      if (parent) {
        this.$nextTick(() => {
          this.$refs.crud?.clearValidate?.(['parentId', 'parentCargoCode']);
        });
      }
      if (!parent) {
        this.form.cargoCode = '';
        return;
      }
      if (!this.form.parentCargoCode) {
        this.form.cargoCode = '';
        return;
      }
      getNextCode(this.form.parentCargoCode).then(res => {
        this.form.cargoCode = res.data.data;
      });
    },
    normalizeRow(row) {
      row.typeLevel = Number(row.typeLevel || 1);
      row.cargoName = String(row.cargoName || '').trim();
      row.cargoCode = String(row.cargoCode || '').trim();
      row.remark = String(row.remark || '').trim();
      if (row.typeLevel === 1) {
        row.parentId = undefined;
        row.parentCargoName = '';
        row.parentCargoCode = '';
      }
      return row;
    },
    validateRow(row) {
      if (![1, 2].includes(row.typeLevel)) {
        this.$message.warning('请选择货物类型级别');
        return false;
      }
      if (row.typeLevel === 2 && !row.parentId) {
        this.$message.warning('请选择上级货物类型');
        return false;
      }
      if (!row.cargoName) {
        this.$message.warning('请输入货物类型名称');
        return false;
      }
      if (row.cargoName.length > 50) {
        this.$message.warning('货物类型名称不能超过50字符');
        return false;
      }
      const pattern = row.typeLevel === 1 ? /^\d{2}$/ : /^\d{4}$/;
      if (!pattern.test(row.cargoCode)) {
        this.$message.warning('货物类型编码格式不正确');
        return false;
      }
      if (row.typeLevel === 2 && !row.cargoCode.startsWith(row.parentCargoCode)) {
        this.$message.warning('二级编码前2位必须与上级货物类型编码一致');
        return false;
      }
      if (row.remark.length > 200) {
        this.$message.warning('备注不能超过200字');
        return false;
      }
      return true;
    },
    rowSave(row, done, loading) {
      const submitRow = this.normalizeRow(row);
      if (!this.validateRow(submitRow)) {
        loading();
        return;
      }
      submit(submitRow).then(
        () => {
          this.onLoad(this.page);
          this.$message({ type: 'success', message: '操作成功!' });
          done();
        },
        error => {
          loading();
        }
      );
    },
    rowUpdate(row, index, done, loading) {
      const submitRow = this.normalizeRow(row);
      if (!this.validateRow(submitRow)) {
        loading();
        return;
      }
      submit(submitRow).then(
        () => {
          this.onLoad(this.page);
          this.$message({ type: 'success', message: '操作成功!' });
          done();
        },
        error => {
          loading();
        }
      );
    },
    rowDel(row) {
      this.$confirm('确定要删除该货物类型吗？删除后不可恢复。', {
        confirmButtonText: '确定',
        cancelButtonText: '取消',
        type: 'warning',
      })
        .then(() => remove(row.id))
        .then(() => {
          this.afterDelete(1);
          this.$message({ type: 'success', message: '操作成功!' });
        });
    },
    handleDelete() {
      if (this.selectionList.length === 0) {
        this.$message.warning('请选择至少一条数据');
        return;
      }
      this.$confirm('确定删除所选数据，删除后不可恢复?', {
        confirmButtonText: '确定',
        cancelButtonText: '取消',
        type: 'warning',
      })
        .then(() => remove(this.ids))
        .then(() => {
          this.afterDelete(this.selectionList.length);
          this.$message({ type: 'success', message: '操作成功!' });
          this.$refs.crud.toggleSelection();
        });
    },
    afterDelete(deleteCount) {
      if (this.page.currentPage > 1 && this.data.length <= deleteCount) {
        this.page.currentPage -= 1;
      }
      this.onLoad(this.page, this.query);
    },
    beforeOpen(done, type) {
      this.dialogType = type || 'add';
      if (['edit', 'view'].includes(type)) {
        // 列表已返回完整 CargoTypeVO，直接复用 Avue 填充的 this.form，无需再请求 detail
        this.ensureParentOption(this.form);
        this.syncColumnDisplay();
        done();
        return;
      }
      this.form = {
        typeLevel: 2,
        cargoName: '',
        cargoCode: '',
        parentId: undefined,
        parentCargoName: '',
        parentCargoCode: '',
        remark: '',
      };
      this.syncColumnDisplay();
      done();
    },
    searchReset() {
      this.query = {};
      this.page.currentPage = 1;
      this.onLoad(this.page);
    },
    searchChange(params, done) {
      this.query = params;
      this.page.currentPage = 1;
      this.onLoad(this.page, params);
      done();
    },
    selectionChange(list) {
      this.selectionList = list;
    },
    selectionClear() {
      this.selectionList = [];
      this.$refs.crud.toggleSelection();
    },
    currentChange(currentPage) {
      this.page.currentPage = currentPage;
    },
    sizeChange(pageSize) {
      this.page.pageSize = pageSize;
    },
    refreshChange() {
      this.onLoad(this.page, this.query);
    },
    onLoad(page, params = {}) {
      this.loading = true;
      getList(page.currentPage, page.pageSize, { ...params, ...this.query })
        .then(res => {
          const data = res.data.data;
          this.page.total = data.total;
          this.data = data.records || [];
          this.selectionClear();
        })
        .finally(() => {
          this.loading = false;
        });
    },
    handleImport() {
      openImportDialog(this, '货物类型', undefined, {
        failDetailDecorator: decorateCargoTypeFailDetail,
      });
    },
    buildExportParams() {
      return {
        ...this.query,
        ...(this.ids ? { ids: this.ids } : {}),
      };
    },
    handleExport() {
      this.$confirm('是否导出货物类型数据?', '提示', {
        confirmButtonText: '确定',
        cancelButtonText: '取消',
        type: 'warning',
      }).then(() => {
        NProgress.start();
        exportBlob(
          '/blade-system/cargo-type/export-cargo-type',
          this.buildExportParams(),
          { feedback: true }
        )
          .then(res => {
            downloadXls(res.data, `货物类型${this.$dayjs().format('YYYY-MM-DD HH:mm:ss')}.xlsx`);
          })
          .finally(() => {
            NProgress.done();
          });
      });
    },
    handleTemplate() {
      NProgress.start();
      exportBlob('/blade-system/cargo-type/export-template', {}, { feedback: true })
        .then(res => {
          downloadXls(res.data, '货物类型导入模板.xlsx');
        })
        .catch(() => {
          this.$message.error('模板下载失败，请稍后重试');
        })
        .finally(() => {
          NProgress.done();
        });
    },
  },
};
</script>

<style lang="scss" scoped>
.cargo-type-page {
  :deep(.avue-crud__header) {
    margin-top: 12px;
    background: transparent;
  }

  // ��除 basic-container 卡片内层 el-card 的 padding（规范 4.4）
  :deep(.basic-container__card) > .el-card__body {
    padding: 0;
  }

  // 搜索栏 label 收窄（覆盖 Avue 内置 min-width:160px）
  :deep(.avue-crud__search) .el-form-item_label {
    min-width: 50px !important;
    width: 50px !important;
  }

  :deep(.el-table) {
    --el-table-border-color: #eff1f7;
    --el-table-row-hover-bg-color: #f5f7fa;
    --el-table-row-height: 40px;

    // 表头加高
    .el-table__header-wrapper .el-table__cell {
      padding: 10px 0;
    }

    // 数据行保持紧凑
    .el-table__body .el-table__cell {
      padding: 6px 0;
    }
  }

  // 底部空白区域自适应：表格 body 不再强制撑满计算高度
  :deep(.avue-crud .el-table__body-wrapper) {
    max-height: none !important;
    height: auto !important;
  }

  // 同步让外层表格容器也自适应
  //:deep(.avue-crud .el-table) {
  //  height: auto !important;
  //}

  :deep(.el-table__body tr:nth-child(even) > td.el-table__cell) {
    background: #fafafa;
  }

  :deep(.el-table__body tr:nth-child(even) > td.el-table-fixed-column--left),
  :deep(.el-table__body tr:nth-child(even) > td.el-table-fixed-column--right) {
    background: #fafafa;
  }
}
</style>
