<template>
  <div class="mod-config">
    <el-card class="overview-card" shadow="never">
      <div slot="header" class="card-title-row">
        <div>
          <div class="page-title">任务执行手工补录台账</div>
          <div class="page-desc">用于 PLC 信息缺失场景的人工补录，确保任务执行链路完整可追溯</div>
        </div>
        <el-button plain class="add-btn" @click="openDialog">新增补录</el-button>
      </div>
      <div class="overview-grid">
        <div class="overview-item">
          <div class="overview-label">补录总数</div>
          <div class="overview-value">{{ summary.totalCount }}</div>
        </div>
        <div class="overview-item">
          <div class="overview-label">补录总数量</div>
          <div class="overview-value">{{ summary.totalQty }}</div>
        </div>
        <div class="overview-item">
          <div class="overview-label">过站补录</div>
          <div class="overview-value">{{ summary.typeCount['过站补录'] || 0 }}</div>
        </div>
        <div class="overview-item">
          <div class="overview-label">上挂补录</div>
          <div class="overview-value">{{ summary.typeCount['上挂补录'] || 0 }}</div>
        </div>
        <div class="overview-item">
          <div class="overview-label">下挂补录</div>
          <div class="overview-value">{{ summary.typeCount['下挂补录'] || 0 }}</div>
        </div>
        <div class="overview-item">
          <div class="overview-label">完工补录</div>
          <div class="overview-value">{{ summary.typeCount['完工补录'] || 0 }}</div>
        </div>
      </div>
    </el-card>

    <el-form :inline="true" label-position="top" class="query-form">
      <el-form-item label="任务单号">
        <el-input v-model.trim="query.jobCode" clearable placeholder="请输入任务单号" style="width: 200px" @keyup.enter.native="loadList" />
      </el-form-item>
      <el-form-item label="补录类型">
        <el-select v-model="query.recordType" clearable placeholder="全部类型" style="width: 180px">
          <el-option v-for="item in recordTypeOptions" :key="item" :label="item" :value="item" />
        </el-select>
      </el-form-item>
      <el-form-item label="关联单号">
        <el-input v-model.trim="query.docNo" clearable placeholder="模糊查询" style="width: 180px" @keyup.enter.native="loadList" />
      </el-form-item>
      <el-form-item label=" ">
        <el-button plain class="search-btn" :loading="loading" @click="loadList">查询</el-button>
        <el-button plain class="reset-btn" @click="resetQuery">重置</el-button>
      </el-form-item>
    </el-form>

    <el-table
      class="data-table"
      :data="dataList"
      border
      stripe
      style="width: 100%"
      v-loading="loading"
      :height="tableHeight">
      <el-table-column type="index" width="50" />
      <el-table-column prop="recordId" label="record_id" width="170" />
      <el-table-column label="类型" width="110">
        <template slot-scope="scope">
          <el-tag size="mini" :type="recordTypeTag(scope.row.recordType)">{{ scope.row.recordType || '-' }}</el-tag>
        </template>
      </el-table-column>
      <el-table-column prop="jobId" label="job_id" width="130" />
      <el-table-column prop="docNo" label="关联单号" min-width="150" show-overflow-tooltip />
      <el-table-column label="挂具" width="100">
        <template slot-scope="scope">{{ payloadValue(scope.row, 'rackCode') || '-' }}</template>
      </el-table-column>
      <el-table-column label="工序" width="120">
        <template slot-scope="scope">{{ payloadValue(scope.row, 'stepCode') || '-' }}</template>
      </el-table-column>
      <el-table-column label="站点" width="120">
        <template slot-scope="scope">{{ payloadValue(scope.row, 'stationId') || '-' }}</template>
      </el-table-column>
      <el-table-column label="缺失原因" min-width="150" show-overflow-tooltip>
        <template slot-scope="scope">{{ payloadValue(scope.row, 'missingReason') || '-' }}</template>
      </el-table-column>
      <el-table-column prop="qty" label="数量" width="80" align="right" />
      <el-table-column prop="operatorName" label="补录人" width="110" />
      <el-table-column prop="reviewerName" label="复核人" width="110" />
      <el-table-column label="补录时间" min-width="170">
        <template slot-scope="scope">{{ formatDateTime(scope.row.recordTime) }}</template>
      </el-table-column>
    </el-table>

    <el-dialog
      title="PLC缺失信息手工补录"
      :visible.sync="dialogVisible"
      width="900px"
      top="5vh"
      class="manual-dialog"
      :close-on-click-modal="false"
      v-drag>
      <el-form ref="manualForm" :model="form" :rules="rules" label-position="top" class="manual-form">
        <el-row :gutter="12">
          <el-col :span="8">
            <el-form-item label="补录类型" prop="recordType">
              <el-select v-model="form.recordType" style="width: 100%">
                <el-option v-for="item in recordTypeOptions" :key="item" :label="item" :value="item" />
              </el-select>
            </el-form-item>
          </el-col>
          <el-col :span="10">
            <el-form-item label="任务单号" prop="selectedJobCode">
              <el-select
                v-model="form.selectedJobCode"
                filterable
                clearable
                :loading="jobLoading"
                placeholder="请选择任务单号"
                style="width: 100%"
                @change="onDialogJobChange">
                <el-option
                  v-for="item in jobOptions"
                  :key="item.jobCode"
                  :label="`${item.jobCode} / ${item.status || '-'} / ${item.inboundNos || '-'}`"
                  :value="item.jobCode" />
              </el-select>
            </el-form-item>
          </el-col>
          <el-col :span="6">
            <el-form-item label="补录数量" prop="qty">
              <el-input-number v-model="form.qty" :min="0" :precision="0" style="width: 100%" />
            </el-form-item>
          </el-col>
        </el-row>

        <el-row :gutter="12">
          <el-col :span="12">
            <el-form-item label="任务明细（可选）">
              <el-select
                v-model="form.selectedDetailKey"
                clearable
                filterable
                :loading="detailLoading"
                placeholder="选择后自动带入 batch_id / part_id"
                style="width: 100%"
                @change="onDetailChange">
                <el-option
                  v-for="item in jobDetailOptions"
                  :key="item._key"
                  :label="`${item.inboundNo || '-'} / ${item.partNo || '-'} / 剩余${item.remainingQty || 0}`"
                  :value="item._key" />
              </el-select>
            </el-form-item>
          </el-col>
          <el-col :span="12">
            <el-form-item label="关联单号" prop="docNo">
              <el-input v-model.trim="form.docNo" placeholder="建议：任务单+工序+挂具组合号">
                <el-button slot="append" @click="fillDocNoByContext">自动生成</el-button>
              </el-input>
            </el-form-item>
          </el-col>
        </el-row>

        <el-row :gutter="12">
          <el-col :span="8"><el-form-item label="batch_id"><el-input v-model="form.batchId" disabled /></el-form-item></el-col>
          <el-col :span="8"><el-form-item label="part_id"><el-input v-model="form.partId" disabled /></el-form-item></el-col>
          <el-col :span="8">
            <el-form-item label="补录时间">
              <el-date-picker v-model="form.recordTime" type="datetime" style="width: 100%" />
            </el-form-item>
          </el-col>
        </el-row>

        <el-row :gutter="12">
          <el-col :span="8"><el-form-item label="挂具码"><el-input v-model.trim="form.rackCode" placeholder="例如 RACK-001" /></el-form-item></el-col>
          <el-col :span="8"><el-form-item label="工序编码"><el-input v-model.trim="form.stepCode" placeholder="例如 POOL-001" /></el-form-item></el-col>
          <el-col :span="8"><el-form-item label="站点ID"><el-input v-model.trim="form.stationId" placeholder="例如 PLC-POOL-001" /></el-form-item></el-col>
        </el-row>

        <el-row :gutter="12">
          <el-col :span="8">
            <el-form-item label="缺失原因">
              <el-select v-model="form.missingReason" style="width: 100%">
                <el-option v-for="item in missingReasonOptions" :key="item" :label="item" :value="item" />
              </el-select>
            </el-form-item>
          </el-col>
          <el-col :span="16">
            <el-form-item label="原因说明">
              <el-input v-model.trim="form.reasonRemark" placeholder="可填写故障说明、补录依据等" />
            </el-form-item>
          </el-col>
        </el-row>

        <el-row :gutter="12">
          <el-col :span="12"><el-form-item label="补录人"><el-input v-model.trim="form.operatorName" placeholder="例如 班组长A" /></el-form-item></el-col>
          <el-col :span="12"><el-form-item label="复核人"><el-input v-model.trim="form.reviewerName" placeholder="例如 工艺工程师B" /></el-form-item></el-col>
        </el-row>

        <el-form-item label="扩展JSON（可选）" prop="payloadJson">
          <el-input
            v-model.trim="form.payloadJson"
            type="textarea"
            :rows="4"
            placeholder='如 {"manualSource":"paper-log"}，留空则自动按上方字段生成' />
        </el-form-item>
      </el-form>

      <el-footer style="height: 40px; text-align: center; margin-top: 10px;">
        <el-button plain class="reset-btn" @click="dialogVisible = false">取消</el-button>
        <el-button plain class="add-btn" :loading="submitLoading" @click="submit">保存补录</el-button>
      </el-footer>
    </el-dialog>
  </div>
</template>

<script>
import { listJob, listJobDetailsByCode, listManualRecord, saveManualRecord } from '@/api/rack/closedLoop'

const RECORD_TYPE_OPTIONS = ['过站补录', '上挂补录', '下挂补录', '完工补录', '其他补录']
const MISSING_REASON_OPTIONS = ['PLC数据缺失', 'PLC离线', 'PLC通信中断', 'PLC数据丢包', '人工确认补录', '其他']

const emptyForm = () => ({
  recordType: '过站补录',
  selectedJobCode: '',
  jobId: null,
  selectedDetailKey: '',
  batchId: '',
  partId: '',
  docNo: '',
  qty: 0,
  rackCode: '',
  stepCode: '',
  stationId: '',
  missingReason: 'PLC数据缺失',
  reasonRemark: '',
  operatorName: '',
  reviewerName: '',
  recordTime: new Date(),
  payloadJson: ''
})

export default {
  data () {
    return {
      tableHeight: window.innerHeight - 320,
      loading: false,
      jobLoading: false,
      detailLoading: false,
      submitLoading: false,
      dialogVisible: false,
      dataList: [],
      jobOptions: [],
      jobDetailOptions: [],
      query: {
        jobCode: '',
        recordType: '',
        docNo: ''
      },
      form: emptyForm(),
      recordTypeOptions: RECORD_TYPE_OPTIONS,
      missingReasonOptions: MISSING_REASON_OPTIONS,
      rules: {
        recordType: [{ required: true, message: '请选择补录类型', trigger: 'change' }],
        selectedJobCode: [{ required: true, message: '请选择任务单号', trigger: 'change' }],
        docNo: [{ required: true, message: '请输入关联单号', trigger: 'blur' }],
        qty: [{ type: 'number', required: true, message: '请输入补录数量', trigger: 'change' }],
        payloadJson: [{ validator: (rule, value, callback) => this.validatePayloadJson(value, callback), trigger: 'blur' }]
      }
    }
  },
  computed: {
    summary () {
      const result = {
        totalCount: this.dataList.length,
        totalQty: 0,
        typeCount: {}
      }
      this.dataList.forEach(item => {
        const type = item.recordType || '未知'
        result.typeCount[type] = (result.typeCount[type] || 0) + 1
        result.totalQty += Number(item.qty) || 0
      })
      return result
    }
  },
  mounted () {
    this.loadJobOptions()
    this.loadList()
  },
  methods: {
    async loadJobOptions () {
      this.jobLoading = true
      try {
        const { data } = await listJob({})
        this.jobOptions = data.rows || []
      } finally {
        this.jobLoading = false
      }
    },
    resolveJobByCode (jobCode) {
      const key = String(jobCode || '').trim()
      if (!key) {
        return null
      }
      return (this.jobOptions || []).find(item => item && String(item.jobCode || '').trim() === key) || null
    },
    async resolveJobIdForQuery () {
      const key = String(this.query.jobCode || '').trim()
      if (!key) {
        return null
      }
      let matched = this.resolveJobByCode(key)
      if (!matched) {
        const { data } = await listJob({ jobCode: key })
        const rows = data.rows || []
        matched = rows.find(item => item && String(item.jobCode || '').trim() === key) || rows[0] || null
      }
      return matched ? matched.jobId : -1
    },
    async loadList () {
      this.loading = true
      try {
        const jobId = await this.resolveJobIdForQuery()
        if (jobId === -1) {
          this.dataList = []
          this.$message.warning(`任务单不存在：${this.query.jobCode}`)
          return
        }
        const params = {
          recordType: this.query.recordType,
          docNo: this.query.docNo
        }
        if (jobId) {
          params.jobId = jobId
        }
        const { data } = await listManualRecord(params)
        this.dataList = (data.rows || []).map(row => ({
          ...row,
          _payload: this.safeParseJson(row.payloadJson)
        }))
      } finally {
        this.loading = false
      }
    },
    resetQuery () {
      this.query = { jobCode: '', recordType: '', docNo: '' }
      this.loadList()
    },
    openDialog () {
      this.form = emptyForm()
      this.jobDetailOptions = []
      if (!this.jobOptions.length) {
        this.loadJobOptions()
      }
      if (this.query.jobCode) {
        this.form.selectedJobCode = this.query.jobCode
        this.onDialogJobChange(this.query.jobCode)
      }
      this.dialogVisible = true
      this.$nextTick(() => {
        this.$refs.manualForm && this.$refs.manualForm.clearValidate()
      })
    },
    async onDialogJobChange (jobCode) {
      this.form.jobId = null
      this.form.selectedDetailKey = ''
      this.form.batchId = ''
      this.form.partId = ''
      this.jobDetailOptions = []

      if (!jobCode) {
        return
      }
      let job = this.resolveJobByCode(jobCode)
      if (!job) {
        const { data } = await listJob({ jobCode })
        const rows = data.rows || []
        job = rows.find(item => item && item.jobCode === jobCode) || rows[0] || null
      }
      this.form.jobId = job ? job.jobId : null
      await this.loadJobDetails(jobCode)
    },
    async loadJobDetails (jobCode) {
      if (!jobCode) {
        this.jobDetailOptions = []
        return
      }
      this.detailLoading = true
      try {
        const { data } = await listJobDetailsByCode(jobCode)
        const rows = data.rows || []
        this.jobDetailOptions = rows.map(item => ({
          ...item,
          _key: `${item.inboundId || ''}_${item.partNo || ''}`
        }))
      } finally {
        this.detailLoading = false
      }
    },
    onDetailChange (key) {
      if (!key) {
        this.form.batchId = ''
        this.form.partId = ''
        return
      }
      const detail = (this.jobDetailOptions || []).find(item => item._key === key)
      if (!detail) {
        return
      }
      this.form.batchId = detail.inboundId || ''
      this.form.partId = detail.partId || ''
      if (!this.form.qty || Number(this.form.qty) <= 0) {
        this.form.qty = Number(detail.remainingQty) > 0 ? Number(detail.remainingQty) : (Number(detail.plannedQty) || 0)
      }
      if (!this.form.docNo) {
        this.fillDocNoByContext()
      }
    },
    fillDocNoByContext () {
      const code = this.form.selectedJobCode || 'NOJOB'
      const step = this.form.stepCode || 'NOSTEP'
      const rack = this.form.rackCode || 'NORACK'
      this.form.docNo = `${code}-${step}-${rack}-${Date.now()}`
    },
    safeParseJson (jsonText) {
      if (!jsonText) {
        return {}
      }
      try {
        return JSON.parse(jsonText)
      } catch (e) {
        return {}
      }
    },
    payloadValue (row, field) {
      const payload = row && row._payload ? row._payload : {}
      return payload[field]
    },
    validatePayloadJson (value, callback) {
      if (!value) {
        callback()
        return
      }
      try {
        JSON.parse(value)
        callback()
      } catch (e) {
        callback(new Error('扩展JSON格式不合法'))
      }
    },
    buildPayloadFromForm () {
      let payload = {}
      if (this.form.payloadJson) {
        payload = JSON.parse(this.form.payloadJson)
      }
      const selectedDetail = (this.jobDetailOptions || []).find(item => item._key === this.form.selectedDetailKey)
      return {
        ...payload,
        fillScene: 'PLC_MISSING',
        manualFill: true,
        recordType: this.form.recordType,
        jobCode: this.form.selectedJobCode || '',
        rackCode: this.form.rackCode || '',
        stepCode: this.form.stepCode || '',
        stationId: this.form.stationId || '',
        missingReason: this.form.missingReason || '',
        reasonRemark: this.form.reasonRemark || '',
        inboundNo: selectedDetail ? (selectedDetail.inboundNo || '') : '',
        partNo: selectedDetail ? (selectedDetail.partNo || '') : ''
      }
    },
    async submit () {
      if (this.submitLoading) {
        return
      }
      this.$refs.manualForm.validate(async valid => {
        if (!valid) {
          return
        }
        let payloadObj = null
        try {
          payloadObj = this.buildPayloadFromForm()
        } catch (e) {
          this.$message.warning((e && e.message) || '扩展JSON格式错误')
          return
        }
        this.submitLoading = true
        try {
          await saveManualRecord({
            recordType: this.form.recordType,
            docNo: this.form.docNo,
            batchId: this.form.batchId || null,
            jobId: this.form.jobId || null,
            partId: this.form.partId || null,
            qty: Number(this.form.qty) || 0,
            operatorName: this.form.operatorName,
            reviewerName: this.form.reviewerName,
            recordTime: this.form.recordTime || new Date(),
            payloadJson: JSON.stringify(payloadObj)
          })
          this.$message.success('补录保存成功')
          this.dialogVisible = false
          this.loadList()
        } catch (e) {
          this.$message.error((e && e.message) || '补录保存失败')
        } finally {
          this.submitLoading = false
        }
      })
    },
    recordTypeTag (recordType) {
      const map = {
        过站补录: 'warning',
        上挂补录: 'success',
        下挂补录: '',
        完工补录: 'danger',
        其他补录: 'info'
      }
      return map[recordType] || 'info'
    },
    formatDateTime (v) {
      if (!v) return '-'
      let date = null
      if (typeof v === 'number') {
        date = new Date(v)
      } else if (typeof v === 'string') {
        const trimmed = v.trim()
        if (/^\d+$/.test(trimmed)) {
          date = new Date(Number(trimmed))
        } else {
          date = new Date(trimmed)
        }
      } else if (v instanceof Date) {
        date = v
      } else {
        date = new Date(v)
      }
      if (!(date instanceof Date) || Number.isNaN(date.getTime())) {
        return String(v).replace('T', ' ')
      }
      const y = date.getFullYear()
      const m = String(date.getMonth() + 1).padStart(2, '0')
      const d = String(date.getDate()).padStart(2, '0')
      const hh = String(date.getHours()).padStart(2, '0')
      const mm = String(date.getMinutes()).padStart(2, '0')
      const ss = String(date.getSeconds()).padStart(2, '0')
      return `${y}-${m}-${d} ${hh}:${mm}:${ss}`
    }
  }
}
</script>

<style scoped>
.overview-card {
  margin-bottom: 12px;
}

.card-title-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
}

.page-title {
  font-size: 16px;
  font-weight: 600;
  color: #303133;
}

.page-desc {
  margin-top: 4px;
  color: #909399;
  font-size: 12px;
}

.overview-grid {
  display: grid;
  grid-template-columns: repeat(6, minmax(120px, 1fr));
  gap: 10px;
}

.overview-item {
  border: 1px solid #ebeef5;
  border-radius: 6px;
  padding: 10px;
  background: #fff;
}

.overview-label {
  color: #909399;
  font-size: 12px;
}

.overview-value {
  margin-top: 6px;
  font-size: 20px;
  font-weight: 600;
  color: #303133;
}

.manual-dialog >>> .el-dialog__body {
  padding: 12px 20px 10px;
  max-height: 72vh;
  overflow-y: auto;
}

.manual-form >>> .el-form-item {
  margin-bottom: 10px;
}

.data-table {
  background-color: #fff;
  border-radius: 4px;
}

.data-table >>> .el-table__header-wrapper th,
.data-table >>> .el-table__fixed-header-wrapper th {
  background-color: #f5f7fa !important;
  color: #333;
  font-weight: 600;
  border-color: #ebeef5;
  padding: 8px 0;
}

.data-table >>> .el-table__header-wrapper .cell,
.data-table >>> .el-table__fixed-header-wrapper .cell,
.data-table >>> .el-table__body-wrapper .cell,
.data-table >>> .el-table__fixed-body-wrapper .cell {
  padding: 0 10px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-size: 13px !important;
}

.query-form {
  background-color: #fff;
  padding: 15px 15px 5px 15px;
  border-radius: 4px;
  margin-bottom: 12px;
}

.query-form >>> .el-form-item__label {
  color: #333;
  font-size: 13px;
  padding-bottom: 5px;
}

.query-form >>> .el-input__inner {
  height: 32px;
  line-height: 32px;
  border-radius: 4px;
  font-size: 13px;
}

.query-form >>> .el-button {
  height: 32px;
  padding: 0 15px;
  font-size: 13px;
  border-radius: 4px;
}

.search-btn {
  background-color: #ecf5ff;
  border-color: #b3d8ff;
  color: #409eff;
}

.search-btn:hover {
  background-color: #409eff;
  border-color: #409eff;
  color: #fff;
}

.reset-btn {
  background-color: #f5f7fa;
  border-color: #d3d4d6;
  color: #606266;
}

.reset-btn:hover {
  background-color: #909399;
  border-color: #909399;
  color: #fff;
}

.add-btn {
  background-color: #f0f9eb;
  border-color: #c2e7b0;
  color: #67c23a;
}

.add-btn:hover {
  background-color: #67c23a;
  border-color: #67c23a;
  color: #fff;
}
</style>
