<template>
  <div class="aps-quick-sheet excel-theme">
    <div class="sheet-toolbar">
      <div class="sheet-actions">
        <el-button size="small" icon="el-icon-refresh" @click="loadRows">刷新</el-button>
        <el-button size="small" type="primary" icon="el-icon-finished" :loading="saving" @click="saveAll">保存</el-button>
        <el-button size="small" icon="el-icon-plus" @click="addRow">新增行</el-button>
        <el-button size="small" icon="el-icon-download" @click="exportCsv">导出</el-button>
        <el-button size="small" icon="el-icon-setting" @click="columnSettingVisible = true">列设置</el-button>
        <el-date-picker
          v-model="filter.range"
          type="daterange"
          range-separator="至"
          start-placeholder="开始日期"
          end-placeholder="结束日期"
          value-format="yyyy-MM-dd"
          size="small"
          style="width: 240px"
          @change="onFilterChange"
        />
      </div>
      <div class="preset-bar">
        <span class="preset-title">预设方案：</span>
        <el-button
          v-for="line in lineOptions"
          :key="line.lineId"
          size="mini"
          plain
          @click="applyPreset(line)"
        >
          {{ line.lineName || line.lineCode || ('产线' + line.lineId) }}
        </el-button>
      </div>
    </div>

    <div class="sheet-body">
      <el-table
        ref="quickSheetTable"
        v-loading="loading"
        :data="displayRows"
        border
        size="mini"
        class="excel-table"
      >
        <el-table-column label="序号" width="60" align="center" fixed="left">
          <template slot-scope="scope">
            {{ ((pager.pageNum - 1) * pager.pageSize) + scope.$index + 1 }}
          </template>
        </el-table-column>
        <el-table-column
          v-for="(col, colIndex) in displayColumns"
          :key="col.prop || col.label"
          :label="col.label"
          :prop="col.prop"
          :width="col.width"
          :min-width="col.minWidth"
          :align="col.align || 'center'"
          :fixed="fixedProps.includes(col.prop) ? 'left' : false"
          :show-overflow-tooltip="col.showOverflowTooltip !== false"
        >
          <template slot-scope="scope">
            <template v-if="isTimeField(col.prop)">
              <el-date-picker
                v-model="scope.row[col.prop]"
                type="datetime"
                value-format="yyyy-MM-dd HH:mm:ss"
                size="mini"
                style="width: 100%"
                @change="onCellChange(scope.row)"
                @input="onCellChange(scope.row)"
                @keydown.native.enter.prevent="focusNextCell(scope.$index, colIndex, 'down')"
                @keydown.native.tab.prevent="focusNextCell(scope.$index, colIndex, 'right')"
              />
            </template>
            <template v-else>
              <el-autocomplete
                v-if="col.prop === 'lineName'"
                v-model="scope.row[col.prop]"
                size="mini"
                clearable
                :fetch-suggestions="queryLineHistory"
                @select="onLineHistorySelect(scope.row)"
                @input="onLineHistoryInput(scope.row)"
                @keydown.native.enter.prevent="focusNextCell(scope.$index, colIndex, 'down')"
                @keydown.native.tab.prevent="focusNextCell(scope.$index, colIndex, 'right')"
              />
              <el-input
                v-else
                v-model="scope.row[col.prop]"
                size="mini"
                clearable
                @input="onCellChange(scope.row)"
                @keydown.native.enter.prevent="focusNextCell(scope.$index, colIndex, 'down')"
                @keydown.native.tab.prevent="focusNextCell(scope.$index, colIndex, 'right')"
              />
            </template>
          </template>
        </el-table-column>
        <el-table-column label="操作" width="70" fixed="right" align="center">
          <template slot-scope="scope">
            <el-button type="text" size="mini" @click="clearRow(scope.row)">清空</el-button>
          </template>
        </el-table-column>
      </el-table>
     
      <div class="pager-wrap">
        <el-pagination
          small
          background
          layout="prev, pager, next, total"
          :current-page.sync="pager.pageNum"
          :page-size="pager.pageSize"
          :total="totalRows"
        />
      </div>
    </div>
    <div v-if="missingRows.length" class="missing-tip">
        <div v-for="msg in missingRows" :key="msg" class="missing-item">{{ msg }}</div>
      </div>
    <el-drawer
      title="列设置"
      :visible.sync="columnSettingVisible"
      direction="rtl"
      size="55%"
      append-to-body
      @open="resetColumnDraft">
      <div class="col-setting-body">
        <div class="col-setting-toolbar">
          <el-button size="mini" @click="restoreDefaultColumns">恢复默认</el-button>
          <el-button size="mini" @click="resetColumnDraft">重置</el-button>
          <el-button size="mini" type="primary" @click="saveColumnSettings">保存</el-button>
        </div>

        <div class="col-section">
          <div class="col-section-title">固定列（最多5列）</div>
          <draggable v-model="fixedColumnList" handle=".drag-handle" animation="200" class="col-setting-grid">
            <div v-for="item in fixedColumnList" :key="`fixed-${item.prop}`" class="col-setting-item">
              <i class="el-icon-rank drag-handle" />
              <span class="col-label">{{ item.label }}</span>
              <el-button type="text" size="mini" @click="removeFromFixed(item.prop)">移除</el-button>
            </div>
          </draggable>
        </div>

        <div class="col-section">
          <div class="col-section-title">其他列</div>
          <draggable v-model="normalColumnList" handle=".drag-handle" animation="200" class="col-setting-grid">
            <div v-for="item in normalColumnList" :key="`normal-${item.prop}`" class="col-setting-item">
              <i class="el-icon-rank drag-handle" />
              <span class="col-label">{{ item.label }}</span>
              <el-button type="text" size="mini" @click="addToFixed(item.prop)">加入固定</el-button>
            </div>
          </draggable>
        </div>
      </div>
    </el-drawer>

  </div>
</template>

<script>
import { fetchQuickSheetList, fetchQuickSheetPreset, saveQuickSheet, exportQuickSheet, deleteQuickSheetRow } from '@/api/aps/quickSheet'
import { listProductionLine } from '@/api/wms/productionLine'
import { getTemplateByKey } from './sheets/templates'
import { saveAs } from 'file-saver'
import draggable from 'vuedraggable'

export default {
  name: 'ApsQuickSheet',
  components: { draggable },
  data() {
    return {
      loading: false,
      saving: false,
      rows: [],
      lineOptions: [],
      lineHistory: [],
      dirtyIds: new Set(),
      autoSaveTimer: null,
      templateKey: 'unified',
      filter: {
        range: []
      },
      pager: {
        pageNum: 1,
        pageSize: 25
      },
      columnSettingVisible: false,
      columnSettingList: [],
      fixedColumnList: [],
      normalColumnList: []
    }
  },
  computed: {
    currentTemplate() {
      return getTemplateByKey(this.templateKey)
    },
    flatColumns() {
      const res = []
      const loop = (cols) => {
        ;(cols || []).forEach(c => {
          if (c.children && c.children.length) loop(c.children)
          else res.push(c)
        })
      }
      loop(this.currentTemplate.columns || [])
      return res.filter(c => c && c.prop)
    },
    displayColumns() {
      const setting = this.columnSettingList || []
      const hasSetting = setting.length > 0
      const base = this.flatColumns

      const selected = hasSetting
        ? setting.filter(i => i.visible).map(i => base.find(c => c.prop === i.prop)).filter(Boolean)
        : base

      const selectedSet = new Set(selected.map(c => c.prop))
      const rest = base.filter(c => !selectedSet.has(c.prop))
      return [...selected, ...rest]
    },
    fixedProps() {
      return (this.columnSettingList || []).filter(i => i.visible && i.fixed).map(i => i.prop).slice(0, 5)
    },
    displayRows() {
      const [startAfter, endBefore] = this.filter.range || []
      const filtered = this.rows.filter(r => {
        if (!r.startTime) return true
        const d = String(r.startTime).slice(0, 10)
        if (startAfter && d < startAfter) return false
        if (endBefore && d > endBefore) return false
        return true
      })
      const start = (this.pager.pageNum - 1) * this.pager.pageSize
      const page = filtered.slice(start, start + this.pager.pageSize)
      if (page.length < this.pager.pageSize) {
        return page.concat(this.buildEmptyRows(this.pager.pageSize - page.length))
      }
      return page
    },
    totalRows() {
      const [startAfter, endBefore] = this.filter.range || []
      return this.rows.filter(r => {
        if (!r.startTime) return true
        const d = String(r.startTime).slice(0, 10)
        if (startAfter && d < startAfter) return false
        if (endBefore && d > endBefore) return false
        return true
      }).length
    },
    missingRows() {
      return this.collectMissing(this.displayRows)
    }
  },
  created() {
    const today = new Date()
    const start = `${today.getFullYear()}-${`${today.getMonth() + 1}`.padStart(2, '0')}-${`${today.getDate()}`.padStart(2, '0')}`
    this.filter.range = [start, '']
    this.initColumnSettings()
    this.loadRows()
    this.loadLines()
    window.addEventListener('keydown', this.handleGlobalKeydown)
  },
  beforeDestroy() {
    if (this.autoSaveTimer) clearTimeout(this.autoSaveTimer)
    this.persistColumnSettings()
    window.removeEventListener('keydown', this.handleGlobalKeydown)
  },
  methods: {
    handleGlobalKeydown(e) {
      const isMac = /Mac|iPod|iPhone|iPad/.test(navigator.userAgent)
      const ctrlOrCmd = isMac ? e.metaKey : e.ctrlKey
      if (ctrlOrCmd && (e.key === 's' || e.key === 'S')) {
        e.preventDefault()
        this.saveAll(false)
      }
    },
    focusNextCell(visibleRowIndex, colIndex, direction) {
      const pageStart = (this.pager.pageNum - 1) * this.pager.pageSize
      const targetRow = direction === 'down' ? visibleRowIndex + 1 : visibleRowIndex
      const targetCol = direction === 'right' ? colIndex + 1 : colIndex
      if (targetCol >= this.displayColumns.length) return

      const globalRowIndex = pageStart + targetRow
      if (globalRowIndex >= this.rows.length) {
        this.rows.push(this.buildEmptyRow())
      }

      this.$nextTick(() => {
        const wrappers = this.$el.querySelectorAll('.excel-table .el-table__body-wrapper tbody tr')
        const tr = wrappers[targetRow]
        if (!tr) return
        const tds = tr.querySelectorAll('td')
        const td = tds[targetCol + 1]
        if (!td) return
        const input = td.querySelector('input, textarea, .el-input__inner')
        if (input) input.focus()
      })
    },
    async loadLines() {
      const res = await listProductionLine({ pageNum: 1, pageSize: 1000 })
      this.lineOptions = res.rows || []
    },
    async loadRows() {
      this.loading = true
      try {
        const res = await fetchQuickSheetList()
        this.rows = (res.data || []).map(r => this.normalizeRow(r))
        this.lineHistory = this.rows
          .map(r => r.lineName)
          .filter(v => v && v.trim())
          .filter((v, i, arr) => arr.indexOf(v) === i)
      } finally {
        this.loading = false
      }
    },
    buildEmptyRows(count) {
      return Array.from({ length: count }).map(() => this.buildEmptyRow())
    },
    async applyPreset(line) {
      if (!line || !line.lineId) return
      const res = await fetchQuickSheetPreset({ lineId: line.lineId })
      const preset = res.data || []
      if (!preset.length) return
      const targetRow = this.rows.find(r => !r.lineId && !r.lineName) || this.buildEmptyRow()
      const base = this.normalizeRow(preset[0])
      Object.keys(base).forEach(k => {
        if (k === 'quickSheetId') return
        targetRow[k] = base[k]
      })
      targetRow.lineId = line.lineId
      targetRow.lineName = line.lineName || line.lineCode || ''
      if (!this.rows.includes(targetRow)) {
        this.rows.push(targetRow)
      }
      if (this.rows.length < 25) {
        this.rows = this.rows.concat(this.buildEmptyRows(25 - this.rows.length))
      }
      this.markDirty(targetRow)
      this.scheduleAutoSave()
    },
    onCellChange(row) {
      if (row && !this.rows.includes(row)) {
        this.rows.push(row)
      }
      this.markDirty(row)
      this.scheduleAutoSave()
    },
    queryLineHistory(query, cb) {
      const list = this.lineHistory || []
      const q = (query || '').trim().toLowerCase()
      const res = list
        .filter(item => !q || String(item).toLowerCase().includes(q))
        .map(item => ({ value: item }))
      cb(res)
    },
    onLineHistoryInput(row) {
      if (!row) return
      if (row.lineId && row.lineName && row.lineName.trim() !== String(row.lineName).trim()) {
        row.lineId = null
      }
      this.onCellChange(row)
    },
    onLineHistorySelect(row) {
      return () => {
        this.onCellChange(row)
      }
    },
    onFilterChange() {
      this.pager.pageNum = 1
    },
    normalizeRow(row) {
      const base = this.buildEmptyRow()
      Object.keys(base).forEach(k => {
        if (row && row[k] !== undefined && row[k] !== null) base[k] = row[k]
      })
      const idVal = row ? (row.quickSheetId !== undefined && row.quickSheetId !== null ? row.quickSheetId : row.id) : null
      base.quickSheetId = idVal != null ? idVal : null
      return base
    },
    buildEmptyRow() {
      const row = { quickSheetId: null }
      this.flatColumns.forEach(col => {
        if (!col.prop) return
        row[col.prop] = ''
      })
      return row
    },
    isRowEmpty(row) {
      if (!row) return true
      return !this.flatColumns.some(col => col.prop && row[col.prop])
    },
    isTimeField(prop) {
      return prop === 'startTime' || prop === 'endTime'
    },
    isLeadingColumn(col) {
      if (!col || !col.prop) return false
      return this.leadingPropsByRole.includes(col.prop)
    },
    initColumnSettings() {
      const key = this.getColumnSettingKey()
      const stored = localStorage.getItem(key)
      const base = this.flatColumns.map((col, idx) => ({ prop: col.prop, label: col.label, visible: true, fixed: idx < 5 }))
      if (!stored) {
        this.columnSettingList = base
        this.resetColumnDraft()
        return
      }
      try {
        const parsed = JSON.parse(stored)
        if (!Array.isArray(parsed)) {
          this.columnSettingList = base
          this.resetColumnDraft()
          return
        }
        const savedProps = parsed.map(i => i.prop)
        const extras = base.filter(i => !savedProps.includes(i.prop))
        this.columnSettingList = [...parsed.filter(i => base.some(b => b.prop === i.prop)).map(i => {
          const match = base.find(b => b.prop === i.prop)
          return { ...match, visible: i.visible !== false, fixed: i.fixed === true }
        }), ...extras]
        this.resetColumnDraft()
      } catch (e) {
        this.columnSettingList = base
        this.resetColumnDraft()
      }
    },
    resetColumnDraft() {
      const fixed = (this.columnSettingList || []).filter(i => i.visible && i.fixed).slice(0, 5)
      const normal = (this.columnSettingList || []).filter(i => !i.fixed || !i.visible)
      this.fixedColumnList = fixed.map(i => ({ ...i, visible: true, fixed: true }))
      this.normalColumnList = normal.map(i => ({ ...i, fixed: false }))
    },
    saveColumnSettings() {
      const fixed = (this.fixedColumnList || []).map(i => ({ ...i, visible: true, fixed: true }))
      const normal = (this.normalColumnList || []).map(i => ({ ...i, fixed: false }))
      this.columnSettingList = [...fixed, ...normal]
      this.persistColumnSettings()
      this.columnSettingVisible = false
      this.pager.pageNum = 1
      this.loadRows().finally(() => {
        this.$nextTick(() => {
          this.$refs.quickSheetTable && this.$refs.quickSheetTable.doLayout && this.$refs.quickSheetTable.doLayout()
        })
      })
    },
    addToFixed(prop) {
      if ((this.fixedColumnList || []).length >= 5) {
        this.$message.warning('固定列最多5列')
        return
      }
      const idx = this.normalColumnList.findIndex(i => i.prop === prop)
      if (idx < 0) return
      const item = this.normalColumnList.splice(idx, 1)[0]
      this.fixedColumnList.push({ ...item, visible: true, fixed: true })
    },
    removeFromFixed(prop) {
      const idx = this.fixedColumnList.findIndex(i => i.prop === prop)
      if (idx < 0) return
      const item = this.fixedColumnList.splice(idx, 1)[0]
      this.normalColumnList.unshift({ ...item, fixed: false })
    },
    persistColumnSettings() {
      const key = this.getColumnSettingKey()
      const payload = (this.columnSettingList || []).map(item => ({
        prop: item.prop,
        label: item.label,
        visible: item.visible !== false,
        fixed: item.fixed === true
      }))
      localStorage.setItem(key, JSON.stringify(payload))
    },
    restoreDefaultColumns() {
      const base = this.flatColumns.map((col, idx) => ({ prop: col.prop, label: col.label, visible: true, fixed: idx < 5 }))
      this.columnSettingList = base
      this.resetColumnDraft()
    },
    getColumnSettingKey() {
      return `apsQuickSheetColumns_${this.templateKey}`
    },
    markDirty(row) {
      if (!row) return
      if (!row._tmpId) row._tmpId = Math.random().toString(36).slice(2)
      this.dirtyIds.add(row._tmpId)
    },
    async clearRow(row) {
      if (!row) return
      if (!row.quickSheetId) {
        this.flatColumns.forEach(col => {
          if (!col.prop) return
          row[col.prop] = ''
        })
        row.quickSheetId = null
        return
      }
      await deleteQuickSheetRow(row.quickSheetId)
      this.flatColumns.forEach(col => {
        if (!col.prop) return
        row[col.prop] = ''
      })
      row.quickSheetId = null
    },
    scheduleAutoSave() {
      if (this.autoSaveTimer) clearTimeout(this.autoSaveTimer)
      this.autoSaveTimer = setTimeout(() => {
        this.saveAll(true)
      }, 800)
    },
    async saveAll(isAuto = false, payload) {
      const rows = payload && payload.rows
        ? payload.rows
        : this.rows.filter(r => r && r._tmpId && this.dirtyIds.has(r._tmpId))
          .map(r => ({
            ...r,
            quickSheetId: r.quickSheetId || null
          }))
      if (!rows.length) {
        if (!isAuto) this.$message.warning('暂无可保存数据')
        return
      }
      const missing = this.collectMissing(rows)
      if (missing.length && !isAuto) {
        this.$message.warning(`必填项未填写：${missing.join('；')}`)
        return
      }
      this.saving = true
      try {
        await saveQuickSheet({ rows })
        if (!isAuto) this.$message.success('保存成功')
        rows.forEach(r => {
          if (r._tmpId) this.dirtyIds.delete(r._tmpId)
        })
      } finally {
        this.saving = false
      }
    },
    exportCsv() {
      this.loading = true
      exportQuickSheet()
        .then(blob => {
          const filename = `quick_sheet_${new Date().getTime()}.xlsx`
          saveAs(new Blob([blob], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' }), filename)
        })
        .finally(() => {
          this.loading = false
        })
    },
    addRow() {
      this.rows.unshift(this.buildEmptyRow())
      this.pager.pageNum = 1
    },
    collectMissing(rows) {
      const msgs = []
      rows.forEach((row, idx) => {
        if (this.isRowEmpty(row)) return
        const line = idx + 1
        const missing = []
        if (!row.lineName && !row.lineId) missing.push('产线')
        if (!row.planCode) missing.push('计划号')
        if (!row.startTime) missing.push('开始时间')
        if (!row.endTime) missing.push('结束时间')
        if (missing.length) {
          msgs.push(`第${line}行缺少${missing.join('、')}`)
        }
      })
      return msgs
    }
  }
}
</script>

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

.sheet-toolbar,
.sheet-body {
  border: 1px solid #eef2f7;
  border-radius: 8px;
  background: #fff;
}

.sheet-toolbar {
  margin-bottom: 8px;
  padding: 8px 12px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
}

.sheet-actions { display: flex; gap: 8px; }

.preset-bar { display: flex; align-items: center; gap: 8px; font-size: 12px; color: #667085; }
.preset-title { font-weight: 600; color: #475467; }

::v-deep .excel-table {
  border: 1px solid #edf1f7;
}
::v-deep .excel-table th.el-table__cell {
  background: #fafbfe;
  color: #5d6b82;
  font-weight: 600;
  border-right: 1px solid #edf1f7;
  border-bottom: 1px solid #edf1f7;
  padding: 4px 0;
}
::v-deep .excel-table td.el-table__cell {
  border-right: 1px solid #f0f2f6;
  border-bottom: 1px solid #f0f2f6;
  padding: 1px 2px;
}
::v-deep .excel-table .el-table__row:hover > td {
  background-color: #f7faff !important;
}

::v-deep .el-input__inner {
  border-radius: 0;
  height: 26px;
  line-height: 26px;
  border: none;
  box-shadow: none;
  background: transparent;
}

::v-deep .el-input__inner:focus {
  border: none;
  box-shadow: inset 0 0 0 1px #4a90e2;
  background: #fff;
}

.missing-tip {
  margin-top: 8px;
  padding: 8px 12px;
  background: #fff7e6;
  border: 1px solid #ffd591;
  border-radius: 6px;
  font-size: 12px;
  color: #d46b08;
}

.missing-item {
  line-height: 1.6;
}

.col-setting-body {
  padding: 12px;
  height: calc(100% - 12px);
  overflow: hidden;
}

.col-setting-toolbar {
  margin-bottom: 10px;
  display: flex;
  justify-content: flex-end;
}

.col-section {
  margin-bottom: 12px;
}

.col-section-title {
  font-size: 13px;
  font-weight: 600;
  color: #303133;
  margin-bottom: 8px;
}

.col-setting-grid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 8px;
}

.col-setting-item {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 8px 10px;
  border: 1px solid #ebeef5;
  border-radius: 6px;
  background: #fff;
  margin-bottom: 0;
  min-height: 38px;
}

.col-setting-item:hover {
  border-color: #d9ecff;
  background: #f5faff;
}

.drag-handle {
  cursor: move;
  color: #909399;
}

</style>
