<template>
  <div class="app-container">
    <div class="headTitle">{{ boardTitle }}</div>
    <div class="subTitle">
      <span v-if="boardCode">boardCode: {{ boardCode }}</span>
      <span v-else>缺少 boardCode</span>
      <span class="split">|</span>
      <span>刷新: {{ refreshIntervalSec }}s</span>
      <span class="split">|</span>
      <span>最近更新: {{ lastUpdateText }}</span>
    </div>

    <div v-if="errorMsg" class="error">{{ errorMsg }}</div>

    <div class="content" v-else>
      <div class="stats">
        <div class="stat stat-pending">
          <div class="stat-label">待处理</div>
          <div class="stat-value">{{ stats.pending || 0 }}</div>
        </div>
        <div class="stat stat-processing">
          <div class="stat-label">处理中</div>
          <div class="stat-value">{{ stats.processing || 0 }}</div>
        </div>
        <div class="stat stat-resolved">
          <div class="stat-label">已解决</div>
          <div class="stat-value">{{ stats.resolved || 0 }}</div>
        </div>
        <div class="stat stat-cancelled">
          <div class="stat-label">已取消</div>
          <div class="stat-value">{{ stats.cancelled || 0 }}</div>
        </div>
        <div class="stat stat-total">
          <div class="stat-label">总数</div>
          <div class="stat-value">{{ stats.total || 0 }}</div>
        </div>
      </div>

      <div class="panels">
        <div class="panel">
          <div class="panel-title">待处理 / 处理中 ({{ stats.active || 0 }})</div>
          <div class="table">
            <div class="grid-header" :style="gridStyle(activeColumns)">
              <div
                v-for="col in activeColumns"
                :key="col.field"
                class="cell header"
                :style="cellStyle(col)"
              >
                {{ col.label }}
              </div>
            </div>
            <div class="grid-body">
              <div
                v-for="(row, rowIndex) in activeEvents"
                :key="row.eventId || rowIndex"
                class="grid-row"
                :style="gridStyle(activeColumns)"
              >
                <div
                  v-for="col in activeColumns"
                  :key="col.field"
                  class="cell"
                  :style="cellStyle(col)"
                >
                  <span
                    v-if="col.field === 'eventStatus'"
                    :class="['status', statusClass(row.eventStatus)]"
                  >
                    {{ statusText(row.eventStatus) }}
                  </span>
                  <span v-else>
                    {{ formatValue(row, col.field, rowIndex) }}
                  </span>
                </div>
              </div>
              <div v-if="!activeEvents || activeEvents.length === 0" class="empty">暂无数据</div>
            </div>
          </div>
        </div>

        <div class="panel">
          <div class="panel-title">已解决 / 已取消 ({{ closedEvents.length }})</div>
          <div class="table">
            <div class="grid-header" :style="gridStyle(closedColumns)">
              <div
                v-for="col in closedColumns"
                :key="col.field"
                class="cell header"
                :style="cellStyle(col)"
              >
                {{ col.label }}
              </div>
            </div>
            <div class="grid-body">
              <div
                v-for="(row, rowIndex) in closedEvents"
                :key="row.eventId || rowIndex"
                class="grid-row"
                :style="gridStyle(closedColumns)"
              >
                <div
                  v-for="col in closedColumns"
                  :key="col.field"
                  class="cell"
                  :style="cellStyle(col)"
                >
                  <span
                    v-if="col.field === 'eventStatus'"
                    :class="['status', statusClass(row.eventStatus)]"
                  >
                    {{ statusText(row.eventStatus) }}
                  </span>
                  <span v-else>
                    {{ formatValue(row, col.field, rowIndex) }}
                  </span>
                </div>
              </div>
              <div v-if="!closedEvents || closedEvents.length === 0" class="empty">暂无数据</div>
            </div>
          </div>
        </div>
      </div>

      <div v-if="loading" class="loading">加载中...</div>
    </div>
  </div>
</template>

<script>
import { viewAndonBoard } from '@/api/production/andonBoard'
import { parseTime } from '@/utils/ruoyi'

export default {
  name: 'AndonBoard',
  data() {
    return {
      boardCode: '',
      loading: false,
      fetching: false,
      errorMsg: '',
      config: {},
      stats: {},
      activeEvents: [],
      closedEvents: [],
      activeColumns: [],
      closedColumns: [],
      refreshIntervalSec: 10,
      lastServerTime: null,
      refreshTimer: null,
      refreshTimerSec: null,
    }
  },
  computed: {
    boardTitle() {
      const name = this.config && this.config.boardName ? this.config.boardName : '安灯看板'
      return name
    },
    lastUpdateText() {
      return this.lastServerTime ? parseTime(this.lastServerTime, '{y}-{m}-{d} {h}:{i}:{s}') : '-'
    }
  },
  created() {
    this.boardCode = this.getBoardCode()
    this.reload()
  },
  watch: {
    '$route.query.boardCode': function () {
      const nextCode = this.getBoardCode()
      if (nextCode !== this.boardCode) {
        this.boardCode = nextCode
        this.reload()
      }
    }
  },
  beforeDestroy() {
    this.clearRefreshTimer()
  },
  methods: {
    getBoardCode() {
      return (this.$route.query && this.$route.query.boardCode) || (this.$route.params && this.$route.params.boardCode) || ''
    },
    reload() {
      this.clearRefreshTimer()
      if (!this.boardCode) {
        this.errorMsg = '请在URL中传入参数 boardCode，例如：/andonBoard?boardCode=AD-001'
        return
      }
      this.errorMsg = ''
      this.lastServerTime = null
      this.fetchBoardData()
    },
    fetchBoardData() {
      if (this.fetching) {
        return Promise.resolve()
      }
      const showLoading = !this.lastServerTime
      this.fetching = true
      if (showLoading) {
        this.loading = true
      }
      return viewAndonBoard(this.boardCode)
        .then((res) => {
          const data = (res && res.data) || {}
          this.errorMsg = ''
          this.config = data.config || {}
          this.stats = data.stats || {}
          this.activeEvents = data.activeEvents || []
          this.closedEvents = data.closedEvents || []
          this.lastServerTime = data.serverTime || null

          const interval = Number(this.config && this.config.refreshIntervalSec)
          this.refreshIntervalSec = interval && interval > 0 ? interval : 10

          const cols = this.parseDisplayFields(this.config && this.config.displayFields)
          this.activeColumns = cols.active
          this.closedColumns = cols.closed

          this.resetRefreshTimer()
        })
        .catch((e) => {
          this.errorMsg = (e && e.message) || '加载失败'
        })
        .finally(() => {
          this.fetching = false
          if (showLoading) {
            this.loading = false
          }
          this.resetRefreshTimer()
        })
    },
    clearRefreshTimer() {
      if (this.refreshTimer) {
        clearInterval(this.refreshTimer)
        this.refreshTimer = null
        this.refreshTimerSec = null
      }
    },
    resetRefreshTimer() {
      const sec = this.refreshIntervalSec
      if (!sec || sec <= 0) {
        return
      }
      if (this.refreshTimer && this.refreshTimerSec === sec) {
        return
      }
      this.clearRefreshTimer()
      this.refreshTimerSec = sec
      this.refreshTimer = setInterval(() => {
        this.fetchBoardData()
      }, sec * 1000)
    },
    parseDisplayFields(raw) {
      const fallbackActive = ['callCode', 'callTypeCode', 'stationCode', 'deviceCode', 'eventStatus', 'priority', 'createTime', 'description']
      const fallbackClosed = ['callCode', 'callTypeCode', 'stationCode', 'deviceCode', 'eventStatus', 'responseEndTime', 'resolution', 'cancelReason']

      if (!raw) {
        return {
          active: this.normalizeColumns(fallbackActive),
          closed: this.normalizeColumns(fallbackClosed),
        }
      }

      if (typeof raw === 'string') {
        const trimmed = raw.trim()
        if (trimmed && trimmed[0] !== '[' && trimmed[0] !== '{') {
          const fields = trimmed.split(/[,，;；\s]+/).filter(Boolean)
          if (fields.length) {
            const cols = this.normalizeColumns(fields)
            return { active: cols, closed: cols }
          }
        }
      }

      let parsed
      try {
        parsed = typeof raw === 'string' ? JSON.parse(raw) : raw
      } catch (e) {
        return {
          active: this.normalizeColumns(fallbackActive),
          closed: this.normalizeColumns(fallbackClosed),
        }
      }

      if (Array.isArray(parsed)) {
        const cols = this.normalizeColumns(parsed)
        return { active: cols, closed: cols }
      }

      if (parsed && typeof parsed === 'object') {
        const activeRaw = parsed.activeFields || parsed.active || parsed.fields || parsed
        const closedRaw = parsed.closedFields || parsed.closed || parsed.fields || parsed

        const activeCols = Array.isArray(activeRaw) || typeof activeRaw === 'object' ? this.normalizeColumns(activeRaw) : this.normalizeColumns(fallbackActive)
        const closedCols = Array.isArray(closedRaw) || typeof closedRaw === 'object' ? this.normalizeColumns(closedRaw) : this.normalizeColumns(fallbackClosed)

        return {
          active: activeCols && activeCols.length ? activeCols : this.normalizeColumns(fallbackActive),
          closed: closedCols && closedCols.length ? closedCols : this.normalizeColumns(fallbackClosed),
        }
      }

      return {
        active: this.normalizeColumns(fallbackActive),
        closed: this.normalizeColumns(fallbackClosed),
      }
    },
    normalizeColumns(input) {
      if (!input) return []

      if (Array.isArray(input)) {
        return input
          .map((item) => {
            if (!item) return null
            if (typeof item === 'string') {
              return { field: item, label: this.fieldLabel(item) }
            }
            if (typeof item === 'object') {
              const field = item.field || item.prop || item.key
              if (!field) return null
              return {
                field,
                label: item.label || item.title || this.fieldLabel(field),
                width: item.width,
                align: item.align,
              }
            }
            return null
          })
          .filter(Boolean)
      }

      if (input && typeof input === 'object') {
        return Object.keys(input).map((field) => {
          const val = input[field]
          if (typeof val === 'string') {
            return { field, label: val }
          }
          if (typeof val === 'object' && val) {
            return {
              field,
              label: val.label || val.title || this.fieldLabel(field),
              width: val.width,
              align: val.align,
            }
          }
          return { field, label: this.fieldLabel(field) }
        })
      }

      return []
    },
    fieldLabel(field) {
      const map = {
        index: '序号',
        eventId: '事件ID',
        callCode: '呼叫单号',
        callTypeCode: '呼叫类型',
        sourceType: '触发源类型',
        sourceRefId: '触发源',
        productLineCode: '产线',
        stationCode: '工位',
        teamCode: '班组',
        orderCode: '工单号',
        materialCode: '物料编码',
        deviceCode: '设备编码',
        priority: '优先级',
        eventStatus: '状态',
        description: '描述',
        ackBy: '确认人',
        ackTime: '确认时间',
        responseStartTime: '开始处理时间',
        responseEndTime: '完成时间',
        resolution: '解决措施',
        cancelReason: '取消原因',
        escalateLevel: '升级级别',
        escalateTime: '升级时间',
        ackDeadline: '确认截止',
        resolveDeadline: '解决截止',
        createTime: '创建时间',
        updateTime: '更新时间',
      }
      return map[field] || field
    },
    formatValue(row, field, rowIndex) {
      if (field === 'index') {
        return rowIndex + 1
      }
      const v = row ? row[field] : null
      if (v === null || v === undefined) return ''

      if (field === 'eventStatus') {
        return this.statusText(v)
      }

      if (field === 'sourceType') {
        return this.sourceTypeText(v)
      }

      if (/(Time|Deadline)$/i.test(field)) {
        const text = parseTime(v, '{y}-{m}-{d} {h}:{i}:{s}')
        return text || ''
      }

      return String(v)
    },
    statusText(status) {
      if (status === '0') return '待处理'
      if (status === '1') return '处理中'
      if (status === '2') return '已解决'
      if (status === '3') return '已取消'
      return String(status || '')
    },
    statusClass(status) {
      if (status === '0') return 'pending'
      if (status === '1') return 'processing'
      if (status === '2') return 'resolved'
      if (status === '3') return 'cancelled'
      return ''
    },
    sourceTypeText(v) {
      if (v === '0') return '工位'
      if (v === '1') return '设备'
      if (v === '2') return '报警'
      if (v === '3') return '手动'
      return String(v || '')
    },
    gridStyle(cols) {
      const list = Array.isArray(cols) ? cols : []
      const template = list
        .map((c) => {
          if (c && c.width) {
            if (typeof c.width === 'number') return c.width + 'px'
            return String(c.width)
          }
          return '1fr'
        })
        .join(' ')

      return {
        gridTemplateColumns: template || '1fr',
      }
    },
    cellStyle(col) {
      const style = {}
      if (col && col.align) {
        style.textAlign = col.align
      }
      return style
    },
  }
}
</script>

<style scoped lang="less">
.app-container {
  background-image: url("../../../assets/board/boardBg2.jpg");
  background-repeat: no-repeat;
  background-size: 100% 100%;
  width: 100%;
  height: 100%;
  position: absolute;
  top: 0;
  left: 0;
  padding: 4.2vw 2vw 1.2vw 2vw;
  box-sizing: border-box;
  color: #d6eaed;
  overflow: hidden;
}

.headTitle {
  position: absolute;
  top: 5%;
  left: 50%;
  transform: translate(-50%, -100%);
  font-size: 1.6vw;
  letter-spacing: 0.3vw;
  white-space: nowrap;
}

.subTitle {
  position: absolute;
  top: 8.1%;
  left: 50%;
  transform: translate(-50%, -100%);
  font-size: 0.85vw;
  color: #a9d5e8;
  white-space: nowrap;
}

.split {
  display: inline-block;
  margin: 0 0.6vw;
  color: rgba(255, 255, 255, 0.35);
}

.content {
  height: 100%;
  display: flex;
  flex-direction: column;
}

.stats {
  display: grid;
  grid-template-columns: repeat(5, 1fr);
  gap: 1vw;
  margin-bottom: 1.2vw;
}

.stat {
  height: 5.6vw;
  border-radius: 0.6vw;
  padding: 0.8vw 1vw;
  box-sizing: border-box;
  background: rgba(0, 0, 0, 0.35);
  border: 1px solid rgba(255, 255, 255, 0.12);
  display: flex;
  flex-direction: column;
  justify-content: space-between;
}

.stat-label {
  font-size: 0.95vw;
  opacity: 0.9;
}

.stat-value {
  font-size: 2.1vw;
  font-weight: 700;
  line-height: 1;
}

.stat-pending .stat-value {
  color: #ff5f5f;
}

.stat-processing .stat-value {
  color: #ffb020;
}

.stat-resolved .stat-value {
  color: #16ceb9;
}

.stat-cancelled .stat-value {
  color: #9aa3ad;
}

.stat-total .stat-value {
  color: #ffffff;
}

.panels {
  flex: 1;
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 1.2vw;
  min-height: 0;
}

.panel {
  background: rgba(0, 0, 0, 0.25);
  border: 1px solid rgba(255, 255, 255, 0.12);
  border-radius: 0.6vw;
  padding: 0.8vw;
  box-sizing: border-box;
  display: flex;
  flex-direction: column;
  min-height: 0;
}

.panel-title {
  font-size: 1.05vw;
  font-weight: 700;
  margin-bottom: 0.6vw;
  letter-spacing: 0.1vw;
}

.table {
  flex: 1;
  min-height: 0;
  display: flex;
  flex-direction: column;
}

.grid-header {
  display: grid;
  gap: 0;
  background: rgba(9, 65, 112, 0.75);
  border-radius: 0.4vw;
  overflow: hidden;
}

.grid-body {
  flex: 1;
  min-height: 0;
  overflow: auto;
  margin-top: 0.4vw;
}

.grid-body::-webkit-scrollbar {
  width: 0;
  height: 0;
}

.grid-row {
  display: grid;
  background: rgba(3, 45, 87, 0.55);
}

.grid-row:nth-child(2n) {
  background: rgba(5, 52, 96, 0.55);
}

.cell {
  padding: 0.55vw 0.6vw;
  font-size: 0.85vw;
  box-sizing: border-box;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  border-right: 1px solid rgba(255, 255, 255, 0.06);
}

.cell:last-child {
  border-right: none;
}

.cell.header {
  font-size: 0.85vw;
  font-weight: 700;
  color: #ffffff;
}

.status {
  font-weight: 700;
}

.status.pending {
  color: #ff5f5f;
}

.status.processing {
  color: #ffb020;
}

.status.resolved {
  color: #16ceb9;
}

.status.cancelled {
  color: #9aa3ad;
}

.empty {
  padding: 1vw;
  text-align: center;
  color: rgba(255, 255, 255, 0.55);
  font-size: 0.9vw;
}

.error {
  margin-top: 6vw;
  padding: 1vw;
  background: rgba(0, 0, 0, 0.45);
  border: 1px solid rgba(255, 95, 95, 0.6);
  border-radius: 0.6vw;
  font-size: 1vw;
  color: #ffbdbd;
}

.loading {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  font-size: 1vw;
  color: rgba(255, 255, 255, 0.8);
  background: rgba(0, 0, 0, 0.35);
  padding: 0.6vw 1.2vw;
  border-radius: 0.4vw;
}
</style>
