<template>
	<gui-page :custom-header="true" :header-class="['gui-theme-background-color']">
		<template #gHeader>
			<view style="height:44px;" class="gui-flex gui-nowrap gui-rows gui-align-items-center">
				<!-- 使用组件实现返回按钮及返回首页按钮 -->
				<text style="font-size:44rpx;" class="gui-header-leader-btns gui-color-white font-icons"
					@tap="goBack">&#xe6c5;</text>
				<!-- 导航文本此处也可以是其他自定义内容 -->
				<text
					class="gui-h4 gui-blod gui-flex1 gui-text-center gui-ellipsis gui-color-white gui-primary-text">扫描出库明细</text>
				<!-- 此处加一个右侧展位元素与左侧同宽，实现标题居中 -->
				<!-- 实际宽度请根据自己情况设置 -->
				<view style="width:40px;" />
				<!-- 如果右侧有其他内容可以利用条件编译和定位来实现-->
			</view>
		</template>
		<template #gBody>
			<view class="list-content">
        <view class="scan" v-if="scanTie">
          <view class="scan-card" style="margin-top:8px;">
						<uni-easyinput
							ref="tmInput"
							v-model="tmId"
							:input-border="false"
							:clearable="false"
							type="text"
							placeholder="请扫描或输入贴纸ID"
							@confirm="handleTmConfirm"
						/>
						<text class="font-icons" @click="setTmOnly">&#xe6b7;</text>
					</view>
        </view>
        <view class="scan" v-if="scanTie">
          <view class="scan-card" style="margin-top:8px;">
						<uni-easyinput
							ref="partInput"
							v-model="tmMaterialNo"
							:input-border="false"
							:clearable="false"
							type="text"
							placeholder="请输入料号"
							@confirm="handlePartKeydown"
						/>
						<text class="font-icons" @click="handleQueryPart">&#xe6b7;</text>
					</view>

        </view>
				<view class="scan">
					<view class="scan-card">
            <!-- 禁用软键盘 -->
						<!-- <uni-easyinput ref="easyinput" v-model="scanBatchNumber" :input-border="false"
							:clearable="false" type="text" focus @focus="handleInputFocus" placeholder="请扫描物料二维码"
							@confirm="handleKeydown" /> -->
              <!-- 不禁用软键盘(且不自动获取焦点) -->
            <uni-easyinput ref="easyinput" v-model="scanBatchNumber" :input-border="false"
							:clearable="false" type="text" placeholder="请扫描物料二维码"
							@confirm="handleKeydown" />
						<text class="font-icons" @click="handleScanMaterial">&#xe6b7;</text>
					</view>
				</view>
				<view class="tabs">
					<div class="tabs-list">
						<text :class="!isBefore?'tabs-item-active':'tabs-item'" @click="isBefore = false">物料需求</text>
						<text :class="isBefore?'tabs-item-active':'tabs-item'" @click="isBefore = true">已扫物料</text>
					</div>
				</view>
				<view v-if="!isBefore" class="custom-table">
					<uni-table border stripe empty-text="暂无更多数据">
						<!-- 表头行 -->
						<uni-tr class="custom-table-head">
							<uni-th align="center" width="180px" class="break-col">可出库位(数量)</uni-th>
							<uni-th align="center" width="180px">物料</uni-th>
							<uni-th align="center" width="120px">应备数</uni-th>
							<uni-th align="center" width="120px">已备数</uni-th>
						</uni-tr>
						<!-- 表格数据行 -->
             <!-- 可点击行，方法存在 -->
						<uni-tr v-for="(item, key) in tableData" :key="key" @click="handleToDetails(item)">
             <!-- 不可点击行 -->
						<!-- <uni-tr v-for="(item, key) in tableData" :key="key"> -->
							<uni-td align="center" class="break-cell">{{ item.ableStockLocation }}</uni-td>
							<uni-td align="center">{{ item.materialNo }}({{ item.materialName }})</uni-td>
							<uni-td align="center">{{ item.nowDeliveredQty }}</uni-td>
							<uni-td align="center"
								style="color: orange;font-weight: bold;">{{ item.completedQty }}</uni-td>
						</uni-tr>
					</uni-table>
				</view>
				<view v-else class="custom-table">
					<scroll-view scroll-y class="scroll-box" style="height: 300px;">
						<view class="cell-row">
							<view class="cell1">物料</view>
							<view class="cell2">数量</view>
							<view class="cell3">批号</view>
						</view>
						<view 
							v-for="(item, idx) in beforeTableData"
							:key="item.uniqueId"
							class="swipe-row"
							@touchstart="touchStart"
							@touchmove="touchMove"
							@touchend="touchEnd"
							:data-index="idx"
						>
							<view class="content-area" :style="`transform: translateX(${item.slideX}px)`">
								<view class="cell1">{{ item.materialNo }}({{ item.materialName }})</view>
								<view class="cell2">{{ item.batchQty }}</view>
								<view class="cell3">{{ item.batchNumber }}</view>
							</view>
							<view class="btn-area" @click="deleteItem(idx)">删除</view>
						</view>
					</scroll-view>
				</view>
				<view class="card-list-item"
				style="margin: 12px 0;display: grid;grid-template-columns: 1fr 1fr;grid-template-rows: 1fr;gap: 10px;">
				<view class="sign-btn" :class="{ disabled: saveDisabled }" @click="handleSave">
					<text :style="saveBtnTextStyle">保存</text>
				</view>
				<view class="sign-btn" :class="{ disabled: submitDisabled }" @click="handleSubmit">
					<text :style="submitBtnTextStyle">提交</text>
				</view>
					<view style="width: 0px;">
						<!-- <uni-easyinput ref="signInput" v-model="signText" @focus="handleInputFocus"
							:input-border="false" :clearable="false" type="text" @confirm="handleComplete" /> -->
              <uni-easyinput ref="signInput" v-model="signText"
							:input-border="false" :clearable="false" type="text" @confirm="handleComplete" />
					</view>
				</view>
				<gui-modal ref="modalForm" :custom-class="['gui-bg-white', 'gui-dark-bg-level-3', 'gui-border-radius']"
					title="提示">
					<template #content>
						<view class="gui-padding gui-bg-gray gui-dark-bg-level-2">
							<text class="gui-block gui-text-center gui-text gui-color-gray"
								style="line-height:100rpx; padding:10rpx;">备料超出，是否拆分？</text>
						</view>
					</template>

					<!-- 利用 flex 布局 可以放置多个自定义按钮哦  -->
					<template #btns>
						<view class="gui-flex gui-row gui-space-between operation-flex">
							<view hover-class="gui-tap" class="modal-btns gui-flex1" @tap="modalForm.close()">
								<text class="modal-btns gui-color-gray">取消</text>
							</view>
							<view class="line" />
							<view hover-class="gui-tap" class="modal-btns gui-flex1" @tap="handleSplitMaterial">
								<text class="modal-btns gui-primary-color">确认</text>
							</view>
						</view>
					</template>
				</gui-modal>
				<uni-popup ref="errorTip" type="dialog">
							<uni-popup-dialog type="error" cancel-text="关闭" confirm-text="确认" title="提示"
								:content="errorTipMessage" @confirm="handleCloseErrorTipsModal"
								@close="handleCloseErrorTipsModal" />
						</uni-popup>
						<!-- FIFO 二次确认弹窗 -->
						<uni-popup ref="fifoPopup" type="dialog">
							<uni-popup-dialog
								title="FIFO 提示"
								:content="fifoMsg"
								confirm-text="继续"
								cancel-text="取消"
								@confirm="fifoContinue"
								@close="fifoCancel" />
						</uni-popup>
			</view>
		</template>
	</gui-page>
</template>

<script>
import {
  onReachBottom,
  onShow
} from '@dcloudio/uni-app'
import {
  ref,
  onMounted,
  defineComponent,
  onBeforeMount,
  computed,
  watch,
  nextTick
} from 'vue'

export default defineComponent({
  setup(options) {
    const popup = ref()
    const queryParams = ref({
      pageSize: 20,
      pageNo: 1,
      masterId: options?.id ?? '',
      wmsProductionWorkOrderBomId: options?.id ?? ''
    })
    const errorTip = ref('')
    const errorTipMessage = ref('')
    const easyinput = ref('')
    const partInput = ref(null)       // ref 指向料号输入框
    const tmMaterialNo = ref('')        // 料号
    const tmId = ref('')          // 贴纸ID
    const tmInput = ref(null)     // ref 指向贴纸ID输入框
    const scanTie = ref(0)     // 控制贴纸和料号扫描框显示
    const errorState = ref(0)
    const modalForm = ref()
    const parentRow = uni.getStorageSync('masterId') ?? {}
    const masterId = ref('')
    const businessType = ref('')
    // const saveId = ref('')
    const signInput = ref()
    const signText = ref('')
    const isLightText = ref('')
    const isSubmitLight = ref('')
    const scanBatchNumber = ref('')
    const isBefore = ref(false)
    const tableData = ref([])
    const beforeTableData = ref([])
    const scanMaterialList = ref([])
    const receiveList = ref([])
    const currentWarehouseId = ref('')
    const currentWarehouseName = ref('')
    // 当前处理的数据行
    const fdIndex = ref(-1)
    // 当前扫描的物料
    const currentScanMaterial = ref([])
    // 前端临时缓存：已扫物料
    const localScannedList = ref([])
    // 控制保存按钮能否点击
    const saveDisabled = ref(false)
    // 控制提交按钮能否点击
    const submitDisabled = ref(false)

    /* -------------------- 下面 4 行是新增变量 -------------------- */
    const fifoPopup = ref(null)   // 弹窗实例
    const fifoMsg = ref('')     // 提示语
    let fifoQrCode = ''          // 缓存本次二维码
    const fifoGo = ref(false)       // 用户是否点了“继续”

    // 存储fifo_check_order_type字典数据
    const fifoCheckOrderTypeDict = ref([])
    // 标记businessType是否在fifo_check_order_type字典内
    const isBusinessTypeInFifoDict = ref(false)

    onBeforeMount(() => {
      initMasterData()
      // 获取fifo_check_order_type字典数据
      getFifoCheckOrderTypeDict()
    })
    
    // 获取fifo_check_order_type字典数据
    const getFifoCheckOrderTypeDict = function() {
      uni.$reqGet('getDictDataPage', {
        dictType: 'fifo_check_order_type'
      })
      .then(({ code, data, msg }) => {
        if (code === 0) {
          fifoCheckOrderTypeDict.value = data?.list || []
          console.log('fifo_check_order_type字典数据:', fifoCheckOrderTypeDict.value)
          console.log('fifo_check_order_type字典数据长度:', fifoCheckOrderTypeDict.value.length)
          // 判断businessType是否在字典内
          checkBusinessTypeInFifoDict()
        } else {
          console.error('获取fifo_check_order_type字典失败:', msg)
        }
      })
      .catch(error => {
        console.error('获取fifo_check_order_type字典异常:', error)
      })
    }
    
    // 判断businessType是否在fifo_check_order_type字典内
    const checkBusinessTypeInFifoDict = function() {
      // 使用some方法检查businessType是否存在于字典数据中
      isBusinessTypeInFifoDict.value = fifoCheckOrderTypeDict.value.some(item => 
        String(item?.value).trim() === String(businessType.value).trim()
      )
      console.log('businessType是否在fifo_check_order_type字典内:', isBusinessTypeInFifoDict.value)
    }

    const search = function() {
      uni.$reqGet('getScannedOutMatersDetails', { id: masterId.value })
        .then(({ code, data, msg }) => {
          if (code === 0) {
            uni.setStorageSync('ids', JSON.stringify(data?.inoutRequestDetailPDARespVOList?.[0] || {}))
            // saveId.value = data?.id
            receiveList.value = data
            scanTie.value = data?.scanTie
            currentWarehouseId.value = data?.warehouseId
            currentWarehouseName.value = data?.warehouseName
            tableData.value = data?.inoutRequestDetailPDARespVOList || []
            console.log('获取到的scanTie:', scanTie.value)
            // 1. 先清空本地已扫列表，准备重新填充
            localScannedList.value = []
            
            // 2. 将后端返回的已扫物料数据塞进localScannedList
            tableData.value.forEach(item => {
              if (item.inoutRequestSubdetailList?.length) {
                localScannedList.value.push(...item.inoutRequestSubdetailList)
              }
            })
            
            // 3. 调用flushBeforeTableData()，以localScannedList为准重新生成beforeTableData
            flushBeforeTableData()
            
            // // 新增：根据 scanTie 决定首次焦点
            // nextTick(() => {
            //   if (Number(scanTie.value) === 1) {
            //     // 先让贴纸 ID 框聚焦
            //     tmInput.value.onBlur()
            //     tmInput.value.onFocus()
            //   } else {
            //     setInputFocus()
            //   }
            // })
          } else {
            uni.showToast({
              title: msg,
              icon: 'none',
              duration: 2000
            })
          }
        })
    }

    onMounted(() => {
      search()
    })
	const initMasterData = () => {
	  const parsedData = JSON.parse(parentRow)
	  masterId.value = parsedData?.id
	  businessType.value = parsedData?.businessType || '0'
	  console.log('获取到的businessType:', businessType.value)
	  if (businessType.value == '5') {
	    submitDisabled.value = true
	  }
	}
	onShow(() => {
	  initMasterData()
	  if (masterId.value) {
	    // 检查是否需要刷新（从详情页返回时）
	    const needRefresh = uni.getStorageSync('needRefreshScanOut')
	    if (needRefresh === 'true') {
	      search()
	      uni.removeStorageSync('needRefreshScanOut')
	    }
	  }
	})

    const goBack = function() {
      if (uni.getStorageSync('masterId')) {
        uni.removeStorageSync('masterId')
      }
      if (uni.getStorageSync('ids')) {
        uni.removeStorageSync('ids')
      }
      uni.$goBack('/pages/workbranch/warehouse/scanInOut/Out/scanOutPage')
    }

    const handleScanMaterial = async function() {
      // #ifdef APP-PLUS
      /* 0. 基本校验 */
	  // if (businessType.value == '5') {
	  //     if (!tmId.value.trim()) {
	  //       uni.showToast({
	  //         title: '请先扫描贴纸ID',
	  //         icon: 'none',
	  //         duration: 2000
	  //       });
	  //       nextTick(() => tmInput.value?.onFocus());
	  //       return;
	  //     }
	  //     if (!tmMaterialNo.value.trim()) {
	  //       uni.showToast({
	  //         title: '请先扫描料号',
	  //         icon: 'none',
	  //         duration: 2000
	  //       });
	  //       nextTick(() => partInput.value?.onFocus());
	  //       return;
	  //     }
	  //   }
      /* 1. 先调摄像头 */
      const mpaasScanModule = uni.requireNativePlugin('Mpaas-Scan-Module');
      const ret = await new Promise(resolve => 
        mpaasScanModule.mpaasScan(
          { scanType: ['qrCode', 'barCode'], hideAlbum: false },
          resolve
        )
      );
      if (ret.resp_code !== 1000) return;

      const qrCode = ret.resp_result;

      /* 2. FIFO 校验 */
      const ok = await checkFifo(qrCode);
      if (!ok && !fifoGo.value) {
        // 新增：清空二维码框并重新聚焦
        resetAllInputs()          // 如果你只想清二维码，也可以只写 scanBatchNumber.value = ''
        nextTick(() => easyinput.value.onFocus())
        return;
      }

      /* 3. 业务接口 */
      uni.$reqGet('scanPrepareMaterial', {
        qrCode,
        requestNo: receiveList.value.requestNo,
        businessType: receiveList.value.businessType,
        tmMaterialNo: tmMaterialNo.value.trim(),
        tmId: tmId.value.trim()
      })
        .then(({ code, data, msg }) => {
          fifoGo.value = false;
          if (code !== 0) {
            // #ifdef APP-PLUS
            plus.device.beep(2);
            // #endif
            resetAllInputs();   // ← 新增
            errorTipMessage.value = msg;
            errorTip.value.open();
            errorState.value = 0;
            /* 补焦点 */
            // nextTick(() => {
            //   Number(scanTie.value) === 1 ? tmInput.value.onFocus() : easyinput.value.onFocus()
            // });
			nextTick(() => {
			    easyinput.value.onFocus()  // ← 固定回到二维码框
			});
            return;
          }
        
          /* ---------- 新增仓库ID校验 ---------- */
          if (!validateWarehouseId(data)) {
            return; // 仓库ID不一致，终止后续逻辑
          }
          /* ------------------------------------ */
          
          /* ---------- 新增批号重复校验 ---------- */
          const cur = Array.isArray(data) ? data[0] : data;
          if (cur && isBatchExist(cur.batchNumber)) {
            showBatchRepeatTip();
            return;// 直接终止
          }
          /* ------------------------------------ */
        
          scanBatchNumber.value = qrCode;
          // === 新增：将 tmMaterialNo 和 tmId 插入返回数据 ===
          if (Object.prototype.toString.call(data) === '[object Array]') {
            data.forEach(item => {
              item.tmMaterialNo = tmMaterialNo.value.trim()
              item.tmId = tmId.value.trim()
            })
          } else if (data && typeof data === 'object') {
            data.tmMaterialNo = tmMaterialNo.value.trim()
            data.tmId = tmId.value.trim()
          }
          // ============================================
          // 以下保持你原有逻辑不变
          if (Object.prototype.toString.call(data) === '[object Array]') {
            fdIndex.value = tableData.value.findIndex(
              (item) => item?.materialNo === data[0]?.materialNo
            );
          }
          if (fdIndex.value === -1) {
            // #ifdef APP-PLUS
            plus.device.beep(2);
            // #endif
            errorTipMessage.value = '请扫描所需物料的物料条码';
            errorTip.value.open();
            errorState.value = 0;
            return;
          }
        
          currentScanMaterial.value = data[0] ?? [];
          const row = tableData.value[fdIndex.value];
          if (row.nowDeliveredQty > row.completedQty) {
            /* ===== 前端暂存逻辑 ===== */
            row.completedQty += currentScanMaterial.value.receiptQty || 1;
            localScannedList.value.push({
              ...currentScanMaterial.value,
              batchQty: currentScanMaterial.value.receiptQty || 1,
              supplierName: currentScanMaterial.value.supplierName || '',
            });
            flushBeforeTableData();

            /* 唯一成功出口：全部清空 */
            resetAllInputs();

            /* 再决定下一个焦点 */
            nextTick(() => {
              Number(scanTie.value) === 1
                ? tmInput.value.onFocus()   // 贴纸模式→回到贴纸框
                : easyinput.value.onFocus() // 原模式→回到二维码框
            });
          } else {
            // #ifdef APP-PLUS
            plus.device.beep(2);
            // #endif
            errorTipMessage.value = '已备数量已满，无需再扫';
            errorTip.value.open();
            errorState.value = 0;
          }
        }).catch(() => {
          // 异常也要复位
          fifoGo.value = false;
        });
      // #endif
    };

    const handleToNavigate = function() {
      uni.navigateTo({
        url: '/pages/workbranch/warehouse/production/materialIssuance'
      })
    }

    const handleComplete = function(e) {
      // #ifdef APP-PLUS
      // 扫描员工工号
      uni.$reqPost('scanPrepareMaterialSign', {
        encodedEmployeeId: e,
        id: masterId.value
      })
        .then(({
          code,
          data,
          msg
        }) => {
          if (code === 0) {
            uni.showToast({
              title: '扫码成功',
              icon: 'none',
              duration: 2000
            })
            setTimeout(() => {
              goBack();
            }, 500)
          } else {
            // #ifdef APP-PLUS
            plus.device.beep(2)
            // #endif
            errorTipMessage.value = msg
            errorTip.value.open()
            errorState.value = -1
          }
          isLightText.value = false
          signText.value = ''
        })
      // #endif
    }

    // 物料拆分
    const handleSplitMaterial = function() {
      uni.$reqPost('prepareSplit', {
        prepareId: masterId.value,
        id: scanBatchNumber.value,
        inQty: currentScanMaterial.value?.receiptQty,
        splitQty: tableData.value[fdIndex.value].completedQty - currentScanMaterial.value?.receiptQty
      })
        .then(res => {
          search()
          modalForm.value.close()
          if (res.code === 0) {
            // 调取打印机拆分物料后打印标签
            uni.showToast({
              title: '拆分完毕',
              icon: 'none',
              duration: 2000
            })
          } else {
            // #ifdef APP-PLUS
            plus.device.beep(2)
            // #endif
            errorTipMessage.value = res.msg
            errorTip.value.open()
            errorState.value = 0
          }
        })
    }

    const handleKeydown = async function (e) {
      const qrCode = e;
	  // if (businessType.value == '5') {
	  //     if (!tmId.value.trim()) {
	  //       uni.showToast({
	  //         title: '请先扫描贴纸ID',
	  //         icon: 'none',
	  //         duration: 2000
	  //       });
	  //       nextTick(() => tmInput.value?.onFocus());
	  //       return;
	  //     }
	  //     if (!tmMaterialNo.value.trim()) {
	  //       uni.showToast({
	  //         title: '请先扫描料号',
	  //         icon: 'none',
	  //         duration: 2000
	  //       });
	  //       nextTick(() => partInput.value?.onFocus());
	  //       return;
	  //     }
	  //   }
      /* ===== 新增 FIFO 校验 ===== */
      const ok = await checkFifo(qrCode);
      if (!ok && !fifoGo.value) {
        resetAllInputs()
        nextTick(() => easyinput.value.onFocus())
        return;
      }
      /* ========================= */

      uni.$reqGet('scanPrepareMaterial', {
        qrCode,
        requestNo: receiveList.value.requestNo,
        businessType: receiveList.value.businessType,
        tmMaterialNo: tmMaterialNo.value.trim(),
        tmId: tmId.value.trim(),
      })
        .then(async ({ code, data, msg }) => {
          scanBatchNumber.value = qrCode;
          // === 新增：将 tmMaterialNo 和 tmId 插入返回数据 ===
          if (Object.prototype.toString.call(data) === '[object Array]') {
            data.forEach(item => {
              item.tmMaterialNo = tmMaterialNo.value.trim()
              item.tmId = tmId.value.trim()
            })
          } else if (data && typeof data === 'object') {
            data.tmMaterialNo = tmMaterialNo.value.trim()
            data.tmId = tmId.value.trim()
          }
          // ============================================
        fifoGo.value = false;
          if (code !== 0) {
            // #ifdef APP-PLUS
            plus.device.beep(2);
            // #endif
            /* 1. 全部输入框清空（含二维码） */
            resetAllInputs()
            errorTipMessage.value = msg;
            errorTip.value.open();
            errorState.value = 0;
            /* 2. 焦点回到正确的输入框 */
            // nextTick(() => {
            //   Number(scanTie.value) === 1 ? tmInput.value.onFocus() : easyinput.value.onFocus()
            // });
			nextTick(() => {
			    easyinput.value.onFocus()  // ← 固定回到二维码框
			});
            return;
          }
        
          /* ---------- 新增仓库ID校验 ---------- */
          if (!validateWarehouseId(data)) {
            return; // 仓库ID不一致，终止后续逻辑
          }
          /* ------------------------------------ */
          
          /* ---------- 新增批号重复校验 ---------- */
          const cur = Array.isArray(data) ? data[0] : data;
          if (cur && isBatchExist(cur.batchNumber)) {
            showBatchRepeatTip();
            return;// 直接终止
          }
          /* ------------------------------------ */
        
          if (Object.prototype.toString.call(data) === '[object Array]') {
            fdIndex.value = tableData.value.findIndex(
              (item) => item?.materialNo === data[0]?.materialNo
            );
          }
          if (fdIndex.value === -1) {
            // #ifdef APP-PLUS
            plus.device.beep(2);
            // #endif
            errorTipMessage.value = '请扫描所需物料的物料条码';
            errorTip.value.open();
            errorState.value = 0;
            return;
          }
        
          currentScanMaterial.value = data[0] ?? [];
          const row = tableData.value[fdIndex.value];
          if (row.nowDeliveredQty > row.completedQty) {
            /* ===== 前端暂存逻辑 ===== */
            row.completedQty += currentScanMaterial.value.receiptQty || 1;
            localScannedList.value.push({
              ...currentScanMaterial.value,
              batchQty: currentScanMaterial.value.receiptQty || 1,
              supplierName: currentScanMaterial.value.supplierName || '',
            });
            flushBeforeTableData();
			resetAllInputs();
            setInputFocus();
          } else {
            // #ifdef APP-PLUS
            plus.device.beep(2);
            // #endif
            errorTipMessage.value = '已备数量已满，无需再扫';
            errorTip.value.open();
            errorState.value = 0;
          }
        }).catch(() => {
      // 异常也要复位
      fifoGo.value = false
    });
    };

    const handleToDetails = function(ret) {
      // 设置刷新标记，从详情页返回时需要刷新
      uni.setStorageSync('needRefreshScanOut', 'true')
      
      uni.navigateTo({
        url: '/pages/workbranch/warehouse/scanInOut/Out/materialsDetail'
      })
      uni.setStorageSync('mixMaterialDetail', JSON.stringify(ret))
    }

    // 设置高亮
    const handleBtnLight = function() {
      // #ifdef APP-PLUS
      signInput.value.onBlur()
      isLightText.value = true
      signInput.value.onFocus()
      // #endif
    }

    // const setInputFocus = function() {
    //   if (Number(scanTie.value) === 1) {
    //     // 闭环：回到贴纸 ID
    //     nextTick(() => {
    //       tmInput.value.onBlur()
    //       tmInput.value.onFocus()
    //     })
    //   } else {
    //     // 原逻辑：继续在二维码框循环
    //     easyinput.value.onBlur()
    //     easyinput.value.onFocus()
    //   }
    // }
	
	const setInputFocus = function() {
	    // 统一回到物料二维码输入框
	    nextTick(() => {
	        easyinput.value?.onBlur()
	        easyinput.value?.onFocus()
	    })
	}
    
    /* 统一出口：清空所有输入框 */
    const resetAllInputs = () => {
      scanBatchNumber.value = ''
      tmMaterialNo.value = ''
      tmId.value = ''
    }
    
    /* ===== 2. 键盘回车 ===== */
    const handlePartKeydown = async (e) => {
      const desc = tmMaterialNo.value.trim()
      if (!desc) return
      await queryPart(desc)
    }
    
    /* ===== 3. 右侧图标点击 ===== */
    // 将 handleQueryPart 改为扫码方法
    const handleQueryPart = async () => {
      // #ifdef APP-PLUS
      const mpaasScanModule = uni.requireNativePlugin('Mpaas-Scan-Module');
      const ret = await new Promise(resolve => 
        mpaasScanModule.mpaasScan(
          { scanType: ['qrCode', 'barCode'], hideAlbum: false },
          resolve
        )
      );
      if (ret.resp_code !== 1000) return;
      
      tmMaterialNo.value = ret.resp_result;  // 回填扫码结果
      
      // 扫码成功后自动跳转到二维码输入框
      if (Number(scanTie.value) === 1) {
        nextTick(() => {
          easyinput.value.onBlur()
          easyinput.value.onFocus()
        })
      } else {
        nextTick(() => easyinput.value.onFocus())
      }
      // #endif
    }
    
    /* ===== 4. 真正查料号 ===== */
    /* ===== 料号框：只保存，不调接口 ===== */
    const queryPart = (desc) => {
      tmMaterialNo.value = desc.trim()        // 1. 保存
      if (Number(scanTie.value) === 1) {
        nextTick(() => {                      // 2. 跳二维码框
          easyinput.value.onBlur()
          easyinput.value.onFocus()
        })
      } else {
        nextTick(() => easyinput.value.onFocus())
      }
    }
    
    /* ===== 5. 料号框重新聚焦 ===== */
    const setPartFocus = () => {
      if (Number(scanTie.value) === 1) {
        nextTick(() => {
          easyinput.value.onBlur()
          easyinput.value.onFocus()
        })
      } else {
        // 非贴纸模式保持原逻辑（仅保存）
        partInput.value.onBlur()
        partInput.value.onFocus()
      }
    }
    
    /* ===== 2. 仅保存贴纸ID，不请求 ===== */
	const setTmOnly = async () => {
	// #ifdef APP-PLUS
		const mpaasScanModule = uni.requireNativePlugin('Mpaas-Scan-Module');
		const ret = await new Promise(resolve => 
			mpaasScanModule.mpaasScan(
			{ scanType: ['qrCode', 'barCode'], hideAlbum: false },
			resolve
			)
		);
		if (ret.resp_code !== 1000) return;
  
		tmId.value = ret.resp_result;  // 回填扫码结果
  
		// 扫码成功后自动跳转到料号输入框（贴纸模式下）
		if (Number(scanTie.value) === 1) {
			nextTick(() => {
			partInput.value.onBlur()
			partInput.value.onFocus()
			})
		}
	// #endif
	}
    
    // 相同物料+相同批号才合并数量，否则新增一行
    const flushBeforeTableData = function() {
      const map = new Map()
      localScannedList.value.forEach(it => {
        // 用“物料编码+批号”当唯一键
        const key = `${it.materialNo}__${it.batchNumber}`
        if (map.has(key)) {
          map.get(key).batchQty += it.batchQty // 同批号累加
        } else {
          map.set(key, { ...it })// 新批号新开一行
        }
      })
      // 为每个项目添加唯一ID和滑动属性
      beforeTableData.value = Array.from(map.values()).map((v, i) => ({
        ...v,
        uniqueId: `${v.materialNo}_${v.batchNumber}_${i}`,
        slideX: 0
      }))
    }

    /* ========= 左滑删除 ========= */
    const touchStart = (e) => {
      const idx = e.currentTarget.dataset.index
      beforeTableData.value.forEach((v, i) => {
        if (i !== idx) v.slideX = 0        // 其余归位
      })
      beforeTableData.value[idx].startX = e.touches[0].pageX
      beforeTableData.value[idx].slideX  = beforeTableData.value[idx].slideX || 0
    }

    const touchMove = (e) => {
      const idx = e.currentTarget.dataset.index
      const row = beforeTableData.value[idx]
      const delta = e.touches[0].pageX - row.startX
      if (delta < 0) {                      // 只允许左滑
        row.slideX = Math.max(delta, -70)   // 70 = 按钮宽度
      } else {
        row.slideX = Math.min(delta, 0)
      }
    }

    const touchEnd = (e) => {
      const idx = e.currentTarget.dataset.index
      const row = beforeTableData.value[idx]
      row.slideX = row.slideX <= -35 ? -70 : 0   // 过半则露出，否则收回
    }

    /** 
     * 删除一条已扫物料 
     * @param {number} idx 在 beforeTableData 中的下标 
     */ 
    const deleteItem = async (idx) => { 
      const target = beforeTableData.value[idx]; 

      /* 1. 有 id 就先调接口删后端 */ 
      if (target.id) { 
        try { 
          const { code, msg } = await uni.$reqDelete('deleteScanOutMaterial', { id: target.id }); 
          if (code !== 0) { 
            // 接口明确返回失败，提示用户并终止后续逻辑 
            errorTipMessage.value = msg || '后端删除失败'; 
            errorTip.value.open(); 
            return; 
          } 
        } catch (err) { 
          // 网络或其它异常 
          errorTipMessage.value = err.errMsg || '网络异常，删除失败'; 
          errorTip.value.open(); 
          return; 
        } 
      } 

      /* 2. 无论有没有 id、接口成不成功，只要走到这里就删本地 */ 
      // 2.1 从 localScannedList 里删掉对应项（同物料+同批号） 
      const key = `${target.materialNo}__${target.batchNumber}`; 
      const listIdx = localScannedList.value.findIndex( 
        v => `${v.materialNo}__${v.batchNumber}` === key 
      ); 
      if (listIdx > -1) localScannedList.value.splice(listIdx, 1); 

      // 2.2 重新合并生成 beforeTableData 
      flushBeforeTableData(); 

      // 2.3 把对应物料的“已备数”回退 
      const row = tableData.value.find(r => r.materialNo === target.materialNo); 
      if (row) row.completedQty -= target.batchQty; 
    }
    
    // 关闭错误信息弹窗
    const handleCloseErrorTipsModal = async function() {
      errorTip.value.close()
      if (errorState.value === 0) {
        await setInputFocus()
      }
    }
    /* ===================== 公共校验函数 ===================== */
    // 仓库ID校验函数
    const validateWarehouseId = (scanData) => {
	  // businessType 为 '1' 时跳过仓库ID校验
		if (businessType.value == '1') {
		return true;
		}
      const cur = Array.isArray(scanData) ? scanData[0] : scanData;
      if (cur && cur.warehouseId && currentWarehouseId.value && cur.warehouseId !== currentWarehouseId.value) {
        // #ifdef APP-PLUS
        plus.device.beep(2);
        // #endif
        errorTipMessage.value = `物料仓库(${cur.erpStockName})与当前仓库(${currentWarehouseName.value})不一致`;
        errorTip.value.open();
        errorState.value = 0;
        return false;
      }
      return true;
    };

    // 仅扫描本地缓存池，不再读 beforeTableData
    const isBatchExist = (batchNo) =>
      beforeTableData.value.some((it) => it.batchNumber === batchNo);

    const showBatchRepeatTip = () => {
      // #ifdef APP-PLUS
      plus.device.beep(2);
      // #endif
      errorTipMessage.value = '该批号已存在，请勿重复扫描';
      errorTip.value.open();
      errorState.value = 0;
    };
    // 禁用软键盘
    const handleInputFocus = function() {
      setTimeout(() => {
        uni.hideKeyboard()
      }, 100)
    }
    
    // 把 beforeTableData 追加到 tableData 对应物料的 inoutRequestSubdetailList
    const mergeBeforeIntoTable = () => {
      // 创建新数组存储合并结果
      const mergedTableData = JSON.parse(JSON.stringify(tableData.value))
      
      // 先建索引
      const map = {}
      mergedTableData.forEach(row => {
        if (!row.inoutRequestSubdetailList) row.inoutRequestSubdetailList = []
        map[row.materialNo] = row
      })

      // 只追加，不新增
      beforeTableData.value.forEach(item => {
        const target = map[item.materialNo]
        if (target) {
          target.inoutRequestSubdetailList.push({ ...item }) // 整条记录丢进去
        }
        // 不存在就跳过
      })
      
      return mergedTableData
    }

    // 保存按钮点击事件
    const handleSave = async function() {
      if (saveDisabled.value) return
      saveDisabled.value = true
      try {
        // 保存逻辑实现
        isLightText.value = true
        // 先合并数据，获取合并后的新数组
        const mergedData = mergeBeforeIntoTable()
        // 调用保存API，使用合并后的新数组作为参数
        await uni.$reqPost('saveScannedOutMaterials', {
          id: receiveList.value?.id,
          requestNo: receiveList.value?.requestNo,
          requestType: receiveList.value?.requestType,
          businessType: receiveList.value?.businessType,
          businessSubType: receiveList.value?.businessSubType,
          status: receiveList.value?.status,
          priority: receiveList.value?.priority,
          inoutRequestDetailPDASaveReqVOList: mergedData
        })
          .then(({ code, data, msg }) => {
            if (code === 0) {
              uni.showModal({
                title: '提示',
                content: '保存成功',
                showCancel: false
              })
              search();
            } else {
              // #ifdef APP-PLUS
              plus.device.beep(2)
              // #endif
              errorTipMessage.value = msg
              errorTip.value.open()
              errorState.value = 0
            }
          })
      } finally {
        saveDisabled.value = false
      }
    }
    
    // 提交按钮点击事件
    const handleSubmit = async function() {
      if (submitDisabled.value) return
      submitDisabled.value = true
      try {
        // 提交逻辑实现
        isSubmitLight.value = true
        // 先合并数据，获取合并后的新数组
        const mergedData = mergeBeforeIntoTable()
        // 调用提交API，使用合并后的新数组作为参数
        await uni.$reqPut('submitScannedOutMaterials', {
          id: receiveList.value?.id,
          requestNo: receiveList.value?.requestNo,
          requestType: receiveList.value?.requestType,
          businessType: receiveList.value?.businessType,
          businessSubType: receiveList.value?.businessSubType,
          status: receiveList.value?.status,
          priority: receiveList.value?.priority,
          inoutRequestDetailPDASaveReqVOList: mergedData
        })
          .then(({ code, data, msg }) => {
            if (code === 0) {
              uni.showModal({
                title: '提示',
                content: '提交成功',
                showCancel: false
              })
              search();
              // 保存成功后可以跳转到其他页面或执行其他操作
              // goBack()
            } else {
              // #ifdef APP-PLUS
              plus.device.beep(2)
              // #endif
              errorTipMessage.value = msg
              errorTip.value.open()
              errorState.value = 0
            }
          })
      } finally {
        submitDisabled.value = false
      }
    }

    // uniapp移动端触底事件
    onReachBottom(() => {
      queryParams.value.pageNo += 1
      uni.$reqGet('getPrepareMaterialList', queryParams.value)
        .then(({
          data
        }) => {
          Array.prototype.push.call(scanMaterialList.value, ...data?.list ?? [])
        })
    })
    
    // 保存按钮文字样式
    const saveBtnTextStyle = computed(() => ({
      fontSize: '14px',
      fontWeight: 'bold',
      color: saveDisabled.value ? '#ccc' : (isLightText.value ? 'rgba(0,160,233,1)' : '')
    }))
    
    // 提交按钮文字样式
    const submitBtnTextStyle = computed(() => ({
      fontSize: '14px',
      fontWeight: 'bold',
      color: submitDisabled.value ? '#ccc' : (isSubmitLight.value ? 'rgba(0,160,233,1)' : '')
    }))
    
    // 移除status监听，提交按钮和保存按钮均始终可用
    // watch(() => receiveList.value?.status, (newStatus) => {
    //   submitDisabled.value = newStatus !== 0
    // })

    /* -------------------- 新增 3 个方法 -------------------- */
    // 真正继续扫码（关闭弹窗并置标志）
    const fifoContinue = () => {
      fifoPopup.value.close()
      fifoGo.value = true
      // 用下一个 tick 把老流程续起来
      nextTick(() => {
        if (fifoQrCode) handleKeydown(fifoQrCode)
      })
    }
    const fifoCancel = () => { fifoPopup.value.close() } // 什么都不做

    // 统一 FIFO 校验入口
const checkFifo = (qrCode) => {
  // 用户已点“继续”，直接放行
  if (fifoGo.value) return Promise.resolve(true)

  if (!isBusinessTypeInFifoDict.value) return Promise.resolve(true)

  return uni.$reqPost('fifoCheck', { qrCode,
			requestNo: receiveList.value.requestNo,
			businessType: receiveList.value.businessType,
   }).then(({ code, data, msg }) => {
    if (code !== 0) {
      errorTipMessage.value = msg || 'FIFO 校验异常'
      errorTip.value.open()
      return false
    }
    if (data === null) return true
    fifoMsg.value = `当前条码（${qrCode}）不是库存中生产日期最早的物料条码（${data}），是否继续发料？`
    fifoQrCode = qrCode
    fifoPopup.value.open()
    return false
  })
}
// 回车触发 - 只跳转，不打开摄像头
const handleTmConfirm = () => {
  if (!tmId.value.trim()) {
    // 如果值为空，可能是误触发，聚焦到料号框
    nextTick(() => partInput.value?.onFocus());
    return;
  }
  // 有值的话，直接跳转到料号框
  nextTick(() => {
    partInput.value?.onBlur();
    partInput.value?.onFocus();
  });
};

    
    return {
      goBack,
      popup,
      signText,
      isBefore,
      tableData,
      beforeTableData,
      signInput,
      modalForm,
      easyinput,
	  handleTmConfirm,
      errorTip,
      errorTipMessage,
      handleInputFocus,
      isLightText,
      isSubmitLight,
      handleBtnLight,
      handleKeydown,
      scanBatchNumber,
      handleScanMaterial,
      handleToNavigate,
      saveDisabled,
      submitDisabled,
      saveBtnTextStyle,
      submitBtnTextStyle,
      scanMaterialList,
      handleComplete,
      handleSplitMaterial,
      handleToDetails,
      handleCloseErrorTipsModal,
      handleSubmit,
      handleSave,
      // 左滑删除相关
      touchStart,
      touchMove,
      touchEnd,
      deleteItem,
      scanTie,
      // 料号输入相关
      tmMaterialNo,
      partInput,
      handlePartKeydown,
      handleQueryPart,
      // 贴纸ID输入相关
      tmId,
      tmInput,
      setTmOnly,
      // FIFO相关
      fifoPopup,
      fifoMsg,
      fifoContinue,
      fifoCancel
    }
  }
})
</script>

<style lang="scss" scoped>
	.gui-header-leader-btns {
		color: black;
		font-size: 24px !important;
		margin-left: 24rpx;
	}

	.list-content {
		margin-top: 80px;
		background-color: #edeeee;
	}

	.card-list-flexbox {
		display: flex;
		flex-direction: row;
		align-items: center;
		flex-wrap: wrap;
		margin: 3px 2px;

		.card-list-item {
			width: 750rpx;
			height: 40px;
			margin: 2rpx 0;
			display: flex;
			flex-direction: row;
			align-items: center;
			justify-content: space-between;
			background-color: #fff;

			uni-text {
				font-size: 14px;
				height: 50rpx;
				text-align: left;
				padding: 0 12px;
				display: flex;
				flex-direction: row;
				align-items: center;
			}

			.text-1 {
				flex: 1;
				height: 40px;
				justify-content: flex-start;
			}

			.text-2 {
				flex: 3;
				height: 40px;
				justify-content: flex-end;
				margin-right: 4px;
				padding: 2px 6px;
			}
		}

	}

	.card-list-flexbox:nth-of-type(2) {
		margin-top: 48px;
	}

	.fixedTop {
		bottom: 0 !important;
		top: 3.25rem !important;
	}

	.popup-content {
		height: 75vh;
		overflow-y: scroll;
		background-color: #edeeee;
	}

	.font-icons {
		width: 40px;
		font-size: 20px;
	}

	.scan {
		height: 45px;
		width: calc(100% - 48px);
		margin: 12px;
		padding: 0 12px;
		display: flex;
		justify-content: space-between;
		align-items: center;
		border-radius: 6px;
		background-color: white;

		.scan-card {
			width: 100%;
			display: grid;
			grid-template-rows: 1fr;
			grid-template-columns: 7fr 2fr;
			align-items: center;

			input {
				height: 35px;
				line-height: 35px;
			}

			text {
				width: 100%;
				text-align: right;
			}
		}
	}

	.custom-table {
		height: calc(100vh - 265px);
		min-height: 230px;
		margin: 5px 0;
		// min-height: 600px;
		overflow-y: scroll;
	}

	.modal-btns {
		height: 100rpx;
		line-height: 100rpx;
		display: flex;
		justify-content: center;
		align-items: center;
	}

	.line {
		margin-top: 10rpx;
		height: 80rpx;
		width: 1rpx;
		background-color: #dcdcdc;
	}

	.tabs {
		width: 100%;
		height: 45px;
		display: flex;
		align-items: flex-end;
		padding: 0 2px;
		background-color: white;
		
		.tabs-list {
			border-radius: 3px;
			overflow: hidden;
		}
	
		.tabs-item {
			display: inline-block;
			width: 72px;
			height: 30px;
			line-height: 30px;
			padding: 0 8px;
			font-size: 14px;
			font-weight: bold;
			text-align: center;
			color: black;
			border-bottom: 1.5px dashed #00a0e9;
			transition: all .5s ease-in-out;
		}
	
		.tabs-item-active {
			position: relative;
			display: inline-block;
			width: 72px;
			height: 30px;
			line-height: 30px;
			padding: 0 8px;
			font-size: 14px;
			font-weight: bold;
			text-align: center;
			color: white;
			border-left: 1px solid #00a0e9;
			border-top: 1px solid #00a0e9;
			border-right: 1px solid #00a0e9;
			border-bottom: 1.5px solid #00a0e9;
			border-radius: 5px 5px 0 0;
			animation: .3s linear show;
			background-color: #00a0e9;
		}
	
		.tabs-item-active::before {
			content: '';
			position: absolute;
			left: -10px;
			bottom: 0;
			width: 10px;
			height: 10px;
			background: radial-gradient(circle at 0% 25%, transparent 10px, #00a0e9 0)
		}
	
		.tabs-item-active::after {
			content: '';
			position: absolute;
			right: -10px;
			bottom: 0;
			width: 10px;
			height: 10px;
			background: radial-gradient(circle at 100% 25%, transparent 10px, #00a0e9 0)
		}
	}
	
	@keyframes show {
		from {
			transform: translateY(5%);
		}
	
		to {
			transform: translateY(0%);
		}
	}

	.sign-btn {
		display: flex;
		align-items: center;
		justify-content: center;
		margin: 0 8px;
		border: 1px solid #999999;
		background-color: white;
		border-radius: 6px;
	}
	
	.sign-btn.disabled {
		border-color: #ccc;
		background-color: #f5f5f5;
		pointer-events: none;
	}

	/* 左滑删除样式 */
	.scroll-box{
		height:100%;                 /* 继承父级高度 */
	}
	.cell-row {
		display: flex;
		background-color: #f5f7fa;
		font-weight: bold;
		border-radius: 4px;
		margin-bottom: 5px;
	}
	.swipe-row{
		position:relative;
		width:100%;
		height:44px;
		overflow:hidden;
		border-bottom:1px solid #eee;
		margin-bottom: 5px;
		border-radius: 4px;
	}
	.content-area{
		position:absolute;
		left:0;
		top:0;
		right:0;
		bottom:0;
		z-index:2;
		background:#fff;
		display:flex;
		align-items:center;
		transition: transform .25s;
		border-radius: 4px;
	}
	.cell1{
		flex:2;
		text-align:center;
		font-size:14px;
		color:#333;
		height: 44px;
		line-height: 44px;
	}
  .cell2{
		flex:1;
		text-align:center;
		font-size:14px;
		color:#333;
		height: 44px;
		line-height: 44px;
	}
  .cell3{
		flex:2;
		text-align:center;
		font-size:14px;
		color:#333;
		height: 44px;
		line-height: 44px;
	}
	.btn-area{
		position:absolute;
		right:0;
		top:0;
		width:70px;
		height:100%;
		background:#e54d42;
		color:#fff;
		display:flex;
		align-items:center;
		justify-content:center;
		font-size:14px;
		z-index:1;
		border-radius: 4px;
	}
	// /* 表头也允许换行，保证与列宽对齐 */
	// ::v-deep .break-col {
	//   white-space: normal !important;
	//   word-break: break-all !important;
	//   line-height: 1.2;
	// }
	
	// /* 单元格超长自动分段 */
	// ::v-deep .break-cell {
	//   white-space: normal !important;
	//   word-break: break-all !important;
	//   line-height: 1.2;
	//   padding: 4px 2px;          /* 上下留一点空隙，视觉更舒服 */
	// }
</style>