<template>
  <view>
    <navbar-back :autoBack="false" titleWidth="800" :title="title" @leftClick="customBack">
      <view class="navbar-right" @click="navRightClick">
        <text>填写任务单</text>
        <u-icon color="" name="edit-pen" size="19"></u-icon>
      </view>
    </navbar-back>

    <u-row gutter="8">
      <u-col span="3" style="height: 60px">
        <up-tabs
          class="content-tabs"
          :current="activeAssayTypeIndex"
          :list="assayGroups"
          lineColor="#5ac725"
          :activeStyle="{
            fontWeight: 'bold',
            color: '#0055a2'
          }"
          :itemStyle="{
            height: '35px'
          }"
          @change="handleAssayTypeChange"
        ></up-tabs>
        <u-gap height="5" bg-color="#0055A2"></u-gap>
      </u-col>
      <u-col span="6" style="height: 60px">
        <view class="content-title-name">
          <view class="current-sample-code">{{ currentSampleData.sampleCode }}</view>
          <view>数据采集或录入</view>
        </view>
        <u-gap height="5" bg-color="#0055A2"></u-gap>
      </u-col>
      <u-col span="3" style="height: 60px">
        <u-dropdown>
          <u-dropdown-item
            v-model="curParameterKey"
            :title="curParameterTitle"
            height="70vh"
            :options="fieldGroup"
            @change="parameterClassifyChange"
          ></u-dropdown-item>
        </u-dropdown>
        <u-gap height="5" bg-color="#0055A2"></u-gap>
      </u-col>
    </u-row>
    <u-row gutter="8" align="top">
      <u-col span="3">
        <scroll-view class="content-left-scroll" scroll-with-animation scroll-y :scroll-top="scrollTop">
          <view
            v-for="(sample, index) in sampleDataList"
            :key="index"
            class="u-tab-item"
            :class="[currentSampleIndex === index ? 'u-tab-item-active' : '']"
            :data-current="index"
            @tap.stop="switchSample(index)"
          >
            <u-badge type="warning" :value="index + 1"></u-badge>
            <view class="ml20">
              <view>
                {{ sample.sampleCode }}
              </view>
              <view class="mt10"> {{ sample.sampleName }} </view>
            </view>
          </view>
        </scroll-view>
        <view v-if="taskIsIngredients == 1" class="x-f">
          <template v-if="taskIngredientsWay === 'initial'">
            <u-button class="btn-operation mr10" type="primary" @click="handleIngredients()">自动配料</u-button>
            <u-button class="btn-operation ml10" type="primary" @click="handleManualIngredients()">人工配料</u-button>
          </template>
          <template v-else>
            <u-button
              v-if="taskIngredientsStatus === 'allow_submit'"
              class="btn-operation"
              type="primary"
              @click="submitTask()"
              >数据上报</u-button
            >
            <u-button v-else class="btn-operation" type="primary" :disabled="taskIngredientsStatus === 'in_progress'"
              >等待配料</u-button
            >
          </template>
        </view>
        <u-button v-else class="btn-operation" type="primary" @click="submitTask()">数据上报</u-button>
      </u-col>
      <u-col span="6">
        <view class="x-bc">
          <view class="field-name" v-html="selectedField.title" />
          <u-button
            v-if="fillingWay.length > 1"
            type="primary"
            shape="circle"
            plain
            size="small"
            style="width: 15%"
            :text="`切换${currentFillingWay == 'collect' ? '录入' : '采集'}`"
            @click="switchFillingWay"
          ></u-button>
        </view>
        <zzjc-num-keyboard
          ref="myKeyboard"
          v-show="currentFillingWay == 'keyboard' || (selectedField.type == 'project' && selectedField.isEdit)"
          :showSymbol="selectedField.type == 'project' && selectedField.isEdit"
          :numKeyboardParam="numKeyboardParam"
        ></zzjc-num-keyboard>
        <view v-if="currentFillingWay == 'collect'" class="y-f">
          <view class="auncel" @click="selectAuncel">
            <view class="code">{{ currentAuncel.code }}</view>
            <view class="auncel-title"> 杯号：{{ currentCupNum }} </view>
            <view class="auncel-weight">
              <view class="weight">
                <view
                  :style="{ textAlign: !currentAuncel.isConnected ? 'center' : 'right' }"
                  :class="
                    currentAuncel.weightStable === 0
                      ? 'weight-data-yellow'
                      : currentAuncel.weightStable === 1
                      ? 'weight-data'
                      : 'weight-data-warning'
                  "
                >
                  {{ currentAuncel.weightData }}
                </view>
              </view>
              <view class="weight-unit">{{ currentAuncel.weightUnit }}</view>
            </view>
          </view>

          <u-button
            class="btn-operation"
            type="success"
            :disabled="confirmWeightDisabled"
            shape="circle"
            @click="saveAuncelData"
          >
            确认采集
          </u-button>
        </view>
        <view v-if="currentFillingWay === 'input'" class="p8">
          <up-textarea v-model="inputValue" placeholder="请输入内容"></up-textarea>
          <view class="x-c mt20 pl100 pr100">
            <up-button @click="handleResetInputValue" style="width: 30%" :plain="true" text="清空"></up-button>
            <up-button @click="handleInputConfirm" style="width: 30%" type="success" text="确认"></up-button>
          </view>
        </view>
      </u-col>
      <u-col span="3">
        <view class="pt10">
          <scroll-view class="content-right-scroll" scroll-y scroll-with-animation :scroll-top="scrollFieldTop">
            <view>
              <up-collapse ref="collapseRef" :value="activeCollapses" :border="false">
                <template v-for="(fields, groupIndex) in currentGroup">
                  <up-collapse-item v-if="fields.label !== '全部'">
                    <template #title>
                      <text class="font-bold fs18">{{ fields.label }}</text>
                    </template>
                    <template v-for="(field, fieldIndex) in fields.fields" :key="groupIndex + '-' + fieldIndex">
                      <view
                        class="form-item-my"
                        @click="fieldClick(field, groupIndex + '-' + fieldIndex)"
                        v-show="field.hidden != 1"
                        :class="{
                          'selected-field': groupFieldIndex === groupIndex + '-' + fieldIndex,
                          'disabled-field': !field.isEdit,
                          'flex-column': field.dataType === 'datetime'
                        }"
                      >
                        <view
                          :class="['label-my', { 'label-high-light': field.highlight == 1 }]"
                          v-html="field.title"
                        ></view>
                        <view class="content-my">
                          <!--普通输入框 使用文本显示-->
                          <view class="content-my-text" v-if="field.dataType != 'select'">
                            <text v-if="!field.value" class="content-my-text-placeholder">{{
                              !field.fillingWay || field.fillingWay == 'calculate'
                                ? '计算值'
                                : field.fillingWay == 'datetime'
                                ? '请选择时间'
                                : '请输入'
                            }}</text>
                            <text
                              v-else
                              :class="['content-my-text-value', { 'field-high-light': field.highlight == 1 }]"
                              ><text v-if="field.symbol !== '='" class="mr5">{{ field.symbol }}</text
                              >{{ field.value }}</text
                            >
                          </view>
                        </view>
                      </view>
                      <view
                        v-if="field.validation"
                        class="fs12"
                        :class="field.validation?.promptType === 'warning' ? 'valid-warning' : 'valid-error'"
                        >{{ field.validation?.promptMsg }}</view
                      >
                    </template>
                  </up-collapse-item>
                </template>
              </up-collapse>
            </view>
          </scroll-view>
          <u-button class="btn-operation" type="success" @click="saveDetail()">保存样品数据</u-button>
        </view>
      </u-col>
    </u-row>
    <up-datetime-picker
      :show="dateTimeShow"
      v-model="dateTimeDefaultValue"
      @confirm="handleDateConfirm"
      @cancel="dateTimeShow = false"
      mode="datetime"
    ></up-datetime-picker>
    <!--    天平选择-->
    <auncel-select-popup
      ref="auncelSelector"
      v-model:showAuncelSelector="showAuncelSelector"
      :previousAuncelId="currentAuncel.id"
      @doSelect="auncelDoSelect"
    ></auncel-select-popup>
  </view>
</template>

<script setup>
import { ref, reactive, computed, nextTick, watch, getCurrentInstance } from 'vue'
import { onLoad, onBackPress, onShow, onHide, onUnload } from '@dcloudio/uni-app'
import request from '@/nx/request'
import {
  calcAnalysisValue,
  handleRoundFiveNumber,
  calcRowAnalysisValue,
  evaluateGetFromFormula,
  math,
  groupByField,
  validateElementRange
} from '@/nx/helper/calcAnalysisValue'
import { number } from 'mathjs'
import AuncelSelectPopup from '@/components/sample/auncel-select-popup.vue'
import { getTenantId } from '@/defaultBaseUrl'
import { useScreenOrientation } from '@/nx/hooks/useScreenOrientation'
import nx from '@/nx'
import { getDataSourceTypeShow } from '../common'
import tools from '@/nx/utils/tools'

const { proxy } = getCurrentInstance()

// 响应式数据定义
const taskId = ref('')
const taskIngredientsStatus = ref('') //配料状态
const taskIsIngredients = ref('')
const taskIngredientsWay = ref('')
const configReportTemplateKey = ref('')
const elId = nx.$helper.uuid()
const scrollTop = ref(0) //tab标题的滚动条位置
const scrollFieldTop = ref(0)
const menuHeight = ref(0) // 左边菜单的高度
const menuItemHeight = ref(0) // 左边菜单item的高度
const weightDataIsToZero = ref(false) //重量数据是否归零
const currentSampleIndex = ref(0) // 预设当前项的值
let sampleDataList = ref([])
const title = ref('')
const numKeyboardParam = reactive({
  decimal: '-1' //数字键盘小数位数，-1为不限制
})
const showAuncelSelector = ref(false) //显示天平选择框
const currentAuncel = ref({
  id: '',
  name: '',
  code: '',
  weightStable: 0,
  weightData: '请选天平',
  weightUnit: ''
})
let selectedField = ref({})
const groupFieldIndex = ref('') //分组的索引
const curParameterTitle = ref('选择字段分类')
const curParameterKey = ref('all')
const conAssayTaskId = ref('')
const busSubCSampleId = ref('')
let fieldGroup = ref([])
const collaHeights = ref([])
const cupNumKey = '杯号'
const inputValue = ref('')
const dateTimeShow = ref(false)
const dateTimeDefaultValue = ref(new Date())

function handleResetInputValue() {
  inputValue.value = ''
}
// refs
const myKeyboard = ref(null)
const auncelSelector = ref(null)

// 计算属性
const confirmWeightDisabled = computed(() => {
  if (currentAuncel.value.weightStable === 1 && Number(currentAuncel.value.weightData) > 0) {
    return false
  }
  return true
})

const userInfo = computed(() => nx.$store('user').userInfo)

// 方法定义
const getDomHeight = async () => {
  await nextTick() // 等待 DOM 更新完成
  collaHeights.value = []
  if (fieldGroup.value.length) {
    fieldGroup.value.forEach((item, index) => {
      proxy.$u.getRect('#elId' + index).then(res => {
        collaHeights.value.push(res.height)
      })
    })
  }
}

//返回上一页
const customBack = () => {
  uni.redirectTo({
    url: '/pages/analysis/sample/sample-work-list'
  })
}

const navRightClick = () => {
  let url = `/pages/analysis/sample/sample-work-edit-task?currentTaskId=${taskId.value}&configReportTemplateKey=${configReportTemplateKey.value}`
  uni.navigateTo({
    url: url
  })
}

const parameterClassifyChange = v => {
  curParameterKey.value = v
  curParameterTitle.value = currentGroup.value[0].label
  groupFieldIndex.value = ''
  selectedField.value = {}
  nextTick(() => {
    collapseRef.value.init()
  })
  autoNextField()
}

function handleInputConfirm() {
  selectedField.value.value = inputValue.value
  syncFieldValueByEqualParamNo()
  autoNextField()
}
function handleDateConfirm(e) {
  selectedField.value.value = nx.$dayjs(e.value).format('YYYY-MM-DD HH:mm:ss')
  dateTimeShow.value = false
  autoNextField()
}
const fieldClick = (field, key) => {
  if (!field.isEdit) return
  currentFillingIndex.value = 0
  selectedField.value = field
  groupFieldIndex.value = key
  if (currentFillingWay.value === 'input') {
    inputValue.value = field.value
  }
  if (currentFillingWay.value === 'datetime') {
    dateTimeShow.value = true
  }
  if (myKeyboard.value) {
    myKeyboard.value.clearNum()
  }
  //判断小数位数
  let decimalPosition = field.decimalPosition
  if (decimalPosition == null || decimalPosition < -1) decimalPosition = -1
  numKeyboardParam.decimal = decimalPosition
}

const currentFillingIndex = ref(0)
const fillingWay = computed(() => {
  if (selectedField.value.fillingWay) {
    return selectedField.value.fillingWay.split(',')
  } else {
    return []
  }
})
const currentFillingWay = computed(() => {
  return fillingWay.value[currentFillingIndex.value] || ''
})
watch(
  () => currentFillingWay.value,
  newVal => {
    if (newVal == 'collect') {
      listenDeviceData()
    } else {
      closeDeviceListener()
    }
  }
)
const switchFillingWay = () => {
  currentFillingIndex.value = (currentFillingIndex.value + 1) % fillingWay.value.length
}
//自动切换到下一个字段
const autoNextField = () => {
  let groupIndex = 0
  let fieldIndex = 0
  if (typeof groupFieldIndex.value === 'undefined' || groupFieldIndex.value === '') groupFieldIndex.value = '0-'
  const indexV = groupFieldIndex.value.split('-')
  groupIndex = number(indexV[0])
  fieldIndex = indexV[1] === '' ? -1 : number(indexV[1])
  const group = currentGroup.value[groupIndex]
  const fields = group.fields
  if (fields.length > fieldIndex + 1) {
    //切换到下一个字段
    const key = groupIndex + '-' + (fieldIndex + 1)
    fieldClick(fields[fieldIndex + 1], key)
  }
}

//自动切换到下一个样品
const autoNextSample = indexParam => {
  let index = 0
  if (indexParam !== undefined) {
    index = indexParam
  } else {
    index = currentSampleIndex.value + 1
  }

  // 在数组范围内，且当前样品是 in_progress，就继续往后找
  while (index < sampleDataList.value.length) {
    const sample = sampleDataList.value[index]

    if (sample.rollbackStatus !== 'in_progress') {
      // 找到了合法的样品，切换
      switchSample(index)
      return
    }
    index++
  }
}

//手动切换样品
const switchSample = async index => {
  //重置天平归0
  weightDataIsToZero.value = false
  if (index === currentSampleIndex.value) return
  currentSampleIndex.value = index
  // 如果为0，意味着尚未初始化
  if (menuHeight.value === 0 || menuItemHeight.value === 0) {
    const rect = await getElRect('u-tab-item')
    menuItemHeight.value = rect.height
  }
  // 将菜单菜单活动item垂直居中
  scrollTop.value = index * menuItemHeight.value + menuItemHeight.value / 2 - menuHeight.value / 2 - 50
  uni.showLoading({ title: '加载中...' })

  setValueToField()
  autoGenerateCupNum()
  setTimeout(() => {
    uni.hideLoading()
  }, 500)
}

// 获取一个目标元素的高度
const getElRect = (elClass, maxRetry = 50) => {
  return new Promise((resolve, reject) => {
    let retryCount = 0
    const execQuery = () => {
      uni
        .createSelectorQuery()
        .in(proxy)
        .select('.' + elClass)
        .fields({ size: true, rect: true })
        .exec(res => {
          const result = res[0] // exec 返回数组，取第一个
          if (result) {
            resolve(result)
          } else if (retryCount < maxRetry) {
            retryCount++
            setTimeout(execQuery, 10)
          } else {
            reject(new Error(`无法获取元素 .${elClass} 的尺寸，已重试 ${maxRetry} 次`))
          }
        })
    }

    execQuery()
  })
}

//读取样品明细字段
const getDetailFieldsAndStatus = autoSelectNextField => {
  const taskDetailId = currentSampleData.value.id
  //读取回收率配置
  loadConRecoveryList()
  conAssayTaskId.value = res.additionalProperties.conAssayTaskId
  busSubCSampleId.value = res.additionalProperties.busSubCSampleId
  const detail = res.additionalProperties.taskDetail
  //处理硫值、硫量：未保存过的数据，读取接口返回的硫值、硫量
  loadSValue(detail)
  calAndCheck()
}

const checkLoadSValue = () => {
  const vKey = 'sRange'
  const vF = getFieldByKey(vKey)
  if (vF === null) return false
  const v = vF.value
  if (v === null || v === '') return true
  try {
    if (v === 0 || number(v) === 0) return true
  } catch (e) {}
  return false
}

//读取硫值、硫量
const loadSValue = detail => {
  let flag = checkLoadSValue()
  if (!flag) return
  const vKey = 'sValue'
  const rKey = 'sRange'
  const vF = getFieldByKey(vKey)
  if (vF !== null) {
    vF.value = detail.svalue
  }
  const rF = getFieldByKey(rKey)
  if (rF !== null) {
    rF.value = detail.srange
  }
}

const getFieldByKey = key => {
  const group = fieldGroup.value
  let field = null
  for (let g of group) {
    for (let f of g.fields) {
      const dicKey = f.dicKey
      if (dicKey && dicKey === key) {
        field = f
        break
      }
    }
  }
  return field
}

//按公式计算值，并检查原数据与计算后的数据是否一致
const calAndCheck = () => {
  //提取原本数值
  const oldVal = fitUpValues()
  calcAnalysisValue(fieldGroup.value)
  if (checkDataNew(oldVal)) return
  const newVal = fitUpValues(oldVal)
  //检查是否一致
  let modifyFlag = false
  for (const o in oldVal) {
    let old = oldVal[o]
    if (old === null) old = 0
    //判断是否number
    try {
      if (number(old) !== number(newVal[o])) {
        modifyFlag = true
      }
    } catch (e) {
      if (old !== newVal[o]) modifyFlag = true
    }
  }
  if (modifyFlag)
    uni.showToast({
      title: '数据有修改，请检查所有样品，并重新保存！',
      duration: 2000,
      icon: 'error'
    })
}

//检查是否是新数据
const checkDataNew = data => {
  for (const o in data) {
    if (data[o] !== null && data[o] !== '0') return false
  }
  return true
}

//组装表单值，用于数据比对
const fitUpValues = () => {
  const val = {}
  for (const g of fieldGroup.value) {
    for (const f of g.fields) {
      const detailId = f.detailId
      if (!detailId) continue
      val[detailId] = f.value
    }
  }
  return val
}

const checkBh = () => {
  //检查杯号
  let hasHb = true
  for (const g of fieldGroup.value) {
    for (const f of g.fields) {
      if (f.title && f.title.indexOf(cupNumKey) >= 0 && f.hidden != 1) {
        if (typeof f.value === 'undefined' || f.value === null || f.value === '') hasHb = false
      }
    }
  }
  if (!hasHb) {
    nx.$helper.showToast({
      title: '杯号不能为空，请填写杯号！'
    })
    return false
  }
  return true
}
const checkRange = async () => {
  for (const g of fieldGroup.value) {
    for (const f of g.fields) {
      if (f.validation) {
        if (f.validation.promptType === 'error') {
          nx.$helper.showToast({
            title: '存在范围校验错误，请修正后再保存！',
            icon: 'error',
            duration: 2000
          })
          return false
        }
        if (f.validation.promptType === 'warning') {
          const confirm = await tools.showPromiseModal('提示', '检测到范围警告，是否继续保存？')
          return confirm
        }
      }
    }
  }
  return true // 无问题，通过
}
const saveAuncelData = () => {
  //保存数据
  if (!weightDataIsToZero.value) {
    nx.$helper.showToast({
      title: '天平必须先回零！'
    })
    return
  }
  //获取当前重量
  let weight = currentAuncel.value.weightData
  selectedField.value.value = weight

  syncFieldValueByEqualParamNo()
  //计算
  try {
    calcAnalysisValue(fieldGroup.value, dynamicFormData, taskIngredientsWay.value)
  } catch (e) {
    console.error(e)
  }

  //自动跳转下一个字段
  setTimeout(() => {
    autoNextField()
    weightDataIsToZero.value = false
  }, 100)
}
let dynamicFormData = reactive({})
const saveDetail = async () => {
  //检查杯号
  if (!checkBh()) return
  // 检查范围校验
  if (!(await checkRange())) return
  setValueToSample()
  let params = {
    businessAssayTaskId: taskId.value
  }

  // 如果是空白样和标样就需要根据配置信息来计算质控样、分析样
  if (activeAssayTypeKey.value === 'kby' || activeAssayTypeKey.value === 'by' || activeAssayTypeKey.value === 'zkkby') {
    // 处理其他页签的输入变化
    const configInfomation = currentAssayType.value.configQCSampleMethodInfo
    const row = currentSampleData.value
    configInfomation.forEach(item => {
      const sourceKey = item.source
      const sourceValue = row[sourceKey]
      if (sourceValue !== undefined) {
        if (item.calcMethod === 'calculateAverageValue') {
          item.value = calcAverageValue(sourceKey, currentAssayType.value.tableData)
        } else {
          item.value = handleRoundFiveNumber(row[sourceKey].value, row.decimalPosition)
        }
        // 如果处理后的值不为空，重新赋值该字段到其他样品类型下的样品上，并触发每一个样品的计算
        for (const col of currentAssayType.value.columns) {
          if (col.hidden != 1 && col.fieldIndex === sourceKey) {
            if (item.value) {
              dynamicFormData[item.target] = item.value
            } else {
              dynamicFormData[item.target] = row[sourceKey].value
            }
          }
        }
        updateTableDataByConfigFields()
      }
    })
    params.formValue = JSON.stringify(dynamicFormData)
    params.assayTaskAnalysisDataList = assayGroups.value.map(item => ({
      datas: item.tableData,
      analysisType: item.value
    }))
  } else {
    const datas = currentSampleData.value
    params.assayTaskAnalysisDataList = [{ datas: [datas], analysisType: activeAssayTypeKey.value }]
  }

  await nx.$api.assayTask.saveBatchSmpleAndQcAnalysis(params)
  // getSampleAnalysisByTaskId()
  autoNextSample()
}
// 计算表格列平均值
function calcAverageValue(fieldIndex, tableData) {
  const rows = tableData.map(row => row[fieldIndex])
  const decimalPosition = rows[0].decimalPosition
  const values = rows.map(row => Number(row.value))
  if (values.some(item => item == null)) return null
  return handleRoundFiveNumber(math.mean(values), decimalPosition)
}

// 表格数据更新后重新计算
function updateTableDataByConfigFields() {
  let needCalcTabs = []
  needCalcTabs = assayGroups.value.filter(t => t.value !== 'by' && t.value !== 'kby' && t.value !== 'zkkby')
  if (needCalcTabs.length === 0) return
  for (const key in dynamicFormData) {
    for (const tab of needCalcTabs) {
      const columnObj = tab.columns.find(c => {
        if (c.formula && c.hidden !== 1) {
          let FromKey = c.formula.split(':')
          return FromKey[1] === key || FromKey[0] === 'GetFrom'
        }
        return false
      })
      if (!columnObj) continue
      tab.tableData.forEach(row => {
        // 赋值配置列参与计算
        if (row[columnObj.fieldIndex]) {
          if (columnObj.formula.startsWith('From')) {
            row[columnObj.fieldIndex].value = dynamicFormData[key]
          }
          if (columnObj.formula.startsWith('GetFrom')) {
            row[columnObj.fieldIndex].value = evaluateGetFromFormula(
              columnObj.formula,
              true,
              dynamicFormData,
              columnObj,
              row,
              tab.columns
            )
          }
        }
        calcRowAnalysisValue(row, columnObj, tab.columns, dynamicFormData, taskIngredientsWay.value)
      })
    }
  }
}

// 把字段值保存回样品数据中
function setValueToSample() {
  let fields = fieldGroup.value.flatMap(item => item.fields)
  fields.forEach(item => {
    if (
      currentSampleData.value.hasOwnProperty(item.fieldIndex) &&
      nx.$test.object(currentSampleData.value[item.fieldIndex])
    ) {
      currentSampleData.value[item.fieldIndex].value = item.value
      currentSampleData.value[item.fieldIndex].symbol = item.symbol
    }
  })
}

//自动生成杯号（仅顺序称重）：第一杯：手填，后续杯 = 上一杯 + 1
const autoGenerateCupNum = () => {
  let cupNum = 0
  let currentIndex = currentSampleIndex.value
  //第一杯
  if (currentIndex === 0) return
  //取上一个样品的杯号
  const sample = sampleDataList.value[currentIndex - 1]
  cupNum = sample[cupNumFieldIndex.value]?.value
  if (!cupNum) return
  //杯号赋值到当前样品
  putCupNum(Number(cupNum) + 1, currentIndex, Number(cupNum))
}

const putCupNum = (cupNum, sampleIndex, lastCupNum) => {
  for (const fields of fieldGroup.value) {
    if (typeof fields === 'undefined') continue
    //杯号
    for (const field of fields.fields) {
      if (field.fieldIndex === cupNumFieldIndex.value) {
        if (typeof field.value === 'undefined' || field.value === null || field.value === '') {
          field.value = cupNum
          return true
        }
      }
    }
  }
}

const loadConRecoveryList = () => {
  const conBaseSampleId = currentSampleData.value.conBaseSampleId
  const rParam = {
    pageNo: 1,
    pageSize: -1,
    conBaseSampleId: conBaseSampleId
  }
  const storageKey = 'ConRecoveryRateList'
  nx.$api.assayTask
    .queryConRecoveryRateList(rParam)
    .then(res => {
      const result = res.result
      if (typeof result === 'undefined' || result === null || !result) {
        uni.setStorage(storageKey, [])
        return
      }
      const records = result.records
      if (!records || records.length === 0) {
        uni.setStorage(storageKey, [])
        return
      }
      uni.setStorageSync(storageKey, records)
    })
    .catch(err => {
      console.error(err)
    })
}

// 分析样品组
let assayGroups = ref([])
const activeAssayTypeKey = ref('')
const activeAssayTypeIndex = ref(0)
//元素结果范围
let conRangeElementAnalysisList = ref([])
// 杯号fieldIndex
const cupNumFieldIndex = ref('')
const currentAssayType = computed(() => {
  return assayGroups.value.find(item => item.value === activeAssayTypeKey.value)
})
// 当前样品数据
const currentSampleData = computed(() => {
  if (sampleDataList.value.length > 0) {
    return sampleDataList.value[currentSampleIndex.value]
  }
  return {}
})
watch(
  () => currentAssayType.value,
  () => {
    sampleDataList.value = currentAssayType.value.tableData
    fieldGroup.value = groupByField(currentAssayType.value.columns, cupNumFieldIndex)
    autoNextSample(0)
    setValueToField()
    // getDomHeight()
    activeCollapses.value = fieldGroup.value.map((_, index) => index)
  }
)
const currentCupNum = computed(() => {
  for (const item of fieldGroup.value) {
    const field = item.fields.find(field => field.fieldIndex === cupNumFieldIndex.value)
    if (field) {
      return field.value
    }
  }
  return null
})
const currentGroup = computed(() => {
  if (!currentAssayType.value || curParameterKey.value === 'all') {
    return fieldGroup.value
  } else {
    return fieldGroup.value.filter(g => g.value === curParameterKey.value)
  }
})
watch(
  () => currentGroup.value,
  () => {
    fieldGroup.value.forEach(item => {
      item.fields.forEach(field => {
        const validation = validateElementRange(
          field.fieldIndex,
          currentSampleData.value,
          conRangeElementAnalysisList.value
        )
        field.validation = validation
      })
    })
  }
)
const collapseRef = ref()
const activeCollapses = ref([])
function handleAssayTypeChange({ index, value }) {
  scrollFieldTop.value = 0
  activeAssayTypeKey.value = value
  activeAssayTypeIndex.value = index
  currentSampleIndex.value = 0
  groupFieldIndex.value = ''
  selectedField.value = {}
  curParameterKey.value = 'all'
  curParameterTitle.value = '选择字段分类'
  nextTick(() => {
    collapseRef.value.init()
  })
}
// 获取任务数据
async function getSampleAnalysisByTaskId() {
  const {
    assayTaskAnalysisDataList,
    configAssayMethodProjectRangeList,
    businessAssayTasNo,
    formValue,
    ingredientsStatus,
    isIngredients,
    ingredientsWay
  } = await nx.$api.assayTask.batchSampleAndQcAnalysisByTaskId(taskId.value)
  title.value = '样品分析-任务单编号：' + businessAssayTasNo
  taskIngredientsStatus.value = ingredientsStatus
  taskIsIngredients.value = isIngredients
  taskIngredientsWay.value = ingredientsWay
  // 处理分析数据
  assayGroups.value = assayTaskAnalysisDataList.map(group => {
    // 必须深拷贝 datas！防止多个表格共享引用
    const tableData = JSON.parse(JSON.stringify(group.datas || []))
    const columns = group.columns.filter(item => item.paramNo) || []

    return {
      value: group.analysisType,
      name: group.analysisName,
      columns,
      tableData,
      configQCSampleMethodInfo: group.configQCSampleMethod?.configInfomation
        ? JSON.parse(group.configQCSampleMethod['configInfomation'])['set']
        : []
    }
  })
  dynamicFormData = formValue ? JSON.parse(formValue) : {}
  // 默认激活第一个 类型
  if (!activeAssayTypeKey.value) {
    activeAssayTypeKey.value = assayGroups.value.length > 0 ? assayGroups.value[0].value : ''
  }
  conRangeElementAnalysisList.value = configAssayMethodProjectRangeList || []
}
// 设置字段值
function setValueToField() {
  for (const group of fieldGroup.value) {
    group.fields.forEach(field => {
      let value = getFieldValue(field)
      field.value = value
      let symbol = getFieldSymbol(field)
      field.symbol = symbol
      field.hidden = getField(field) ? 0 : 1
    })
  }
  nextTick(() => {
    collapseRef.value.init()
  })
}
function getField(field) {
  const fieldObj = currentSampleData.value[field.fieldIndex]
  return fieldObj
}
function getFieldValue(field) {
  const fieldValue = currentSampleData.value[field.fieldIndex]?.value
  if (fieldValue) {
    return fieldValue
  } else {
    return ''
  }
}
function getFieldSymbol(field) {
  const fieldSymbol = currentSampleData.value[field.fieldIndex]?.symbol
  if (fieldSymbol) {
    return fieldSymbol
  } else {
    return '='
  }
}

const apiRequest = async url => {
  return request({
    url: url,
    method: 'GET'
  })
}

//读取字段里的API选项
const loadFieldApiData = async fieldGroups => {
  for (const fields of fieldGroups) {
    for (const field of fields.fields) {
      const api = field.api
      const type = field.type
      if (type === 'select' && api && api !== '') {
        //读取API选项
        try {
          const res = await apiRequest(api)
          const data = res
          field.options = data
          field.rangeKey = 'displayName'
        } catch (e) {}
      }
    }
  }
}

/*
 * 选择器组件确认事件
 * event： 事件默认参数
 * field： 当前字段
 * 处理逻辑：
 *   field.value = 选中的值
 *   field.valueText = 选中的文本
 * */
const dicPickerConfirm = (event, field) => {
  const checked = event.value[0]
  const displayName = checked.displayName
  const value = checked.dictValue
  const extField1 = checked.extField1
  field.value = value
  field.valueText = value

  const relatedFieldNo = '8'
  //查找并处理关联字段
  for (const fieldGroup of fieldGroup.value) {
    for (const field of fieldGroup.fields) {
      if (field.paramNo === relatedFieldNo) {
        field.value = extField1
        break
      }
    }
  }
  //触发计算公式
  calcAnalysisValue(fieldGroup.value)
}
// 天平监听
const listenDeviceData = () => {
  //监听websocket返回来的数据
  //设备数据
  uni.$on('deviceData', res => {
    switch (res.deviceType) {
      case 'balance':
        if (currentAuncel.value.id === res.deviceId) {
          currentAuncel.value.weightData = res.weightData
          currentAuncel.value.weightUnit = res.weightUnit
          currentAuncel.value.weightStable = res.weightStable
          currentAuncel.value.isConnected = true
          if (Number(res.weightData) === 0) {
            weightDataIsToZero.value = true
          }
        }
        break
      default:
        break
    }
  })
  //设备状态
  uni.$on('deviceStatus', res => {
    if (currentAuncel.value.id === res.deviceId) {
      if (res.connected === 0) {
        currentAuncel.value.weightStable = 0
        currentAuncel.value.weightData = '天平断开'
        currentAuncel.value.weightUnit = ''
      }
    }
    currentAuncel.value.isConnected = res.connected
  })
  //控制设备状态
  uni.$on('controlDevice', res => {
    if (currentAuncel.value.id === res.deviceId && !res.isControl) {
      currentAuncel.value.id = ''
      currentAuncel.value.name = ''
      currentAuncel.value.code = ''
      currentAuncel.value.weightStable = 0
      currentAuncel.value.weightData = '请选天平'
      currentAuncel.value.weightUnit = ''
    }
  })
  //连接断开
  uni.$on('connClose', res => {
    //重置
    currentAuncel.value.weightData = ''
    currentAuncel.value.weightUnit = ''
    currentAuncel.value.weightStable = 0
    currentAuncel.value.controlUserName = ''
    currentAuncel.value.isConnected = false
  })
}
const closeDeviceListener = () => {
  uni.$off('deviceData')
  uni.$off('deviceStatus')
  uni.$off('controlDevice')
  uni.$off('connClose')
}
const loadDevice = () => {
  //注册websocket
  let regData = {
    msgId: nx.$helper.uuid(),
    cmd: 'register',
    clientType: 'caaClient',
    data: {
      userId: userInfo.value.id,
      tenantId: getTenantId(),
      userRealName: userInfo.value.realname
    }
  }
  nx.$measure.setRegData(JSON.stringify(regData))
  nx.$measure.open()
}

// 键盘监听
const listenNumKeyboard = () => {
  //键盘监听
  uni.$on('keyboardOK', res => {
    if (res === null) {
      clearFieldVal()
      return
    }
    //自动补全小数位数
    const decimalPosition = selectedField.value.decimalPosition
    let val = res.val
    const symbol = res.symbol
    if (decimalPosition == null) {
      selectedField.value.value = val
    } else {
      selectedField.value.value = handleRoundFiveNumber(val, decimalPosition)
    }
    if (symbol) {
      selectedField.value.symbol = symbol
    }
    syncFieldValueByEqualParamNo()
    calcAnalysisValue(fieldGroup.value, dynamicFormData, taskIngredientsWay.value)
    //自动跳转下一个字段
    setTimeout(() => {
      autoNextField()
    }, 60)
  })
}
// 查找paramNo相同的列，并且类型相同，使其值同步
function syncFieldValueByEqualParamNo() {
  for (const group of fieldGroup.value) {
    group.fields.forEach(field => {
      if (
        field.paramNo === selectedField.value.paramNo &&
        field.type === selectedField.value.type &&
        field.hidden === selectedField.value.hidden
      ) {
        field.value = selectedField.value.value
      }
    })
  }
}
const clearFieldVal = () => {
  uni.showModal({
    title: '提示',
    content: '清空当前字段的值，是否继续？',
    cancelColor: '#0055A2',
    confirmColor: '#0055A2',
    success: res => {
      if (res.cancel) {
        return
      }
      selectedField.value.value = ''
      //重新计算
      calcAnalysisValue(fieldGroup.value, dynamicFormData, taskIngredientsWay.value)
    }
  })
}
const closeNumKeyBoardListener = () => {
  uni.$off('keyboardOK')
}

const closeDeviceLink = () => {
  const deviceId = currentAuncel.value.id
  releaseDeviceControl(deviceId)
}

//释放设备控制
const releaseDeviceControl = deviceId => {
  if (!deviceId || deviceId === '') return
  let controlDevice = {
    msgId: deviceId,
    cmd: 'controlDevice',
    clientType: 'caaClient',
    data: {
      deviceId: deviceId,
      isControl: false,
      controlRealName: userInfo.value.nickname,
      controlUserId: userInfo.value.id
    }
  }
  //发送控制数据
  nx.$measure.send(JSON.stringify(controlDevice))
}

// 天平选择
const selectAuncel = () => {
  showAuncelSelector.value = true
}
// 天平选择回调
const auncelDoSelect = res => {
  const data = res.data
  if (data) {
    currentAuncel.value.id = data.deviceId
    currentAuncel.value.name = data.deviceName
    currentAuncel.value.code = data.deviceCode
  }
}

//提交任务单
const submitTask = () => {
  if (checkSampleReturning()) return
  const url = `/pages/analysis/sample/pdf-preview?businessAssayTaskId=${taskId.value}&reportKey=${configReportTemplateKey.value}&showConfirmBtn=true`
  uni.navigateTo({ url })
}
// 自动配料
function handleIngredients() {
  if (checkSampleReturning()) return
  const params = {
    businessAssayTaskId: taskId.value
  }
  nx.$api.assayTask.taskIngredients(params).then(res => {
    getSampleAnalysisByTaskId()
  })
}
// 人工配料
function handleManualIngredients() {
  const params = {
    businessAssayTaskId: taskId.value
  }
  nx.$api.assayTask.manualIngredients(params).then(res => {
    getSampleAnalysisByTaskId()
  })
}
//
function checkSampleReturning() {
  const analysisSampleData = assayGroups.value.find(t => t.value == 'analysis').tableData
  const hasReturning = analysisSampleData.some(item => item.rollbackStatus === 'in_progress')
  if (hasReturning) {
    nx.$helper.showToast('该任务单存在退回中的样品')
    return true
  }
  return false
}
// 生命周期
const { lockOrientation } = useScreenOrientation()

onLoad(param => {
  lockOrientation('landscape')
  if (param.currentTaskId) {
    taskId.value = param.currentTaskId
    configReportTemplateKey.value = param.configReportTemplateKey
    getSampleAnalysisByTaskId()
  }
  loadFieldApiData(fieldGroup.value)
  listenNumKeyboard()
})

onShow(() => {
  loadDevice()
  // listenDeviceData()
})

onHide(() => {
  closeDeviceListener()
})

onUnload(() => {
  closeDeviceLink()
  closeDeviceListener()
  closeNumKeyBoardListener()
})

onBackPress(() => {
  customBack()
  return true
})
</script>

<style lang="scss" scoped>
/* 原始样式保留不变 */
.navbar-right {
  font-size: 16px;
  color: #fff;
  display: flex;
}
.content-title-name {
  font-size: 22px;
  display: flex;
  align-items: center;
  justify-content: center;
  height: 100%;
}
.content-tabs {
  height: 100%;
  :deep(.u-tabs__wrapper) {
    height: 100%;
  }
}
.current-sample-code {
  font-weight: bold;
  margin-right: 20px;
}
:deep(.u-dropdown) {
  height: 100%;
  .u-dropdown__menu {
    height: 60px !important;
    .u-dropdown__menu__item__text {
      font-size: 18px !important;
    }
  }
}
.form-item-my {
  display: flex;
  align-items: center;
  min-height: 35px;
  font-size: 16px;
  border-bottom: 1px solid #dcdcdc;
}
.selected-field {
  background-color: #bada55;
}
.disabled-field {
  background-color: #eee;
}
.flex-column {
  display: flex;
  flex-direction: column;
  align-items: start;
  padding: 4px;
}
.label-my {
  flex: 5;
}

.label-high-light {
  color: #000;
  font-weight: 600;
  font-size: 1.2em;
}

.field-high-light {
  color: #000;
  font-weight: 600;
  font-size: 1.2em;
}

.label-my sub {
  font-size: 0.6em;
  vertical-align: sub;
}

.content-my {
  flex: 2;
  text-align: right;
  padding-right: 4px;
  .select-my {
    color: #303133;
    font-size: 15px;
    padding: 6px 8px;
    border: 1px solid #dcdcdc;
    border-radius: 5px;
  }
}

.content-my-text-value {
  color: rgb(48, 49, 51);
}
.content-my-text-placeholder {
  color: #c0c4cc;
}
.content-left-scroll {
  height: 75vh;
}
.content-right-scroll {
  height: 74vh;
}
.valid-warning {
  color: orange;
}
.valid-error {
  color: red;
}

.u-tab-item {
  display: flex;
  align-items: center;
  font-size: 16px;
  color: #444;
  padding: 8px 16px;
  box-sizing: border-box;
  border-bottom: 2px dotted #444;
}

.u-tab-item-active {
  color: #0055a2;
  font-weight: 600;
}
.u-tab-item-disabled {
  background-color: #ddd;
  pointer-events: none;
  opacity: 0.6;
}

.btn-operation {
  width: 80%;
  font-size: 18px;
  margin-top: 10px;
}

.auncel {
  width: 90%;
  height: 55vh;
  background-image: url(/static/images/auncel.png);
  background-repeat: no-repeat;
  background-size: 100% 100%;
  background-position: center;
  display: flex;
  flex-direction: column;
  position: relative;
  .code {
    position: absolute;
    font-style: 18px;
    top: 25px;
    left: 70px;
  }
}

.auncel-title {
  flex: 3;
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  font-size: 32px;
}

.auncel-weight {
  flex: 2.5;
  display: flex;
  align-items: center;
  padding-bottom: 20px;
  box-sizing: border-box;
  position: relative;
}

.weight {
  font-size: 42px;
  width: 100%;
  padding-right: 80px;
  line-height: 1;
}

.weight-data {
  color: #4cd964;
  font-family: zzjc-lcd;
}

.weight-data-yellow {
  color: #ffff00;
  font-family: zzjc-lcd;
}

.weight-data-warning {
  color: #ff3333;
  font-family: zzjc-lcd;
}

.weight-unit {
  position: absolute;
  right: 30px;
  color: #ffffff;
  font-size: 32px;
}
@media (max-width: 700px) {
  .auncel {
    height: 45vh;
  }
  .auncel-title {
    font-size: 20px;
  }
  .auncel-weight {
    padding-bottom: 15px;
  }
  .weight {
    font-size: 26px;
  }
  .weight-unit {
    font-size: 20px;
  }
}

.field-name {
  font-size: 26px;
  padding: 16px;
  width: 100%;
}

.my-collapse {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 5px 10px 5px 0;
  .title {
    font-weight: bold;
  }
}
.content {
  overflow: hidden;
  padding-right: 10px;
  transition: height 100ms;
}

@media (max-width: 700px) {
  .content-left-scroll {
    height: 45vh;
  }
  .content-right-scroll {
    height: 55vh;
  }
  .field-name {
    font-size: 16px;
    width: 100%;
  }
}
</style>
