<template>
  <div class="app-container">
    <el-card shadow="never">
      <el-form ref="queryForm" :model="queryParams" size="small" :inline="true">
        <el-form-item>
          <template slot="label">{{ tmT("queryEntryDate") }}</template>
          <el-date-picker
            v-model="queryDateRange"
            type="daterange"
            value-format="yyyy-MM-dd"
            range-separator="-"
            :start-placeholder="tmT('queryDateRangePh')"
            :end-placeholder="tmT('queryDateRangeEndPh')"
            clearable
            style="width: 240px"
          />
        </el-form-item>
        <el-form-item prop="certNo">
          <template slot="label">{{ tmT("queryCertNo") }}</template>
          <el-input
            v-model="queryParams.certNo"
            :placeholder="tmT('queryCertNoPh')"
            clearable
            style="width: 180px"
            @keyup.enter.native="handleQuery"
          />
        </el-form-item>
        <el-form-item prop="supplierId">
          <template slot="label">{{ tmT("querySupplier") }}</template>
          <el-select v-model="queryParams.supplierId" :placeholder="tmCommon('pleaseSelect')" clearable filterable style="width: 200px">
            <el-option v-for="item in supplierOptions" :key="item.id" :label="item.supplierName" :value="item.id" />
          </el-select>
        </el-form-item>
        <el-form-item>
          <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">{{ tmCommon("search") }}</el-button>
          <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">{{ tmCommon("reset") }}</el-button>
          <el-button
            v-hasPermi="['tradeMarket:entryIsolation:add']"
            type="primary"
            plain
            icon="el-icon-plus"
            size="mini"
            @click="handleAdd"
          >{{ tmCommon("add") }}</el-button>
        </el-form-item>
      </el-form>
    </el-card>

    <br />

    <el-card shadow="never">
      <el-table v-loading="loading" :data="tableList" border>
        <el-table-column :label="tmT('colEntryTime')" prop="entryTime" align="center" width="160" />
        <el-table-column :label="tmT('colSupplier')" prop="supplierName" align="center" min-width="120" :show-overflow-tooltip="true" />
        <el-table-column :label="tmT('colCertNo')" prop="certNo" align="center" min-width="130" :show-overflow-tooltip="true" />
        <el-table-column :label="tmT('colQuantity')" align="center" width="90">
          <template slot-scope="scope">
            <span>{{ scope.row.quantity }}{{ tmT("unitHead") }}</span>
          </template>
        </el-table-column>
        <el-table-column :label="tmT('colPenAlloc')" align="center" width="120">
          <template slot-scope="scope">
            <el-button type="text" size="mini" @click="openPenAllocView(scope.row)">{{ tmT("penAllocTableLink") }}</el-button>
          </template>
        </el-table-column>
        <el-table-column :label="tmT('colIsolationDays')" align="center" width="110">
          <template slot-scope="scope">
            <span>{{ scope.row.isolationDays }}{{ tmT("unitDay") }}</span>
          </template>
        </el-table-column>
        <el-table-column :label="tmT('colReleaseDate')" prop="expectedReleaseDate" align="center" width="120" />
        <el-table-column :label="tmCommon('colOp')" align="center" class-name="small-padding fixed-width" width="200" fixed="right">
          <template slot-scope="scope">
            <el-button v-hasPermi="['tradeMarket:entryIsolation:query']" type="text" size="mini" @click="handleView(scope.row)">{{ tmCommon("view") }}</el-button>
            <el-button v-hasPermi="['tradeMarket:entryIsolation:edit']" type="text" size="mini" @click="handleEdit(scope.row)">{{ tmCommon("edit") }}</el-button>
            <el-button v-hasPermi="['tradeMarket:entryIsolation:remove']" type="text" size="mini" @click="handleDelete(scope.row)">{{ tmCommon("delete") }}</el-button>
          </template>
        </el-table-column>
      </el-table>
      <pagination
        v-show="total > 0"
        :total="total"
        :page.sync="queryParams.pageNum"
        :limit.sync="queryParams.pageSize"
        @pagination="getList"
      />
    </el-card>

    <!-- 新增/编辑 -->
    <el-dialog :title="dialogTitle" :visible.sync="open" width="780px" append-to-body @close="cancel">
      <el-form :key="formKey" ref="form" :model="form" label-width="120px">
        <el-form-item prop="entryTime" :rules="formRules.entryTime">
          <template slot="label">{{ tmT("formEntryTime") }}</template>
          <el-date-picker
            v-model="form.entryTime"
            type="datetime"
            value-format="yyyy-MM-dd HH:mm:ss"
            :placeholder="tmCommon('pleaseSelect')"
            style="width: 100%"
            @change="recalcExpectedReleaseDate"
          />
        </el-form-item>
        <el-form-item prop="supplierId" :rules="formRules.supplierId">
          <template slot="label">{{ tmT("formSupplier") }}</template>
          <el-select
            v-model="form.supplierId"
            :placeholder="tmT('phSupplierFilter')"
            filterable
            style="width: 100%"
          >
            <el-option v-for="item in supplierOptions" :key="item.id" :label="item.supplierName" :value="item.id" />
          </el-select>
        </el-form-item>
        <el-form-item prop="certFilePath">
          <template slot="label">{{ tmT("formCertFile") }}</template>
          <el-upload
            class="upload-file-uploader"
            :action="uploadAction"
            :headers="uploadHeaders"
            :before-upload="beforeCertUpload"
            :on-success="handleCertUploadSuccess"
            :on-error="handleUploadHttpError"
            :show-file-list="false"
          >
            <el-button size="mini" type="primary">{{ tmT("btnPickCert") }}</el-button>
          </el-upload>
          <div class="el-upload__tip">{{ tmT("tipCertFile") }}</div>
          <!-- <div class="el-upload__tip text-muted">{{ tmT("tipOcrLater") }}</div> -->
          <ul v-if="form.certFilePath" class="upload-file-list">
            <li class="upload-file-item">
              <el-link :href="form.certFileUrl || '#'" :underline="false" target="_blank">
                <span class="el-icon-document">{{ certDisplayName }}</span>
              </el-link>
              <el-link type="danger" :underline="false" @click="clearCertFile">{{ tmCommon("delete") }}</el-link>
            </li>
          </ul>
        </el-form-item>
        <el-form-item prop="certNo" :rules="formRules.certNo">
          <template slot="label">{{ tmT("formCertNo") }}</template>
          <el-input v-model="form.certNo" :placeholder="tmT('phCertNo')" maxlength="50" show-word-limit />
        </el-form-item>
        <el-form-item prop="earTagsText" :rules="formRules.earTagsText">
          <template slot="label">{{ tmT("formEarTags") }}</template>
          <el-input
            v-model="form.earTagsText"
            type="textarea"
            :rows="2"
            :placeholder="tmT('phEarTags')"
            @blur="onEarTagsBlur"
          />
        </el-form-item>
        <el-form-item prop="quantity" :rules="formRules.quantity">
          <template slot="label">{{ tmT("formQuantity") }}</template>
          <el-input-number v-model="form.quantity" :min="1" :precision="0" :step="1" controls-position="right" style="width: 200px" />
          <span class="form-unit">{{ tmT("unitHead") }}</span>
        </el-form-item>
        <el-form-item prop="isolationDays" :rules="formRules.isolationDays">
          <template slot="label">{{ tmT("formIsolationDays") }}</template>
          <el-input-number
            v-model="form.isolationDays"
            :min="1"
            :max="3650"
            :precision="0"
            :step="1"
            controls-position="right"
            style="width: 200px"
            @change="recalcExpectedReleaseDate"
          />
          <span class="form-unit">{{ tmT("unitDay") }}</span>
        </el-form-item>
        <el-form-item :label="tmT('formExpectedRelease')">
          <span>{{ form.expectedReleaseDate || $t("tradeMarket.status.dash") }}</span>
        </el-form-item>
        <el-form-item prop="penAllocList" :rules="formRules.penAllocList">
          <template slot="label">{{ tmT("formPenAlloc") }}</template>
          <el-button type="primary" plain size="mini" icon="el-icon-plus" @click="openPenAllocDialog(-1)">{{ tmT("btnAddPen") }}</el-button>
          <el-table :data="form.penAllocList" border size="small" style="margin-top: 8px">
            <el-table-column :label="tmT('colPenCode')" prop="penCode" align="center" width="100" />
            <el-table-column :label="tmT('colPenQuantity')" align="center" width="90">
              <template slot-scope="scope">
                <span>{{ scope.row.quantity }}{{ tmT("unitHead") }}</span>
              </template>
            </el-table-column>
            <el-table-column :label="tmT('colPenEarTags')" align="center" min-width="160" :show-overflow-tooltip="true">
              <template slot-scope="scope">
                <span>{{ formatEarTagsDisplay(scope.row.earTagList) }}</span>
              </template>
            </el-table-column>
            <el-table-column :label="tmCommon('colOp')" align="center" width="120">
              <template slot-scope="scope">
                <el-button type="text" size="mini" @click="openPenAllocDialog(scope.$index)">{{ tmCommon("edit") }}</el-button>
                <el-button type="text" size="mini" @click="removePenAllocRow(scope.$index)">{{ tmCommon("delete") }}</el-button>
              </template>
            </el-table-column>
          </el-table>
        </el-form-item>
      </el-form>
      <div slot="footer" class="dialog-footer">
        <el-button type="primary" @click="submitForm">{{ tmCommon("ok") }}</el-button>
        <el-button @click="cancel">{{ tmCommon("cancel") }}</el-button>
      </div>
    </el-dialog>

    <!-- 添加/编辑分圈 -->
    <el-dialog :title="penAllocDialogTitle" :visible.sync="penAllocOpen" width="480px" append-to-body>
      <el-form ref="penAllocFormRef" :model="penAllocForm" label-width="100px">
        <el-form-item prop="penId" :rules="penAllocRules.penId">
          <template slot="label">{{ tmT("formPenCode") }}</template>
          <el-select v-model="penAllocForm.penId" :placeholder="tmCommon('pleaseSelect')" style="width: 100%">
            <el-option
              v-for="item in availablePenOptions"
              :key="item.id"
              :label="item.penCode"
              :value="item.id"
              :disabled="isPenDisabled(item.id)"
            />
          </el-select>
        </el-form-item>
        <el-form-item prop="earTagList" :rules="penAllocRules.earTagList">
          <template slot="label">{{ tmT("formPenEarTags") }}</template>
          <el-select v-model="penAllocForm.earTagList" multiple :placeholder="tmCommon('pleaseSelect')" style="width: 100%">
            <el-option
              v-for="tag in selectableEarTagsForPen"
              :key="tag"
              :label="tag"
              :value="tag"
            />
          </el-select>
        </el-form-item>
        <el-form-item :label="tmT('formPenQuantity')">
          <span>{{ penAllocForm.earTagList.length }}{{ tmT("unitHead") }}</span>
        </el-form-item>
      </el-form>
      <div slot="footer" class="dialog-footer">
        <el-button type="primary" @click="confirmPenAlloc">{{ tmCommon("ok") }}</el-button>
        <el-button @click="penAllocOpen = false">{{ tmCommon("cancel") }}</el-button>
      </div>
    </el-dialog>

    <!-- 查看 -->
    <el-dialog :title="tmCommon('viewTitle')" :visible.sync="viewOpen" width="760px" append-to-body>
      <el-form label-width="120px" size="small">
        <el-form-item :label="tmT('formEntryTime')"><span>{{ viewRow.entryTime }}</span></el-form-item>
        <el-form-item :label="tmT('formSupplier')"><span>{{ viewRow.supplierName }}</span></el-form-item>
        <el-form-item :label="tmT('formCertFile')">
          <el-link v-if="viewRow.certFileUrl" type="primary" :href="viewRow.certFileUrl" target="_blank">{{ tmCommon("view") }}</el-link>
          <span v-else>{{ $t("tradeMarket.status.dash") }}</span>
        </el-form-item>
        <el-form-item :label="tmT('formCertNo')"><span>{{ viewRow.certNo }}</span></el-form-item>
        <el-form-item :label="tmT('formQuantity')"><span>{{ viewRow.quantity }}{{ tmT("unitHead") }}</span></el-form-item>
        <el-form-item :label="tmT('formEarTags')"><span>{{ viewEarTagsText }}</span></el-form-item>
        <el-form-item :label="tmT('formIsolationDays')"><span>{{ viewRow.isolationDays }}{{ tmT("unitDay") }}</span></el-form-item>
        <el-form-item :label="tmT('formExpectedRelease')"><span>{{ viewRow.expectedReleaseDate }}</span></el-form-item>
        <el-form-item :label="tmT('formPenAlloc')">
          <el-table :data="viewRow.penAllocList || []" border size="small">
            <el-table-column :label="tmT('colPenCode')" prop="penCode" align="center" />
            <el-table-column :label="tmT('colPenQuantity')" prop="quantity" align="center" />
            <el-table-column :label="tmT('colPenEarTags')" align="center" :show-overflow-tooltip="true">
              <template slot-scope="scope">
                <span>{{ formatEarTagsDisplay(scope.row.earTagList) || scope.row.earTags }}</span>
              </template>
            </el-table-column>
          </el-table>
        </el-form-item>
      </el-form>
      <div slot="footer" class="dialog-footer">
        <el-button v-hasPermi="['tradeMarket:entryIsolation:edit']" type="primary" @click="handleEditFromView">{{ tmCommon("edit") }}</el-button>
        <el-button @click="viewOpen = false">{{ tmCommon("close") }}</el-button>
      </div>
    </el-dialog>

    <!-- 列表圈位分配表 -->
    <el-dialog :title="tmT('penAllocViewTitle')" :visible.sync="penAllocViewOpen" width="560px" append-to-body>
      <el-table :data="penAllocViewList" border size="small">
        <el-table-column :label="tmT('colPenCode')" prop="penCode" align="center" />
        <el-table-column :label="tmT('colPenQuantity')" prop="quantity" align="center" />
        <el-table-column :label="tmT('colPenEarTags')" align="center" :show-overflow-tooltip="true">
          <template slot-scope="scope">
            <span>{{ formatEarTagsDisplay(scope.row.earTagList) || scope.row.earTags }}</span>
          </template>
        </el-table-column>
      </el-table>
      <div slot="footer" class="dialog-footer">
        <el-button @click="penAllocViewOpen = false">{{ tmCommon("close") }}</el-button>
      </div>
    </el-dialog>
  </div>
</template>

<script>
import { getToken } from "@/utils/auth"
import { parseTime } from "@/utils/ruoyi"
import tradeMarketLocaleMixin from "@/mixins/tradeMarketLocaleMixin"
import { listSupplier } from "@/api/tradeMarket/supplier"
import { listIsolationPen, getIsolationSetting } from "@/api/tradeMarket/isolationPen"
import {
  listEntryIsolation,
  getEntryIsolation,
  addEntryIsolation,
  updateEntryIsolation,
  delEntryIsolation
} from "@/api/tradeMarket/entryIsolation"

const CERT_EXTS = ["pdf", "doc", "docx", "xls", "xlsx", "ppt", "pptx"]
const MAX_CERT_MB = 30
const DEFAULT_ISOLATION_DAYS = 3

export default {
  name: "TradeMarketEntryIsolation",
  mixins: [tradeMarketLocaleMixin],
  data() {
    return {
      tmNs: "entryIsolation",
      loading: false,
      open: false,
      viewOpen: false,
      penAllocOpen: false,
      penAllocViewOpen: false,
      viewRow: {},
      penAllocViewList: [],
      dialogEdit: false,
      formKey: 0,
      total: 0,
      tableList: [],
      queryDateRange: [],
      queryParams: {
        pageNum: 1,
        pageSize: 20,
        certNo: undefined,
        supplierId: undefined
      },
      supplierOptions: [],
      penOptions: [],
      form: {},
      penAllocForm: { penId: undefined, earTagList: [] },
      penAllocEditIndex: -1,
      certDisplayName: ""
    }
  },
  computed: {
    dialogTitle() {
      return this.dialogEdit ? this.tmT("dialogEdit") : this.tmT("dialogAdd")
    },
    penAllocDialogTitle() {
      return this.penAllocEditIndex >= 0 ? this.tmT("penDialogEditTitle") : this.tmT("penDialogTitle")
    },
    uploadAction() {
      return process.env.VUE_APP_BASE_API + "/common/upload"
    },
    uploadHeaders() {
      return { Authorization: "Bearer " + getToken() }
    },
    viewEarTagsText() {
      const list = this.viewRow.earTagList
      if (list && list.length) {
        return list.join("、")
      }
      return this.viewRow.earTags || this.$t("tradeMarket.status.dash")
    },
    parsedMainEarTags() {
      return this.parseEarTags(this.form.earTagsText)
    },
    selectableEarTagsForPen() {
      const all = this.parsedMainEarTags
      const used = new Set()
      ;(this.form.penAllocList || []).forEach((row, idx) => {
        if (idx !== this.penAllocEditIndex) {
          ;(row.earTagList || []).forEach((t) => used.add(t))
        }
      })
      const current = this.penAllocForm.earTagList || []
      return all.filter((t) => !used.has(t) || current.includes(t))
    },
    availablePenOptions() {
      return this.penOptions
    },
    formRules() {
      return {
        entryTime: [{ required: true, message: this.tmT("ruleEntryTime"), trigger: "change" }],
        supplierId: [{ required: true, message: this.tmT("ruleSupplier"), trigger: "change" }],
        certNo: [
          { required: true, message: this.tmT("ruleCertNo"), trigger: "blur" },
          { min: 1, max: 50, message: this.tmT("ruleCertNo"), trigger: "blur" }
        ],
        quantity: [{ required: true, message: this.tmT("ruleQuantity"), trigger: "change" }],
        earTagsText: [{ validator: this.validateEarTagsText, trigger: "blur" }],
        isolationDays: [{ required: true, message: this.tmT("ruleIsolationDays"), trigger: "change" }],
        penAllocList: [{ validator: this.validatePenAllocList, trigger: "change" }]
      }
    },
    penAllocRules() {
      return {
        penId: [{ required: true, message: this.tmT("rulePenCode"), trigger: "change" }],
        earTagList: [{ validator: this.validatePenEarTags, trigger: "change" }]
      }
    }
  },
  created() {
    this.loadSupplierOptions()
    this.loadPenOptions()
    this.getList()
  },
  methods: {
    parseEarTags(text) {
      if (!text || !String(text).trim()) {
        return []
      }
      const parts = String(text)
        .split(/[,，]/)
        .map((s) => s.trim())
        .filter(Boolean)
      const seen = new Set()
      const list = []
      for (const p of parts) {
        if (seen.has(p)) {
          continue
        }
        seen.add(p)
        list.push(p)
      }
      return list
    },
    formatEarTagsDisplay(list) {
      return (list || []).join("、")
    },
    formatNow() {
      return parseTime(new Date(), "{y}-{m}-{d} {h}:{i}:{s}")
    },
    loadSupplierOptions() {
      listSupplier({ pageNum: 1, pageSize: 500 }).then((res) => {
        this.supplierOptions = res.rows || []
      })
    },
    loadPenOptions() {
      listIsolationPen({ pageNum: 1, pageSize: 100 }).then((res) => {
        this.penOptions = res.rows || []
      })
    },
    loadDefaultIsolationDays() {
      return getIsolationSetting().then((res) => {
        const days = res.data && res.data.defaultDays
        return days != null && days > 0 ? days : DEFAULT_ISOLATION_DAYS
      }).catch(() => DEFAULT_ISOLATION_DAYS)
    },
    recalcExpectedReleaseDate() {
      if (!this.form.entryTime || !this.form.isolationDays) {
        this.form.expectedReleaseDate = undefined
        return
      }
      const datePart = String(this.form.entryTime).substring(0, 10)
      const d = new Date(datePart.replace(/-/g, "/"))
      if (isNaN(d.getTime())) {
        this.form.expectedReleaseDate = undefined
        return
      }
      d.setDate(d.getDate() + Number(this.form.isolationDays))
      const y = d.getFullYear()
      const m = String(d.getMonth() + 1).padStart(2, "0")
      const day = String(d.getDate()).padStart(2, "0")
      this.form.expectedReleaseDate = `${y}-${m}-${day}`
    },
    onEarTagsBlur() {
      const tags = this.parsedMainEarTags
      if (tags.length > 0) {
        this.form.quantity = tags.length
      }
    },
    validateEarTagsText(rule, value, callback) {
      const tags = this.parseEarTags(value)
      if (!tags.length) {
        callback(new Error(this.tmT("ruleEarTags")))
        return
      }
      const raw = String(value || "")
        .split(/[,，]/)
        .map((s) => s.trim())
        .filter(Boolean)
      if (raw.length !== tags.length) {
        callback(new Error(this.tmT("ruleEarTagDup")))
        return
      }
      for (const t of tags) {
        if (t.length < 1 || t.length > 32) {
          callback(new Error(this.tmT("ruleEarTagLen")))
          return
        }
      }
      callback()
    },
    validatePenAllocList(rule, value, callback) {
      const list = this.form.penAllocList || []
      if (!list.length) {
        callback(new Error(this.tmT("rulePenAlloc")))
        return
      }
      callback()
    },
    validatePenEarTags(rule, value, callback) {
      if (!value || !value.length) {
        callback(new Error(this.tmT("rulePenEarTags")))
        return
      }
      callback()
    },
    validateConsistencyBeforeSubmit() {
      const tags = this.parsedMainEarTags
      const qty = this.form.quantity
      if (qty !== tags.length) {
        this.$modal.msgError(this.tmT("ruleQtyEarMismatch"))
        return false
      }
      const allocList = this.form.penAllocList || []
      if (!allocList.length) {
        this.$modal.msgError(this.tmT("rulePenAlloc"))
        return false
      }
      let sum = 0
      const allocSet = new Set()
      const mainSet = new Set(tags)
      for (const row of allocList) {
        sum += row.quantity
        for (const t of row.earTagList || []) {
          if (allocSet.has(t)) {
            this.$modal.msgError(this.tmT("rulePenEarExtra"))
            return false
          }
          allocSet.add(t)
          if (!mainSet.has(t)) {
            this.$modal.msgError(this.tmT("rulePenEarExtra"))
            return false
          }
        }
      }
      if (sum !== qty) {
        this.$modal.msgError(this.tmT("rulePenQtySum"))
        return false
      }
      for (const t of tags) {
        if (!allocSet.has(t)) {
          this.$modal.msgError(this.tmT("rulePenEarMissing"))
          return false
        }
      }
      return true
    },
    buildListParams() {
      const params = { ...this.queryParams }
      if (this.queryDateRange && this.queryDateRange.length === 2) {
        params.entryDateStart = this.queryDateRange[0]
        params.entryDateEnd = this.queryDateRange[1]
      } else {
        params.entryDateStart = undefined
        params.entryDateEnd = undefined
      }
      return params
    },
    getList() {
      this.loading = true
      listEntryIsolation(this.buildListParams())
        .then((res) => {
          this.tableList = res.rows || []
          this.total = res.total != null ? res.total : 0
        })
        .finally(() => {
          this.loading = false
        })
    },
    handleQuery() {
      this.queryParams.pageNum = 1
      this.getList()
    },
    resetQuery() {
      this.queryDateRange = []
      this.queryParams.certNo = undefined
      this.queryParams.supplierId = undefined
      this.resetForm("queryForm")
      this.handleQuery()
    },
    resetFormModel() {
      this.form = {
        id: undefined,
        entryTime: this.formatNow(),
        supplierId: undefined,
        certFileUrl: undefined,
        certFilePath: undefined,
        certNo: undefined,
        quantity: undefined,
        earTagsText: "",
        isolationDays: DEFAULT_ISOLATION_DAYS,
        expectedReleaseDate: undefined,
        penAllocList: []
      }
      this.certDisplayName = ""
    },
    fillFormFromApi(data) {
      const tags = data.earTagList || this.parseEarTags(data.earTags)
      this.form = {
        id: data.id,
        entryTime: data.entryTime,
        supplierId: data.supplierId,
        certFileUrl: data.certFileUrl,
        certFilePath: data.certFilePath,
        certNo: data.certNo,
        quantity: data.quantity,
        earTagsText: tags.join(","),
        isolationDays: data.isolationDays,
        expectedReleaseDate: data.expectedReleaseDate,
        penAllocList: (data.penAllocList || []).map((row) => ({
          penId: row.penId,
          penCode: row.penCode,
          quantity: row.quantity,
          earTagList: row.earTagList ? [...row.earTagList] : this.parseEarTags(row.earTags)
        }))
      }
      this.certDisplayName = data.certFilePath ? data.certFilePath.split("/").pop() : ""
      this.recalcExpectedReleaseDate()
    },
    handleAdd() {
      this.loadDefaultIsolationDays().then((days) => {
        this.formKey += 1
        this.resetFormModel()
        this.form.isolationDays = days
        this.recalcExpectedReleaseDate()
        this.dialogEdit = false
        this.open = true
        this.$nextTick(() => this.resetForm("form"))
      })
    },
    handleEdit(row) {
      getEntryIsolation(row.id).then((res) => {
        this.formKey += 1
        this.dialogEdit = true
        this.fillFormFromApi(res.data || {})
        this.open = true
        this.$nextTick(() => {
          if (this.$refs.form) {
            this.$refs.form.clearValidate()
          }
        })
      })
    },
    handleEditFromView() {
      this.viewOpen = false
      this.handleEdit(this.viewRow)
    },
    handleView(row) {
      getEntryIsolation(row.id).then((res) => {
        this.viewRow = res.data || {}
        this.viewOpen = true
      })
    },
    openPenAllocView(row) {
      getEntryIsolation(row.id).then((res) => {
        this.penAllocViewList = (res.data && res.data.penAllocList) || []
        this.penAllocViewOpen = true
      })
    },
    handleDelete(row) {
      this.$modal
        .confirm(this.tmT("confirmDelete", { certNo: row.certNo }))
        .then(() => delEntryIsolation(row.id))
        .then(() => {
          this.$modal.msgSuccess(this.tmCommon("msgDelOk"))
          this.getList()
        })
        .catch(() => {})
    },
    isPenDisabled(penId) {
      return (this.form.penAllocList || []).some((row, idx) => idx !== this.penAllocEditIndex && row.penId === penId)
    },
    openPenAllocDialog(index) {
      const tags = this.parsedMainEarTags
      if (!tags.length) {
        this.$modal.msgError(this.tmT("ruleEarTags"))
        return
      }
      this.penAllocEditIndex = index
      if (index >= 0) {
        const row = this.form.penAllocList[index]
        this.penAllocForm = {
          penId: row.penId,
          earTagList: [...(row.earTagList || [])]
        }
      } else {
        this.penAllocForm = { penId: undefined, earTagList: [] }
      }
      this.penAllocOpen = true
      this.$nextTick(() => {
        if (this.$refs.penAllocFormRef) {
          this.$refs.penAllocFormRef.clearValidate()
        }
      })
    },
    confirmPenAlloc() {
      this.$refs.penAllocFormRef.validate((valid) => {
        if (!valid) {
          return
        }
        const pen = this.penOptions.find((p) => p.id === this.penAllocForm.penId)
        const penCode = pen ? pen.penCode : ""
        if (this.isPenDisabled(this.penAllocForm.penId) && this.penAllocEditIndex < 0) {
          this.$modal.msgError(this.tmT("rulePenDup", { code: penCode }))
          return
        }
        const row = {
          penId: this.penAllocForm.penId,
          penCode,
          quantity: this.penAllocForm.earTagList.length,
          earTagList: [...this.penAllocForm.earTagList]
        }
        const list = [...(this.form.penAllocList || [])]
        if (this.penAllocEditIndex >= 0) {
          list[this.penAllocEditIndex] = row
        } else {
          list.push(row)
        }
        this.form.penAllocList = list
        this.penAllocOpen = false
        this.$refs.form && this.$refs.form.validateField("penAllocList")
      })
    },
    removePenAllocRow(index) {
      const list = [...(this.form.penAllocList || [])]
      list.splice(index, 1)
      this.form.penAllocList = list
    },
    extOf(fileName) {
      if (!fileName || fileName.lastIndexOf(".") < 0) {
        return ""
      }
      return fileName.slice(fileName.lastIndexOf(".") + 1).toLowerCase()
    },
    beforeCertUpload(file) {
      const ext = this.extOf(file.name)
      if (!CERT_EXTS.includes(ext)) {
        this.$modal.msgError(this.tmT("errCertFmt"))
        return false
      }
      if (file.size / 1024 / 1024 > MAX_CERT_MB) {
        this.$modal.msgError(this.tmT("errCertMb"))
        return false
      }
      return true
    },
    handleCertUploadSuccess(res, file) {
      if (res.code === 200) {
        this.form.certFileUrl = res.url
        this.form.certFilePath = res.fileName
        this.certDisplayName = res.originalFilename || file.name
      } else {
        this.$modal.msgError(res.msg || this.tmT("errCertFmt"))
      }
    },
    clearCertFile() {
      this.form.certFileUrl = undefined
      this.form.certFilePath = undefined
      this.certDisplayName = ""
    },
    handleUploadHttpError() {
      this.$modal.msgError(this.tmT("errCertFmt"))
    },
    buildSubmitPayload() {
      const earTagList = this.parsedMainEarTags
      return {
        entryTime: this.form.entryTime,
        supplierId: this.form.supplierId,
        certFileUrl: this.form.certFileUrl,
        certFilePath: this.form.certFilePath,
        certNo: (this.form.certNo || "").trim(),
        quantity: this.form.quantity,
        earTagList,
        isolationDays: this.form.isolationDays,
        penAllocList: (this.form.penAllocList || []).map((row) => ({
          penId: row.penId,
          earTagList: row.earTagList
        }))
      }
    },
    submitForm() {
      this.$refs.form.validate((valid) => {
        if (!valid) {
          return
        }
        if (!this.validateConsistencyBeforeSubmit()) {
          return
        }
        const payload = this.buildSubmitPayload()
        if (this.dialogEdit) {
          payload.id = this.form.id
          updateEntryIsolation(payload).then(() => {
            this.$modal.msgSuccess(this.tmCommon("msgModOk"))
            this.open = false
            this.getList()
          })
        } else {
          addEntryIsolation(payload).then(() => {
            this.$modal.msgSuccess(this.tmCommon("msgAddOk"))
            this.open = false
            this.getList()
          })
        }
      })
    },
    cancel() {
      this.open = false
      this.resetFormModel()
    }
  }
}
</script>

<style scoped>
.form-unit {
  margin-left: 8px;
  color: #909399;
  font-size: 12px;
}
.text-muted {
  color: #909399;
  font-size: 12px;
  line-height: 1.5;
}
.upload-file-list {
  list-style: none;
  padding: 0;
  margin: 8px 0 0;
}
.upload-file-item {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 4px 8px;
  border: 1px solid #e4e7ed;
}
</style>
