<template>
  <basic-container class="port-terminal-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"
          icon="el-icon-upload"
          plain
          v-if="hasPermission('port_terminal_import')"
          @click="handleImport"
          >批量导入
        </el-button>
        <el-button
          type="primary"
          icon="el-icon-download"
          plain
          v-if="hasPermission('port_terminal_template')"
          @click="handleTemplate"
          >下载模板
        </el-button>
        <el-button
          type="primary"
          icon="el-icon-download"
          plain
          v-if="hasPermission('port_terminal_export')"
          @click="handleExport"
          >批量导出
        </el-button>
        <el-button
          type="danger"
          icon="el-icon-delete"
          plain
          v-if="hasPermission('port_terminal_delete')"
          @click="handleDelete"
          >批量删除
        </el-button>
      </template>
      <template #parentName="{ row }">
        <span>{{ row.category === '港口' ? '-' : row.parentName }}</span>
      </template>
      <template #parentCode="{ row }">
        <span>{{ row.category === '港口' ? '-' : row.parentCode }}</span>
      </template>
      <template #name-header>
        <span>港口/码头</span>
      </template>
      <template #status="{ row }">
        <el-tag :type="row.status === 1 ? 'primary' : 'info'">
          {{ row.status === 1 ? '启用' : '停用' }}
        </el-tag>
      </template>
      <template #country-form>
        <el-select
          v-model="form.countryCode"
          clearable
          filterable
          :disabled="isParentRegionLocked"
          :placeholder="isParentRegionLocked ? '自动带出' : '请选择国家'"
          style="width: 100%"
          @change="handleCountryChange"
        >
          <el-option
            v-for="item in countryOptions"
            :key="item.id"
            :label="item.title"
            :value="item.id"
          />
        </el-select>
      </template>
      <template #category-form>
        <el-radio-group v-model="form.category" @change="handleCategoryChange">
          <el-radio label="港口">港口</el-radio>
          <el-radio label="码头">码头</el-radio>
        </el-radio-group>
      </template>
      <template #code-form>
        <el-input
          v-if="form.category !== '码头'"
          v-model="form.code"
          clearable
          maxlength="5"
          placeholder="请输入5位大写字母"
          @input="handleCodeChange"
          @blur="handleCodeChange(form.code)"
        />
        <div v-else>
          <el-input
            v-model="form.terminalCode"
            clearable
            maxlength="24"
            placeholder="请输入码头标识"
            @input="handleTerminalCodeChange"
          />
        </div>
      </template>
      <template #menu="{ row, index }">
        <el-link
          type="primary"
          v-if="hasPermission('port_terminal_edit')"
          @click="$refs.crud.rowEdit(row, index)"
        >
          编辑
        </el-link>
        <el-link
          type="primary"
          v-if="hasPermission('port_terminal_status')"
          @click="handleStatus(row)"
        >
          {{ row.status === 1 ? '停用' : '启用' }}
        </el-link>
      </template>
      <template #cityCode-form>
        <el-select
          v-model="form.cityCode"
          clearable
          filterable
          :loading="cityLoading"
          :disabled="isCityDisabled"
          :placeholder="isParentRegionLocked ? '自动带出' : '请先选择国家'"
          style="width: 100%"
          @change="handleCityChange"
        >
          <el-option
            v-for="item in cityOptions"
            :key="item.id"
            :label="item.title"
            :value="item.id"
          />
        </el-select>
      </template>
      <template #districtCode-form>
        <el-select
          v-model="form.districtCode"
          clearable
          filterable
          :loading="districtLoading"
          :disabled="isDistrictDisabled"
          :placeholder="
            isParentRegionLocked ? '自动带出' : form.cityCode ? '请选择区县' : '请先选择城市'
          "
          style="width: 100%"
          @change="handleDistrictChange"
        >
          <el-option
            v-for="item in districtOptions"
            :key="item.id"
            :label="item.title"
            :value="item.id"
          />
        </el-select>
      </template>
      <template #detailAddress="{ row }">
        <span class="port-terminal-page__detail-address">{{ row.detailAddress || '-' }}</span>
      </template>
      <template #longitude-form>
        <el-input
          v-model="form.longitude"
          clearable
          placeholder="请输入经度"
          @input="handleCoordinateInput('longitude', $event)"
        />
      </template>
      <template #latitude-form>
        <el-input
          v-model="form.latitude"
          clearable
          placeholder="请输入纬度"
          @input="handleCoordinateInput('latitude', $event)"
        />
      </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,
  getDetail,
  submit,
  remove,
  changeStatus,
  getPortSelect,
} from '@/api/base/port-terminal';
import { getLazyTree } from '@/api/base/region';
import { exportBlob } from '@/api/common';
import { mapGetters } from 'vuex';
import { downloadXls } from '@/utils/util';
import { openImportDialog } from '@/utils/import-excel';
import { formatUpdateUserName } from '@/utils/audit';
import { getToken } from '@/utils/auth';
import { getCoordinateValidationMessage, normalizeCoordinateInput } from '@/utils/coordinate';
import NProgress from 'nprogress';
import 'nprogress/nprogress.css';

const DEFAULT_COUNTRY_CODE = '+86';
const EXCLUDED_EXCEL_HEADERS = ['数据来源', '启停状态'];
const REQUIRED_EXPORT_HEADERS = [
  '港口码头名称',
  '港口/码头名称',
  '类型',
  '国家',
  '城市',
  '经度',
  '纬度',
];

const getExcelCellText = value => {
  if (value === undefined || value === null) return '';
  if (typeof value === 'object') {
    if (Array.isArray(value.richText)) {
      return value.richText.map(item => item.text || '').join('');
    }
    if (value.text) return value.text;
    if (value.result) return value.result;
  }
  return String(value);
};

const removeWorkbookColumnsByHeaders = workbook => {
  workbook.eachSheet(worksheet => {
    const maxHeaderRow = Math.min(worksheet.rowCount || 0, 10);
    for (let rowIndex = 1; rowIndex <= maxHeaderRow; rowIndex += 1) {
      const row = worksheet.getRow(rowIndex);
      const indexes = [];
      row.eachCell((cell, colNumber) => {
        const text = getExcelCellText(cell.value).trim();
        if (EXCLUDED_EXCEL_HEADERS.includes(text)) {
          indexes.push(colNumber);
        }
      });
      if (indexes.length) {
        indexes.sort((a, b) => b - a).forEach(colNumber => worksheet.spliceColumns(colNumber, 1));
        break;
      }
    }
  });
};

const addWorkbookRequiredHeaderMarks = workbook => {
  workbook.eachSheet(worksheet => {
    const maxHeaderRow = Math.min(worksheet.rowCount || 0, 10);
    for (let rowIndex = 1; rowIndex <= maxHeaderRow; rowIndex += 1) {
      const row = worksheet.getRow(rowIndex);
      let hasRequiredHeader = false;
      row.eachCell(cell => {
        const text = getExcelCellText(cell.value).trim();
        const header = text.replace(/\*+$/g, '').trim();
        if (REQUIRED_EXPORT_HEADERS.includes(header)) {
          cell.value = `${header}*`;
          hasRequiredHeader = true;
        }
      });
      if (hasRequiredHeader) break;
    }
  });
};

const removeExcelColumnsByHeaders = async (blob, options = {}) => {
  const { markRequiredHeaders = false } = options;
  const ExcelJS = await import('exceljs');
  const workbook = new ExcelJS.Workbook();
  await workbook.xlsx.load(await blob.arrayBuffer());
  removeWorkbookColumnsByHeaders(workbook);
  if (markRequiredHeaders) {
    addWorkbookRequiredHeaderMarks(workbook);
  }
  const buffer = await workbook.xlsx.writeBuffer();
  return new Blob([buffer], { type: 'application/vnd.ms-excel' });
};

export default {
  data() {
    const validateCode = (rule, value, callback) => {
      const code = String(value || '').toUpperCase();
      if (this.form.category === '港口') {
        if (!/^[A-Z]{5}$/.test(code)) {
          callback(new Error('港口编码为5位大写字母，如：CNSHG'));
        } else {
          callback();
        }
        return;
      }
      if (this.form.category === '码头') {
        if (!/^[A-Z]{5}-[A-Z0-9]+$/.test(code)) {
          callback(new Error('码头编码格式为“港口编码-码头标识”，如：CNSHG-CT1'));
        } else if (this.form.parentCode && !code.startsWith(`${this.form.parentCode}-`)) {
          callback(new Error(`码头编码须以所选上级港口编码 ${this.form.parentCode}- 开头`));
        } else {
          callback();
        }
        return;
      }
      callback();
    };
    const validateLongitude = (rule, value, callback) => {
      const message = getCoordinateValidationMessage(value, 'longitude');
      if (message) {
        callback(new Error(message));
      } else {
        callback();
      }
    };
    const validateLatitude = (rule, value, callback) => {
      const message = getCoordinateValidationMessage(value, 'latitude');
      if (message) {
        callback(new Error(message));
      } else {
        callback();
      }
    };
    return {
      form: {},
      query: {},
      loading: true,
      data: [],
      excelBox: false,
      excelForm: {},
      portOptions: [],
      countryOptions: [],
      cityOptions: [],
      cityLoading: false,
      cityOptionCache: {},
      districtOptions: [],
      districtLoading: false,
      districtOptionCache: {},
      page: {
        pageSize: 10,
        pageSizes: [10, 20, 50, 100],
        currentPage: 1,
        total: 0,
      },
      selectionList: [],
      option: {
        height: 'auto',
        calcHeight: 32,
        dialogWidth: 980,
        labelPosition: 'right',
        labelWidth: 'auto',
        tip: false,
        searchShow: true,
        searchLabelWidth: 160,
        searchIcon: true,
        searchIndex: 4,
        searchMenuSpan: 24,
        searchMenuPosition: 'right',
        border: true,
        index: true,
        indexLabel: '序号',
        indexWidth: 70,
        viewBtn: false,
        delBtn: false,
        editBtn: false,
        selection: true,
        dialogClickModal: false,
        menuWidth: 180,
        column: [
          {
            label: '编码',
            prop: 'code',
            search: true,
            formslot: true,
            width: 140,
            span: 12,
            order: 70,
            placeholder: '请输入编码',
            rules: [
              { required: true, message: '请输入编码', trigger: 'blur' },
              { validator: validateCode, trigger: 'blur' },
            ],
            change: ({ value }) => this.handleCodeChange(value),
            blur: ({ value }) => this.handleCodeChange(value),
          },
          {
            label: '港口/码头名称',
            prop: 'name',
            minWidth: 140,
            search: true,
            searchOrder: 7,
            span: 12,
            order: 80,
            placeholder: '请输入',
            rules: [{ required: true, message: '请输入港口/码头名称', trigger: 'blur' }],
          },
          {
            label: '类型',
            prop: 'category',
            type: 'select',
            search: true,
            searchOrder: 6,
            formslot: true,
            span: 24,
            order: 100,
            dicData: [
              { label: '全部', value: '' },
              { label: '港口', value: '港口' },
              { label: '码头', value: '码头' },
            ],
            rules: [{ required: true, message: '请选择类型', trigger: 'change' }],
            change: ({ value }) => this.handleCategoryChange(value),
          },
          {
            label: '上级港口',
            prop: 'parentId',
            type: 'select',
            props: {
              label: 'name',
              value: 'id',
            },
            dicData: [],
            hide: true,
            span: 12,
            order: 90,
            placeholder: '请选择',
            rules: [{ required: false, message: '请选择上级港口', trigger: 'change' }],
            change: ({ value }) => this.handleParentChange(value),
          },
          {
            label: '上级港口',
            prop: 'parentName',
            minWidth: 140,
            slot: true,
            addDisplay: false,
            editDisplay: false,
          },
          {
            label: '上级港口编码',
            prop: 'parentCode',
            minWidth: 120,
            slot: true,
            span: 12,
            addDisplay: false,
            editDisplay: false,
            placeholder: '自动带出',
            rules: [{ required: false, message: '请选择上级港口', trigger: 'change' }],
          },
          {
            label: '国家',
            prop: 'country',
            type: 'select',
            search: true,
            searchOrder: 5,
            formslot: true,
            filterable: true,
            dicData: [],
            span: 12,
            order: 60,
            minWidth: 140,
            overHidden: false,
            placeholder: '自动带出',
            searchPlaceholder: '请选择 国家',
            change: ({ value }) => this.handleCountryNameChange(value),
            rules: [{ required: true, message: '请选择国家', trigger: 'change' }],
          },
          {
            label: '城市',
            prop: 'cityCode',
            formslot: true,
            hide: true,
            span: 12,
            order: 50,
            placeholder: '自动带出',
            rules: [{ required: true, message: '请选择所属城市', trigger: 'change' }],
          },
          {
            label: '城市',
            prop: 'city',
            type: 'select',
            search: true,
            searchOrder: 4,
            filterable: true,
            dicData: [],
            addDisplay: false,
            editDisplay: false,
            minWidth: 100,
            change: ({ value }) => this.handleCityNameChange(value),
          },
          {
            label: '区县',
            prop: 'districtCode',
            type: 'select',
            formslot: true,
            hide: true,
            props: {
              label: 'title',
              value: 'id',
            },
            dicData: [],
            span: 12,
            placeholder: '选择城市后再选择区县',
            rules: [{ required: true, message: '请选择区县', trigger: 'change' }],
          },
          {
            label: '区县',
            prop: 'districtName',
            type: 'select',
            search: true,
            searchOrder: 3,
            filterable: true,
            dicData: [],
            minWidth: 100,
            hide: true,
            addDisplay: false,
            editDisplay: false,
          },
          {
            label: '经度',
            prop: 'longitude',
            formslot: true,
            minWidth: 130,
            span: 12,
            order: 20,
            placeholder: '请输入',
            overHidden: false,
            rules: [
              { required: true, message: '请输入经度', trigger: 'blur' },
              { validator: validateLongitude, trigger: 'blur' },
            ],
          },
          {
            label: '纬度',
            prop: 'latitude',
            formslot: true,
            minWidth: 130,
            span: 12,
            order: 10,
            placeholder: '请输入',
            overHidden: false,
            rules: [
              { required: true, message: '请输入纬度', trigger: 'blur' },
              { validator: validateLatitude, trigger: 'blur' },
            ],
          },
          {
            label: '行政区划编码',
            prop: 'regionCode',
            minWidth: 140,
            span: 12,
            placeholder: '选择区县后自动填写',
            addDisplay: false,
            editDisplay: false,
            rules: [{ max: 32, message: '行政区划编码不能超过32字', trigger: 'blur' }],
          },
          {
            label: '详细地址',
            prop: 'detailAddress',
            type: 'textarea',
            slot: true,
            minRows: 3,
            span: 24,
            minWidth: 220,
            overHidden: false,
            order: 30,
            placeholder: '请输入',
            maxlength: 255,
            showWordLimit: true,
            rules: [{ max: 255, message: '详细地址不能超过255字', trigger: 'blur' }],
          },
          {
            label: '数据来源',
            prop: 'dataSource',
            type: 'select',
            search: true,
            searchOrder: 2,
            minWidth: 120,
            overHidden: false,
            addDisplay: false,
            editDisplay: false,
            dicData: [
              { label: '全部', value: '' },
              { label: '初始化导入', value: '初始化导入' },
              { label: '批量导入', value: '批量导入' },
              { label: '手工导入', value: '手工导入' },
            ],
          },
          {
            label: '备注',
            prop: 'remark',
            type: 'textarea',
            minRows: 4,
            span: 24,
            hide: true,
            maxlength: 200,
            showWordLimit: true,
            rules: [{ max: 200, message: '备注不能超过200个字', trigger: 'blur' }],
          },
          {
            label: '更新人',
            prop: 'updateUserName',
            formatter: formatUpdateUserName,
            addDisplay: false,
            editDisplay: false,
            minWidth: 120,
          },
          {
            label: '更新时间',
            prop: 'updateTime',
            sortable: true,
            type: 'datetime',
            format: 'YYYY-MM-DD HH:mm:ss',
            valueFormat: 'YYYY-MM-DD HH:mm:ss',
            addDisplay: false,
            editDisplay: false,
            minWidth: 160,
          },
          {
            label: '创建时间',
            prop: 'createTime',
            sortable: true,
            type: 'datetime',
            format: 'YYYY-MM-DD HH:mm:ss',
            valueFormat: 'YYYY-MM-DD HH:mm:ss',
            addDisplay: false,
            editDisplay: false,
            minWidth: 160,
          },
          {
            label: '状态',
            prop: 'status',
            type: 'select',
            search: true,
            searchOrder: 1,
            slot: true,
            dataType: 'number',
            minWidth: 110,
            overHidden: false,
            addDisplay: false,
            editDisplay: false,
            dicData: [
              { label: '全部', value: '' },
              { label: '启用', value: 1 },
              { label: '停用', value: 2 },
            ],
          },
        ],
      },
      excelOption: {
        labelPosition: 'right',
        submitBtn: false,
        emptyBtn: false,
        column: [
          {
            label: '模板上传',
            prop: 'excelFile',
            type: 'upload',
            drag: true,
            loadText: '模板上传中，请稍等',
            span: 24,
            propsHttp: {
              res: 'data',
            },
            tip: '请上传 .xls,.xlsx 标准格式文件',
            accept: '.xls,.xlsx',
            action: '/blade-system/port-terminal/import-port-terminal',
          },
          {
            label: '模板下载',
            prop: 'excelTemplate',
            formslot: true,
            span: 24,
          },
        ],
      },
    };
  },
  computed: {
    ...mapGetters(['permission', 'userInfo']),
    permissionList() {
      return {
        addBtn: this.hasPermission('port_terminal_add'),
      };
    },
    isAdmin() {
      const authority = this.userInfo && this.userInfo.authority;
      return Array.isArray(authority)
        ? authority.includes('admin')
        : String(authority || '').includes('admin');
    },
    isParentRegionLocked() {
      return this.form.category === '码头';
    },
    isCityDisabled() {
      return this.isParentRegionLocked || !this.form.countryCode;
    },
    isDistrictDisabled() {
      return this.isParentRegionLocked || !this.form.cityCode;
    },
    ids() {
      let ids = [];
      this.selectionList.forEach(ele => {
        ids.push(ele.id);
      });
      return ids.join(',');
    },
  },
  created() {
    this.loadCountryOptions();
    this.loadPortOptions();
  },
  methods: {
    hasPermission(code) {
      return this.isAdmin || this.validData(this.permission && this.permission[code], false);
    },
    handleCodeChange(value) {
      const code = String(value || '').toUpperCase();
      if (this.form.category === '港口') {
        this.form.code = code.replace(/[^A-Z]/g, '').slice(0, 5);
        return;
      }
      if (this.form.category === '码头') {
        const terminalCode = this.getTerminalCodePart(code).replace(/[^A-Z0-9]/g, '');
        if (this.form.parentCode) {
          this.handleTerminalCodeChange(terminalCode);
        } else {
          this.form.terminalCode = terminalCode;
          this.form.code = code.replace(/[^A-Z0-9-]/g, '');
        }
      }
    },
    handleTerminalCodeChange(value) {
      const terminalCode = String(value || '')
        .toUpperCase()
        .replace(/[^A-Z0-9]/g, '');
      this.form.terminalCode = terminalCode;
      this.form.code =
        this.form.parentCode && terminalCode ? `${this.form.parentCode}-${terminalCode}` : '';
    },
    getTerminalCodePart(code) {
      const value = String(code || '').toUpperCase();
      if (this.form.parentCode && value.startsWith(`${this.form.parentCode}-`)) {
        return value.slice(this.form.parentCode.length + 1);
      }
      return value.split('-').slice(1).join('-');
    },
    syncTerminalCode() {
      if (this.form.category !== '码头') return;
      this.form.terminalCode = this.getTerminalCodePart(this.form.code);
      this.handleTerminalCodeChange(this.form.terminalCode);
    },
    setColumnDisplay(prop, display) {
      const column = this.findColumn(this.option.column, prop);
      if (!column) return;
      column.display = display;
      column.addDisplay = display;
      column.editDisplay = display;
      column.viewDisplay = display;
    },
    loadCountryOptions() {
      return getLazyTree('0').then(res => {
        this.countryOptions = (res.data.data || []).map(this.normalizeRegionOption);
        const countryColumn = this.findColumn(this.option.column, 'country');
        countryColumn.dicData = this.countryOptions.map(country => ({
          label: country.title,
          value: country.title,
          id: country.id,
        }));
      });
    },
    loadPortOptions() {
      getPortSelect().then(res => {
        this.portOptions = res.data.data;
        this.findColumn(this.option.column, 'parentId').dicData = this.portOptions;
      });
    },
    clearParentPortFields() {
      this.form.parentId = undefined;
      this.form.parentCode = '';
      this.form.parentName = '';
      this.form.countryCode = '';
      this.form.country = '';
      this.clearCityValue();
    },
    handleCategoryChange(value, reset = true) {
      const parentColumn = this.findColumn(this.option.column, 'parentId');
      parentColumn.rules[0].required = value === '码头';
      this.setColumnDisplay('parentId', value === '码头');
      if (value === '港口') {
        this.form.parentId = undefined;
        this.form.parentCode = '';
        this.form.parentName = '';
        this.form.terminalCode = '';
        this.form.code = reset ? '' : String(this.form.code || '').split('-')[0];
      } else if (reset) {
        this.clearParentPortFields();
      }
      this.handleCodeChange(this.form.code);
    },
    handleCountryChange(value) {
      const country = this.countryOptions.find(item => item.id === value);
      this.form.country = country ? country.title : '';
      this.clearCityValue();
      this.loadCityOptions(value);
    },
    handleCountryNameChange(value) {
      const country = this.countryOptions.find(item => item.title === value);
      this.setDistrictOptions([]);
      this.loadCityOptions(country ? country.id : '');
    },
    syncCountryName(countryCode) {
      const country = this.countryOptions.find(item => item.id === countryCode);
      if (country) {
        this.form.country = country.title;
      }
    },
    normalizeRegionOption(region) {
      return {
        ...region,
        id: region.id === undefined || region.id === null ? region.id : String(region.id),
        parentCode:
          region.parentCode === undefined || region.parentCode === null
            ? region.parentCode
            : String(region.parentCode),
      };
    },
    setCityOptions(cityOptions) {
      this.cityOptions = cityOptions;
      const cityCodeColumn = this.findColumn(this.option.column, 'cityCode');
      if (cityCodeColumn) {
        cityCodeColumn.dicData = cityOptions;
      }
      const cityColumn = this.findColumn(this.option.column, 'city');
      if (cityColumn) {
        cityColumn.dicData = cityOptions.map(city => ({
          label: city.title,
          value: city.title,
          id: city.id,
        }));
      }
    },
    clearCityValue() {
      this.form.cityCode = undefined;
      this.form.city = '';
      this.clearDistrictValue();
    },
    clearDistrictValue() {
      this.form.districtCode = undefined;
      this.form.districtName = '';
      this.form.regionCode = '';
    },
    loadCityOptions(countryCode) {
      if (!countryCode) {
        this.setCityOptions([]);
        return Promise.resolve([]);
      }
      if (this.cityOptionCache[countryCode]) {
        this.setCityOptions(this.cityOptionCache[countryCode]);
        return Promise.resolve(this.cityOptionCache[countryCode]);
      }
      this.cityLoading = true;
      return getLazyTree(countryCode)
        .then(res => {
          const firstLevelList = (res.data.data || []).map(this.normalizeRegionOption);
          return Promise.all(
            firstLevelList.map(parent => {
              return getLazyTree(parent.id).then(childRes => {
                const childList = (childRes.data.data || []).map(this.normalizeRegionOption);
                return childList.map(child => ({
                  ...child,
                  parentCode: child.parentCode || parent.id,
                }));
              });
            })
          ).then(cityGroups => {
            const cityList = cityGroups.flat();
            const options = cityList.length > 0 ? cityList : firstLevelList;
            this.cityOptionCache[countryCode] = options;
            this.setCityOptions(options);
            return options;
          });
        })
        .finally(() => {
          this.cityLoading = false;
        });
    },
    resolveCityCode(cityName, regionCode) {
      const city = this.cityOptions.find(item => item.title === cityName || item.id === regionCode);
      return city ? city.id : '';
    },
    setDistrictOptions(districtOptions) {
      this.districtOptions = districtOptions;
      const districtCodeColumn = this.findColumn(this.option.column, 'districtCode');
      if (districtCodeColumn) {
        districtCodeColumn.dicData = districtOptions;
      }
      const districtNameColumn = this.findColumn(this.option.column, 'districtName');
      if (districtNameColumn) {
        districtNameColumn.dicData = districtOptions.map(district => ({
          label: district.title,
          value: district.title,
          id: district.id,
        }));
      }
    },
    loadDistrictOptions(cityCode) {
      if (!cityCode) {
        this.setDistrictOptions([]);
        return Promise.resolve([]);
      }
      if (this.districtOptionCache[cityCode]) {
        this.setDistrictOptions(this.districtOptionCache[cityCode]);
        return Promise.resolve(this.districtOptionCache[cityCode]);
      }
      this.districtLoading = true;
      return getLazyTree(cityCode)
        .then(res => {
          const options = (res.data.data || []).map(this.normalizeRegionOption);
          this.districtOptionCache[cityCode] = options;
          this.setDistrictOptions(options);
          return options;
        })
        .finally(() => {
          this.districtLoading = false;
        });
    },
    resolveDistrictCode(districtName, regionCode) {
      const district = this.districtOptions.find(
        item => item.id === regionCode || item.title === districtName
      );
      return district ? district.id : regionCode || '';
    },
    handleParentChange(value) {
      const parent = this.portOptions.find(item => item.id === value);
      if (!parent) {
        this.clearParentPortFields();
        this.syncTerminalCode();
        return;
      }
      const terminalCode =
        this.form.terminalCode ||
        String(this.form.code || '')
          .split('-')
          .slice(1)
          .join('-');
      this.form.parentCode = parent.code;
      this.form.parentName = parent.name;
      this.form.terminalCode = terminalCode;
      this.handleTerminalCodeChange(terminalCode);
      this.form.country = parent.country;
      this.form.city = parent.city;
      this.form.districtCode = parent.districtCode;
      this.form.districtName = parent.districtName;
      this.form.regionCode = parent.regionCode;
      this.resolveCountryCode(parent.country)
        .then(countryCode => {
          this.form.countryCode = countryCode;
          this.syncCountryName(countryCode);
          return this.loadCityOptions(countryCode);
        })
        .then(() => {
          this.form.cityCode = this.resolveCityCode(parent.city, parent.regionCode);
          return this.loadDistrictOptions(this.form.cityCode);
        })
        .then(() => {
          this.form.districtCode = this.resolveDistrictCode(parent.districtName, parent.regionCode);
          this.handleDistrictChange(this.form.districtCode);
        });
    },
    handleCityChange(value) {
      const city = this.cityOptions.find(item => item.id === value);
      this.form.city = city ? city.title : '';
      this.clearDistrictValue();
      this.loadDistrictOptions(value);
    },
    handleCityNameChange(value) {
      const city = this.cityOptions.find(item => item.title === value);
      this.setDistrictOptions([]);
      this.loadDistrictOptions(city ? city.id : '');
    },
    handleDistrictChange(value) {
      const district = this.districtOptions.find(item => item.id === value);
      this.form.districtName = district ? district.title : '';
      this.form.regionCode = value || '';
    },
    handleCoordinateInput(prop, value) {
      this.form[prop] = normalizeCoordinateInput(value);
    },
    resolveCountryCode(country) {
      if (!country) {
        return Promise.resolve('');
      }
      const countryOption = this.countryOptions.find(
        item => item.title === country || item.id === country
      );
      if (countryOption) {
        return Promise.resolve(countryOption.id);
      }
      return this.loadCountryOptions().then(() => {
        const option = this.countryOptions.find(
          item => item.title === country || item.id === country
        );
        return option ? option.id : DEFAULT_COUNTRY_CODE;
      });
    },
    normalizeRow(row) {
      const submitRow = { ...row };
      submitRow.code = String(submitRow.code || '').toUpperCase();
      submitRow.regionCode = String(submitRow.regionCode || '').trim();
      submitRow.districtCode = String(submitRow.districtCode || '').trim();
      submitRow.districtName = String(submitRow.districtName || '').trim();
      submitRow.detailAddress = String(submitRow.detailAddress || '').trim();
      submitRow.longitude = normalizeCoordinateInput(submitRow.longitude);
      submitRow.latitude = normalizeCoordinateInput(submitRow.latitude);
      if (submitRow.category === '港口') {
        submitRow.parentId = undefined;
        submitRow.parentCode = undefined;
        submitRow.parentName = undefined;
      }
      if (!submitRow.dataSource) submitRow.dataSource = '手工导入';
      if (!submitRow.status) submitRow.status = 1;
      delete submitRow.terminalCode;
      delete submitRow.cityCode;
      delete submitRow.countryCode;
      return submitRow;
    },
    validateRequiredFields(row) {
      const isBlank = value => value === undefined || value === null || String(value).trim() === '';
      if (isBlank(row.code)) {
        this.$message.warning('请输入编码');
        return false;
      }
      if (isBlank(row.name)) {
        this.$message.warning('请输入港口/码头名称');
        return false;
      }
      if (isBlank(row.category)) {
        this.$message.warning('请选择类型');
        return false;
      }
      if (row.category === '码头' && isBlank(row.parentId)) {
        this.$message.warning('请选择上级港口');
        return false;
      }
      if (isBlank(row.regionCode)) {
        this.$message.warning('请选择区县');
        return false;
      }
      if (isBlank(row.longitude)) {
        this.$message.warning('请输入经度');
        return false;
      }
      const longitudeMessage = getCoordinateValidationMessage(row.longitude, 'longitude');
      if (longitudeMessage) {
        this.$message.warning(longitudeMessage);
        return false;
      }
      if (isBlank(row.latitude)) {
        this.$message.warning('请输入纬度');
        return false;
      }
      const latitudeMessage = getCoordinateValidationMessage(row.latitude, 'latitude');
      if (latitudeMessage) {
        this.$message.warning(latitudeMessage);
        return false;
      }
      return true;
    },
    stopSubmitLoading(loading) {
      if (typeof loading === 'function') {
        loading();
      }
    },
    rowSave(row, done, loading) {
      const submitRow = this.normalizeRow(row);
      if (!this.validateRequiredFields(submitRow)) {
        this.stopSubmitLoading(loading);
        return;
      }
      submit(submitRow).then(
        () => {
          this.onLoad(this.page);
          this.loadPortOptions();
          this.$message({ type: 'success', message: '操作成功!' });
          done();
        },
        error => {
          window.console.log(error);
          loading();
        }
      );
    },
    rowUpdate(row, index, done, loading) {
      const submitRow = this.normalizeRow(row);
      if (!this.validateRequiredFields(submitRow)) {
        this.stopSubmitLoading(loading);
        return;
      }
      submit(submitRow).then(
        () => {
          this.onLoad(this.page);
          this.loadPortOptions();
          this.$message({ type: 'success', message: '操作成功!' });
          done();
        },
        error => {
          window.console.log(error);
          loading();
        }
      );
    },
    rowDel(row) {
      this.$confirm('确定将选择数据删除?', {
        confirmButtonText: '确定',
        cancelButtonText: '取消',
        type: 'warning',
      })
        .then(() => remove(row.id))
        .then(() => {
          this.onLoad(this.page);
          this.loadPortOptions();
          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.onLoad(this.page);
          this.loadPortOptions();
          this.$message({ type: 'success', message: '操作成功!' });
          this.$refs.crud.toggleSelection();
        });
    },
    handleStatus(row) {
      const nextStatus = row.status === 1 ? 2 : 1;
      const actionName = nextStatus === 1 ? '启用' : '停用';
      this.$confirm(`是否确认${actionName}该条数据？`, {
        confirmButtonText: '确定',
        cancelButtonText: '取消',
        type: 'warning',
      })
        .then(() => changeStatus(row.id, nextStatus))
        .then(() => {
          this.onLoad(this.page);
          this.loadPortOptions();
          this.$message({ type: 'success', message: '操作成功!' });
        });
    },
    beforeOpen(done, type) {
      if (type === 'add') {
        this.form.category = this.form.category || '港口';
        this.form.dataSource = this.form.dataSource || '手工导入';
        this.form.status = this.form.status || 1;
      }
      this.handleCategoryChange(this.form.category || '港口');
      if (['edit', 'view'].includes(type)) {
        getDetail(this.form.id).then(res => {
          this.form = res.data.data;
          this.form.terminalCode = this.getTerminalCodePart(this.form.code);
          this.resolveCountryCode(this.form.country)
            .then(countryCode => {
              this.form.countryCode = countryCode;
              this.syncCountryName(countryCode);
              return this.loadCityOptions(countryCode);
            })
            .then(() => {
              this.form.cityCode = this.resolveCityCode(this.form.city, this.form.regionCode);
              return this.loadDistrictOptions(this.form.cityCode);
            })
            .then(() => {
              this.form.districtCode = this.resolveDistrictCode(
                this.form.districtName,
                this.form.regionCode
              );
              if (!this.form.regionCode) {
                this.handleDistrictChange(this.form.districtCode);
              }
              this.handleCategoryChange(this.form.category, false);
              this.syncTerminalCode();
              done();
            });
        });
        return;
      }
      this.resolveCountryCode(this.form.country)
        .then(countryCode => {
          this.form.countryCode = countryCode;
          this.syncCountryName(countryCode);
          return this.loadCityOptions(countryCode);
        })
        .then(() => {
          this.form.cityCode = this.resolveCityCode(this.form.city, this.form.regionCode);
          return this.loadDistrictOptions(this.form.cityCode);
        })
        .then(() => {
          this.form.districtCode = this.resolveDistrictCode(
            this.form.districtName,
            this.form.regionCode
          );
          if (!this.form.regionCode) {
            this.handleDistrictChange(this.form.districtCode);
          }
          done();
        });
    },
    searchReset() {
      this.query = {};
      this.setCityOptions([]);
      this.setDistrictOptions([]);
      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,
        '港口码头主数据',
        () => {
          this.loadPortOptions();
        },
        {
          failDetailDecorator: removeWorkbookColumnsByHeaders,
        }
      );
    },
    handleExport() {
      this.$confirm('是否导出港口码头主数据?', '提示', {
        confirmButtonText: '确定',
        cancelButtonText: '取消',
        type: 'warning',
      }).then(() => {
        NProgress.start();
        exportBlob('/blade-system/port-terminal/export-port-terminal', this.buildExportParams(), {
          feedback: true,
        })
          .then(async res => {
            const blob = await removeExcelColumnsByHeaders(res.data, {
              markRequiredHeaders: true,
            });
            downloadXls(blob, `港口码头主数据${this.$dayjs().format('YYYY-MM-DD HH:mm:ss')}.xlsx`);
          })
          .finally(() => {
            NProgress.done();
          });
      });
    },
    buildExportParams() {
      return {
        ...this.query,
        ids: this.ids,
        [this.website.tokenHeader]: getToken(),
      };
    },
    handleTemplate() {
      exportBlob(
        `/blade-system/port-terminal/export-template?${this.website.tokenHeader}=${getToken()}`,
        undefined,
        { feedback: true }
      ).then(async res => {
        const blob = await removeExcelColumnsByHeaders(res.data);
        downloadXls(blob, '港口码头主数据模板.xlsx');
      });
    },
  },
};
</script>

<style lang="scss" scoped>
.port-terminal-page__detail-address {
  display: block;
  white-space: normal;
  word-break: break-all;
  line-height: 20px;
  padding: 4px 0;
}
</style>
