<template>
  <div class="card">
    <div class="header-container">
      <el-select v-model="currentPartitionCode" placeholder="请选择移动库区" @change="onPartitionChange">
        <el-option v-for="item in partitionList" :key="item.PartitionCode" :label="item.PartitionName" :value="item.PartitionCode" />
      </el-select>
      <div class="info-badge" v-if="targetPartitionName">
        目标库区：{{ targetPartitionName }}
      </div>
    </div>

    <div class="stock-list">
      <div class="stock-item" v-for="item in stockList" :key="item.StockCode" @click="onStockCardClick(item)">
        <div class="stock-header">
          <span class="stock-title">{{ item.StockName }}</span>
          <div class="stock-tags">
            <van-tag type="danger" v-if="item.TaskId != null">任务中</van-tag>
            <van-tag type="primary" v-if="item.StockStatus == false && !item.TrayNo">空库位</van-tag>
            <van-tag type="warning" v-if="item.StockStatus == false && item.TrayNo">空托盘</van-tag>
            <van-tag type="success" v-if="item.StockStatus == true">满料</van-tag>
          </div>
        </div>
        <div class="stock-info">
          <span><i class="iconfont icon-project"></i> 项目名称：<b>{{ item.ProjectNo || '无' }}</b></span>
          <span><i class="iconfont icon-product"></i> 间隔编号：<b>{{ item.IntervalNo || '无' }}</b></span>
          <span><i class="iconfont icon-model"></i> 部件位置：<b>{{ item.ComponentLocation || '无' }}</b></span>
          <span><i class="iconfont icon-tuopan"></i> 托盘编号：<b>{{ item.TrayNo || '无' }}</b></span>
        </div>
      </div>
    </div>

    <el-button style="position: fixed; bottom: 20px; right: 150px; z-index: 9999999;" type="warning" size="large"
      v-if="!moveDialogShow" @click="onUnbindClick">
      解绑产品
    </el-button>

    <el-button style="position: fixed; bottom: 20px; right: 20px; z-index: 9999999;" type="primary" size="large"
      v-if="!moveDialogShow" @click="onMoveBtnClick">
      一键移库
    </el-button>

    <el-dialog v-model="moveDialogShow" title="一键移库" width="90vw" :close-on-click-modal="false" class="move-dialog">
      <div class="target-info">
        <div>
          <span class="label">起始库区：</span>
          <span class="value">{{ currentPartitionName }}</span>
        </div>
        <div>
          <span class="label">目标库区：</span>
          <span class="value">{{ targetPartitionName }}</span>
        </div>
        <div>
          <span class="label">目标空库位数量：</span>
          <span class="value" :class="{ 'warning': targetEmptyStockCount < getFilledInputsCount() }">
            {{ targetEmptyStockCount }}个
            <span v-if="targetEmptyStockCount < getFilledInputsCount()" class="warning-text">
              (已填写{{ getFilledInputsCount() }}个{{ scanInputLabel }}，超出可用库位数量)
            </span>
          </span>
        </div>
      </div>
      <div class="scan-inputs">
        <div class="scan-item" v-for="(code, index) in materialCodes" :key="index">
          <el-input v-model="materialCodes[index]" :placeholder="`请扫描第${index + 1}个${scanInputLabel}`" clearable
            @input="onMaterialInput(index)" @keyup.enter="onInputEnter(index)">
            <template #prefix>
              <i class="el-icon-barcode"></i>{{ index + 1 }}：
            </template>
            <template #suffix>
              <el-button v-if="materialCodes[index]" icon="el-icon-close" circle plain size="small"
                @click="materialCodes[index] = ''"></el-button>
            </template>
          </el-input>
        </div>
      </div>
      <template #footer>
        <el-button @click="moveDialogShow = false">取消</el-button>
        <el-button type="primary" @click="onMoveConfirm" :disabled="!canSubmit()">确认移库</el-button>
      </template>
    </el-dialog>

    <el-dialog v-model="unbindDialogShow" title="解绑产品" width="320px" :close-on-click-modal="false">
      <el-form @submit.prevent>
        <el-form-item label="托盘码">
          <el-input v-model="unbindCode" placeholder="请扫描托盘码" clearable autofocus @keyup.enter="onUnbindConfirm" />
        </el-form-item>
      </el-form>
      <template #footer>
        <el-button @click="onUnbindCancel">取消</el-button>
        <el-button type="primary" @click="onUnbindConfirm">确认解绑</el-button>
      </template>
    </el-dialog>

    <!-- 选择一键移库的目标库区（来自关联表可能为多个） -->
    <el-dialog v-model="showMoveTargetPartitionDialog" title="选择目标库区" width="320px" :close-on-click-modal="false">
      <el-select v-model="selectedMoveTargetPartition" placeholder="请选择目标库区" style="width: 100%">
        <el-option v-for="item in moveTargetPartitionCandidates" :key="item.PartitionCode" :label="item.PartitionName" :value="item.PartitionCode" />
      </el-select>
      <template #footer>
        <el-button @click="showMoveTargetPartitionDialog = false">取消</el-button>
        <el-button type="primary" @click="onMoveTargetPartitionConfirm">确认</el-button>
      </template>
    </el-dialog>

    <!-- 空库位 -> 叫料：选择来源库位（来自当前库区的叫料库区） -->
    <el-dialog v-model="showCallMaterialDialog" :title="callDialogTitle" width="90vw" :close-on-click-modal="false" class="call-dialog">
      <div v-if="callMaterialStockList.length > 0">
        <div v-for="item in callMaterialStockList" :key="item.StockCode" @click="onCallMaterialStockClick(item)"
          style="cursor:pointer; border-bottom:1px solid #eee; padding:12px 0;">
          <div style="display:flex;flex-direction:column;">
            <span><b>库位名称：</b>{{ item.StockName }}</span>
            <span><b>项目名称：</b>{{ item.ProjectNo || '-' }}</span>
            <span><b>间隔编号：</b>{{ item.IntervalNo || '-' }}</span>
            <span><b>部件位置：</b>{{ item.ComponentLocation || '-' }}</span>
            <span><b>托盘编号：</b>{{ item.TrayNo || '-' }}</span>
          </div>
        </div>
      </div>
      <div v-else style="text-align:center;color:#888;">暂无可用库位</div>
    </el-dialog>
  </div>
</template>

<script setup>
import { v4 as uuidv4 } from 'uuid'
import { inject, onMounted, ref, computed } from 'vue'
import { ElMessage, ElMessageBox } from 'element-plus'
import { useAppStore } from '@/store/app.js'
import { storeToRefs } from 'pinia'
const store = useAppStore()
const { user } = storeToRefs(store)

const ExecDatabaseByParam = inject('ExecDatabaseByParam')
const ExecAgvApi = inject('ExecAgvApi')

// 库区数据
const partitionList = ref([]) // 当前工位可选库区（由 MES_计划BOM_工位与名称_库位编号_查询 得到）
const currentPartitionCode = ref('')
const currentPartitionName = ref('')
const targetPartitionCode = ref('')
const targetPartitionName = ref('')
const allPartitions = ref([]) // AGV 返回的所有库区，用于名称映射

// 库区内库位数据
const stockList = ref([])
// 目标库区空库位数据
const targetEmptyStocks = ref([])
const targetEmptyStockCount = ref(0)

// 移库对话框相关
const moveDialogShow = ref(false)
const materialCodes = ref(['', '', '', '', '', '']) // 六个输入框对应的物料码

// 空库位 -> 叫料相关
const showCallMaterialDialog = ref(false)
const callPartitionCode = ref('')
const callPartitionName = ref('')
const callMaterialStockList = ref([])
const currentEmptyStock = ref(null)
const callDialogTitle = ref('')

// 解绑产品
const unbindDialogShow = ref(false)
const unbindCode = ref('')

// 空支架区判定与扫描提示：切换整体移库逻辑到“空托盘模式”
const isEmptyFrameTarget = computed(() => targetPartitionName.value.includes('空支架区'))
// 扫描输入框的占位文本与提示
const scanInputLabel = computed(() => (isEmptyFrameTarget.value ? '托盘码' : '组合产品码'))
// 顶部提示、弹窗文案中用于描述当前操作主体
const headerActionLabel = computed(() => (isEmptyFrameTarget.value ? '托盘' : '物料'))

// 统一处理扫码字符串：去除首尾空格
const normalizeScanCode = (code) => (typeof code === 'string' ? code.trim() : '')
// 解析扫码结果：期望格式 “组合产品码”；若是托盘码则仅一段
const parseIntervalComponentFromScan = (code) => {
  const trimmed = normalizeScanCode(code)
  if (!trimmed) return { projectName: '', intervalNo: '', componentLocation: '', trayOnly: '' }
  const parts = trimmed.split('&')
  if (parts.length === 1) {
    return { projectName: '', intervalNo: '', componentLocation: '', trayOnly: trimmed }
  }
  if (parts.length !== 3) return { projectName: '', intervalNo: '', componentLocation: '', trayOnly: '' }
  const projectName = normalizeScanCode(parts[0])
  const intervalNo = normalizeScanCode(parts[1])
  const componentLocation = normalizeScanCode(parts[2])
  return { projectName, intervalNo, componentLocation, trayOnly: '' }
}

// 空托盘判断：用于空支架区移库与解绑校验
const isPureEmptyPallet = (stock) => {
  if (!stock) return false
  const hasTray = !!stock.TrayNo
  const noInterval = !stock.IntervalNo || stock.IntervalNo === ''
  const noComponent = !stock.ComponentLocation || stock.ComponentLocation === ''
  return hasTray && noInterval && noComponent && stock.StockStatus === false
}

// 库位升序排序（送料）：目标库位按 StockCode 从小到大（1 -> 8）
const compareStockAsc = (a, b) => {
  const codeA = parseInt(a.StockCode)
  const codeB = parseInt(b.StockCode)
  if (!isNaN(codeA) && !isNaN(codeB)) {
    return codeA - codeB
  }
  return a.StockCode.localeCompare(b.StockCode)
}

// 库位降序排序（取料）：源库位按 StockCode 从大到小（8 -> 1）
const compareStockDesc = (a, b) => {
  const codeA = parseInt(a.StockCode)
  const codeB = parseInt(b.StockCode)
  if (!isNaN(codeA) && !isNaN(codeB)) {
    return codeB - codeA
  }
  return b.StockCode.localeCompare(a.StockCode)
}

// 获取 AGV 全量库区列表
// 拉取全部库区：用于名称映射与目标库区显示
const fetchAllPartitions = async () => {
  const partitionRes = await ExecAgvApi('getPartitionList', {})
  if (partitionRes.Result) {
    allPartitions.value = partitionRes.Data || []
  } else {
    allPartitions.value = []
  }
}

// 依据工位，获取可选库区列表（逗号分隔的库区号）
// MES 工位配置 -> 获取可操作的库区列表
// 特殊：当返回 -1 时，说明是管理员账号，可操作所有库区
const isAdminUser = ref(false) // 管理员标识
const fetchWorkstationPartitions = async () => {
  const res = await ExecDatabaseByParam('11', 'MES_计划BOM_工位与名称_库位编号_查询', [['工位号', user.value.opName]])
  if (res.data && res.data.length > 0) {
    const codeStr = (res.data[0].库位编号 || '').toString().trim()
    
    // 判断是否为管理员（返回 -1）
    if (codeStr === '-1') {
      isAdminUser.value = true
      // 管理员：显示所有库区
      partitionList.value = allPartitions.value.map(p => ({
        PartitionCode: p.PartitionCode,
        PartitionName: p.PartitionName
      }))
    } else {
      isAdminUser.value = false
      // 普通用户：按配置的库区号过滤
      const codes = codeStr.split(',').map(s => s.trim()).filter(Boolean)
      partitionList.value = codes.map(code => {
        const p = allPartitions.value.find(x => x.PartitionCode == code)
        return { PartitionCode: code, PartitionName: p ? p.PartitionName : `库区${code}` }
      })
    }
    
    if (partitionList.value.length > 0) {
      currentPartitionCode.value = partitionList.value[0].PartitionCode
      currentPartitionName.value = partitionList.value[0].PartitionName
      await onPartitionChange(currentPartitionCode.value)
    } else {
      ElMessage.warning('此工位无对应库区!')
    }
  } else {
    ElMessage.warning('此工位无对应库区!')
  }
}

// 库区选择变更处理
// 切换源库区时重置界面状态并刷新库位信息
const onPartitionChange = async () => {
  if (!currentPartitionCode.value) return
  // 更新当前库区名称
  const currentPartition = partitionList.value.find(p => p.PartitionCode == currentPartitionCode.value)
  currentPartitionName.value = currentPartition ? currentPartition.PartitionName : ''
  // 清空先前选择的目标库区
  targetPartitionCode.value = ''
  targetPartitionName.value = ''
  // 获取源库区库位信息
  await fetchStockList()
}

// 获取源库区库位信息
// 拉取当前库区的全部库位数据
const fetchStockList = async () => {
  try {
    const res = await ExecAgvApi('getStockList', { PartitionCode: currentPartitionCode.value })
    if (res.Result) {
      // 过滤掉"无库位"的库位
      stockList.value = (res.Data || []).filter(item => item.StockName !== '无库位')
    } else {
      ElMessage.error(res.ErrMsg || '获取库位信息失败')
      stockList.value = []
    }
  } catch (error) {
    console.error('获取库位信息失败:', error)
    ElMessage.error('获取库位信息失败')
    stockList.value = []
  }
}

// 查询目标库区空库位并按序号排序（用于先进先出）
const fetchTargetEmptyStocks = async () => {
  try {
    const res = await ExecAgvApi('getStockList', { PartitionCode: targetPartitionCode.value })
    if (res.Result) {
      // 筛选空库位(无托盘且状态为空)并按StockCode升序排列（送料从小到大）
      targetEmptyStocks.value = (res.Data || [])
        .filter(i => !i.TrayNo && i.StockStatus === false && i.TaskId == null && i.StockName !== '无库位')
        .sort(compareStockAsc)
      targetEmptyStockCount.value = targetEmptyStocks.value.length
    } else {
      ElMessage.error(res.ErrMsg || '获取目标库区信息失败')
      targetEmptyStocks.value = []
      targetEmptyStockCount.value = 0
    }
  } catch (error) {
    console.error('获取目标库区信息失败:', error)
    ElMessage.error('获取目标库区信息失败')
    targetEmptyStocks.value = []
    targetEmptyStockCount.value = 0
  }
}

// 点击一键移库按钮
// 一键移库：先选择目标库区（当前库区可能对应多个目标库区）
const moveTargetPartitionCandidates = ref([])
const showMoveTargetPartitionDialog = ref(false)
const selectedMoveTargetPartition = ref('')

// 获取当前库区的一键移库目标库区候选列表
const fetchMoveTargetPartitionsForCurrent = async () => {
  moveTargetPartitionCandidates.value = []
  selectedMoveTargetPartition.value = ''
  
  // 管理员：可以移库到任意库区（排除当前库区）
  if (isAdminUser.value) {
    moveTargetPartitionCandidates.value = allPartitions.value
      .filter(p => p.PartitionCode != currentPartitionCode.value)
      .map(p => ({
        PartitionCode: p.PartitionCode,
        PartitionName: p.PartitionName
      }))
    if (moveTargetPartitionCandidates.value.length === 0) {
      ElMessage.warning('无可用目标库区')
    }
    return
  }
  
  // 普通用户：按配置的关联表查询
  const res = await ExecDatabaseByParam('11', 'PTCHV_AGV_一键移库关联_查询', [])
  if (!res.data || res.data.length === 0) {
    ElMessage.warning('未获取到移库关联数据')
    return
  }
  const row = res.data.find(r => (r.移动库区号 || '').toString() == currentPartitionCode.value)
  if (!row) {
    ElMessage.warning('当前库区未配置一键移库关联')
    return
  }
  let targets = (row.目标库区号 || '').toString()
  targets = targets.replace(/[()]/g, '')
  const codes = targets.split(',').map(s => s.trim()).filter(Boolean)
  moveTargetPartitionCandidates.value = codes.map(code => {
    const p = allPartitions.value.find(x => x.PartitionCode == code)
    return { PartitionCode: code, PartitionName: p ? p.PartitionName : `库区${code}` }
  })
}

const onMoveBtnClick = async () => {
  await fetchMoveTargetPartitionsForCurrent()
  if (moveTargetPartitionCandidates.value.length === 0) return
  showMoveTargetPartitionDialog.value = true
}

const onMoveTargetPartitionConfirm = async () => {
  if (!selectedMoveTargetPartition.value) {
    ElMessage.warning('请选择目标库区')
    return
  }
  targetPartitionCode.value = selectedMoveTargetPartition.value
  const p = moveTargetPartitionCandidates.value.find(i => i.PartitionCode == targetPartitionCode.value)
  targetPartitionName.value = p ? p.PartitionName : ''
  showMoveTargetPartitionDialog.value = false

  // 清空扫描输入
  materialCodes.value = ['', '', '', '', '', '']
  // 刷新目标库区空库位数据
  await fetchTargetEmptyStocks()
  // 打开移库对话框
  moveDialogShow.value = true
}

// 统计有效扫码数量（根据模式自动判断空字符串）
const getFilledInputsCount = () => {
  if (isEmptyFrameTarget.value) {
    return materialCodes.value.filter(code => normalizeScanCode(code) !== '').length
  }
  return materialCodes.value.filter(code => {
    const { projectName, intervalNo, componentLocation } = parseIntervalComponentFromScan(code)
    return !!projectName && !!intervalNo && !!componentLocation
  }).length
}

// 判断是否可以提交：至少一个有效扫码且不超可用空位
const canSubmit = () => {
  const filledCount = getFilledInputsCount()
  return filledCount > 0 && filledCount <= targetEmptyStockCount.value
}

// 输入框回车处理：快速定位下一个输入框
const onInputEnter = (index) => {
  // 如果当前输入框有值且不是最后一个，自动聚焦下一个输入框
  if (materialCodes.value[index] && index < materialCodes.value.length - 1) {
    const nextInput = document.querySelector(`.scan-item:nth-child(${index + 2}) input`)
    if (nextInput) {
      nextInput.focus()
    }
  }
}

// 确认移库：构建任务、排序并创建调度
const onMoveConfirm = async () => {
  const isTargetEmptyFrameArea = isEmptyFrameTarget.value

  const validEntries = materialCodes.value
    .map(code => normalizeScanCode(code))
    .filter(code => code !== '')

  if (validEntries.length === 0) {
    ElMessage.warning(`请至少扫描一个${scanInputLabel.value}`)
    return
  }

  if (validEntries.length > targetEmptyStockCount.value) {
    ElMessage.warning(`目标库区只有${targetEmptyStockCount.value}个空库位，当前扫描了${validEntries.length}个${scanInputLabel.value}`)
    return
  }

  const materialsToMove = []
  const missingCodes = []

  for (const code of validEntries) {
    let stock
    if (isTargetEmptyFrameArea) {
      stock = stockList.value.find(s => s.TrayNo === code)
    } else {
      const { projectName, intervalNo, componentLocation } = parseIntervalComponentFromScan(code)
      if (!projectName || !intervalNo || !componentLocation) {
        missingCodes.push(code)
        continue
      }
      stock = stockList.value.find(s => s.ProjectNo === projectName && s.IntervalNo === intervalNo && s.ComponentLocation === componentLocation)
    }

    if (!stock) {
      missingCodes.push(code)
      continue
    }

    if (stock.TaskId) {
      ElMessage.warning(`库位 ${stock.StockName} 存在未完成的任务，无法移库`)
      return
    }

    if (isTargetEmptyFrameArea && !isPureEmptyPallet(stock)) {
      ElMessage.warning(`托盘 ${code} 非空托盘，请先解绑后再移库`)
      return
    }

    materialsToMove.push(stock)
  }

  if (missingCodes.length > 0) {
    const label = isTargetEmptyFrameArea ? '托盘码' : '组合产品码'
    ElMessage.warning(`以下${label}在当前库区未找到：${missingCodes.join(', ')}`)
    return
  }

  try {
    await ElMessageBox.confirm(
      `确认将 ${materialsToMove.length} 个${scanInputLabel.value}从 ${currentPartitionName.value} 移库到 ${targetPartitionName.value}？`,
      '确认移库',
      {
        confirmButtonText: '确认',
        cancelButtonText: '取消',
        type: 'warning'
      }
    )

    const taskList = []
    const taskRecords = []

    // 取料从大到小（StockCode降序），送料从小到大（StockCode升序）
    const sortedSources = [...materialsToMove].sort(compareStockDesc)
    const sortedTargets = [...targetEmptyStocks.value].slice(0, sortedSources.length).sort(compareStockAsc)
    console.log('sortedSources', sortedSources)
    console.log('sortedTargets', sortedTargets)
    for (let i = 0; i < sortedSources.length; i++) {
      const source = sortedSources[i]
      const target = sortedTargets[i]

      if (!target) {
        ElMessage.warning('目标库位数量不足，请刷新后重试')
        return
      }

      const taskId = uuidv4()

      taskList.push({
        taskId,
        pickPosition: source.StockCode,
        dropPosition: target.StockCode
      })

      taskRecords.push([
        ['任务号', taskId],
        ['取料库位', source.StockCode],
        ['取料库位名称', source.StockName],
        ['取料项目名称', source.ProjectNo || ''],
        ['取料间隔编号', source.IntervalNo || ''],
        ['取料部件位置', source.ComponentLocation || ''],
        ['取料托盘编号', source.TrayNo || ''],
        ['送料库位', target.StockCode],
        ['送料库位名称', target.StockName],
        ['操作人', user.value.name],
        ['type', 4],
      ])
    }
    console.log(taskList)
    console.log(taskRecords)

    const res = await ExecAgvApi('oneclickinstock', { list: taskList })
    if (res.Result) {
      for (const record of taskRecords) {
        await ExecDatabaseByParam('12', 'PTCHV_AGV_送料记录_增加', record)
      }

      ElMessage.success(`成功创建 ${taskList.length} 个移库任务`)
      moveDialogShow.value = false

      fetchStockList()
    } else {
      ElMessage.error(res.ErrMsg || '创建移库任务失败')
    }
  } catch (e) {
    console.log('用户取消移库操作')
  }
}

const onMaterialInput = (index) => {
  const raw = materialCodes.value[index]
  materialCodes.value[index] = normalizeScanCode(raw)
}

// 解绑产品：扫描托盘码后清空当前库区对应库位的物料信息（保留托盘号）
const onUnbindClick = () => {
  if (!currentPartitionCode.value) {
    ElMessage.warning('请先选择移动库区')
    return
  }
  unbindCode.value = ''
  unbindDialogShow.value = true
}

// 关闭解绑弹窗
const onUnbindCancel = () => {
  unbindDialogShow.value = false
}

// 执行解绑：根据托盘码找到库位，清空物料信息（项目名称、间隔编号、部件位置），保留托盘号
const onUnbindConfirm = async () => {
  const trayCode = normalizeScanCode(unbindCode.value)
  if (!trayCode) {
    ElMessage.warning('请输入托盘码')
    return
  }

  // 根据托盘码查找库位
  const stock = stockList.value.find(s => s.TrayNo === trayCode)
  if (!stock) {
    ElMessage.warning(`托盘码 ${trayCode} 在当前库区未找到`)
    return
  }

  if (stock.TaskId) {
    ElMessage.warning(`库位 ${stock.StockName} 存在未完成的任务，无法解绑`)
    return
  }

  // 检查是否有产品信息可以解绑
  if (!stock.ProjectNo && !stock.IntervalNo && !stock.ComponentLocation) {
    ElMessage.warning(`托盘 ${trayCode} 当前没有绑定产品信息，无需解绑`)
    return
  }

  try {
    await ElMessageBox.confirm(
      `确认将托盘 ${trayCode} 从库位 ${stock.StockName} 解绑产品信息？\n项目名称：${stock.ProjectNo || '-'}\n间隔编号：${stock.IntervalNo || '-'}\n部件位置：${stock.ComponentLocation || '-'}`,
      '确认解绑',
      {
        confirmButtonText: '确认',
        cancelButtonText: '取消',
        type: 'warning'
      }
    )

    const res = await ExecAgvApi('updateStockInfo', {
      StockCode: stock.StockCode,
      TrayNo: stock.TrayNo, // 保留托盘号
      ProjectNo: null,      // 清空项目名称
      IntervalNo: null,     // 清空间隔编号
      ComponentLocation: null, // 清空部件位置
      StockStatus: false,   // 状态改为空
      TaskId: stock.TaskId,
    })

    if (res.Result) {
      await ExecDatabaseByParam('12', 'PTCHV_AGV_库位更新记录_增加', [
        ['库位号', stock.StockCode],
        ['库位名称', stock.StockName || ''],
        ['项目名称', ''],
        ['间隔编号', ''],
        ['部件位置', ''],
        ['托盘编号', stock.TrayNo || ''],
        ['项目名称_old', stock.ProjectNo || ''],
        ['间隔编号_old', stock.IntervalNo || ''],
        ['部件位置_old', stock.ComponentLocation || ''],
        ['托盘编号_old', stock.TrayNo || ''],
        ['操作人', user.value.name],
        ['type', 2],
      ])
      ElMessage.success('解绑成功')
      await fetchStockList()
    } else {
      ElMessage.error(res.ErrMsg || '解绑失败')
    }
  } catch (e) {
    console.log('用户取消解绑操作')
  }

  unbindDialogShow.value = false
}

onMounted(async () => {
  await fetchAllPartitions()
  await fetchWorkstationPartitions()
})

// 点击库位卡片：空库位 -> 叫料
const onStockCardClick = async (item) => {
  // 仅空库位（无托盘、无物料）支持叫料
  const isEmptySlot = (!item.TrayNo) && (item.StockStatus === false)
  if (!isEmptySlot) return

  currentEmptyStock.value = item

  // 查询预设路线，拿到叫料库区（此模块按库区号传入“库位号”参数）
  try {
    const routeRes = await ExecDatabaseByParam('11', 'PTCHV_AGV_送料路线_PDA查询_初始化', [['库位号', currentPartitionCode.value]])
    if (!routeRes.data || routeRes.data.length === 0 || !routeRes.data[0].叫料库区) {
      ElMessage.warning('未配置该库区叫料路线')
      return
    }
    callPartitionCode.value = routeRes.data[0].叫料库区
    const part = allPartitions.value.find(p => p.PartitionCode == callPartitionCode.value)
    callPartitionName.value = part ? part.PartitionName : `库区${callPartitionCode.value}`
    callDialogTitle.value = `${callPartitionName.value} 库区叫料`

    // 拉取叫料库区的库位列表
    const stockRes = await ExecAgvApi('getStockList', { PartitionCode: callPartitionCode.value })
    if (!stockRes.Result) {
      ElMessage.error(stockRes.ErrMsg || '获取库位失败')
      return
    }

    // 过滤：空库位不可叫；允许 空托盘 或 满料（且无任务更稳妥）；排除"无库位"
    const isEmptyPallet = (s) => s.TrayNo && (!s.IntervalNo || s.IntervalNo === '') && (!s.ComponentLocation || s.ComponentLocation === '') && s.StockStatus === false
    const isFull = (s) => s.StockStatus === true
    
    // 判断来料库区是否为空支架区
    const isFromEmptyFrameArea = callPartitionName.value.includes('空支架区')
    
    let filteredList = (stockRes.Data || [])
      .filter(s => !s.TaskId && s.StockName !== '无库位' && (isEmptyPallet(s) || isFull(s)))
    
    // 如果来料库区是空支架区，只显示空托盘（但显示所有空托盘，点击时再校验）
    if (isFromEmptyFrameArea) {
      // 只保留空托盘，排序后显示所有
      const emptyPallets = filteredList.filter(s => isEmptyPallet(s))
      if (emptyPallets.length === 0) {
        ElMessage.warning('空支架区没有可用的空托盘')
        return
      }
      // 按 StockCode 降序排序，方便用户识别哪个是最外侧的
      emptyPallets.sort(compareStockDesc)
      callMaterialStockList.value = emptyPallets // 显示所有空托盘
    } else {
      callMaterialStockList.value = filteredList
    }

    if (callMaterialStockList.value.length === 0) {
      ElMessage.warning('目标叫料库区没有可调用的库位')
      return
    }

    showCallMaterialDialog.value = true
  } catch (e) {
    console.error('获取路线信息失败:', e)
    ElMessage.error('获取路线信息失败')
  }
}

// 选择来源库位后，创建叫料任务
const onCallMaterialStockClick = (source) => {
  // 如果来料库区是空支架区，校验是否选择了序号最大的空托盘（最外侧）
  const isFromEmptyFrameArea = callPartitionName.value.includes('空支架区')
  if (isFromEmptyFrameArea) {
    // 从当前显示列表中找出所有空托盘
    const isEmptyPallet = (s) => s.TrayNo && (!s.IntervalNo || s.IntervalNo === '') && (!s.ComponentLocation || s.ComponentLocation === '') && s.StockStatus === false
    const allEmptyPallets = callMaterialStockList.value.filter(s => isEmptyPallet(s))
    if (allEmptyPallets.length > 0) {
      // 按 StockCode 降序排序，找出序号最大的（最外侧的）
      allEmptyPallets.sort(compareStockDesc)
      const maxStock = allEmptyPallets[0]
      if (source.StockCode !== maxStock.StockCode) {
        ElMessage.warning(`空支架区只能选择最外侧的空托盘：${maxStock.StockName}`)
        return
      }
    }
  }
  
  ElMessageBox.confirm(`是否将物料从库位【${source.StockName}】送至库位【${currentEmptyStock.value.StockName}】？`, '确认叫料', {
    confirmButtonText: '确认',
    cancelButtonText: '取消',
    type: 'warning'
  }).then(async () => {
    const taskId = uuidv4()
    const res = await ExecAgvApi('createTask', {
      taskId,
      pickPosition: source.StockCode,
      dropPosition: currentEmptyStock.value.StockCode,
    })
    if (res.Result) {
      await ExecDatabaseByParam('12', 'PTCHV_AGV_送料记录_增加', [
        ['任务号', taskId],
        ['取料库位', source.StockCode],
        ['取料库位名称', source.StockName],
        ['取料项目名称', source.ProjectNo || ''],
        ['取料间隔编号', source.IntervalNo || ''],
        ['取料部件位置', source.ComponentLocation || ''],
        ['取料托盘编号', source.TrayNo || ''],
        ['送料库位', currentEmptyStock.value.StockCode],
        ['送料库位名称', currentEmptyStock.value.StockName],
        ['操作人', user.value.name],
        ['type', 1],
      ])
      ElMessage.success('叫料任务创建成功')
      showCallMaterialDialog.value = false
      await fetchStockList()
    } else {
      ElMessage.error(res.ErrMsg || '叫料任务创建失败')
    }
  }).catch(() => {})
}
</script>

<style lang="scss" scoped>
.call-dialog {
  :deep(.el-dialog__body) {
    max-height: 60vh;
    overflow-y: auto;
    padding-top: 8px;
  }
}
.card {
  background: #fff;
  border-radius: 12px;
  box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
  padding: 16px;
  // height: calc(100vh - 40px);
  overflow-y: auto;
  position: relative;
}

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

.info-badge {
  padding: 6px 12px;
  background-color: #ecf5ff;
  color: #409eff;
  border-radius: 4px;
  font-size: 14px;
}

.stock-list {
  display: flex;
  flex-wrap: wrap;
  gap: 16px;
  margin-bottom: 60px;
}

.stock-item {
  background: #f8f8f8;
  border-radius: 10px;
  padding: 12px;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
  flex: 1 1 280px;
  min-width: 280px;
  max-width: 320px;
}

.stock-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 8px;
  border-bottom: 1px solid #eee;
  padding-bottom: 6px;
}

.stock-title {
  font-weight: bold;
  font-size: 16px;
}

.stock-tags {
  display: flex;
  gap: 4px;
}

.stock-info {
  display: flex;
  flex-direction: column;
  gap: 8px;

  span {
    display: flex;
    gap: 4px;
    align-items: center;

    i {
      color: #409eff;
    }

    b {
      margin-left: 4px;
    }
  }
}

.move-dialog {
  .target-info {
    background: #f8f8f8;
    border-radius: 6px;
    padding: 12px;
    margin-bottom: 16px;
    display: flex;
    flex-wrap: wrap;
    gap: 8px;

    > div {
      display: flex;
      align-items: center;
      width: 100%;
      gap: 8px;
    }

    .label {
      font-weight: bold;
      color: #666;
      width: 40%;
    }

    .value {
      color: #333;
      width: 50%;

      &.warning {
        color: #e6a23c;
      }

      .warning-text {
        color: #f56c6c;
        font-size: 12px;
      }
    }
  }

  .scan-inputs {
    display: grid;
    grid-template-columns: repeat(2, 1fr);
    gap: 16px;

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

    .scan-item {
      .el-input {
        width: 100%;
      }
    }
  }
}
</style>
