<template>
  <div class="labeling-page-container">
    <!-- 顶部操作栏：保留图片切换/缩放，新增审核通过/不通过按钮 -->
    <div class="labeling-header">
      <div class="header-left">
        <el-button-group>
          <el-button icon="el-icon-arrow-left" @click="prevImage" title="上一张" :disabled="imageList.length <= 1"></el-button>
          <el-button icon="el-icon-arrow-right" @click="nextImage" title="下一张" :disabled="imageList.length <= 1"></el-button>
          <el-button icon="el-icon-zoom-in" @click="zoomIn" title="放大"></el-button>
          <el-button icon="el-icon-zoom-out" @click="zoomOut" title="缩小"></el-button>
          <el-button icon="el-icon-refresh" @click="resetZoom" title="重置视图"></el-button>
        </el-button-group>
      </div>

      <div class="header-right">
        <!-- 审核操作按钮 -->
        <el-button type="success" @click="auditPass" class="audit-btn">审核通过</el-button>
        <el-button type="danger" @click="openRejectDialog" class="audit-btn">审核不通过</el-button>
      </div>
    </div>

    <!-- 主体内容区：分类标注图片展示 + 分类标注结果回显 -->
    <div class="labeling-main-wrapper">
      <div class="labeling-main">
        <!-- 左侧图片展示区：保留分类标注的拖拽/缩放核心交互 -->
        <div class="labeling-image-area">
          <div v-if="imageLoading" class="image-loading">
            <el-skeleton :rows="10" animated />
          </div>
          <div v-else ref="labelContainer" class="image-container"
               @wheel.prevent="handleWheelZoom"
               @mousedown="handleImageMouseDown"
               @mousemove="handleImageMouseMove"
               @mouseup="handleImageMouseUp"
               @mouseleave="handleImageMouseUp">
            <!-- 无效数据提示：醒目展示 -->
            <div v-if="currentImage.isInvalidData === '0'" class="invalid-data-tip">无效数据</div>
            <img
              ref="labelImage"
              :src="currentImage.filePath"
              alt="分类审核图片"
              class="label-image"
              @load="onImageLoad"
              @error="onImageError"
              @mousedown.prevent
            />
          </div>
          <!-- 图片分页/缩放信息 -->
          <div class="image-pagination" v-if="!imageLoading">
            第 {{ currentImageIndex + 1 }} 张/共 {{ imageList.length }} 张 | 缩放比例：{{ Math.round(zoomScale * 100) }}%
          </div>
        </div>

        <!-- 右侧分类标注结果展示区：适配审批场景的分类标签回显 -->
        <div class="label-result-area">
          <div class="result-title">分类标注结果</div>
          <div class="result-content">
            <div v-if="getSelectedLabelNames().length === 0 && currentImage.isInvalidData !== '0'" class="no-result">暂无分类标注</div>
            <div v-if="currentImage.isInvalidData === '0'" class="invalid-result">已标为无效数据</div>
            <div class="result-tag" v-for="label in getSelectedLabelNames()" :key="label.id">
              {{ label.name }}
            </div>
          </div>
        </div>
      </div>
    </div>

    <!-- 审核不通过弹窗：保留原审批逻辑，带原因校验 -->
    <el-dialog
      title="审核不通过"
      :visible.sync="rejectDialogVisible"
      width="500px"
      :close-on-click-modal="false"
      :before-close="handleDialogClose"
    >
      <div class="reject-dialog-content">
        <label class="reject-label">不通过原因:</label>
        <el-input
          type="textarea"
          v-model="auditRemark"
          :rows="8"
          placeholder="请输入审核不通过的原因..."
          class="reject-textarea"
        />
      </div>
      <div slot="footer" class="dialog-footer">
        <el-button @click="rejectDialogVisible = false">取消</el-button>
        <el-button type="primary" @click="confirmReject" :loading="isAuditing">提交</el-button>
      </div>
    </el-dialog>
  </div>
</template>

<script>
// 引入分类标注标签树接口、审批图片列表接口、审批提交接口
import { getLabelingTaskLabelTreeAPI } from '@/api/data/labeling'
import { getAuditPicturesAPI, submitAuditResultAPI } from '@/api/data/audit'
import { decryptWithSM4 } from "@/utils/sm";

export default {
  name: 'LabelingClassifyAudit',
  data() {
    return {
      // 图片相关：保留分类标注的核心参数
      imageList: [],
      currentImageIndex: 0,
      currentImage: {},
      imageLoading: false,
      imageLoaded: false,
      // 标签相关：用于分类标签回显
      labelGroups: [],
      labelLoading: false,
      // 缩放/拖拽核心参数：完整保留分类标注的交互逻辑
      zoomScale: 1.0,
      imgOffsetX: 0,
      imgOffsetY: 0,
      dragState: {
        isDragging: false,
        startX: 0,
        startY: 0,
        startImgX: 0,
        startImgY: 0
      },
      // 审批核心参数
      labelingTaskId: this.convertToNumber(decryptWithSM4(this.$route.query.labelingTaskId || '')),
      isAuditing: false, // 审核提交状态锁
      rejectDialogVisible: false, // 不通过弹窗显隐
      auditRemark: '' // 不通过原因
    }
  },
  mounted() {
    // 并行加载审批图片和标签树，提升体验
    Promise.all([this.loadAuditImages(), this.loadLabelTreeData()]).then(() => {
      if (this.imageList.length > 0) {
        this.currentImage = this.imageList[this.currentImageIndex]
      }
    })
  },
  methods: {
    // 数字转换工具方法：复用分类标注的逻辑
    convertToNumber(value) {
      if (!value || value === '' || value === 'undefined' || value === 'null') {
        return '';
      }
      const num = Number(value);
      return isNaN(num) ? '' : num;
    },

    // 加载审批图片列表：适配分类标注的数据解析规则
    async loadAuditImages() {
      try {
        this.imageLoading = true
        if (!this.labelingTaskId) {
          this.$message.warning('分类审批任务ID不能为空');
          return;
        }
        // 调用审批图片列表接口
        const res = await getAuditPicturesAPI({ labelingTaskId: this.labelingTaskId })
        if (res.code === 200 && res.data && Array.isArray(res.data)) {
          // 按图片分组解析：适配分类标注的labelingDataList结构
          const imageMap = {}
          res.data.forEach(item => {
            const key = item.labelingSampleId
            if (!imageMap[key]) {
              imageMap[key] = {
                id: item.labelingSampleId, // 审批提交用的核心ID
                datasetSampleId: item.datasetSampleId,
                filePath: item.filePath,
                isInvalidData: item.isInvalidData || '1', // 0=无效 1=有效
                selectedLabelIds: [] // 分类标注核心：保存选中标签ID
              }
            }
            // 解析分类标注的标签ID：兼容JSON和直接取labelId两种格式
            try {
              const labelingData = JSON.parse(item.labelingCoordinate || '{}')
              const labelId = labelingData.labelId || item.labelId
              if (labelId && !imageMap[key].selectedLabelIds.includes(labelId)) {
                imageMap[key].selectedLabelIds.push(labelId)
              }
            } catch (e) {
              // 兜底：直接取接口的labelId
              if (item.labelId && !imageMap[key].selectedLabelIds.includes(item.labelId)) {
                imageMap[key].selectedLabelIds.push(item.labelId)
              }
            }
          })
          // 转换为数组并赋值
          this.imageList = Object.values(imageMap)
          if (this.imageList.length === 0) {
            this.$message.info('暂无分类审批图片数据')
          }
        } else {
          this.$message.warning('审批图片加载失败：' + (res.msg || '接口返回异常'))
          this.imageList = []
        }
      } catch (error) {
        console.error('加载审批图片失败：', error)
        this.$message.error('审批图片加载失败，请刷新重试')
        this.imageList = []
      } finally {
        this.imageLoading = false
      }
    },

    // 加载标签树数据：仅用于分类标签名称回显，复用分类标注接口
    async loadLabelTreeData() {
      try {
        this.labelLoading = true
        if (!this.labelingTaskId) return;
        const res = await getLabelingTaskLabelTreeAPI({ labelingTaskId: this.labelingTaskId })
        if (res.code === 200 && res.data) {
          this.labelGroups = res.data.map(group => ({
            ...group,
            expanded: true,
            labels: group.labels || []
          }))
        } else {
          this.$message.warning('标签数据加载失败：' + (res.msg || '接口返回异常'))
          this.labelGroups = []
        }
      } catch (error) {
        console.error('加载标签树失败：', error)
        this.$message.error('标签数据加载失败，请刷新重试')
        this.labelGroups = []
      } finally {
        this.labelLoading = false
      }
    },

    // 图片加载完成：初始化缩放和画布，复用分类标注逻辑
    onImageLoad() {
      this.imageLoaded = true
      this.calcFitScale()
      this.imgOffsetX = 0
      this.imgOffsetY = 0
      this.initImageCanvas()
    },

    // 初始化画布：承载分类标注图片的拖拽/缩放，复用原逻辑
    initImageCanvas() {
      const container = this.$refs.labelContainer
      const image = this.$refs.labelImage
      if (!container || !image) return

      // 移除旧画布
      const oldCanvas = container.querySelector('.image-canvas')
      if (oldCanvas) oldCanvas.remove()

      // 创建新画布
      const canvas = document.createElement('canvas')
      canvas.className = 'image-canvas'
      canvas.style.cssText = 'position:absolute;top:0;left:0;pointer-events:none;z-index:10;width:100%;height:100%;'
      canvas.width = container.offsetWidth
      canvas.height = container.offsetHeight
      container.appendChild(canvas)
      this.updateImageCanvas()
    },

    // 重绘画布：核心拖拽/缩放视觉实现，复用分类标注逻辑
    updateImageCanvas() {
      const container = this.$refs.labelContainer
      const image = this.$refs.labelImage
      const canvas = container.querySelector('.image-canvas')
      if (!container || !image || !canvas) return

      const ctx = canvas.getContext('2d')
      canvas.width = container.offsetWidth
      canvas.height = container.offsetHeight
      ctx.clearRect(0, 0, canvas.width, canvas.height)
      ctx.save()

      // 核心绘制逻辑：居中 + 缩放 + 拖拽偏移
      ctx.translate(
        container.offsetWidth / 2 + this.imgOffsetX,
        container.offsetHeight / 2 + this.imgOffsetY
      )
      ctx.scale(this.zoomScale, this.zoomScale)
      ctx.translate(-image.naturalWidth / 2, -image.naturalHeight / 2)

      // 绘制图片
      ctx.drawImage(image, 0, 0, image.naturalWidth, image.naturalHeight)
      ctx.restore()
    },

    // 计算适配缩放比例：让图片完整显示，复用分类标注逻辑
    calcFitScale() {
      const container = this.$refs.labelContainer
      const image = this.$refs.labelImage
      if (!container || !image) return

      const containerW = container.clientWidth
      const containerH = container.clientHeight
      const imgW = image.naturalWidth
      const imgH = image.naturalHeight

      const scaleW = containerW / imgW
      const scaleH = containerH / imgH
      this.zoomScale = Math.min(scaleW, scaleH)
      this.zoomScale = Math.max(0.1, Math.min(2.0, this.zoomScale))
    },

    // 图片加载失败提示，复用分类标注逻辑
    onImageError() {
      this.$message.error(`图片加载失败：${this.currentImage.filePath}`)
      this.imageLoaded = false
    },

    // 滚轮缩放，复用分类标注逻辑
    handleWheelZoom(e) {
      e.preventDefault()
      const delta = e.deltaY > 0 ? -0.1 : 0.1
      this.zoomScale = Math.max(0.1, Math.min(2.0, this.zoomScale + delta))
      this.updateImageCanvas()
    },

    // 鼠标按下：开启拖拽，复用分类标注逻辑
    handleImageMouseDown(e) {
      e.preventDefault()
      this.dragState = {
        isDragging: true,
        startX: e.clientX,
        startY: e.clientY,
        startImgX: this.imgOffsetX,
        startImgY: this.imgOffsetY
      }
      this.$refs.labelContainer.style.cursor = 'move'
    },

    // 鼠标移动：处理拖拽，复用分类标注逻辑
    handleImageMouseMove(e) {
      e.preventDefault()
      if (!this.dragState.isDragging) return
      const moveX = e.clientX - this.dragState.startX
      const moveY = e.clientY - this.dragState.startY
      this.imgOffsetX = this.dragState.startImgX + moveX
      this.imgOffsetY = this.dragState.startImgY + moveY
      this.updateImageCanvas()
    },

    // 鼠标松开/离开：结束拖拽，复用分类标注逻辑
    handleImageMouseUp() {
      if (this.dragState.isDragging) {
        this.dragState.isDragging = false
        this.$refs.labelContainer.style.cursor = 'default'
      }
    },

    // 放大图片，复用分类标注逻辑
    zoomIn() {
      this.zoomScale = Math.min(2.0, this.zoomScale + 0.1)
      this.updateImageCanvas()
    },

    // 缩小图片，复用分类标注逻辑
    zoomOut() {
      this.zoomScale = Math.max(0.1, this.zoomScale - 0.1)
      this.updateImageCanvas()
    },

    // 重置视图，复用分类标注逻辑
    resetZoom() {
      this.calcFitScale()
      this.imgOffsetX = 0
      this.imgOffsetY = 0
      this.updateImageCanvas()
    },

    getSelectedLabelNames() {
      const selectedLabels = []
      const { selectedLabelIds } = this.currentImage
      if (!selectedLabelIds || selectedLabelIds.length === 0) {
        return selectedLabels
      }
      this.labelGroups.forEach(group => {
        group.labels.forEach(label => {
          if (selectedLabelIds.includes(label.id + '')) {
            selectedLabels.push(label)
          }
        })
      })
      return selectedLabels
    },

    // 上一张图片，复用分类标注逻辑并适配审批切图
    prevImage() {
      if (this.currentImageIndex > 0) {
        this.switchImage(this.currentImageIndex - 1)
      } else {
        this.$message.info('已是第一张！')
      }
    },

    // 下一张图片，复用分类标注逻辑并适配审批切图
    nextImage() {
      if (this.currentImageIndex < this.imageList.length - 1) {
        this.switchImage(this.currentImageIndex + 1)
      } else {
        this.$message.info('已是最后一张！')
      }
    },

    // 切换图片：重置视图并重新绘制，适配审批场景
    switchImage(index) {
      this.currentImageIndex = index
      this.currentImage = this.imageList[index]
      this.imageLoaded = false
      this.imgOffsetX = 0
      this.imgOffsetY = 0
      this.zoomScale = 1.0
      // 重新初始化画布和缩放
      this.$nextTick(() => {
        if (this.$refs.labelImage) {
          this.calcFitScale()
          this.initImageCanvas()
        }
      })
    },

    // 审核通过：调用通用提交方法，状态传1
    async auditPass() {
      await this.submitAuditResult(1)
    },

    // 打开审核不通过弹窗：清空原因输入框
    openRejectDialog() {
      this.auditRemark = ''
      this.rejectDialogVisible = true
    },

    // 关闭弹窗：清空原因并隐藏弹窗
    handleDialogClose() {
      this.rejectDialogVisible = false
      this.auditRemark = ''
    },

    // 确认审核不通过：校验原因后提交，状态传2
    async confirmReject() {
      // 校验原因是否填写
      if (!this.auditRemark.trim()) {
        this.$message.warning('请填写审核不通过的原因！')
        return
      }
      // 提交审核不通过结果
      await this.submitAuditResult(2)
      // 提交成功后关闭弹窗
      this.rejectDialogVisible = false
    },

    // 核心：提交审核结果，适配分类标注的审批参数
// 核心：提交审核结果，适配分类标注的审批参数
    async submitAuditResult(auditStatus) {
      if (this.isAuditing) return
      if (!this.currentImage.id) {
        this.$message.error('当前图片ID为空，无法提交审核！')
        return
      }

      try {
        this.isAuditing = true
        const loadingInstance = this.$loading({ text: '提交审核结果中...' })

        // 构造分类审批提交参数：适配后端接口规范
        const submitParams = {
          labelingTaskId: this.labelingTaskId,
          labelingSampleId: this.currentImage.id, // 分类标注的样本ID
          auditStatus: auditStatus, // 1-通过，2-不通过
          datasetSampleId: this.currentImage.datasetSampleId || '',
          auditRemark: auditStatus === 2 ? this.auditRemark.trim() : '' // 仅不通过时传原因
        }

        console.log('分类审批提交参数：', submitParams)

        // 调用审批提交接口
        const res = await submitAuditResultAPI(submitParams)

        if (res.code === 200) {
          this.$message.success(auditStatus === 1 ? '审核通过提交成功！' : '审核不通过提交成功！')
          // ===== 新增核心代码开始 =====
          await this.loadAuditImages(); // 刷新审批图片列表（等待加载完成）
          // 刷新后重置索引：取原索引和新列表最大索引的最小值，防止越界
          this.currentImageIndex = Math.min(this.currentImageIndex, this.imageList.length - 1);
          // 若刷新后还有图片，重新赋值当前图片并重置视图；无图片则置空
          if (this.imageList.length === 0) {
            this.currentImage = {};
            this.$message.info('暂无剩余审批图片数据');
          }
          // 自动切换到下一张（如果有），提升审批效率
          if (this.imageList.length > 0 && this.currentImageIndex < this.imageList.length - 1) {
            this.nextImage()
          }
        } else {
          this.$message.error('提交失败：' + (res.msg || '接口返回异常'))
        }
      } catch (error) {
        console.error('提交分类审核结果失败：', error)
        this.$message.error('提交失败，请重试！')
      } finally {
        this.isAuditing = false
        this.$loading().close()
      }
    }
  }
}
</script>

<style scoped lang="scss">
// 全局容器：适配审批页面的布局
.labeling-page-container {
  width: 100%;
  height: 90.5vh;
  display: flex;
  flex-direction: column;
  overflow: hidden;
  background-color: #f5f7fa;
  box-sizing: border-box;
}

// 顶部操作栏：新增右侧审核按钮布局
.labeling-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 10px 20px;
  background-color: #fff;
  border-bottom: 1px solid #e6e6e6;
  flex-shrink: 0;
  z-index: 100;

  .header-left {
    display: flex;
    align-items: center;
  }

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

    .audit-btn {
      padding: 8px 20px;
    }
  }
}

// 主体内容外层容器
.labeling-main-wrapper {
  height: 100%;
  overflow: hidden;
  padding: 15px;
}

// 主体内容区：图片+分类标注结果审批展示
.labeling-main {
  display: flex;
  gap: 15px;
  height: 100%;
  min-height: 0;

  // 左侧图片展示区：保留分类标注的拖拽/缩放样式
  .labeling-image-area {
    flex: 2;
    background-color: #fff;
    border-radius: 4px;
    padding: 15px;
    display: flex;
    flex-direction: column;

    .image-loading {
      flex: 1;
      display: flex;
      align-items: center;
      justify-content: center;
      padding: 20px;
    }

    .image-container {
      flex: 1;
      position: relative;
      overflow: hidden;
      border: 1px solid #e6e6e6;
      border-radius: 4px;
      min-height: 400px;
      cursor: default;
      display: flex;
      align-items: center;
      justify-content: center;
      background-color: #f0f0f0;
      padding: 0;
      box-sizing: border-box;

      // 无效数据提示样式：醒目、不遮挡操作
      .invalid-data-tip {
        position: absolute;
        top: 20px;
        left: 20px;
        z-index: 99;
        background-color: rgba(255, 59, 48, 0.9);
        color: #fff;
        padding: 8px 16px;
        font-size: 16px;
        font-weight: 600;
        border-radius: 6px;
        pointer-events: none;
        box-shadow: 0 2px 8px rgba(0, 0, 0, 0.2);
      }

      // 画布承载图片，图片本身隐藏
      .label-image {
        display: none;
      }
    }

    .image-pagination {
      margin-top: 10px;
      font-size: 14px;
      color: #666;
      display: flex;
      justify-content: space-between;
      align-items: center;
    }
  }

  // 右侧分类标注结果展示区：适配审批场景的样式
  .label-result-area {
    width: 280px;
    background-color: #fff;
    border-radius: 4px;
    padding: 15px;
    border: 1px solid #e6e6e6;
    flex-shrink: 0;
    display: flex;
    flex-direction: column;

    .result-title {
      font-size: 16px;
      font-weight: 600;
      margin-bottom: 15px;
      padding-bottom: 8px;
      border-bottom: 1px solid #e6e6e6;
    }

    .result-content {
      flex: 1;
      overflow-y: auto;
      padding: 5px 0;

      .no-result, .invalid-result {
        text-align: center;
        padding: 30px 0;
        font-size: 14px;
      }

      .no-result {
        color: #999;
      }

      .invalid-result {
        color: #ff3b30;
        font-weight: 500;
      }

      .result-tag {
        padding: 8px 12px;
        background-color: #e6f7ff;
        border-radius: 4px;
        margin-bottom: 10px;
        font-size: 14px;
        color: #1890ff;
      }
    }
  }
}

// 审核不通过弹窗样式
.reject-dialog-content {
  padding: 10px 0;

  .reject-label {
    font-weight: normal;
    display: block;
    margin-bottom: 8px;
    font-size: 14px;
    color: #333;
  }

  .reject-textarea {
    width: 100%;
    box-sizing: border-box;
  }
}

// 滚动条样式优化
::v-deep .el-scrollbar__bar {
  width: 6px;
  height: 6px;
}

::v-deep .el-scrollbar__thumb {
  background-color: #ccc;
  border-radius: 3px;
}
</style>
