<template>
  <basic-container class="common-cargo-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-plus"
          plain
          v-if="hasPermission('common_cargo_add')"
          @click="$refs.crud.rowAdd()"
          >新增
        </el-button>
        <el-button
          type="primary"
          icon="el-icon-upload"
          plain
          v-if="config.importUrl && hasPermission('common_cargo_import')"
          @click="handleImport"
          >批量导入
        </el-button>
        <el-button
          type="primary"
          icon="el-icon-download"
          plain
          v-if="config.templateUrl && hasPermission('common_cargo_template')"
          @click="handleTemplate"
          >下载模板
        </el-button>
        <el-button
          type="primary"
          icon="el-icon-download"
          plain
          v-if="config.exportUrl && hasPermission('common_cargo_export')"
          @click="handleExport"
          >批量导出
        </el-button>
        <el-button
          type="danger"
          icon="el-icon-delete"
          plain
          v-if="hasPermission('common_cargo_delete')"
          @click="handleDelete"
          >批量删除
        </el-button>
      </template>

      <template #firstCargoTypeName-form>
        <el-select
          v-model="form.firstCargoTypeCode"
          clearable
          filterable
          remote
          :remote-method="loadFirstCargoTypeOptions"
          :loading="firstCargoTypeLoading"
          :disabled="dialogReadonly || dialogType === 'edit'"
          placeholder="请选择一级货物类型"
          style="width: 100%"
          @change="handleFirstCargoTypeChange"
        >
          <el-option
            v-for="item in firstCargoTypeOptions"
            :key="item.cargoCode"
            :label="item.cargoName"
            :value="item.cargoCode"
          />
        </el-select>
      </template>

      <template #secondCargoTypeName-form>
        <el-select
          v-model="form.secondCargoTypeCode"
          clearable
          filterable
          remote
          :remote-method="loadSecondCargoTypeOptions"
          :loading="secondCargoTypeLoading"
          :disabled="dialogReadonly || dialogType === 'edit' || !form.firstCargoTypeCode"
          :placeholder="form.firstCargoTypeCode ? '请选择二级货物类型' : '请先选择一级货物类型'"
          style="width: 100%"
          @change="handleSecondCargoTypeChange"
        >
          <el-option
            v-for="item in secondCargoTypeOptions"
            :key="item.cargoCode"
            :label="item.cargoName"
            :value="item.cargoCode"
          />
        </el-select>
      </template>

      <template #cargoCode-form>
        <el-input
          v-model="form.cargoCode"
          clearable
          maxlength="20"
          show-word-limit
          placeholder="请输入货物编号"
          :disabled="dialogReadonly || dialogType === 'edit'"
          @input="handleCargoCodeInput"
        />
      </template>

      <template #cargoValue-form>
        <div class="common-cargo-page__value-unit">
          <el-input
            v-model="form.cargoValue"
            clearable
            placeholder="请输入"
            :disabled="dialogReadonly"
            @input="handleCargoValueInput"
          />
          <el-select
            v-model="form.priceUnit"
            clearable
            :disabled="dialogReadonly"
            placeholder="请选择"
          >
            <el-option
              v-for="item in priceUnitOptions"
              :key="item.value"
              :label="item.label"
              :value="item.value"
            />
          </el-select>
        </div>
      </template>

      <template #menu="{ row, index }">
        <el-link
          type="primary"
          v-if="hasPermission('common_cargo_view')"
          @click="$refs.crud.rowView(row, index)"
        >
          查看
        </el-link>
        <el-link
          type="primary"
          v-if="hasPermission('common_cargo_edit') && !row.readonly"
          @click="$refs.crud.rowEdit(row, index)"
        >
          编辑
        </el-link>
        <el-link
          type="primary"
          v-if="hasPermission('common_cargo_delete') && !row.readonly"
          @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="`${config.title}导入`" append-to-body v-model="excelBox" width="555px">
      <avue-form :option="excelOptionConfig" 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 * as api from '@/api/business/common-cargo';
import { getList as getCargoTypeList } from '@/api/base/cargo-type';
import { exportBlob } from '@/api/common';
import { config, excelOption, option } from '@/option/business/common-cargo';
import { priceUnitOptions } from '@/option/business/common';
import { getToken } from '@/utils/auth';
import { openImportDialog } from '@/utils/import-excel';
import { downloadXls } from '@/utils/util';
import { mapGetters } from 'vuex';
import NProgress from 'nprogress';
import 'nprogress/nprogress.css';

export default {
  data() {
    return {
      api,
      config,
      option,
      priceUnitOptions,
      form: {},
      query: {},
      loading: true,
      data: [],
      dialogReadonly: false,
      dialogType: 'add',
      excelBox: false,
      excelForm: {},
      excelOptionConfig: excelOption,
      firstCargoTypeLoading: false,
      secondCargoTypeLoading: false,
      firstCargoTypeOptions: [],
      secondCargoTypeOptions: [],
      page: {
        pageSize: 10,
        pageSizes: [10, 20, 50, 100],
        currentPage: 1,
        total: 0,
      },
      selectionList: [],
    };
  },
  computed: {
    ...mapGetters(['permission', 'userInfo']),
    permissionList() {
      return {
        addBtn: this.hasPermission('common_cargo_add'),
      };
    },
    isAdmin() {
      const authority = this.userInfo && this.userInfo.authority;
      return Array.isArray(authority)
        ? authority.includes('admin')
        : String(authority || '').includes('admin');
    },
    ids() {
      return this.selectionList.map(item => item.id).join(',');
    },
  },
  methods: {
    hasPermission(code) {
      return this.isAdmin || this.validData(this.permission && this.permission[code], false);
    },
    getRecords(res) {
      const data = res && res.data && res.data.data;
      if (Array.isArray(data)) return data;
      return (data && data.records) || [];
    },
    normalizeCargoTypeOptions(list = []) {
      return list
        .map(item => ({
          ...item,
          cargoCode: String(item.cargoCode || ''),
          cargoName: item.cargoName || '',
        }))
        .filter(item => item.cargoCode && item.cargoName);
    },
    ensureCargoTypeOption(listName, optionItem) {
      if (!optionItem || !optionItem.cargoCode) return;
      const exists = this[listName].some(item => item.cargoCode === optionItem.cargoCode);
      if (!exists) {
        this[listName] = [optionItem, ...this[listName]];
      }
    },
    loadFirstCargoTypeOptions(keyword = '') {
      this.firstCargoTypeLoading = true;
      getCargoTypeList(1, 30, {
        typeLevel: 1,
        cargoName: String(keyword || '').trim(),
      })
        .then(res => {
          this.firstCargoTypeOptions = this.normalizeCargoTypeOptions(this.getRecords(res));
        })
        .finally(() => {
          this.firstCargoTypeLoading = false;
        });
    },
    loadSecondCargoTypeOptions(keyword = '') {
      if (!this.form.firstCargoTypeCode) {
        this.secondCargoTypeOptions = [];
        return;
      }
      this.secondCargoTypeLoading = true;
      getCargoTypeList(1, 30, {
        typeLevel: 2,
        parentCargoCode: this.form.firstCargoTypeCode,
        cargoName: String(keyword || '').trim(),
      })
        .then(res => {
          this.secondCargoTypeOptions = this.normalizeCargoTypeOptions(this.getRecords(res));
        })
        .finally(() => {
          this.secondCargoTypeLoading = false;
        });
    },
    handleFirstCargoTypeChange(value) {
      const first = this.firstCargoTypeOptions.find(item => item.cargoCode === value);
      this.form.firstCargoTypeName = first ? first.cargoName : '';
      this.form.firstCargoTypeCode = first ? first.cargoCode : '';
      this.form.secondCargoTypeName = '';
      this.form.secondCargoTypeCode = '';
      this.secondCargoTypeOptions = [];
      this.syncCargoCodePrefix();
      if (first) {
        this.loadSecondCargoTypeOptions();
      }
    },
    handleSecondCargoTypeChange(value) {
      const second = this.secondCargoTypeOptions.find(item => item.cargoCode === value);
      this.form.secondCargoTypeName = second ? second.cargoName : '';
      this.form.secondCargoTypeCode = second ? second.cargoCode : '';
      this.syncCargoCodePrefix();
    },
    getCargoCodePrefix() {
      return this.form.secondCargoTypeCode && this.form.firstCargoTypeCode
        ? this.form.firstCargoTypeCode
        : '';
    },
    syncCargoCodePrefix() {
      const prefix = this.getCargoCodePrefix();
      const current = String(this.form.cargoCode || '').replace(/\D/g, '');
      if (!prefix) {
        this.form.cargoCode = current;
        return;
      }
      const suffix = current.startsWith(prefix) ? current.slice(prefix.length) : current;
      this.form.cargoCode = `${prefix}${suffix}`.slice(0, 20);
    },
    handleCargoCodeInput(value) {
      const prefix = this.getCargoCodePrefix();
      const input = String(value || '').replace(/\D/g, '');
      if (!prefix) {
        this.form.cargoCode = input.slice(0, 20);
        return;
      }
      const suffix = input.startsWith(prefix) ? input.slice(prefix.length) : input;
      this.form.cargoCode = `${prefix}${suffix}`.slice(0, 20);
    },
    handleCargoValueInput(value) {
      const raw = String(value || '').replace(/[^\d.]/g, '');
      const parts = raw.split('.');
      const integer = parts[0] || '';
      const decimal = parts.slice(1).join('').slice(0, 2);
      this.form.cargoValue = parts.length > 1 ? `${integer}.${decimal}` : integer;
    },
    normalizeRow(row) {
      const submitRow = { ...row };
      Object.keys(submitRow).forEach(key => {
        if (typeof submitRow[key] === 'string') {
          submitRow[key] = submitRow[key].trim();
        }
      });
      if (submitRow.cargoValue !== undefined && submitRow.cargoValue !== null) {
        submitRow.cargoValue = String(submitRow.cargoValue).trim();
      }
      return submitRow;
    },
    validateRow(row) {
      if (!row.firstCargoTypeName || !row.firstCargoTypeCode) {
        this.$message.warning('请选择一级货物类型');
        return false;
      }
      if (!row.secondCargoTypeName || !row.secondCargoTypeCode) {
        this.$message.warning('请选择二级货物类型');
        return false;
      }
      if (!row.cargoName) {
        this.$message.warning('请输入货物名称');
        return false;
      }
      if (row.cargoName.length > 100) {
        this.$message.warning('货物名称不能超过100个字符');
        return false;
      }
      const cargoCode = String(row.cargoCode || '');
      const prefix = row.firstCargoTypeCode;
      if (!cargoCode || cargoCode === prefix) {
        this.$message.warning('请输入货物编号');
        return false;
      }
      if (!cargoCode.startsWith(prefix)) {
        this.$message.warning('货物编号需拼接一级货物类型编号在前面');
        return false;
      }
      if (cargoCode.length > 20) {
        this.$message.warning('货物编号不能超过20个字符');
        return false;
      }
      if (row.cargoValue && !/^\d+(\.\d{1,2})?$/.test(String(row.cargoValue))) {
        this.$message.warning('货值只能输入数字，最多保留2位小数');
        return false;
      }
      if (row.remark && row.remark.length > 200) {
        this.$message.warning('备注不能超过200个字符');
        return false;
      }
      return true;
    },
    stopSubmitLoading(loading) {
      if (typeof loading === 'function') {
        loading();
      }
    },
    rowSave(row, done, loading) {
      const submitRow = this.normalizeRow(row);
      if (!this.validateRow(submitRow)) {
        this.stopSubmitLoading(loading);
        return;
      }
      api.submit(submitRow).then(
        () => {
          this.onLoad(this.page);
          this.$message({ type: 'success', message: '操作成功!' });
          done();
        },
        error => {
          window.console.log(error);
          this.stopSubmitLoading(loading);
        }
      );
    },
    rowUpdate(row, index, done, loading) {
      const submitRow = this.normalizeRow(row);
      if (!this.validateRow(submitRow)) {
        this.stopSubmitLoading(loading);
        return;
      }
      api.submit(submitRow).then(
        () => {
          this.onLoad(this.page);
          this.$message({ type: 'success', message: '操作成功!' });
          done();
        },
        error => {
          window.console.log(error);
          this.stopSubmitLoading(loading);
        }
      );
    },
    rowDel(row) {
      this.$confirm('确定将选择数据删除?', {
        confirmButtonText: '确定',
        cancelButtonText: '取消',
        type: 'warning',
      })
        .then(() => api.remove(row.id))
        .then(res => {
          this.afterRemove(res.data.data);
        });
    },
    handleDelete() {
      if (this.selectionList.length === 0) {
        this.$message.warning('请选择至少一条数据');
        return;
      }
      const selection = this.selectionList.filter(item => !item.readonly);
      if (!selection.length) {
        this.$message.warning('所选数据均为只读数据');
        return;
      }
      this.$confirm('确定将选择数据删除?', {
        confirmButtonText: '确定',
        cancelButtonText: '取消',
        type: 'warning',
      })
        .then(() => api.remove(selection.map(item => item.id).join(',')))
        .then(res => {
          this.afterRemove(res.data.data);
        });
    },
    afterRemove(result = {}) {
      this.onLoad(this.page);
      const successCount = result.successCount || 0;
      const skippedCount = result.skippedCount || 0;
      if (skippedCount) {
        this.$message.warning(`成功删除${successCount}条，因业务引用跳过${skippedCount}条`);
      } else {
        this.$message({ type: 'success', message: '删除成功!' });
      }
      this.selectionClear();
    },
    beforeOpen(done, type) {
      this.dialogReadonly = type === 'view';
      this.dialogType = type || 'add';
      if (type === 'add') {
        this.form = {
          priceUnit: '元/吨',
          ...this.form,
        };
        this.loadFirstCargoTypeOptions();
        done();
        return;
      }
      if (['edit', 'view'].includes(type)) {
        api.getDetail(this.form.id).then(res => {
          this.form = res.data.data || {};
          this.ensureCargoTypeOption('firstCargoTypeOptions', {
            cargoName: this.form.firstCargoTypeName,
            cargoCode: this.form.firstCargoTypeCode,
          });
          this.ensureCargoTypeOption('secondCargoTypeOptions', {
            cargoName: this.form.secondCargoTypeName,
            cargoCode: this.form.secondCargoTypeCode,
          });
          if (this.form.firstCargoTypeCode) {
            this.loadSecondCargoTypeOptions();
          }
          done();
        });
        return;
      }
      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 = [];
      if (this.$refs.crud) {
        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;
      api
        .getList(page.currentPage, page.pageSize, { ...params, ...this.query, allDept: 0 })
        .then(res => {
          const result = res.data.data;
          this.page.total = result.total;
          this.data = result.records;
          this.selectionClear();
        })
        .finally(() => {
          this.loading = false;
        });
    },
    buildExportParams() {
      return {
        ...this.query,
        allDept: 0,
        ids: this.ids,
        [this.website.tokenHeader]: getToken(),
      };
    },
    handleExport() {
      this.$confirm(`是否导出${config.exportName}?`, '提示', {
        confirmButtonText: '确定',
        cancelButtonText: '取消',
        type: 'warning',
      }).then(() => {
        NProgress.start();
        exportBlob(config.exportUrl, this.buildExportParams(), { feedback: true })
          .then(res => {
            downloadXls(
              res.data,
              `${config.exportName}${this.$dayjs().format('YYYY-MM-DD HH:mm:ss')}.xlsx`
            );
          })
          .finally(() => {
            NProgress.done();
          });
      });
    },
    handleTemplate() {
      NProgress.start();
      exportBlob(
        config.templateUrl,
        {
          [this.website.tokenHeader]: getToken(),
        },
        { feedback: true }
      )
        .then(res => {
          downloadXls(res.data, `${config.title}模板.xlsx`);
        })
        .finally(() => {
          NProgress.done();
        });
    },
    handleImport() {
      const column = this.excelOptionConfig.column.find(item => item.prop === 'excelFile');
      column.action = config.importUrl;
      openImportDialog(this, config.title, () => this.onLoad(this.page, this.query));
    },
  },
};
</script>

<style lang="scss" scoped>
.common-cargo-page {
  &__value-unit {
    display: flex;
    align-items: center;
    width: 100%;

    .el-input {
      flex: 1;
      min-width: 0;
    }

    .el-select {
      flex: 0 0 112px;
      margin-left: -1px;
    }

    :deep(.el-input__wrapper) {
      border-radius: 4px 0 0 4px;
    }

    .el-select :deep(.el-input__wrapper) {
      border-radius: 0 4px 4px 0;
    }
  }
}
</style>
