<template>
  <div class="opstatus-page">
    <!-- 权限验证组件 -->
    <PermissionVerify ref="permissionVerify" />

    <template v-if="isAuthenticated">
      <!-- 头部 -->
      <div class="header">
        <div class="left title-area" @click="navigateHome">
          <div class="title">工位异常处理</div>
          <div class="subtitle">进站/出站/申请条码重试与接口明细查看</div>
        </div>
        <div class="right">
          <div class="user">登录人：{{ loginUserName }}</div>
          <el-button type="danger" icon="SwitchButton" size="small" @click="handleLogout">退出登录</el-button>
        </div>
      </div>

      <!-- 查询条件与操作 -->
      <div class="toolbar">
        <div class="form-row">
          <div class="form-item">
            <label class="form-label">工位号</label>
            <el-select v-model="selectedStation" placeholder="请选择工位号" filterable class="form-input"
              @change="handleStationChange">
              <el-option v-for="it in stationList" :key="it.value" :label="it.label" :value="it.value" />
            </el-select>
          </div>
          <div class="form-item actions">
            <el-button type="danger" :loading="retryLoading.MesReadOver"
              @click="onConfirmRetry('WorkOver')">强制出站</el-button>
            <el-button type="primary" :loading="retryLoading.MesRead"
              @click="onConfirmRetry('EngineGetOver')">进站重试</el-button>
            <el-button type="warning" :loading="retryLoading.MesReadOver"
              @click="onConfirmRetry('MesRead')">出站重试</el-button>
            <el-tooltip :content="parLoadTooltip" placement="top">
              <span>
                <el-button type="success" :disabled="!canParLoad" :loading="retryLoading.ParLoad"
                  @click="onConfirmRetry('PartLoad')">申请条码</el-button>
              </span>
            </el-tooltip>
            <el-tooltip :content="printCodeTooltip" placement="top">
              <span>
                <el-button type="info" :disabled="!canPrintCode" :loading="retryLoading.PrintCode"
                  @click="onPrintCode">补打条码</el-button>
              </span>
            </el-tooltip>
          </div>
        </div>
      </div>

      <!-- MQTT连接状态提示 -->
      <div class="mqtt-status-bar" v-if="mqttStatus.show" :class="mqttStatus.type">
        <div class="mqtt-status-content">
          <el-icon class="status-icon">
            <component :is="mqttStatus.icon" />
          </el-icon>
          <span>{{ mqttStatus.message }}</span>
        </div>
      </div>

      <!-- 当前在位产品信息 -->
      <div class="content">
        <div class="card">
          <div class="card-header">
            <div class="card-title">在位产品信息</div>
            <div class="card-actions">
              <el-button v-if="currentProduct.产品编号" link type="primary" @click="openMobyDialog">查看接口明细</el-button>
              <el-button link type="primary" @click="openTighteningStateDialog">拧紧状态查看</el-button>
              <el-button link type="primary" @click="openMaterialScanStateDialog">物料扫码状态</el-button>
              <el-button link type="primary" @click="openLogDialog">工位日志查询</el-button>
              <el-button link type="primary" @click="openProductLogDialog">产品日志查询</el-button>
            </div>
          </div>
          <div class="card-body">
            <div v-if="currentProduct.产品编号" class="grid">
              <div class="item"><span class="label">订单号</span><span class="value">{{ currentProduct.订单号 || '-' }}</span>
              </div>
              <div class="item"><span class="label">产品编号</span><span class="value">{{ currentProduct.产品编号 || '-'
              }}</span></div>
              <div class="item"><span class="label">产品型号</span><span class="value">{{ currentProduct.产品型号 || '-'
              }}</span></div>
              <div class="item"><span class="label">托盘号</span><span class="value">{{ currentProduct.托盘号 || '-' }}</span>
              </div>
              <div class="item"><span class="label">到达时间</span><span class="value">{{ currentProduct.到达时间 || '-'
              }}</span></div>
              <div class="item"><span class="label">离开时间</span><span class="value">{{ currentProduct.离开时间 || '-'
              }}</span></div>
              <div class="item"><span class="label">在位时间</span><span class="value">{{ currentProduct.在位时间 || '-'
              }}</span></div>
              <div class="item"><span class="label">状态</span>
                <span class="value">
                  <el-tag :type="statusTagType" size="small">{{ statusText }}</el-tag>
                </span>
              </div>
            </div>
            <div v-else class="empty">当前工位无在位产品</div>
          </div>
        </div>
      </div>

      <!-- 接口明细弹窗 -->
      <el-dialog v-model="mobyDialog.visible" title="产品接口执行明细" :width="dialogWidth" :height="dialogHeight"
        :close-on-click-modal="false">
        <div v-if="mobyDialog.productNo" class="moby-header">产品编号：{{ mobyDialog.productNo }}</div>
        <el-table v-loading="mobyDialog.loading" :data="mobyDialog.rows" :height="tableHeight" border stripe
          style="width: 100%" :row-class-name="mobyRowClassName"
          :header-cell-style="{ background: '#f5f7fa', color: '#303133', fontWeight: 'bold', textAlign: 'center' }"
          :cell-style="{ textAlign: 'center' }">
          <el-table-column type="index" :width="isMobile ? '50' : '60'" label="序号" />
          <el-table-column prop="工位号" label="工位号" :width="isMobile ? '80' : '100'" />
          <el-table-column prop="接口说明" label="接口说明" :min-width="isMobile ? '120' : '180'" show-overflow-tooltip />
          <el-table-column prop="是否启用" label="启用" :width="isMobile ? '60' : '80'">
            <template #default="scope">
              <el-tag :type="scope.row.是否启用 == '1' ? 'success' : 'danger'" size="small">{{ scope.row.是否启用 }}</el-tag>
            </template>
          </el-table-column>
          <el-table-column prop="请求时间" label="请求时间" :width="isMobile ? '140' : '180'" />
          <el-table-column prop="返回时间" label="返回时间" :width="isMobile ? '140' : '180'" />
          <el-table-column prop="返回代码" label="返回代码" :width="isMobile ? '80' : '100'">
            <template #default="scope">
              <el-tag :type="scope.row.返回代码 === '0' ? 'success' : 'warning'" size="small">{{ scope.row.返回代码 }}</el-tag>
            </template>
          </el-table-column>
          <el-table-column prop="累积用时" label="用时(ms)" :width="isMobile ? '80' : '100'" />
          <el-table-column label="操作" :width="isMobile ? '100' : '120'">
            <template #default="scope">
              <el-button link type="primary" size="small" @click="showDetail(scope.row, 'request')">请求内容</el-button>
              <el-button link type="primary" size="small" @click="showDetail(scope.row, 'response')">返回内容</el-button>
            </template>
          </el-table-column>
        </el-table>
      </el-dialog>

      <!-- 请求/返回内容弹窗 -->
      <el-dialog v-model="contentDialog.visible" :title="contentDialog.title" :width="dialogWidth"
        :height="dialogHeight" :close-on-click-modal="false">
        <div class="code-block">
          <pre>{{ contentDialog.content || '无' }}</pre>
        </div>
      </el-dialog>

      <!-- 工位日志弹窗 -->
      <el-dialog v-model="logDialog.visible" title="工位日志" :width="dialogWidth" :height="dialogHeight"
        :close-on-click-modal="false">
        <el-table :data="logDialog.rows" :height="tableHeight" border stripe :cell-style="{ textAlign: 'left' }">
          <el-table-column label="时间" :width="isMobile ? '140' : '180'" align="center">
            <template #default="scope">{{ scope.row.操作时间 }}</template>
          </el-table-column>
          <el-table-column label="内容" :min-width="isMobile ? '200' : '300'">
            <template #default="scope">
              <span v-if="scope.row.消息类型 === 'ERROR'" style="color: #ff0000;">{{ scope.row.内容 }}</span>
              <span v-else-if="scope.row.消息类型 === 'WARNING'" style="color: #ffa500;">{{ scope.row.内容 }}</span>
              <span v-else>{{ scope.row.内容 }}</span>
            </template>
          </el-table-column>
        </el-table>
      </el-dialog>

      <!-- 产品日志弹窗 -->
      <el-dialog v-model="productLogDialog.visible" title="产品日志" :width="dialogWidth" :height="dialogHeight"
        :close-on-click-modal="false">
        <div v-if="productLogDialog.productCode" class="moby-header">产品码：{{ productLogDialog.productCode }}</div>
        <el-table v-loading="productLogDialog.loading" :data="productLogDialog.rows" :height="tableHeight" border stripe
          :cell-style="{ textAlign: 'left' }">
          <el-table-column label="工位号" :width="isMobile ? '80' : '100'" align="center">
            <template #default="scope">{{ scope.row.工位号 }}</template>
          </el-table-column>
          <el-table-column label="时间" :width="isMobile ? '140' : '180'" align="center">
            <template #default="scope">{{ scope.row.操作时间 }}</template>
          </el-table-column>
          <el-table-column label="内容" :min-width="isMobile ? '200' : '300'">
            <template #default="scope">
              <span v-if="scope.row.消息类型 === 'ERROR'" style="color: #ff0000;">{{ scope.row.内容 }}</span>
              <span v-else-if="scope.row.消息类型 === 'WARNING'" style="color: #ffa500;">{{ scope.row.内容 }}</span>
              <span v-else>{{ scope.row.内容 }}</span>
            </template>
          </el-table-column>
        </el-table>
      </el-dialog>

      <!-- 物料扫码状态弹窗 -->
      <el-dialog v-model="materialScanDialog.visible" :width="dialogWidth" :height="dialogHeight"
        :close-on-click-modal="false">
        <template #header>
          <div style="display: flex; align-items: center; justify-content: space-between; padding-right: 20px;">
            <span style="font-size: 18px; color: #303133; font-weight: bold;">物料扫码状态</span>
            <el-button type="primary" icon="Refresh" circle size="small" @click="loadMaterialScanStatus" title="刷新数据" />
          </div>
        </template>
        <el-table v-loading="materialScanDialog.loading" :data="materialScanDialog.rows" :height="tableHeight" border
          stripe style="width: 100%"
          :header-cell-style="{ background: '#f5f7fa', color: '#303133', fontWeight: 'bold', textAlign: 'center' }"
          :cell-style="{ textAlign: 'center' }">
          <el-table-column type="index" :width="isMobile ? '50' : '60'" label="序号" align="center" />
          <el-table-column prop="零件名称" label="零件名称" :min-width="isMobile ? '120' : '150'" show-overflow-tooltip
            align="center" />
          <el-table-column prop="物料条码" label="物料条码" :min-width="isMobile ? '160' : '200'" show-overflow-tooltip
            align="center">
            <template #default="scope">
              {{ scope.row.物料条码 || '-' }}
            </template>
          </el-table-column>
          <el-table-column prop="零件批号" label="零件批号" :min-width="isMobile ? '140' : '160'" show-overflow-tooltip
            align="center">
            <template #default="scope">
              {{ scope.row.零件批号 || '-' }}
            </template>
          </el-table-column>
          <el-table-column prop="扫码状态" label="扫码状态" :width="isMobile ? '90' : '100'" align="center">
            <template #default="scope">
              <el-tag :type="getScanStatusType(scope.row.扫码状态)" size="small">
                {{ getScanStatusText(scope.row.扫码状态) }}
              </el-tag>
            </template>
          </el-table-column>
          <el-table-column label="操作" :width="isMobile ? '100' : '120'" align="center" fixed="right">
            <template #default="scope">
              <el-button link type="danger" size="small" @click="resetMaterialScanStatus(scope.row)">重置状态</el-button>
            </template>
          </el-table-column>
        </el-table>
      </el-dialog>

      <!-- 拧紧状态查看弹窗 -->
      <el-dialog v-model="tighteningDialog.visible" :width="dialogWidth" :height="dialogHeight"
        :close-on-click-modal="false">
        <template #header>
          <div style="display: flex; align-items: center; justify-content: space-between; padding-right: 20px;">
            <span style="font-size: 18px; color: #303133; font-weight: bold;">拧紧状态查看</span>
            <el-button type="primary" icon="Refresh" circle size="small" @click="loadTighteningStatus" title="刷新数据" />
          </div>
        </template>
        <el-table v-loading="tighteningDialog.loading" :data="tighteningDialog.rows" :height="tableHeight" border stripe
          style="width: 100%"
          :header-cell-style="{ background: '#f5f7fa', color: '#303133', fontWeight: 'bold', textAlign: 'center' }"
          :cell-style="{ textAlign: 'center' }">
          <el-table-column type="index" :width="isMobile ? '50' : '60'" label="序号" align="center" />
          <el-table-column prop="组号" label="组号(第几颗)" :min-width="isMobile ? '100' : '120'" align="center">
            <template #default="scope">
              {{ scope.row.组号 || '-' }}
            </template>
          </el-table-column>
          <el-table-column prop="套筒号" label="套筒号" :min-width="isMobile ? '80' : '100'" align="center">
            <template #default="scope">
              {{ scope.row.套筒号 || '-' }}
            </template>
          </el-table-column>
          <el-table-column prop="拧紧完成" label="拧紧完成" :min-width="isMobile ? '90' : '110'" align="center">
            <template #default="scope">
              <el-tag :type="scope.row.拧紧完成 === 1 || scope.row.拧紧完成 === '1' ? 'success' : 'info'" size="small">
                {{ scope.row.拧紧完成 === 1 || scope.row.拧紧完成 === '1' ? '已完成' : '未完成' }}
              </el-tag>
            </template>
          </el-table-column>
          <el-table-column prop="不合格拧紧次数" label="不合格次数" :min-width="isMobile ? '90' : '110'" align="center">
            <template #default="scope">
              {{ scope.row.不合格拧紧次数 || '0' }}
            </template>
          </el-table-column>
          <el-table-column prop="是否合格" label="是否合格" :width="isMobile ? '90' : '100'" align="center">
            <template #default="scope">
              <el-tag :type="scope.row.是否合格 === 1 || scope.row.是否合格 === '1' ? 'success' : 'danger'" size="small">
                {{ scope.row.是否合格 === 1 || scope.row.是否合格 === '1' ? '合格' : '不合格' }}
              </el-tag>
            </template>
          </el-table-column>
          <el-table-column label="操作" :width="isMobile ? '100' : '120'" align="center" fixed="right">
            <template #default="scope">
              <el-button link type="danger" size="small" @click="resetTighteningStatus(scope.row)">重置次数</el-button>
            </template>
          </el-table-column>
        </el-table>
      </el-dialog>
    </template>

    <div v-else class="auth-loading">
      <i class="el-icon-loading"></i>
      <p>正在进行权限验证...</p>
    </div>
  </div>
</template>

<script setup>
import { ref, reactive, computed, onMounted, onBeforeUnmount, inject } from 'vue'
import { ElMessage, ElMessageBox } from 'element-plus'
import PermissionVerify from '@/components/PermissionVerify.vue'
import Cookie from 'js-cookie'
import { useRouter } from 'vue-router'
import { Mqtt } from '@/utils/mqtt.js'
import { logAdd } from '@/utils/log.js'

const ExecDatabaseByParam = inject('ExecDatabaseByParam')
const CreateData = inject('CreateData')
const ExecDatabase = inject('ExecDatabase')
const ExecHttpRequest = inject('ExecHttpRequest')

// 路由
const router = useRouter()

// 日志记录快捷方法
const writeLog = (content, operationType = 'StationOperate', msgType = 'WARNING') => {
  logAdd({ ExecDatabaseByParam }, {
    stationNumber: selectedStation.value || '',
    msgType,
    operationType,
    Content: `${Cookie.get('userName') || '-'} ${content}`
  })
}

// 返回导航首页
const navigateHome = () => {
  router.push('/')
}

const isAuthenticated = ref(false)
const permissionVerify = ref(null)
const userInfo = ref({})

const stationList = ref([])
const selectedStation = ref('')
const currentProduct = reactive({})
let statusTimer = null

const retryLoading = reactive({ MesRead: false, MesReadOver: false, ParLoad: false, PrintCode: false })

const mqttStatus = reactive({
  show: false,
  type: 'success',
  message: '',
  icon: 'CircleCheck'
})

let mqttClient = null
const mqttConnection = reactive({
  host: window.g.mqttIP,
  port: window.g.mqttPortNumber,
  endpoint: '/mqtt',
  clean: true,
  connectTimeout: 4000,
  reconnectPeriod: 4000,
  clientId: '',
  username: '',
  password: ''
})
const publication = reactive({ topic: window.g.mqttPublishTopic, qos: 0, payload: '' })

const loginUserName = computed(() => Cookie.get('userName') || userInfo.value.姓名 || userInfo.value.userName || '-')

const dialogWidth = computed(() => {
  if (typeof window !== 'undefined' && window.innerWidth < 768) return '95%'
  return '70%'
})
const dialogHeight = computed(() => {
  if (typeof window !== 'undefined' && window.innerWidth < 768) return '80vh'
  return '70vh'
})
const tableHeight = computed(() => {
  if (typeof window !== 'undefined' && window.innerWidth < 768) return '50vh'
  return '60vh'
})
const isMobile = computed(() => {
  return typeof window !== 'undefined' && window.innerWidth < 768
})

const statusText = computed(() => {
  const v = currentProduct.状态
  if (v === 1 || v === '1') return '已进站'
  if (v === 2 || v === '2') return '已完成'
  return '未进站'
})

const statusTagType = computed(() => {
  const v = currentProduct.状态
  if (v === 1 || v === '1') return 'warning'
  if (v === 2 || v === '2') return 'success'
  return 'info'
})

const canParLoad = computed(() => {
  const sn = (selectedStation.value || '').toUpperCase()
  return sn === 'OP090' || sn === 'OP250'
})
const parLoadTooltip = computed(() => (canParLoad.value ? '申请条码' : '仅允许 OP090 / OP250'))
const canPrintCode = computed(() => {
  const sn = (selectedStation.value || '').toUpperCase()
  return sn === 'OP150' || sn === 'OP250'
})
const printCodeTooltip = computed(() => (canPrintCode.value ? '补打条码' : '仅允许 OP150 / OP250'))

// 接口明细弹窗
const mobyDialog = reactive({ visible: false, loading: false, productNo: '', rows: [] })
const contentDialog = reactive({ visible: false, title: '', content: '' })
const logDialog = reactive({ visible: false, rows: [] })
const productLogDialog = reactive({ visible: false, loading: false, productCode: '', rows: [] })
const materialScanDialog = reactive({ visible: false, loading: false, rows: [] })
const tighteningDialog = reactive({ visible: false, loading: false, rows: [] })

const getScanStatusText = (status) => {
  if (status === 0 || status === '0') return '未验证'
  if (status === 1 || status === '1') return '待批追'
  if (status === 2 || status === '2') return '已完成'
  return '未知'
}

const getScanStatusType = (status) => {
  if (status === 0 || status === '0') return 'info'
  if (status === 1 || status === '1') return 'warning'
  if (status === 2 || status === '2') return 'success'
  return ''
}

const openMaterialScanStateDialog = async () => {
  if (!selectedStation.value) {
    ElMessage.warning('请先选择工位')
    return
  }
  materialScanDialog.visible = true
  await loadMaterialScanStatus()
}

const loadMaterialScanStatus = async () => {
  if (!materialScanDialog.visible) return
  materialScanDialog.loading = true
  try {
    const param = []
    param[0] = ['工位号', selectedStation.value]
    const res = await ExecDatabaseByParam('11', '电子看板_装配零件_临时表_PDA工位查询', param)
    materialScanDialog.rows = (res.data && Array.isArray(res.data)) ? res.data : (res.data?.result || [])
  } catch (e) {
    console.error('查询物料扫码状态失败:', e)
    ElMessage.error('查询物料扫码状态失败')
  } finally {
    materialScanDialog.loading = false
  }
}

const resetMaterialScanStatus = async (row) => {
  try {
    await ElMessageBox.confirm('请确认是否进行状态重置 重置后重新扫码（需与MES状态一致）', '二次确认', {
      confirmButtonText: '确定',
      cancelButtonText: '取消',
      type: 'warning'
    })

    const param = []
    param[0] = ['ID', row.ID || '']
    const data = CreateData('12', '电子看板_装配零件_临时表_PDA重置扫码', param)
    const res = await ExecDatabase(data)

    if (res.data && res.data.length > 0 && res.data[0].result === '1') {
      ElMessage.success('重置扫码状态成功')
      const productNo = currentProduct.产品编号 || '-'
      writeLog(`重置物料扫码状态 产品编号:${productNo} 零件:${row.零件名称 || '-'}`)
      await loadMaterialScanStatus()
    } else {
      ElMessage.error('重置扫码状态失败: ' + (res.data?.[0]?.msg || '未知错误'))
    }
  } catch (e) {
    if (e !== 'cancel') {
      console.error('重置扫码状态异常:', e)
      ElMessage.error('重置扫码状态异常')
    }
  }
}

const openTighteningStateDialog = async () => {
  if (!selectedStation.value) {
    ElMessage.warning('请先选择工位')
    return
  }
  tighteningDialog.visible = true
  await loadTighteningStatus()
}

const loadTighteningStatus = async () => {
  if (!tighteningDialog.visible) return
  tighteningDialog.loading = true
  try {
    const param = []
    param[0] = ['工位号', selectedStation.value]
    const res = await ExecDatabaseByParam('11', '电子看板_工位机型_质量数据测量位置_临时表_PDA工位查询', param)
    tighteningDialog.rows = (res.data && Array.isArray(res.data)) ? res.data : (res.data?.result || [])
  } catch (e) {
    console.error('查询拧紧状态失败:', e)
    ElMessage.error('查询拧紧状态失败')
  } finally {
    tighteningDialog.loading = false
  }
}

const resetTighteningStatus = async (row) => {
  try {
    await ElMessageBox.confirm('是否重置不合格次数 重新拧紧？', '二次确认', {
      confirmButtonText: '确定',
      cancelButtonText: '取消',
      type: 'warning'
    })

    const param = []
    param[0] = ['ID', row.ID || '']
    const data = CreateData('12', '电子看板_工位机型_质量数据测量位置_临时表_PDA重置不合格次数', param)
    const res = await ExecDatabase(data)

    if (res.data && res.data.length > 0 && res.data[0].result === '1') {
      ElMessage.success('重置不合格次数成功')
      const productNo = currentProduct.产品编号 || '-'
      writeLog(`重置拧紧不合格次数 产品编号:${productNo} 组号:${row.组号 || '-'}`)
      await loadTighteningStatus()
    } else {
      ElMessage.error('重置不合格次数失败: ' + (res.data?.[0]?.msg || '未知错误'))
    }
  } catch (e) {
    if (e !== 'cancel') {
      console.error('重置不合格次数异常:', e)
      ElMessage.error('重置不合格次数异常')
    }
  }
}

onMounted(() => {
  createMqttConnection()

  setTimeout(() => {
    if (permissionVerify.value) {
      permissionVerify.value.setCreateData(CreateData)
      permissionVerify.value.setExecDatabase(ExecDatabase)
      permissionVerify.value.setStore({
        state: { station: { stationNumber: '' }, user: { name: Cookie.get('userName') || '' } }
      })
      checkPermission()
    } else {
      ElMessage.error('权限验证组件初始化失败')
    }
  }, 300)

  // 监听窗口大小变化
  window.addEventListener('resize', () => {
    // 触发计算属性重新计算
    dialogWidth.value
    dialogHeight.value
    tableHeight.value
    isMobile.value
  })
})

const createMqttConnection = () => {
  try {
    if (mqttClient) {
      mqttClient.destroyConnection()
    }

    mqttStatus.show = true
    mqttStatus.type = 'warning'
    mqttStatus.icon = 'Warning'
    mqttStatus.message = 'MQTT连接中...'

    mqttClient = new Mqtt(mqttConnection)
    mqttClient.createConnection()

    mqttClient.client.on('connect', () => {
      console.log('MQTT connected in OpStatus')
      mqttStatus.show = true
      mqttStatus.type = 'success'
      mqttStatus.icon = 'CircleCheck'
      mqttStatus.message = 'MQTT已连接'
      setTimeout(() => {
        if (mqttStatus.type === 'success') {
          mqttStatus.show = false
        }
      }, 3000)
    })

    mqttClient.client.on('reconnect', () => {
      console.log('MQTT reconnecting in OpStatus...')
      mqttStatus.show = true
      mqttStatus.type = 'warning'
      mqttStatus.icon = 'Warning'
      mqttStatus.message = 'MQTT重新连接中...'
    })

    mqttClient.client.on('disconnect', () => {
      console.log('MQTT disconnected in OpStatus')
      mqttStatus.show = true
      mqttStatus.type = 'error'
      mqttStatus.icon = 'CircleClose'
      mqttStatus.message = 'MQTT连接已断开，请检查网络或联系管理员'
    })

    mqttClient.client.on('offline', () => {
      console.log('MQTT offline in OpStatus')
      mqttStatus.show = true
      mqttStatus.type = 'error'
      mqttStatus.icon = 'CircleClose'
      mqttStatus.message = 'MQTT离线，请检查网络连接'
    })

    mqttClient.client.on('error', err => {
      console.log('MQTT error in OpStatus:', err)
      mqttStatus.show = true
      mqttStatus.type = 'error'
      mqttStatus.icon = 'CircleClose'
      mqttStatus.message = `MQTT连接错误: ${err.message || '未知错误'}，请联系管理员`
    })
  } catch (e) {
    console.error('createMqttConnection error in OpStatus:', e)
    mqttStatus.show = true
    mqttStatus.type = 'error'
    mqttStatus.icon = 'CircleClose'
    mqttStatus.message = `MQTT初始化失败: ${e.message || '未知错误'}，请刷新页面或联系管理员`
  }
}

const checkPermission = async () => {
  try {
    const ud = Cookie.get('userId')
    const un = Cookie.get('userName')
    if (ud && un) {
      isAuthenticated.value = true
      userInfo.value = { UserID: ud, 姓名: un }
      await initializeData()
      return
    }
    const result = await permissionVerify.value.show({ title: '工位异常处理登录', promptText: '请刷卡进行身份验证', permissionLevel: '高级刷卡权限' })
    if (result.success) {
      isAuthenticated.value = true
      userInfo.value = result.data
      await initializeData()
    }
  } catch (e) {
    if (e && e.cancelled) {
      ElMessage.warning('已取消登录')
    } else {
      ElMessage.error('权限验证失败')
    }
  }
}

const onPrintCode = async () => {
  if (!canPrintCode.value) {
    ElMessage.warning('仅 OP150 / OP250 支持补打条码')
    return
  }

  if (!selectedStation.value) {
    ElMessage.warning('请先选择工位')
    return
  }

  try {
    const { value } = await ElMessageBox.prompt('请输入Model/PACK码', '补打条码', {
      confirmButtonText: '确认',
      cancelButtonText: '取消',
      inputPattern: /.+/,
      inputErrorMessage: 'Model/PACK码不能为空'
    })

    const barcode = (value || '').trim()
    if (!barcode) {
      ElMessage.warning('Model/PACK码不能为空')
      return
    }

    if (!mqttClient) {
      createMqttConnection()
    }

    retryLoading.PrintCode = true
    publication.topic = window.g.mqttPublishTopic
    publication.payload = `WEB|PrintCode|${selectedStation.value}|${barcode}`
    const publishResult = mqttClient && mqttClient.doPublish(publication)
    if (publishResult === true) {
      ElMessage.success('补打条码发送成功')
      writeLog(`补打条码 工位:${selectedStation.value} 条码:${barcode}`)
    } else {
      ElMessage.error('补打条码发送失败')
    }
  } catch (e) {
    if (e !== 'cancel') {
      console.error('补打条码失败:', e)
      ElMessage.error('补打条码发送失败，请稍后重试')
    }
  } finally {
    retryLoading.PrintCode = false
  }
}

const initializeData = async () => {
  await loadStationList()
  if (stationList.value.length > 0) {
    selectedStation.value = stationList.value[0].value
    await handleStationChange()
  }
}

const loadStationList = async () => {
  try {
    const res = await ExecDatabaseByParam('11', 'MES_计划BOM_工位与名称_查询', [])
    if (res.data && res.data.length > 0) {
      stationList.value = res.data.map(it => ({ label: `${it.工位号} - ${it.工位名称 || ''}`, value: it.工位号 }))
    }
  } catch (err) {
    console.error('加载工位列表失败:', err)
    ElMessage.error('加载工位列表失败')
  }
}

const handleStationChange = async () => {
  if (statusTimer) { clearInterval(statusTimer); statusTimer = null }
  await loadStationStatus()
  if (selectedStation.value) {
    statusTimer = setInterval(() => {
      loadStationStatus()
    }, 3000)
  }
}

const loadStationStatus = async () => {
  if (!selectedStation.value) { Object.keys(currentProduct).forEach(k => delete currentProduct[k]); return }
  try {
    const param = []
    param[0] = ['工位号', selectedStation.value]
    const res = await ExecDatabaseByParam('11', 'PAD_工位状态_查询', param)
    let row = null
    if (Array.isArray(res.data) && res.data.length > 0) row = res.data[0]
    if (row) {
      for (const [k, v] of Object.entries(row)) currentProduct[k] = v
      for (const k of Object.keys(currentProduct)) {
        if (!(k in row)) delete currentProduct[k]
      }
    } else {
      Object.keys(currentProduct).forEach(k => delete currentProduct[k])
    }
  } catch (e) {
    console.error('查询工位状态失败:', e)
    ElMessage.error('查询工位状态失败')
  }
}

const openMobyDialog = async () => {
  if (!currentProduct.产品编号) return
  mobyDialog.visible = true
  mobyDialog.loading = true
  mobyDialog.productNo = currentProduct.产品编号
  try {
    const param = []
    param[0] = ['产品编号', currentProduct.产品编号]
    const res = await ExecDatabaseByParam('11', 'PAD_工位状态_产品接口Moby_查询', param)
    mobyDialog.rows = (res.data && Array.isArray(res.data)) ? res.data : (res.data?.result || [])
  } catch (e) {
    console.error('查询接口明细失败:', e)
    ElMessage.error('查询接口明细失败')
  } finally {
    mobyDialog.loading = false
  }
}

const showDetail = (row, type) => {
  contentDialog.title = type === 'request' ? '请求内容' : '返回内容'
  contentDialog.content = type === 'request' ? (row.请求内容 || '') : (row.返回内容 || '')
  contentDialog.visible = true
}

const mobyRowClassName = ({ row }) => {
  const code = row && row.返回代码
  if (code === '0' || code === 0) return 'row-success'
  if (code === '' || code === null || code === undefined) return ''
  return 'row-error'
}

const getRetryLabel = (type) => {
  if (type === 'WorkOver') return '强制出站(不合格放行)'
  if (type === 'EngineGetOver') return '进站重试'
  if (type === 'MesRead') return '出站重试'
  if (type === 'PartLoad') return '申请条码'
  return '操作'
}

const onConfirmRetry = async (type) => {
  try {
    await ElMessageBox.confirm(`确定要执行【${getRetryLabel(type)}】吗？`, '二次确认', {
      confirmButtonText: '确定',
      cancelButtonText: '取消',
      type: 'warning'
    })
    await handleRetry(type)
  } catch { }
}

const handleRetry = async (type) => {
  if (!selectedStation.value) { ElMessage.warning('请先选择工位'); return }
  retryLoading[type] = true
  try {
    const payload = {
      MsgId: Math.random().toString(36).substring(2),
      UserId: Number(Cookie.get('userId') || userInfo.value.UserID || 0),
      OpName: selectedStation.value,
      Type: type
    }
    const res = await ExecHttpRequest(window.g.API_MES_Controller_URL + '/ApiFailRetry', 'post', payload)
    if (res.data && res.data.Code === '200') {
      ElMessage.success('重试请求已发送')
      writeLog(`执行《${getRetryLabel(type)}》 工位:${selectedStation.value}`)
      await loadStationStatus()
    } else {
      ElMessage.error(res.data?.Message || '重试失败')
    }
  } catch (e) {
    console.error('重试失败:', e)
    ElMessage.error('重试失败，请稍后重试')
  } finally {
    retryLoading[type] = false
  }
}

const openLogDialog = async () => {
  if (!selectedStation.value) { ElMessage.warning('请先选择工位'); return }
  try {
    const param = []
    param[0] = ['工位号', selectedStation.value]
    param[1] = ['查询来源', 1]
    param[2] = ['PageCurrent', 1]
    param[3] = ['PageSize', 100]
    param[4] = ['PageCount', '0', 'int', '1']
    param[5] = ['ItemCount', '0', 'int', '1']
    const res = await ExecDatabaseByParam('11', '日志_工位操作_查询', param)
    let rows = []
    if (Array.isArray(res.data)) rows = res.data
    else if (res.data?.result) rows = res.data.result
    logDialog.rows = rows || []
    logDialog.visible = true
  } catch (e) {
    console.error('查询工位日志失败:', e)
    ElMessage.error('查询工位日志失败')
  }
}

const openProductLogDialog = async () => {
  try {
    const { value: productCode } = await ElMessageBox.prompt('请扫描或输入产品码', '产品日志查询', {
      confirmButtonText: '查询',
      cancelButtonText: '取消',
      inputPattern: /.+/,
      inputErrorMessage: '产品码不能为空'
    })
    if (!productCode || !productCode.trim()) {
      ElMessage.warning('产品码不能为空')
      return
    }

    // 先查询数据
    const loadingMsg = ElMessage({ message: '正在查询...', type: 'info', duration: 0 })
    try {
      const param = []
      param[0] = ['码值', productCode.trim()]
      const res = await ExecDatabaseByParam('11', '日志_工位操作_产品码_查询', param)
      let rows = []
      if (Array.isArray(res.data)) rows = res.data
      else if (res.data?.result) rows = res.data.result

      loadingMsg.close()

      // 如果没有数据，只提示不弹窗
      if (!rows || rows.length === 0) {
        ElMessage.warning('未查询到该产品的日志记录')
        return
      }

      // 有数据才打开弹窗
      productLogDialog.productCode = productCode.trim()
      productLogDialog.rows = rows
      productLogDialog.visible = true
    } catch (e) {
      loadingMsg.close()
      console.error('查询产品日志失败:', e)
      ElMessage.error('查询产品日志失败')
    }
  } catch (e) {
    // 用户取消输入
    if (e !== 'cancel') {
      console.error('打开产品日志弹窗失败:', e)
    }
  }
}

const handleLogout = async () => {
  try {
    await ElMessageBox.confirm('确定要退出登录吗？', '提示', { confirmButtonText: '确定', cancelButtonText: '取消', type: 'warning' })
    isAuthenticated.value = false
    userInfo.value = {}
    if (statusTimer) { clearInterval(statusTimer); statusTimer = null }
    Cookie.remove('userId')
    Cookie.remove('userName')
    Object.keys(currentProduct).forEach(k => delete currentProduct[k])
    stationList.value = []
    selectedStation.value = ''
    router.push('/')
  } catch { }
}

onBeforeUnmount(() => {
  if (statusTimer) { clearInterval(statusTimer); statusTimer = null }
  if (mqttClient) {
    mqttClient.destroyConnection()
    mqttClient = null
  }
  // 清理窗口大小监听器
  window.removeEventListener('resize', () => { })
})
</script>

<style lang="scss" scoped>
.opstatus-page {
  width: 100%;
  height: 100vh;
  background: #f0f2f5;
  display: flex;
  flex-direction: column;
  overflow: hidden;
}

.header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 16px 20px;
  background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
  color: #fff;
}

.header .title {
  font-size: 20px;
  font-weight: 600;
}

.header .subtitle {
  opacity: .9;
  font-size: 12px;
}

.header .title-area {
  cursor: pointer;
  transition: opacity 0.2s;
}

.header .title-area:hover {
  opacity: 0.85;
}

.header .right {
  display: flex;
  align-items: center;
  gap: 8px;
}

.header .user {
  opacity: .95;
  margin-right: 10px;
}

.toolbar {
  padding: 12px 16px;
}

.form-row {
  display: flex;
  gap: 12px;
  flex-wrap: wrap;
  align-items: center;
}

.form-item {
  display: flex;
  align-items: center;
}

.form-item.actions {
  margin-left: auto;
  display: flex;
  gap: 8px;
}

.form-label {
  width: 64px;
  text-align: right;
  color: #606266;
  margin-right: 8px;
}

.form-input {
  min-width: 220px;
}

.mqtt-status-bar {
  padding: 8px 16px;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 14px;
  transition: all 0.3s ease;
}

.mqtt-status-bar.success {
  background-color: #f0f9ff;
  color: #67c23a;
  border-bottom: 1px solid #b3e19d;
}

.mqtt-status-bar.error {
  background-color: #fef0f0;
  color: #f56c6c;
  border-bottom: 1px solid #fab6b6;
}

.mqtt-status-bar.warning {
  background-color: #fdf6ec;
  color: #e6a23c;
  border-bottom: 1px solid #f5dab1;
}

.mqtt-status-content {
  display: flex;
  align-items: center;
  gap: 8px;
}

.status-icon {
  font-size: 16px;
}

.content {
  padding: 0 16px 16px;
  flex: 1;
  overflow: auto;
}

.card {
  background: #fff;
  border-radius: 8px;
  box-shadow: 0 2px 8px rgba(0, 0, 0, .08);
  padding: 12px;
}

.card-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 8px;
}

.card-title {
  font-weight: 600;
}

.card-body {
  min-height: 120px;
}

.empty {
  padding: 24px;
  text-align: center;
  color: #909399;
}

.grid {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 10px;
}

.item {
  display: flex;
  gap: 8px;
}

.label {
  width: 84px;
  color: #606266;
  text-align: right;
  flex-shrink: 0;
}

.value {
  color: #303133;
  word-break: break-all;
}

.moby-header {
  margin-bottom: 8px;
  color: #606266;
}

.code-block {
  background: #f5f7fa;
  border: 1px solid #e4e7ed;
  border-radius: 4px;
  padding: 12px;
  max-height: 360px;
  overflow: auto;
}

.code-block pre {
  margin: 0;
  font-family: 'Consolas', 'Monaco', monospace;
  font-size: 13px;
  white-space: pre-wrap;
  word-break: break-word;
}

.auth-loading {
  display: flex;
  height: 100vh;
  align-items: center;
  justify-content: center;
  flex-direction: column;
  color: #909399;
}

@media (max-width: 1024px) {
  .grid {
    grid-template-columns: 1fr;
  }

  .form-item.actions {
    width: 100%;
    justify-content: flex-start;
  }
}

/* 行着色：返回代码 0 绿色，非0 淡红，空值不变 */
:deep(.row-success)>td {
  background-color: #f0fff4 !important;
}

:deep(.row-error)>td {
  background-color: #fff5f5 !important;
}
</style>
