<template>
  <div class="aps-sheet-page excel-theme">
    <el-card class="sheet-header" shadow="never">
      <div class="sheet-header-row">
        <div class="sheet-actions">
          <el-button size="small" icon="el-icon-back" @click="$router.back()">返回</el-button>
          <el-button type="primary" size="small" icon="el-icon-search" @click="handleQuery">查询</el-button>
          <el-button type="success" size="small" icon="el-icon-check" :loading="saving" @click="handleSaveSupplement">保存补录</el-button>
          <el-button size="small" icon="el-icon-download" @click="handleExport">导出 Excel</el-button>
        </div>
      </div>

      <el-form :inline="true" size="small" :model="query" class="sheet-form">
        <el-form-item label="模板">
          <el-input v-model="currentTemplate.name" disabled style="width: 220px" />
        </el-form-item>
        <el-form-item label="机组/产线">
          <el-select v-model="query.lineId" clearable filterable placeholder="全部">
            <el-option
              v-for="line in lineOptions"
              :key="line.lineId"
              :label="line.lineName || ('产线' + line.lineId)"
              :value="line.lineId"
            />
          </el-select>
        </el-form-item>
        <el-form-item label="计划编号">
          <el-input v-model="query.planId" placeholder="计划号/计划编码（可选）" clearable style="width: 220px" />
        </el-form-item>
        <el-form-item label="订单编号">
          <el-input v-model="query.orderId" placeholder="订单号/订单编码（可选）" clearable style="width: 220px" />
        </el-form-item>
        <el-form-item label="时间范围">
          <el-date-picker
            v-model="query.range"
            type="datetimerange"
            start-placeholder="开始时间"
            end-placeholder="结束时间"
            range-separator="至"
            value-format="yyyy-MM-dd HH:mm:ss"
            :default-time="['00:00:00', '23:59:59']"
            style="width: 380px"
          />
        </el-form-item>
      </el-form>
    </el-card>

    <el-card class="sheet-body" shadow="never">
      <div class="sheet-meta" v-if="sheet.header">
        <div class="meta-item"><span class="k">计划号：</span><span class="v">{{ sheet.header.planCode || '-' }}</span></div>
        <div class="meta-item"><span class="k">机组：</span><span class="v">{{ sheet.header.lineName || '-' }}</span></div>
        <div class="meta-item"><span class="k">日期：</span><span class="v">{{ sheet.header.dateText || '-' }}</span></div>
        <div class="meta-item"><span class="k">说明：</span><span class="v">点击“选择原料钢卷”弹窗按库区选卷</span></div>
        <div class="meta-item meta-item-warn"><span class="k">补录提示：</span><span class="v">原料钢卷、原料卷号、钢卷位置、包装要求、切边要求、镀层种类为优先补录项，已前置展示；已有值也可直接修改，修改后自动保存。</span></div>
      </div>

      <el-table
        v-loading="loading"
        :data="sheet.rows"
        border
        size="mini"
        :height="tableHeight"
        class="excel-table"
      >
        <el-table-column
          v-for="col in (currentTemplate.columns || [])"
          :key="col.prop || col.label"
          :label="col.label"
          :prop="col.prop"
          :width="col.width"
          :min-width="col.minWidth"
          :align="col.align || 'center'"
          :show-overflow-tooltip="col.showOverflowTooltip !== false"
        >
          <template slot-scope="scope">
            <template v-if="col.prop === 'rawMaterialId'">
              <el-button
                size="mini"
                type="text"
                class="coil-picker-btn"
                @click="openCoilPicker(scope.row)"
              >
                {{ scope.row.rawCoilNos || '选择原料钢卷' }}
              </el-button>
            </template>

            <template v-else-if="isEditableColumn(col.prop)">
              <el-input
                v-model="scope.row[col.prop]"
                size="mini"
                clearable
                class="excel-cell-input"
                :placeholder="`请输入${col.label}`"
                @change="onCellEdit(scope.row, col.prop)"
              />
            </template>

            <template v-else>
              {{ scope.row[col.prop] == null || scope.row[col.prop] === '' ? '-' : scope.row[col.prop] }}
            </template>
          </template>
        </el-table-column>
      </el-table>

      <div class="sheet-summary" v-if="summaryText">
        <span class="k">合计：</span>
        <span class="v">{{ summaryText }}</span>
      </div>
    </el-card>

    <el-dialog title="选择原料钢卷" :visible.sync="coilPicker.visible" width="1280px" append-to-body>
      <el-form :inline="true" size="small" class="coil-picker-form">
        <el-form-item label="库区">
          <el-select v-model="coilPicker.selectedWarehouseId" clearable filterable placeholder="全部库区" style="width: 220px" @change="onCoilFilterChange">
            <el-option
              v-for="w in coilPicker.warehouseOptions"
              :key="w.actualWarehouseId"
              :label="w.actualWarehouseName"
              :value="w.actualWarehouseId"
            />
          </el-select>
        </el-form-item>
        <el-form-item label="入场钢卷号">
          <el-input v-model="coilPicker.enterCoilNo" clearable placeholder="支持模糊" style="width: 170px" @keyup.enter.native="searchCoils" />
        </el-form-item>
        <el-form-item label="当前钢卷号">
          <el-input v-model="coilPicker.currentCoilNo" clearable placeholder="支持模糊" style="width: 170px" @keyup.enter.native="searchCoils" />
        </el-form-item>
        <el-form-item label="厂家">
          <el-input v-model="coilPicker.manufacturer" clearable placeholder="支持模糊" style="width: 170px" @keyup.enter.native="searchCoils" />
        </el-form-item>
        <el-form-item>
          <el-button size="mini" type="primary" @click="searchCoils">查询</el-button>
        </el-form-item>
      </el-form>

      <div class="coil-stack-wrap" v-loading="coilPicker.loading">
        <el-empty v-if="!coilColumnKeys.length" description="暂无可选原料钢卷" :image-size="60" />
        <div v-else class="coil-bird-wrap">
          <div class="coil-legend">
            <span class="legend-item"><i class="dot layer1" />一层</span>
            <span class="legend-item"><i class="dot layer2" />二层</span>
            <span class="legend-item"><i class="dot occupied" />已占用</span>
          </div>
          <div class="coil-grid-scroll">
            <div class="coil-col-ruler">
              <div class="ruler-empty" />
              <div v-for="col in coilColumnKeys" :key="`ruler-${col}`" class="ruler-col">{{ col }}</div>
            </div>
            <div class="coil-grid-main">
              <div class="coil-row-ruler">
                <div v-for="row in coilMaxRow" :key="`row-${row}`" class="ruler-row">{{ row }}</div>
              </div>
              <div class="coil-grid-columns">
                <div v-for="col in coilColumnKeys" :key="`col-${col}`" class="coil-col-pair">
                  <div class="coil-layer">
                    <div
                      v-for="row in coilMaxRow"
                      :key="`l1-${col}-${row}`"
                      class="coil-cell layer1"
                      :class="{ occupied: !!(getCoilCell(col, row, 1) && getCoilCell(col, row, 1).rawMaterialId) }"
                      @click="selectCoilCell(col, row, 1)"
                    >
                      <template v-if="getCoilCell(col, row, 1)">
                        <div class="line1" :title="getCoilCell(col, row, 1).rawLocation">{{ getCoilCell(col, row, 1).rawLocation }}</div>
                        <div class="line2" :title="getCoilCell(col, row, 1).rawMaterialCode">{{ getCoilCell(col, row, 1).rawMaterialCode || '-' }}</div>
                      </template>
                      <template v-else>-</template>
                    </div>
                  </div>
                  <div class="coil-layer layer2-shift">
                    <div
                      v-for="row in (coilMaxRow - 1)"
                      :key="`l2-${col}-${row}`"
                      class="coil-cell layer2"
                      :class="{ occupied: !!(getCoilCell(col, row, 2) && getCoilCell(col, row, 2).rawMaterialId) }"
                      @click="selectCoilCell(col, row, 2)"
                    >
                      <template v-if="getCoilCell(col, row, 2)">
                        <div class="line1" :title="getCoilCell(col, row, 2).rawLocation">{{ getCoilCell(col, row, 2).rawLocation }}</div>
                        <div class="line2" :title="getCoilCell(col, row, 2).rawMaterialCode">{{ getCoilCell(col, row, 2).rawMaterialCode || '-' }}</div>
                      </template>
                      <template v-else>-</template>
                    </div>
                  </div>
                </div>
              </div>
            </div>
          </div>
        </div>
      </div>
      <div class="coil-picker-foot">共 {{ coilPicker.total || 0 }} 条钢卷（按库位分布展示）</div>
    </el-dialog>
  </div>
</template>

<script>
import { APS_SHEET_TEMPLATES, getTemplateByKey } from './sheets/templates'
import { listProductionLine } from '@/api/wms/productionLine'
import { getMaterialCoilLocationGrid } from '@/api/wms/coil'
import { treeActualWarehouseTwoLevel } from '@/api/wms/actualWarehouse'
import { fetchScheduleSheet, exportScheduleSheet, saveScheduleSheetSupplement } from '@/api/aps/aps'
import { parseTime } from '@/utils/klp'
import { saveAs } from 'file-saver'

export default {
  name: 'ApsScheduleSheet',
  data() {
    return {
      templates: APS_SHEET_TEMPLATES,
      lineOptions: [],
      rawMaterialOptions: [],
      loading: false,
      saving: false,
      autoSaveTimer: null,
      pendingAutoSave: false,
      dirtyOperationIds: [],
      baselineByOperationId: {},
      tableHeight: 520,
      coilPicker: {
        visible: false,
        loading: false,
        currentRow: null,
        selectedWarehouseId: undefined,
        enterCoilNo: '',
        currentCoilNo: '',
        manufacturer: '',
        warehouseOptions: [],
        groupedCoils: [],
        coilGrid: {},
        pageNum: 1,
        pageSize: 20,
        total: 0
      },
      query: {
        templateKey: 'unified',
        lineId: null,
        planId: '',
        orderId: '',
        range: []
      },
      sheet: {
        header: null,
        rows: [],
        summary: null
      }
    }
  },
  computed: {
    currentTemplate() {
      return getTemplateByKey(this.query.templateKey)
    },
    summaryText() {
      const s = this.sheet && this.sheet.summary
      if (!s) return ''
      const parts = []
      if (s.totalPieceCount != null) parts.push(`件数 ${s.totalPieceCount}`)
      if (s.totalWeightTon != null) parts.push(`重量 ${s.totalWeightTon}`)
      return parts.join('，')
    },
    coilColumnKeys() {
      const keys = Object.keys(this.coilPicker.coilGrid || {})
      return keys.map(v => Number(v)).filter(v => !Number.isNaN(v)).sort((a, b) => a - b)
    },
    coilMaxRow() {
      let max = 0
      Object.values(this.coilPicker.coilGrid || {}).forEach(col => {
        const l1 = col.layer1 || []
        const l2 = col.layer2 || []
        ;[...l1, ...l2].forEach(item => {
          const row = Number(item._row || 0)
          if (row > max) max = row
        })
      })
      return max || 1
    }
  },
  created() {
    this.tableHeight = document.documentElement.clientHeight - 280
    this.initDefaultRange()
    Promise.all([this.loadLines(), this.loadRawMaterials()]).finally(() => {
      this.applyRouteQuery()
      this.handleQuery()
    })
  },
  beforeDestroy() {
    if (this.autoSaveTimer) {
      clearTimeout(this.autoSaveTimer)
      this.autoSaveTimer = null
    }
  },
  methods: {
    initDefaultRange() {
      const now = new Date()
      const start = new Date(now.getFullYear(), now.getMonth(), now.getDate(), 0, 0, 0)
      const end = new Date(now.getFullYear(), now.getMonth(), now.getDate() + 7, 23, 59, 59)
      this.query.range = [parseTime(start), parseTime(end)]
    },
    loadLines() {
      return listProductionLine({ pageNum: 1, pageSize: 999 }).then(res => {
        this.lineOptions = (res.rows || res.data || []).map(r => ({
          lineId: r.lineId,
          lineName: r.lineName || r.lineCode
        }))
      }).catch(() => {})
    },
    loadRawMaterials() {
      return this.loadCoilsByWarehouse()
    },
    loadWarehouseOptions() {
      return treeActualWarehouseTwoLevel().then(res => {
        const tree = res.data || []
        const leaf = []
        tree.forEach(p => {
          ;(p.children || []).forEach(c => {
            leaf.push({
              actualWarehouseId: c.actualWarehouseId,
              actualWarehouseName: `${p.actualWarehouseName || ''}/${c.actualWarehouseName || ''}`
            })
          })
        })
        this.coilPicker.warehouseOptions = leaf
      }).catch(() => {
        this.coilPicker.warehouseOptions = []
      })
    },
    async loadCoilsByWarehouse() {
      if (!this.coilPicker.selectedWarehouseId) {
        this.coilPicker.coilGrid = {}
        this.rawMaterialOptions = []
        this.coilPicker.total = 0
        return
      }
      this.coilPicker.loading = true
      try {
        const gridRes = await getMaterialCoilLocationGrid({
          itemType: 'raw_material',
          actualWarehouseId: this.coilPicker.selectedWarehouseId,
          enterCoilNo: this.coilPicker.enterCoilNo || undefined,
          currentCoilNo: this.coilPicker.currentCoilNo || undefined,
          manufacturer: this.coilPicker.manufacturer || undefined
        })

        const data = gridRes.data || {}
        const warehouses = data.warehouses || []
        const coils = (data.coils || []).map(item => ({
          rawMaterialId: item.coilId,
          rawMaterialCode: item.currentCoilNo || item.enterCoilNo || item.coilNo || '',
          enterCoilNo: item.enterCoilNo || '',
          manufacturer: item.manufacturer || '',
          rawMaterialName: item.itemName || item.materialName || '',
          specification: item.specification || '',
          coilWeight: item.netWeight,
          packageType: item.packagingRequirement || item.packageType,
          edgeType: item.trimmingRequirement || item.edgeType,
          zincLayer: item.coatingType || item.zincLayer,
          surfaceTreatmentDesc: item.surfaceTreatmentDesc,
          actualWarehouseId: item.actualWarehouseId,
          actualWarehouseName: item.actualWarehouseName || '未分配库位',
          rawLocation: item.actualWarehouseName || '未分配库位'
        }))
        this.rawMaterialOptions = coils
        this.coilPicker.total = coils.length

        const coilByWarehouseId = {}
        coils.forEach(c => {
          if (c.actualWarehouseId && !coilByWarehouseId[c.actualWarehouseId]) {
            coilByWarehouseId[c.actualWarehouseId] = c
          }
        })

        const grid = {}
        warehouses.forEach(w => {
          const code = String(w.actualWarehouseCode || '')
          const m = code.match(/^([A-Za-z0-9]{3})([^-]+)-(\d{2})-(\d+)$/)
          if (!m) return
          const col = Number(m[2])
          const row = Number(m[3])
          const layer = Number(m[4])
          if (!grid[col]) grid[col] = { layer1: [], layer2: [] }
          const coil = coilByWarehouseId[w.actualWarehouseId] || null
          const cell = {
            _col: col,
            _row: row,
            _layer: layer,
            actualWarehouseId: w.actualWarehouseId,
            actualWarehouseCode: w.actualWarehouseCode,
            rawLocation: w.actualWarehouseName || w.actualWarehouseCode,
            ...(coil || {})
          }
          if (layer === 1) grid[col].layer1.push(cell)
          else if (layer === 2) grid[col].layer2.push(cell)
        })

        Object.keys(grid).forEach(k => {
          grid[k].layer1.sort((a, b) => Number(a._row) - Number(b._row))
          grid[k].layer2.sort((a, b) => Number(a._row) - Number(b._row))
        })
        this.coilPicker.coilGrid = grid
      } finally {
        this.coilPicker.loading = false
      }
    },
    searchCoils() {
      this.loadCoilsByWarehouse()
    },
    onCoilFilterChange() {
      this.loadCoilsByWarehouse()
    },
    hasSelectedWarehouse() {
      return !!this.coilPicker.selectedWarehouseId
    },
    getCoilCell(col, row, layer) {
      const c = this.coilPicker.coilGrid[col]
      if (!c) return null
      const list = layer === 1 ? (c.layer1 || []) : (c.layer2 || [])
      return list.find(i => Number(i._row) === Number(row)) || null
    },
    selectCoilCell(col, row, layer) {
      const item = this.getCoilCell(col, row, layer)
      if (!item) return
      if (!item.rawMaterialId) {
        this.$message.warning('该库位当前无钢卷，请选择有钢卷的库位')
        return
      }
      this.pickRawMaterial(item)
    },
    rawMaterialLabel(item) {
      return `${item.rawMaterialCode || '-'} / ${item.rawMaterialName || '-'} / ${item.specification || '-'}`
    },
    applyRouteQuery() {
      const q = this.$route && this.$route.query ? this.$route.query : {}
      if (q.templateKey) this.query.templateKey = String(q.templateKey)
      if (q.planId) this.query.planId = String(q.planId)
      if (q.orderId) this.query.orderId = String(q.orderId)
      if (q.lineId) {
        const lineIdStr = String(q.lineId)
        const matched = (this.lineOptions || []).find(l => String(l.lineId) === lineIdStr)
        this.query.lineId = matched ? matched.lineId : lineIdStr
      }
      if (q.queryStart && q.queryEnd) this.query.range = [q.queryStart, q.queryEnd]
    },
    isEditableColumn(prop) {
      return ['rawCoilNos', 'rawNetWeight', 'rawPackaging', 'rawEdgeReq', 'rawCoatingType'].includes(prop)
    },
    normalizeSaveRow(r) {
      return {
        operationId: r.operationId,
        rawMaterialId: r.rawMaterialId || null,
        rawCoilNos: r.rawCoilNos || '',
        rawNetWeight: r.rawNetWeight === '' || r.rawNetWeight == null ? null : r.rawNetWeight,
        rawPackaging: r.rawPackaging || '',
        rawEdgeReq: r.rawEdgeReq || '',
        rawCoatingType: r.rawCoatingType || '',
        rawLocation: r.rawLocation || ''
      }
    },
    setBaselineFromRows(rows) {
      const map = {}
      ;(rows || []).forEach(r => {
        if (r && r.operationId) {
          map[r.operationId] = this.normalizeSaveRow(r)
        }
      })
      this.baselineByOperationId = map
      this.dirtyOperationIds = []
    },
    markRowDirty(row) {
      if (!row || !row.operationId) return
      const id = row.operationId
      const curr = this.normalizeSaveRow(row)
      const baseline = this.baselineByOperationId[id] || {}
      const changed = JSON.stringify(curr) !== JSON.stringify(baseline)
      const ids = new Set(this.dirtyOperationIds || [])
      if (changed) ids.add(id)
      else ids.delete(id)
      this.dirtyOperationIds = Array.from(ids)
    },
    onCellEdit(row) {
      this.$forceUpdate()
      this.markRowDirty(row)
      this.scheduleAutoSave(row)
    },
    scheduleAutoSave(row) {
      if (!row || !row.operationId) return
      this.pendingAutoSave = true
      if (this.autoSaveTimer) clearTimeout(this.autoSaveTimer)
      this.autoSaveTimer = setTimeout(() => {
        this.handleSaveSupplement(true)
      }, 900)
    },
    openCoilPicker(row) {
      this.coilPicker.currentRow = row
      this.coilPicker.visible = true
      Promise.all([this.loadWarehouseOptions()]).then(() => {
        if (!this.coilPicker.selectedWarehouseId && this.coilPicker.warehouseOptions.length) {
          this.coilPicker.selectedWarehouseId = this.coilPicker.warehouseOptions[0].actualWarehouseId
          this.$message.info('请先选择库区，再点击查询或直接选择库位钢卷')
        }
        this.loadCoilsByWarehouse()
      })
    },
    pickRawMaterial(item) {
      const row = this.coilPicker.currentRow
      if (!row) return
      if (!item || !item.rawMaterialId) {
        this.$message.warning('请选择有效钢卷')
        return
      }
      this.$set(row, 'rawMaterialId', item.rawMaterialId)
      this.$set(row, 'rawCoilNos', item.rawMaterialCode || item.rawCoilNos || item.rawMaterialName || '')
      this.$set(row, 'rawNetWeight', item.coilWeight != null ? item.coilWeight : (row.rawNetWeight || ''))
      this.$set(row, 'rawPackaging', item.packageType || item.rawPackaging || row.rawPackaging || '')
      this.$set(row, 'rawEdgeReq', item.edgeType || item.rawEdgeReq || row.rawEdgeReq || '')
      this.$set(row, 'rawCoatingType', item.zincLayer || item.surfaceTreatmentDesc || row.rawCoatingType || '')
      this.$set(row, 'rawLocation', item.rawLocation || '')
      this.coilPicker.visible = false
      this.$message.success('已选择钢卷并回填')
      this.$forceUpdate()
      this.markRowDirty(row)
      this.scheduleAutoSave(row)
    },
    handleRawMaterialChange(row, rawMaterialId) {
      const item = (this.rawMaterialOptions || []).find(r => r.rawMaterialId === rawMaterialId)
      if (!item) return
      row.rawMaterialId = item.rawMaterialId
      row.rawCoilNos = item.rawMaterialCode || item.rawCoilNos || item.rawMaterialName || ''
      row.rawNetWeight = item.coilWeight != null ? item.coilWeight : (row.rawNetWeight || '')
      row.rawPackaging = item.packageType || item.rawPackaging || row.rawPackaging || ''
      row.rawEdgeReq = item.edgeType || item.rawEdgeReq || row.rawEdgeReq || ''
      row.rawCoatingType = item.zincLayer || item.surfaceTreatmentDesc || row.rawCoatingType || ''
      row.rawLocation = item.rawLocation || row.rawLocation || ''
      this.$forceUpdate()
      this.markRowDirty(row)
      this.scheduleAutoSave(row)
    },
    buildSavePayload() {
      const dirtyIds = new Set(this.dirtyOperationIds || [])
      const rows = (this.sheet.rows || [])
        .filter(r => r && r.operationId && dirtyIds.has(r.operationId))
        .map(r => this.normalizeSaveRow(r))
      return { rows }
    },
    async handleSaveSupplement(isAuto = false) {
      const payload = this.buildSavePayload()
      if (!payload.rows.length) {
        if (!isAuto) this.$message.warning('暂无可保存的数据')
        return
      }
      if (this.saving) {
        this.pendingAutoSave = true
        return
      }
      const savedIds = payload.rows.map(r => r.operationId)
      this.saving = true
      try {
        await saveScheduleSheetSupplement(payload)
        payload.rows.forEach(r => {
          this.baselineByOperationId[r.operationId] = { ...r }
        })
        const dirtySet = new Set(this.dirtyOperationIds || [])
        savedIds.forEach(id => dirtySet.delete(id))
        this.dirtyOperationIds = Array.from(dirtySet)
        if (isAuto) {
          this.pendingAutoSave = false
        } else {
          this.$message.success('补录保存成功')
        }
      } finally {
        this.saving = false
        if (this.pendingAutoSave) {
          this.pendingAutoSave = false
          if (this.autoSaveTimer) clearTimeout(this.autoSaveTimer)
          this.autoSaveTimer = setTimeout(() => {
            this.handleSaveSupplement(true)
          }, 300)
        }
      }
    },
    handleQuery() {
      if (!this.query.range || this.query.range.length !== 2) {
        this.$message.warning('请先选择时间范围')
        return
      }
      const params = {
        templateKey: this.query.templateKey,
        lineId: this.query.lineId || undefined,
        planId: this.query.planId || undefined,
        orderId: this.query.orderId || undefined,
        queryStart: this.query.range[0],
        queryEnd: this.query.range[1]
      }
      this.loading = true
      fetchScheduleSheet(params)
        .then(res => {
          const data = res.data || res
          this.sheet = {
            header: data.header || null,
            rows: (data.rows || []).map(r => ({ ...r })),
            summary: data.summary || null
          }
          this.setBaselineFromRows(this.sheet.rows)
        })
        .finally(() => {
          this.loading = false
        })
    },
    handleExport() {
      if (!this.query.range || this.query.range.length !== 2) {
        this.$message.warning('请先选择时间范围')
        return
      }
      const params = {
        templateKey: this.query.templateKey,
        lineId: this.query.lineId || undefined,
        planId: this.query.planId || undefined,
        orderId: this.query.orderId || undefined,
        queryStart: this.query.range[0],
        queryEnd: this.query.range[1]
      }
      this.loading = true
      exportScheduleSheet(params)
        .then(blob => {
          const filename = `aps_${this.query.templateKey}_${new Date().getTime()}.xlsx`
          saveAs(new Blob([blob], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' }), filename)
        })
        .finally(() => {
          this.loading = false
        })
    }
  }
}
</script>

<style scoped lang="scss">
.aps-sheet-page {
  padding: 8px;
  background: #f3f5f7;
}

::v-deep .sheet-header.el-card,
::v-deep .sheet-body.el-card {
  border: none;
  box-shadow: none;
}

.sheet-header,
.sheet-body {
  border: 1px solid #d3d7dc;
  border-radius: 2px;
  background: #fff;
}

.sheet-header {
  margin-bottom: 8px;
}
.sheet-header-row {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 8px;
}
.sheet-meta {
  display: flex;
  flex-wrap: wrap;
  gap: 14px;
  margin-bottom: 8px;
  font-size: 12px;
  color: #4d4f53;
}
.meta-item .k {
  color: #8b9098;
}
.meta-item-warn {
  width: 100%;
  padding: 4px 8px;
  border-radius: 4px;
  background: #fff8e6;
  border: 1px solid #f7df9a;
}
.meta-item-warn .k,
.meta-item-warn .v {
  color: #8a6d1d;
}
.sheet-summary {
  margin-top: 8px;
  font-size: 12px;
}
.sheet-summary .k {
  color: #8b9098;
}

::v-deep .excel-table {
  border: 1px solid #bfc5cc;
}
::v-deep .excel-table th.el-table__cell {
  background: #eef1f5;
  color: #3c4045;
  font-weight: 600;
  border-right: 1px solid #bfc5cc;
  border-bottom: 1px solid #bfc5cc;
  padding: 4px 0;
}
::v-deep .excel-table td.el-table__cell {
  border-right: 1px solid #d0d5db;
  border-bottom: 1px solid #d0d5db;
  padding: 1px 2px;
}
::v-deep .excel-table .el-table__row:hover > td {
  background-color: #f5f9ff !important;
}
::v-deep .excel-table .current-row > td {
  background-color: #eaf2ff !important;
}

::v-deep .excel-cell-input .el-input__inner,
::v-deep .excel-cell-select .el-input__inner {
  border: 1px solid transparent;
  border-radius: 0;
  height: 24px;
  line-height: 24px;
  padding: 0 6px;
  background: #fff;
}
::v-deep .excel-cell-input .el-input__inner:focus,
::v-deep .excel-cell-select .el-input__inner:focus {
  border-color: #4a90e2;
  box-shadow: inset 0 0 0 1px #4a90e2;
}

.coil-bird-wrap { border: 1px solid #ebeef5; border-radius: 6px; padding: 8px; }
.coil-legend { display: flex; gap: 14px; font-size: 12px; color: #606266; margin-bottom: 8px; }
.legend-item { display: inline-flex; align-items: center; gap: 4px; }
.dot { width: 8px; height: 8px; border-radius: 2px; display: inline-block; }
.dot.layer1 { background: #fff3e0; border: 1px solid #f5d7a1; }
.dot.layer2 { background: #e8f5e9; border: 1px solid #b7ddb9; }
.dot.occupied { background: #f6f8fb; border: 1px solid #d7dde5; }
.coil-grid-scroll { overflow: auto; max-height: 460px; }
.coil-col-ruler { display: flex; min-width: max-content; }
.ruler-empty { width: 28px; flex: none; }
.ruler-col { width: 138px; text-align: center; font-size: 12px; color: #606266; }
.coil-grid-main { display: flex; min-width: max-content; }
.coil-row-ruler { width: 28px; display: flex; flex-direction: column; }
.ruler-row { height: 56px; display: flex; align-items: center; justify-content: center; font-size: 12px; color: #909399; }
.coil-grid-columns { display: flex; gap: 8px; }
.coil-col-pair { display: grid; grid-template-columns: 1fr 1fr; width: 180px; border: 1px solid #eef2f7; border-radius: 4px; overflow: visible; }
.coil-layer { display: flex; flex-direction: column; }
.coil-layer.layer2-shift { margin-top: 28px; }
.coil-cell { height: 56px; border-bottom: 1px solid #eef2f7; border-right: 1px solid #eef2f7; padding: 4px; font-size: 11px; color: #909399; display: flex; align-items: center; justify-content: center; text-align: center; cursor: pointer; }
.coil-cell.layer1 { background: #fff3e0; color: #e67e22; }
.coil-cell.layer2 { background: #e8f5e9; color: #2e8b57; border-right: none; }
.coil-cell.occupied { font-weight: 600; }
.coil-cell .line1 { width: 100%; font-size: 11px; line-height: 1.1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.coil-cell .line2 { width: 100%; font-size: 11px; line-height: 1.1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.coil-picker-foot { margin-top: 8px; text-align: right; color: #909399; font-size: 12px; }
</style>
