<template>
  <div class="customer-css">
    <el-dialog :title="titleCon" v-drag v-bind="$attrs" v-on="$listeners" width="830px" style="height: 680px;" class="customer-dialog" :show-close="!exceptionRuleLocked" :close-on-press-escape="!exceptionRuleLocked" :before-close="handleMainDialogBeforeClose" @close="onDialogClosed">
      <el-form :inline="true" label-position="top" style="height: auto;">
        <!-- 时间和固定载具 -->
        <el-row style="margin-top: -10px;">
          <el-col :span="11">
            <el-form-item :label=labels.currentTime>
              <el-date-picker style="width: 110px;"
                              v-model="pageData.reportDate"
                              format="yyyy-MM-dd"
                              value-format="yyyy-MM-dd"
                              placeholder="">
              </el-date-picker>
            </el-form-item>
            <el-form-item :label="''" style="margin-top: 23px">
              <el-time-picker style="width: 100px;"
                              v-model="pageData.reportTime"
                              format="HH:mm:ss"
                              value-format="HH:mm:ss"
                              placeholder="">
              </el-time-picker>
            </el-form-item>
          </el-col>
          <el-col :span="6">
            <el-form-item>
              <span style="cursor: pointer" slot="label" @click="queryFixedCarrierList"><a>固定载具</a></span>
              <el-input v-model="pageData.fixture" readonly style="width: 120px;" placeholder="固定载具">
                <i v-if="pageData.fixture"
                   slot="suffix"
                   class="el-icon-circle-close fixture-clear-btn"
                   @click="pageData.fixture = ''">
                </i>
              </el-input>
            </el-form-item>
          </el-col>
          <el-col :span="3">
            <el-form-item label="排数">
              <el-input-number :controls="false" :step="0" v-model="pageData.rowCount" @change="handleRowCountChange" style="width: 60px;"></el-input-number>
            </el-form-item>
          </el-col>
          <el-col :span="3">
            <el-form-item label="分切卷数">
              <el-input-number :controls="false" :step="0" v-model="pageData.rollCount" @change="handleRollCountChange" style="width: 60px;"></el-input-number>
            </el-form-item>
          </el-col>
        </el-row>

        <!-- 排数据表格 -->
        <div class="rq">
          <el-table
            :data="rowDataList"
            border
            style="width: 100%; margin-top: 10px;"
            max-height="350"
            :span-method="objectSpanMethod">
            <el-table-column prop="rowNumber" label="NO." width="50" align="center">
            </el-table-column>
            <el-table-column label="良品数" width="80" align="center">
              <template slot-scope="scope">
                <el-input-number
                  :controls="false" :step="0"
                  v-model="scope.row.goodQty"
                  @change="handleQtyChange(scope.row)"
                  style="width: 100%"
                  class="good-qty-input"
                  :style="{'color': '#67c23a', 'font-weight': 'bold'}">
                </el-input-number>
              </template>
            </el-table-column>
            <el-table-column label="面损" width="80" align="center">
              <template slot-scope="scope">
                <el-input-number
                  :controls="false" :step="0"
                  v-model="scope.row.surfaceLossQty"
                  @change="handleQtyChange(scope.row)"
                  style="width: 100%">
                </el-input-number>
              </template>
            </el-table-column>
            <el-table-column label="性能不良" width="80" align="center">
              <template slot-scope="scope">
                <el-input-number
                  :controls="false" :step="0"
                  v-model="scope.row.poorPerformanceQty"
                  @change="handleQtyChange(scope.row)"
                  style="width: 100%">
                </el-input-number>
              </template>
            </el-table-column>
            <el-table-column label="不良数" width="80" align="right">
              <template slot-scope="scope">
                <div class="defect-display" :style="{'color': '#f56c6c', 'font-weight': 'bold', 'text-align': 'right', 'padding-right': '10px'}">
                  {{ scope.row.defectQty }}
                </div>
              </template>
            </el-table-column>
            <el-table-column label="良率" width="80" align="center">
              <template slot-scope="scope">
                <div class="yield-display" :style="{'color': '#409eff', 'font-weight': 'bold'}">
                  {{ scope.row.yieldRate }}
                </div>
              </template>
            </el-table-column>
            <el-table-column label="总数" width="80" align="right">
              <template slot-scope="scope">
                <div class="total-display" :style="{'text-align': 'right', 'padding-right': '10px'}">
                  {{ scope.row.totalQty }}
                </div>
              </template>
            </el-table-column>
            <el-table-column v-if="scheduleData.packingListFlag === 'Y'" label="Packing List" align="center" class-name="packing-list-column">
              <template slot-scope="scope">
                <div class="remark-wrapper">
                  <el-input
                    type="textarea"
                    v-model="scope.row.packingList"
                    resize="none"
                    :autosize="false"
                    class="remark-textarea">
                  </el-input>
                </div>
              </template>
            </el-table-column>
            <el-table-column label="备注" align="center" class-name="remark-column">
              <template slot-scope="scope">
                <div class="remark-wrapper">
                  <el-input
                    type="textarea"
                    v-model="scope.row.remark"
                    resize="none"
                    :autosize="false"
                    class="remark-textarea">
                  </el-input>
                </div>
              </template>
            </el-table-column>
            <el-table-column label="操作" align="center" width="110" class-name="operation-column">
              <template slot-scope="scope">
                <el-button type="text" size="mini" @click="openRollDefectDialog(scope.$index)">不良原因</el-button>
              </template>
            </el-table-column>
          </el-table>
        </div>
      </el-form>
      <span slot="footer" class="dialog-footer">
        <el-button type="primary" @click="checkCreateSeparateRolllBun" :loading="yieldReportLoading" :disabled="exceptionRuleLocked">产量报告</el-button>
        <el-button type="success" @click="saveShiftChangeTransfer" :loading="shiftChangeLoading" :disabled="exceptionRuleLocked">换班结转</el-button>
        <el-button type="warning" @click="executeAbnormalRollCut" :loading="abnormalCutLoading" :disabled="exceptionRuleLocked">异常截卷</el-button>
        <el-button @click="closeDialog" :disabled="exceptionRuleLocked">{{ buttons.closeButton }}</el-button>
      </span>
      <div
        v-if="exceptionRuleLocked"
        :class="['exception-rule-mask-screen', isWarningLevelStyle() ? 'warning' : 'serious']">
        <div class="exception-rule-bg-grid"></div>
        <div class="exception-rule-vignette"></div>
        <div class="exception-rule-scanline">
          <div class="lines"></div>
          <div class="beam"></div>
        </div>
        <div class="exception-rule-corners">
          <div class="corner tl">
            <svg viewBox="0 0 80 80">
              <path d="M4 40 L4 4 L40 4" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="square" opacity="0.7" />
              <line x1="4" y1="16" x2="10" y2="16" stroke="currentColor" stroke-width="1" opacity="0.4" />
              <line x1="4" y1="28" x2="8" y2="28" stroke="currentColor" stroke-width="1" opacity="0.4" />
              <line x1="16" y1="4" x2="16" y2="10" stroke="currentColor" stroke-width="1" opacity="0.4" />
              <line x1="28" y1="4" x2="28" y2="8" stroke="currentColor" stroke-width="1" opacity="0.4" />
              <g class="arc">
                <circle cx="4" cy="4" r="14" fill="none" stroke="currentColor" stroke-width="1.5" stroke-dasharray="14 74" opacity="0.6" />
              </g>
              <rect x="1" y="1" width="6" height="6" fill="currentColor" opacity="0.9" />
            </svg>
          </div>
          <div class="corner tr">
            <svg viewBox="0 0 80 80">
              <path d="M4 40 L4 4 L40 4" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="square" opacity="0.7" />
              <line x1="4" y1="16" x2="10" y2="16" stroke="currentColor" stroke-width="1" opacity="0.4" />
              <line x1="4" y1="28" x2="8" y2="28" stroke="currentColor" stroke-width="1" opacity="0.4" />
              <line x1="16" y1="4" x2="16" y2="10" stroke="currentColor" stroke-width="1" opacity="0.4" />
              <line x1="28" y1="4" x2="28" y2="8" stroke="currentColor" stroke-width="1" opacity="0.4" />
              <g class="arc">
                <circle cx="4" cy="4" r="14" fill="none" stroke="currentColor" stroke-width="1.5" stroke-dasharray="14 74" opacity="0.6" />
              </g>
              <rect x="1" y="1" width="6" height="6" fill="currentColor" opacity="0.9" />
            </svg>
          </div>
          <div class="corner bl">
            <svg viewBox="0 0 80 80">
              <path d="M4 40 L4 4 L40 4" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="square" opacity="0.7" />
              <line x1="4" y1="16" x2="10" y2="16" stroke="currentColor" stroke-width="1" opacity="0.4" />
              <line x1="4" y1="28" x2="8" y2="28" stroke="currentColor" stroke-width="1" opacity="0.4" />
              <line x1="16" y1="4" x2="16" y2="10" stroke="currentColor" stroke-width="1" opacity="0.4" />
              <line x1="28" y1="4" x2="28" y2="8" stroke="currentColor" stroke-width="1" opacity="0.4" />
              <g class="arc">
                <circle cx="4" cy="4" r="14" fill="none" stroke="currentColor" stroke-width="1.5" stroke-dasharray="14 74" opacity="0.6" />
              </g>
              <rect x="1" y="1" width="6" height="6" fill="currentColor" opacity="0.9" />
            </svg>
          </div>
          <div class="corner br">
            <svg viewBox="0 0 80 80">
              <path d="M4 40 L4 4 L40 4" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="square" opacity="0.7" />
              <line x1="4" y1="16" x2="10" y2="16" stroke="currentColor" stroke-width="1" opacity="0.4" />
              <line x1="4" y1="28" x2="8" y2="28" stroke="currentColor" stroke-width="1" opacity="0.4" />
              <line x1="16" y1="4" x2="16" y2="10" stroke="currentColor" stroke-width="1" opacity="0.4" />
              <line x1="28" y1="4" x2="28" y2="8" stroke="currentColor" stroke-width="1" opacity="0.4" />
              <g class="arc">
                <circle cx="4" cy="4" r="14" fill="none" stroke="currentColor" stroke-width="1.5" stroke-dasharray="14 74" opacity="0.6" />
              </g>
              <rect x="1" y="1" width="6" height="6" fill="currentColor" opacity="0.9" />
            </svg>
          </div>
        </div>
        <div class="exception-rule-statusbar">
          <div class="left">
            <span class="mes">Boing MES</span>
            <span>Site - {{ scheduleData.site || '--' }} / Bu - {{ scheduleData.buNo || '--' }}</span>
          </div>
          <div class="right">
            <span class="lockdown"><span class="dot"></span>{{ getExceptionRuleActiveText() }}</span>
            <span>{{ exceptionRuleClockDate || getNowDateText() }}</span>
            <span class="clock">{{ exceptionRuleClockTime || getNowTimeText() }}</span>
          </div>
        </div>
        <div class="exception-rule-main">
          <div class="exception-rule-alert-icon">
            <div class="pulse-ring d0"></div>
            <div class="pulse-ring d1"></div>
            <div class="pulse-ring d2"></div>
            <div class="alert-glow"></div>
            <div class="alert-core">
              <svg width="48" height="48" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round">
                <path d="m21.73 18-8-14a2 2 0 0 0-3.48 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.73-3Z"/>
                <line x1="12" y1="9" x2="12" y2="13"/>
                <line x1="12" y1="17" x2="12.01" y2="17"/>
              </svg>
            </div>
          </div>

          <div class="exception-rule-title-block">
            <div class="exception-rule-title-cn">{{ getExceptionRuleTitleCn() }}</div>
            <div class="exception-rule-title-en">PROCESS QUALITY FAULT</div>
            <div class="exception-rule-title-rule"></div>
            <div class="exception-rule-title-lock">{{ getExceptionRuleTitleLock() }}</div>
          </div>

          <div class="exception-rule-info-cards">
            <div class="exception-rule-info-card">
              <span class="label">设备编号 / EQUIPMENT ID</span>
              <span class="value">{{ getExceptionRuleEquipmentText() }}</span>
            </div>
            <div class="exception-rule-info-card">
              <span class="label">锁定时间 / LOCKED AT</span>
              <span class="value">{{ getExceptionRuleLockedTimeText() }}</span>
            </div>
            <div class="exception-rule-info-card work-order-card">
              <span class="label">工单编号 / WORK ORDER</span>
              <div class="work-order-value-line">
                <span class="value hl">{{ getExceptionRuleWorkOrderText() }}</span>
                <span class="work-order-seq">{{ getExceptionRuleSeqNoText() }}</span>
              </div>
            </div>
          </div>

          <div class="exception-rule-flow-steps">
            <div class="flow-step done"><div class="dot"></div><div class="label">异常检测</div></div>
            <div class="flow-line done"></div>
            <div class="flow-step done"><div class="dot"></div><div class="label">工位锁定</div></div>
            <div class="flow-line"></div>
            <div class="flow-step active"><div class="dot"></div><div class="label">质量审核</div></div>
            <div class="flow-line"></div>
            <div class="flow-step"><div class="dot"></div><div class="label">解锁生产</div></div>
          </div>
        </div>

        <div class="exception-rule-bottombar">
          <div class="inner">
            <div class="left">
              <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
                <path d="M22 12h-4l-3 9L9 3l-3 9H2"/>
              </svg>
              <span class="ttl">生产质量指标 / QUALITY METRICS</span>
            </div>
            <div class="exception-rule-quality-cards">
              <div class="quality-card">
                <span class="qlabel">不良品率 / DEFECT RATE</span>
                <span class="qvalue hl">{{ formatExceptionRuleDefectRateText() }}</span>
              </div>
              <div class="quality-card">
                <span class="qlabel">影响数量 / AFFECTED</span>
                <span class="qvalue hl">{{ formatExceptionRuleAffectedQtyText() }}</span>
              </div>
              <div class="quality-card">
                <span class="qlabel">已生产数量 / PRODUCED</span>
                <span class="qvalue">{{ formatExceptionRuleProducedQtyText() }}</span>
              </div>
            </div>
            <div class="right">
              <div>实时监控中</div>
              <div class="auth">
                REAL-TIME MONITORING
                <svg width="10" height="10" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
                  <polyline points="9 18 15 12 9 6"/>
                </svg>
              </div>
            </div>
          </div>
        </div>
      </div>
    </el-dialog>

    <!-- 分卷不良原因对话框 -->
    <el-dialog
      title="不良原因"
      :close-on-click-modal="false"
      :visible.sync="rollDefectDialogVisible"
      width="700px"
      append-to-body>
      <div class="roll-defect-summary">
        <span>当前卷：第{{ currentRollDefectIndex }}卷</span>
        <span>面损合计：{{ formatQty(getCurrentRollSurfaceLossQty()) }}</span>
        <span>已选不良合计：{{ formatQty(getCurrentRollDefectTotal()) }}</span>
      </div>
      <el-form :inline="true" label-position="top" class="roll-defect-form">
        <el-form-item>
          <span slot="label" class="defect-code-label" @click="getBaseList(89)"><a>不良代码</a></span>
          <el-input
            v-model="rollDefectForm.defectCode"
            readonly
            class="defect-code-input"
            style="width: 130px"
            placeholder="请选择"
            @click.native="getBaseList(89)">
          </el-input>
        </el-form-item>
        <el-form-item label="不良数量">
          <el-input-number
            v-model="rollDefectForm.defectQty"
            :controls="false"
            :min="0"
            style="width: 120px">
          </el-input-number>
        </el-form-item>
        <el-form-item label="不良描述">
          <el-input
            v-model="rollDefectForm.defectDesc"
            readonly
            style="width: 250px">
          </el-input>
        </el-form-item>
        <el-form-item label=" ">
          <el-button type="primary" @click="addRollDefectItem">添加</el-button>
        </el-form-item>
      </el-form>
      <el-table
        :data="currentRollDefectList"
        border
        height="260"
        style="width: 100%;">
        <el-table-column prop="defectCode" label="不良代码" width="120" align="center"></el-table-column>
        <el-table-column prop="defectDesc" label="不良描述" min-width="260" align="left"></el-table-column>
        <el-table-column prop="defectQty" label="不良数量" width="110" align="right"></el-table-column>
        <el-table-column label="操作" width="80" align="center">
          <template slot-scope="scope">
            <el-button type="text" @click="removeRollDefectItem(scope.$index)">删除</el-button>
          </template>
        </el-table-column>
      </el-table>
      <span slot="footer" class="dialog-footer">
        <el-button type="primary" @click="rollDefectDialogVisible = false">确定</el-button>
      </span>
    </el-dialog>

    <!-- 固定载具选择对话框 -->
    <el-dialog title="固定载具清单" :close-on-click-modal="false" v-drag :visible.sync="carrierModelFlag" width="950px">
      <div class="rq">
        <el-form :inline="true" label-position="top" :model="carrierSearchData">
          <el-form-item label="标签条码">
            <el-input v-model="carrierSearchData.carrierNo" clearable style="width: 150px"></el-input>
          </el-form-item>
          <el-form-item label="载具类型名称">
            <el-input v-model="carrierSearchData.carrierTypeName" clearable style="width: 150px"></el-input>
          </el-form-item>
          <el-form-item label="规格描述">
            <el-input v-model="carrierSearchData.specification" clearable style="width: 150px"></el-input>
          </el-form-item>
          <el-form-item label=" ">
            <el-button type="primary" @click="queryFixedCarrierList">查询</el-button>
            <el-button v-if="!editBatchVisible" @click="editBatchModel" type="success" icon="el-icon-edit">批量编辑</el-button>
            <el-button v-if="editBatchVisible" @click="batchSaveCarrier" type="primary" icon="el-icon-check" :loading="saveLoading">批量保存</el-button>
            <el-button type="success" icon="el-icon-plus" @click="addCarrierModal">新增</el-button>
          </el-form-item>
        </el-form>
        <el-table
          :height="400"
          :data="carrierList"
          @row-dblclick="selectCarrier"
          border
          style="width: 100%;">
          <el-table-column
            prop="carrierNo"
            label="标签条码"
            header-align="center"
            align="left"
            min-width="120">
          </el-table-column>
          <el-table-column
            prop="carrierTypeCode"
            label="载具类型编码"
            header-align="center"
            align="left"
            min-width="120">
          </el-table-column>
          <el-table-column
            prop="carrierTypeName"
            label="载具类型名称"
            header-align="center"
            align="left"
            min-width="150">
          </el-table-column>
          <el-table-column
            prop="specification"
            label="规格描述"
            header-align="center"
            align="left"
            min-width="150">
          </el-table-column>
          <el-table-column
            prop="dimensions"
            label="尺寸"
            header-align="center"
            align="left"
            min-width="100">
          </el-table-column>
          <el-table-column
            label="可用数量"
            header-align="center"
            align="right"
            min-width="120">
            <template slot-scope="scope">
              <el-input-number
                v-if="editBatchVisible"
                v-model="scope.row.availableQty"
                :controls="false"
                :min="0"
                :precision="0"
                style="width: 100%">
              </el-input-number>
              <span v-else>{{ scope.row.availableQty || 0 }}</span>
            </template>
          </el-table-column>
          <el-table-column
            label="操作"
            header-align="center"
            align="center"
            width="80"
            fixed="right">
            <template slot-scope="scope">
              <el-button
                type="text"
                icon="el-icon-printer"
                @click="printCarrier(scope.row)"
                style="color: #409eff;">
                打印
              </el-button>
            </template>
          </el-table-column>
        </el-table>
      </div>
      <el-footer style="height:40px;margin-top: 20px;text-align:center">
        <el-button type="primary" @click="carrierModelFlag=false">关闭</el-button>
      </el-footer>
    </el-dialog>

    <!-- 新增固定载具对话框 -->
    <el-dialog title="新增固定载具" :close-on-click-modal="false" v-drag :visible.sync="addCarrierFlag" width="487px">
      <el-form ref="addCarrierForm" :inline="true" label-position="top" :model="addCarrierData" :rules="addCarrierRules" style="margin-left: 7px;margin-top: -5px;">
        <el-form-item label="状态" prop="status">
          <el-select v-model="addCarrierData.status" placeholder="请选择" style="width: 120px">
            <el-option label="空闲" :value="1"></el-option>
            <el-option label="占用" :value="2"></el-option>
            <el-option label="维修" :value="3"></el-option>
            <el-option label="报废" :value="4"></el-option>
            <el-option label="外借" :value="5"></el-option>
          </el-select>
        </el-form-item>
      </el-form>
      <el-form :inline="true" label-position="top" :model="addCarrierData" :rules="addCarrierRules" style="margin-left: 7px">
        <el-form-item label="载具类型编码" prop="carrierTypeCode">
          <el-input v-model="addCarrierData.carrierTypeCode" style="width: 150px"></el-input>
        </el-form-item>
        <el-form-item label="载具类型名称" prop="carrierTypeName">
          <el-input v-model="addCarrierData.carrierTypeName" style="width: 285px"></el-input>
        </el-form-item>
      </el-form>
      <el-form :inline="true" label-position="top" :model="addCarrierData" style="margin-left: 7px">
        <el-form-item label="固定资产编号">
          <el-input v-model="addCarrierData.assetNo" style="width: 150px"></el-input>
        </el-form-item>
        <el-form-item label="规格描述">
          <el-input v-model="addCarrierData.specification" style="width: 285px"></el-input>
        </el-form-item>
      </el-form>
      <el-form :inline="true" label-position="top" :model="addCarrierData" style="margin-left: 7px">
        <el-form-item label="采购日期">
          <el-date-picker v-model="addCarrierData.purchaseDate" type="date" value-format="yyyy-MM-dd" style="width: 150px"></el-date-picker>
        </el-form-item>
        <el-form-item label="当前位置">
          <el-input v-model="addCarrierData.currentLocation" style="width: 150px"></el-input>
        </el-form-item>
        <el-form-item label="尺寸">
          <el-input v-model="addCarrierData.dimensions" style="width: 120px"></el-input>
        </el-form-item>
      </el-form>
      <el-form :inline="true" label-position="top" :model="addCarrierData" style="margin-left: 7px">
        <el-form-item label="可用数量">
          <el-input-number v-model="addCarrierData.availableQty" :controls="false" style="width: 102px"></el-input-number>
        </el-form-item>
        <el-form-item label="最大承重">
          <el-input-number v-model="addCarrierData.maxWeight" :controls="false" style="width: 102px"></el-input-number>
        </el-form-item>
        <el-form-item label="预期使用次数">
          <el-input-number v-model="addCarrierData.expectedLifeCycles" :controls="false" style="width: 102px"></el-input-number>
        </el-form-item>
        <el-form-item label="预期使用寿命">
          <el-input-number v-model="addCarrierData.expectedLifeDays" :controls="false" style="width: 101px"></el-input-number>
        </el-form-item>
      </el-form>
      <el-form :inline="true" label-position="top" :model="addCarrierData" style="margin-left: 7px">
        <el-form-item label="备注">
          <el-input type="textarea" v-model="addCarrierData.remark" :rows="3" resize='none' show-word-limit style="width: 450px;height: 30px"></el-input>
        </el-form-item>
      </el-form>
      <el-footer style="height:35px;margin-top: 55px;text-align:center">
        <el-button type="primary" :loading="addCarrierLoading" @click="saveAddCarrier">保存</el-button>
        <el-button @click="addCarrierFlag=false">关闭</el-button>
      </el-footer>
    </el-dialog>
    <Chooselist ref="baseList" @getBaseData="getBaseData"></Chooselist>
  </div>
</template>

<script>
  import {
    checkSplitRollExceptionRule,/*创建分卷前异常规则校验*/
    getSplitRuleLockStatus,/*查询创建分卷规则锁定状态*/
    completeSplitRuleTodoOperation,/*创建分卷完成后回写代办操作标识*/
    createSplitSfdcRoll,/*执行创建分卷的操作*/
    getFixedCarrierList,/*获取固定载具列表*/
    getUnprocessedShiftChangeData,/*查询未处理的换班结转数据*/
    saveShiftChangeData,/*保存换班结转数据*/
    markShiftChangeAsProcessed,/*更新换班结转数据为已处理*/
    saveAbnormalRollData,/*保存异常截卷数据*/
  } from '@/api/yieldReport/com_separate_roll.js';
  import { checkDefectCode } from '@/api/yieldReport/com_defect_roll.js';
  import { fixedCarrierSave } from '@/api/fixedCarrier/fixedCarrier.js';
  import Chooselist from '@/views/modules/common/Chooselist';

  /*打印标签专用的js*/
  import {
    printSfdcLabel,
  } from "@/views/modules/yieldReport/print_roll_label.js";

  import {
    searchSysLanguagePackList,
    searchSysLanguageParam,
    searchFunctionButtonList,
    saveButtonList,
    searchSysLanguage,
    searchLanguageListByLanguageCode,
    saveSysLanguageOne,
    searchPageLanguageData,
    removerLanguage,
    saveSysLanguageList
  } from "@/api/sysLanguage.js";
  import {
    getPartLabelTemplateList,
    callUspPartLabelTemplate
  } from '@/api/wms/wms';

  import getLodop from '@/utils/LodopFuncs.js';
  import labelPrintTemplates from '@/mixins/labelPrintTemplates.js';

  var functionId = 'C10000004';

export default {
  name: "com_separate_roll",
  mixins: [labelPrintTemplates],
  components: {
    Chooselist
  },
  data() {
    return {
      titleCon: '创建分卷',
      showDefault: false,
      // 按钮loading状态
      yieldReportLoading: false,      // 产量报告loading
      shiftChangeLoading: false,      // 换班结转loading
      abnormalCutLoading: false,      // 异常截卷loading
      exceptionRuleLocked: false,     // 异常规则触发后的强制锁定
      exceptionRuleLockMessage: '',   // 锁定提示文案
      exceptionRuleWarningLevel: '',  // 预警等级（轻微/一般/严重）
      exceptionRuleLockedAt: '',      // 锁定时间
      exceptionRuleMatchedRollIndex: null, // 触发规则卷序号
      exceptionRuleMatchedDefectRate: null, // 触发规则卷不良率
      exceptionRuleMatchedTotalQty: null, // 触发规则卷总数
      exceptionRuleClockDate: '', // 锁定页面日期
      exceptionRuleClockTime: '', // 锁定页面时间
      exceptionRuleClockTimer: null, // 锁定页面时钟定时器
      pendingRuleFollowupAction: '',  // 提示类规则在成功后需打开的功能动作
      pendingRuleFollowupResultMap: null,
      scheduleData: {
        site: this.$store.state.user.site,
        username: this.$store.state.user.name,
        seqNo: '',
        orderNo: '',
        itemNo: 0,
        resourceId: '',
        scheduledDate: '',
        shiftNo: '',
        partNo: '',
        buNo: '',
        workCenterNo: '',
        workCenterDesc: '',
        resourceDesc: '',
        rollNo: '',
        partDesc: '',
        totalRollQty: 0,
        planStartTime: '',
        planFinishTime: '',
        qtyRequiredOriginal: 0,
        preItemDesc: '',
        nextItemDesc: '',
        nextItemNo: 0,
        operatorId: '',
        functionName: '',
        currentRollFlag: false
      },
      pageData: {
        site: this.$store.state.user.site,
        username: this.$store.state.user.name,
        orderNo: '',
        itemNo: '',
        seqNo: '',
        rollNo: '',
        reportDate: '',
        reportTime: '',
        operatorId: '',
        rollQty: 0,
        rollNums: 1,
        // 新增字段
        fixture: '',      // 固定载具
        rowCount: 0,      // 排数
        rollCount: 0,      // 卷数
        carrierNo: ''
      },
      rowDataList: [],    // 排数据列表
      // 分卷不良原因（前端暂存）
      rollDefectDialogVisible: false,
      currentRollDefectIndex: 1,
      tagNo: '',
      rollDefectForm: {
        defectCode: '',
        defectDesc: '',
        defectQty: null
      },
      rollDefectMap: {},
      currentRollDefectList: [],
      operatorData: {
        site: this.$store.state.user.site,
        username: this.$store.state.user.name,
        operatorId: '',
        operatorName: '',
        status: '',
        seqNo: '',
        showFlag: false
      },
      carrierModelFlag: false,  // 固定载具对话框标记
      carrierList: [],  // 固定载具列表
      carrierSearchData: {  // 固定载具查询条件
        carrierNo: '',
        carrierTypeName: '',
        specification: ''
      },
      editBatchVisible: false,  // 批量编辑状态
      saveLoading: false,  // 保存loading状态
      // 新增固定载具相关
      addCarrierFlag: false,
      addCarrierLoading: false,
      addCarrierData: {
        bu: '',
        site: '',
        buNo: '',
        carrierTypeCode: '',
        carrierTypeName: '',
        assetNo: '',
        specification: '',
        purchaseDate: null,
        currentLocation: '',
        dimensions: '',
        availableQty: null,
        maxWeight: null,
        expectedLifeCycles: null,
        expectedLifeDays: null,
        status: 1,
        remark: ''
      },
      addCarrierRules: {
        carrierTypeCode: [{ required: true, message: '请输入载具类型编码', trigger: 'blur' }],
        carrierTypeName: [{ required: true, message: '请输入载具类型名称', trigger: 'blur' }]
      },
      hasCachedData: false,  // 是否有缓存数据
      cachedDataCount: 0,    // 缓存数据条数
      cachedRowDataList: [],  // 缓存的原始行数据（用于校验）
      isLoadingCachedData: false,  // 是否正在加载缓存数据（防止触发handleRowCountChange）
      lockStatusTimer: null, // 强制锁定状态轮询定时器
      buttons: {
        confirmButton: '确定',
        closeButton: '关闭',
      },
      buttonList: [
        {
          functionId: functionId,
          languageValue: '确定',
          objectId: 'confirmButton',
          objectType: 'button',
          tableId: '*'
        }, {
          functionId: functionId,
          languageValue: '关闭',
          objectId: 'closeButton',
          objectType: 'button',
          tableId: '*'
        },
      ],
      queryButton: {
        functionId: functionId,
        table_id: '*',
        languageCode: this.$i18n.locale,
        objectType: 'button'
      },
      labels: {
        componentTitle: '创建分卷',
        currentTime: '当前时间:',
        rollQty: '良品数量:',
        rollNums: '卷数:',
        approvedQtyMustBeInteger: '良品数量必须是正整数!',
        rollQtyMustBeInteger: '卷数必须是正整数!',
        pleaseSwitchOperator: '请先切换人员!',
        approvedQtyMustMoreTanZeroAndBeInteger: '良品数量必须大于零且是整数!',
        rollQtyMustMoreTanZeroAndBeInteger: '卷数必须是正整数!',
        confirmLabel: '确认',
        cancelLabel: '取消',
      },
      labelsList: [
        {
          functionId: functionId,
          languageValue: '创建分卷',
          objectId: 'componentTitle',
          objectType: 'label',
          tableId: '*'
        }, {
          functionId: functionId,
          languageValue: '当前时间:',
          objectId: 'currentTime',
          objectType: 'label',
          tableId: '*'
        }, {
          functionId: functionId,
          languageValue: '良品数量:',
          objectId: 'rollQty',
          objectType: 'label',
          tableId: '*'
        }, {
          functionId: functionId,
          languageValue: '卷数:',
          objectId: 'rollNums',
          objectType: 'label',
          tableId: '*'
        }, {
          functionId: functionId,
          languageValue: '良品数量必须是正整数!',
          objectId: 'approvedQtyMustBeInteger',
          objectType: 'label',
          tableId: '*'
        }, {
          functionId: functionId,
          languageValue: '卷数必须是正整数!',
          objectId: 'rollQtyMustBeInteger',
          objectType: 'label',
          tableId: '*'
        }, {
          functionId: functionId,
          languageValue: '良品数量必须大于零且是整数!',
          objectId: 'approvedQtyMustMoreTanZeroAndBeInteger',
          objectType: 'label',
          tableId: '*'
        }, {
          functionId: functionId,
          languageValue: '卷数必须大于零且是整数!',
          objectId: 'rollQtyMustMoreTanZeroAndBeInteger',
          objectType: 'label',
          tableId: '*'
        }, {
          functionId: functionId,
          languageValue: '请先切换人员!',
          objectId: 'pleaseSwitchOperator',
          objectType: 'label',
          tableId: '*'
        }, {
          functionId: functionId,
          languageValue: '确认',
          objectId: 'confirmLabel',
          objectType: 'label',
          tableId: '*'
        }, {
          functionId: functionId,
          languageValue: '取消',
          objectId: 'cancelLabel',
          objectType: 'label',
          tableId: '*'
        },
      ],
      queryLabel: {
        functionId: functionId,
        table_id: '*',
        languageCode: this.$i18n.locale,
        objectType: 'label'
      },
    }
  },
  methods: {
    //页面初始化是的方法
    async init(scheduleData, operatorData) {
      // 设置标记，防止初始化过程中触发handleRowCountChange
      this.isLoadingCachedData = true;

      //初始化参数
      this.scheduleData = scheduleData;
      //初始化操作员对象
      this.operatorData = JSON.parse(JSON.stringify(operatorData));
      //重置时间
      this.pageData.reportDate = this.dayjs(new Date()).format('YYYY-MM-DD HH:mm:ss');
      this.pageData.reportTime = this.dayjs(new Date()).format('HH:mm:ss');
      //设置参数
      this.pageData.orderNo = scheduleData.orderNo;
      this.pageData.itemNo = scheduleData.itemNo;
      this.pageData.seqNo = scheduleData.seqNo;
      this.pageData.rollNo = scheduleData.rollNo;
      this.pageData.operatorId = operatorData.operatorId;
      //清空参数
      this.pageData.rollQty = 0;
      this.pageData.rollNums = 1;
      // 初始化新增字段（先设置默认值）
      this.pageData.rowCount = scheduleData.rowCount;
      this.pageData.rollCount = scheduleData.rollCount;
      this.pageData.fixture = scheduleData.carrierNo;
      // 重置异常规则锁定状态
      this.exceptionRuleLocked = false;
      this.exceptionRuleLockMessage = '';
      this.exceptionRuleWarningLevel = '';
      this.exceptionRuleLockedAt = '';
      this.exceptionRuleMatchedRollIndex = null;
      this.exceptionRuleMatchedDefectRate = null;
      this.exceptionRuleMatchedTotalQty = null;
      this.resetPendingRuleFollowup();
      // 重置缓存数据标记
      this.hasCachedData = false;
      this.cachedDataCount = 0;
      this.cachedRowDataList = [];  // 重置缓存的原始行数据
      // 重置分卷不良原因暂存
      this.resetRollDefectData();
      // 清空行数据列表
      this.rowDataList = [];
      //判断是否启用多语言
      // this.getMultiLanguageList();  //刷新多语言的信息
      //获取焦点
      this.$nextTick(() => {
        this.$refs.rollQty && this.$refs.rollQty.focus();
      });
      this.titleCon = this.labels.componentTitle;//重置标题

      // 查询是否有缓存的换班结转数据（等待完成）
      await this.loadCachedShiftChangeData();

      // 如果没有缓存数据，初始化空白行
      if (!this.hasCachedData) {
        this.initRowDataList();
      }

      // 初始化后立即同步一次强制锁定状态
      try {
        await this.refreshSplitRuleLockStatus(false);
      } catch (error) {
        console.error('初始化锁定状态失败:', error);
      }
      if (this.exceptionRuleLocked) {
        this.startSplitRuleLockPolling();
      } else {
        this.stopSplitRuleLockPolling();
      }

      // 取消标记
      this.isLoadingCachedData = false;
    },

    // 查询缓存的换班结转数据
    async loadCachedShiftChangeData() {
      try {
        const params = {
          site: this.scheduleData.site,
          orderNo: this.scheduleData.orderNo,
          seqNo: parseInt(this.scheduleData.seqNo) || 0
        };

        console.log('查询缓存数据参数:', params);

        const {data} = await getUnprocessedShiftChangeData(params);

        console.log('查询缓存数据结果:', data);

        if (data && data.code === 0 && data.data && data.data.length > 0) {
          // 有缓存数据，恢复到界面
          this.hasCachedData = true;
          this.cachedDataCount = data.count;

          const cachedList = data.data;

          console.log('缓存数据列表:', cachedList);

          // 恢复排数和卷数
          if (cachedList.length > 0) {
            this.pageData.rowCount = cachedList[0].rowCount || 0;
            this.pageData.rollCount = cachedList[0].rollCount || 0;
            this.pageData.fixture = cachedList[0].fixtureNo || '';
          }

          // 恢复行数据列表
          this.rowDataList = cachedList.map(item => ({
            rowNumber: item.rowBumber,
            goodQty: Number(item.goodQty) || 0,
            surfaceLossQty: Number(item.surfaceLossQty) || 0,
            poorPerformanceQty: Number(item.poorPerformanceQty) || 0,
            defectQty: Number(item.defectQty) || 0,
            yieldRate: this.calculateYieldRate(Number(item.goodQty) || 0, Number(item.defectQty) || 0),
            totalQty: (Number(item.goodQty) || 0) + (Number(item.defectQty) || 0),
            packingList: item.packingList || '',
            remark: item.remark || ''
          }));

          // 保存缓存的原始数据（用于产量报告时校验）
          this.cachedRowDataList = JSON.parse(JSON.stringify(this.rowDataList));

          console.log('恢复后的行数据:', this.rowDataList);

          this.$message.info(`已加载上次换班结转的缓存数据（${this.cachedDataCount}条）`);
        }
        // 如果没有缓存数据，不做任何处理，由init方法负责初始化
      } catch (error) {
        console.error('加载缓存数据失败:', error);
        // 加载失败时不做处理，由init方法负责初始化
      }
    },

    // 计算良率
    calculateYieldRate(goodQty, defectQty) {
      const totalQty = goodQty + defectQty;
      if (totalQty > 0) {
        return ((goodQty / totalQty) * 100).toFixed(2) + '%';
      }
      return '0.00%';
    },

    // ===================== 新增分卷优化方法 =====================

    // 初始化排数据列表
    initRowDataList() {
      console.log('initRowDataList被调用, isLoadingCachedData=', this.isLoadingCachedData, ', 调用栈:', new Error().stack);
      this.rowDataList = []
      for (let i = 0; i < this.pageData.rowCount; i++) {
        this.rowDataList.push({
          rowNumber: i,
          goodQty: 0,
          surfaceLossQty: 0,
          poorPerformanceQty: 0,
          defectQty: 0,
          yieldRate: '0.00%',
          totalQty: 0,
          packingList: '',
          remark: ''
        })
      }
    },

    // 排数变化时重新初始化
    handleRowCountChange() {
      console.log('handleRowCountChange被调用, isLoadingCachedData=', this.isLoadingCachedData);
      // 如果是从缓存加载数据，不要重新初始化
      if (this.isLoadingCachedData) {
        console.log('跳过初始化，因为正在加载缓存数据');
        return;
      }
      if (this.pageData.rollCount > this.pageData.rowCount) {
        this.pageData.rollCount = this.pageData.rowCount
      }
      this.initRowDataList()
      this.resetRollDefectData()
    },

    // 卷数变化时校验并清理不良原因缓存
    handleRollCountChange() {
      if (this.pageData.rollCount > this.pageData.rowCount) {
        this.pageData.rollCount = this.pageData.rowCount
      }
      const hasDefectReason = Object.keys(this.rollDefectMap).some(key => {
        const list = this.rollDefectMap[key]
        return Array.isArray(list) && list.length > 0
      })
      if (hasDefectReason) {
        this.$message.warning('卷数已变更，原不良原因已清空，请重新维护')
      }
      this.resetRollDefectData()
    },

    // 数量变化时自动计算不良数、良率和总数
    handleQtyChange(row) {
      // 计算不良数 = 面损 + 性能不良
      row.defectQty = (row.surfaceLossQty || 0) + (row.poorPerformanceQty || 0)

      // 计算总数 = 良品数 + 不良数
      row.totalQty = (row.goodQty || 0) + row.defectQty

      // 计算良率 = 良品数 / 总数 * 100%
      if (row.totalQty > 0) {
        const yieldValue = ((row.goodQty || 0) / row.totalQty * 100).toFixed(2)
        row.yieldRate = yieldValue + '%'
      } else {
        row.yieldRate = '0.00%'
      }
    },

    resetRollDefectData() {
      this.rollDefectDialogVisible = false
      this.currentRollDefectIndex = 1
      this.rollDefectMap = {}
      this.currentRollDefectList = []
      this.resetRollDefectForm()
    },

    resetRollDefectForm() {
      this.rollDefectForm = {
        defectCode: '',
        defectDesc: '',
        defectQty: null
      }
    },

    normalizeRollDefectMap() {
      const maxRollCount = Number(this.pageData.rollCount || 0)
      Object.keys(this.rollDefectMap).forEach(key => {
        if (Number(key) > maxRollCount) {
          this.$delete(this.rollDefectMap, key)
        }
      })
    },

    getRollSegments() {
      const totalRows = Array.isArray(this.rowDataList) ? this.rowDataList.length : 0
      const rollCount = Number(this.pageData.rollCount || 0)
      if (totalRows <= 0 || rollCount <= 0) {
        return []
      }
      const rowsPerRoll = Math.floor(totalRows / rollCount)
      const remainingRows = totalRows % rollCount
      const segments = []
      let startRow = 0
      for (let i = 0; i < rollCount; i++) {
        const currentRollRows = rowsPerRoll + (i < remainingRows ? 1 : 0)
        if (currentRollRows <= 0) {
          continue
        }
        segments.push({
          rollIndex: i + 1,
          startRow: startRow,
          endRow: startRow + currentRollRows - 1,
          rowCount: currentRollRows
        })
        startRow += currentRollRows
      }
      return segments
    },

    getRollSegmentByRowIndex(rowIndex) {
      const segments = this.getRollSegments()
      return segments.find(item => rowIndex >= item.startRow && rowIndex <= item.endRow) || null
    },

    getRollSegmentByRollIndex(rollIndex) {
      const segments = this.getRollSegments()
      return segments.find(item => item.rollIndex === rollIndex) || null
    },

    ensureRollDefectList(rollIndex) {
      const key = String(rollIndex)
      if (!Array.isArray(this.rollDefectMap[key])) {
        this.$set(this.rollDefectMap, key, [])
      }
    },

    openRollDefectDialog(rowIndex) {
      const segment = this.getRollSegmentByRowIndex(rowIndex)
      if (!segment) {
        this.$message.warning('当前卷信息无效，请先确认排数和卷数')
        return
      }
      this.currentRollDefectIndex = segment.rollIndex
      this.ensureRollDefectList(segment.rollIndex)
      this.currentRollDefectList = this.rollDefectMap[String(segment.rollIndex)]
      this.resetRollDefectForm()
      this.rollDefectDialogVisible = true
    },

    getRollSurfaceLossQty(rollIndex) {
      const segment = this.getRollSegmentByRollIndex(rollIndex)
      if (!segment) {
        return 0
      }
      let total = 0
      for (let i = segment.startRow; i <= segment.endRow; i++) {
        const row = this.rowDataList[i]
        total += Number(row && row.surfaceLossQty ? row.surfaceLossQty : 0)
      }
      return total
    },

    getCurrentRollSurfaceLossQty() {
      return this.getRollSurfaceLossQty(this.currentRollDefectIndex)
    },

    getRollDefectTotal(rollIndex) {
      const list = this.rollDefectMap[String(rollIndex)] || []
      return list.reduce((sum, item) => sum + Number(item && item.defectQty ? item.defectQty : 0), 0)
    },

    getCurrentRollDefectTotal() {
      return this.getRollDefectTotal(this.currentRollDefectIndex)
    },

    formatQty(value) {
      const num = Number(value || 0)
      return Number(num.toFixed(6)).toString()
    },

    getCurrentWorkCenterNo() {
      return (this.scheduleData.workCenterNo || '').trim()
    },

    buildDefectCheckParams(defectCode, workCenterNo) {
      return {
        site: this.pageData.site,
        orderNo: this.pageData.orderNo,
        itemNo: this.pageData.itemNo,
        seqNo: this.pageData.seqNo,
        rollNo: this.pageData.rollNo,
        defectCode: defectCode,
        workCenterNo: workCenterNo
      }
    },

    async addRollDefectItem() {
      if (!this.currentRollDefectList) {
        return
      }
      const workCenterNo = this.getCurrentWorkCenterNo()
      if (!workCenterNo) {
        this.$message.error('当前派工单未维护加工中心，不能选择不良原因')
        return
      }
      this.rollDefectForm.defectCode = (this.rollDefectForm.defectCode || '').trim().toUpperCase()
      if (!this.rollDefectForm.defectCode) {
        this.$message.error('请先选择不良代码')
        return
      }
      let checkResultMap = {}
      try {
        const { data } = await checkDefectCode(this.buildDefectCheckParams(this.rollDefectForm.defectCode, workCenterNo))
        if (data.code == 500) {
          this.$message.error(data.msg || '不良代码不属于当前加工中心')
          return
        }
        checkResultMap = data.resultMap || {}
      } catch (e) {
        this.$message.error('不良代码校验失败，请稍后重试')
        return
      }
      if (checkResultMap.defectDesc) {
        this.rollDefectForm.defectDesc = checkResultMap.defectDesc
      }
      if (!this.rollDefectForm.defectDesc) {
        this.$message.error('请选择有效的不良代码')
        return
      }
      const defectQty = Number(this.rollDefectForm.defectQty)
      if (!defectQty || defectQty <= 0) {
        this.$message.error('不良数量必须大于0')
        return
      }

      const existing = this.currentRollDefectList.find(item => item.defectCode === this.rollDefectForm.defectCode)
      if (existing) {
        existing.defectQty = Number(existing.defectQty || 0) + defectQty
        existing.defectDesc = this.rollDefectForm.defectDesc
      } else {
        this.currentRollDefectList.push({
          defectCode: this.rollDefectForm.defectCode,
          defectDesc: this.rollDefectForm.defectDesc,
          defectQty: defectQty
        })
      }
      this.resetRollDefectForm()
    },

    removeRollDefectItem(index) {
      if (!this.currentRollDefectList) {
        return
      }
      this.currentRollDefectList.splice(index, 1)
    },

    getBaseData(val) {
      if (this.tagNo === 89) {
        this.rollDefectForm.defectCode = val.DefectCode || ''
        this.rollDefectForm.defectDesc = val.DefectDesc || ''
      }
    },

    getBaseList(val) {
      this.tagNo = val
      this.$nextTick(() => {
        let strVal = ''
        let conSql = ''
        if (val === 89) {
          const workCenterNo = this.getCurrentWorkCenterNo()
          if (!workCenterNo) {
            this.$message.error('当前派工单未维护加工中心，无法选择不良代码')
            return
          }
          strVal = this.rollDefectForm.defectCode || ''
          conSql = " and isnull(A.workCenter_no,'') = '" + workCenterNo + "'"
        }
        this.$refs.baseList.init(val, strVal, conSql)
      })
    },

    getRollDefectDetails(rollIndex) {
      const list = this.rollDefectMap[String(rollIndex)] || []
      return list
        .map(item => ({
          defectCode: item.defectCode,
          defectDesc: item.defectDesc || '',
          defectQty: Number(item.defectQty || 0)
        }))
        .filter(item => item.defectCode && item.defectQty > 0)
    },

    // 校验每卷不良原因合计必须等于该卷面损合计
    validateRollDefectQtyBySurfaceLoss() {
      const segments = this.getRollSegments()
      if (!segments.length) {
        return true
      }
      this.normalizeRollDefectMap()
      for (let i = 0; i < segments.length; i++) {
        const rollIndex = segments[i].rollIndex
        const surfaceLossQty = this.getRollSurfaceLossQty(rollIndex)
        const defectReasonQty = this.getRollDefectTotal(rollIndex)
        if (Math.abs(surfaceLossQty - defectReasonQty) > 0.000001) {
          this.$message.error(`第${rollIndex}卷不良原因数量合计(${this.formatQty(defectReasonQty)})必须等于该卷面损数合计(${this.formatQty(surfaceLossQty)})`)
          return false
        }
      }
      return true
    },

    // 验证排数据
    validateRowData() {
      if (this.pageData.rowCount <= 0) {
        this.$message.warning('请输入有效的排数')
        return false
      }
      if (this.pageData.rollCount <= 0) {
        this.$message.warning('请输入有效的卷数')
        return false
      }
      if (this.pageData.rollCount > this.pageData.rowCount) {
        this.$message.warning('卷数不能大于排数')
        return false
      }

      // 检查是否有数据
      const hasData = this.rowDataList.some(row => (row.goodQty > 0 || row.defectQty > 0))
      if (!hasData) {
        this.$message.warning('请至少输入一行数据')
        return false
      }

      // 检查每一行的良品数必须大于0
      for (let i = 0; i < this.rowDataList.length; i++) {
        const row = this.rowDataList[i]
        if (row.goodQty === null || row.goodQty === undefined || row.goodQty <= 0) {
          this.$message.error(`第 ${i + 1} 排的良品数必须大于0`)
          return false
        }
      }

      return true
    },

    // Packing List 条件必填校验（仅在 packingListFlag = Y 时生效）
    validatePackingListRequired() {
      if (this.scheduleData.packingListFlag !== 'Y') {
        return true
      }

      const segments = this.getRollSegments()
      if (!segments.length) {
        return true
      }

      for (let i = 0; i < segments.length; i++) {
        const segment = segments[i]
        let hasPackingList = false
        for (let rowIndex = segment.startRow; rowIndex <= segment.endRow; rowIndex++) {
          const row = this.rowDataList[rowIndex]
          const packingList = row && row.packingList !== undefined && row.packingList !== null
            ? String(row.packingList).trim()
            : ''
          if (packingList) {
            hasPackingList = true
            break
          }
        }
        if (!hasPackingList) {
          this.$message.error(`第${segment.rollIndex}卷的Packing List不能为空`)
          return false
        }
      }

      return true
    },

    // 换班结转保存
    async saveShiftChangeTransfer() {
      // 人员判断
      if (this.pageData.operatorId === '' || this.pageData.operatorId == null) {
        this.$message.error(this.labels.pleaseSwitchOperator);
        return false;
      }

      // 基础校验
      if (this.pageData.rowCount <= 0) {
        this.$message.warning('请输入有效的排数');
        return false;
      }
      if (this.pageData.rollCount <= 0) {
        this.$message.warning('请输入有效的卷数');
        return false;
      }
      if (this.pageData.rollCount > this.pageData.rowCount) {
        this.$message.warning('卷数不能大于排数');
        return false;
      }

      // 如果有缓存数据，校验本次数据条数必须大于等于之前的数据
      if (this.hasCachedData && this.rowDataList.length < this.cachedDataCount) {
        this.$message.error(`数据条数不能减少！当前缓存数据${this.cachedDataCount}条，本次提交${this.rowDataList.length}条`);
        return false;
      }

      // 开启loading
      this.shiftChangeLoading = true;

      try {
        // 构建保存数据
        const saveData = {
          site: this.scheduleData.site,
          buNo: this.scheduleData.buNo,
          orderNo: this.scheduleData.orderNo,
          seqNo: parseInt(this.scheduleData.seqNo) || 0,
          fixtureNo: this.pageData.fixture,
          shiftFrom: this.scheduleData.shiftNo || '', // 当前班次
          rowCount: this.pageData.rowCount,
          rollCount: this.pageData.rollCount,
          createdBy: this.pageData.operatorId,
          rowDataList: this.rowDataList.map(row => ({
            rowNumber: row.rowNumber,
            goodQty: row.goodQty || 0,
            surfaceLossQty: row.surfaceLossQty || 0,
            poorPerformanceQty: row.poorPerformanceQty || 0,
            defectQty: row.defectQty || 0,
            packingList: row.packingList || '',
            remark: row.remark || ''
          }))
        };

        const {data} = await saveShiftChangeData(saveData);

        if (data && data.code === 0) {
          this.$message.success('换班结转数据保存成功！');
          // 更新缓存状态
          this.hasCachedData = true;
          this.cachedDataCount = this.rowDataList.length;
          // 关闭对话框
          this.closeDialog();
        } else {
          this.$message.error(data.msg || '换班结转保存失败');
        }
      } catch (error) {
        console.error('换班结转保存失败:', error);
        this.$message.error('换班结转保存失败：' + error.message);
      } finally {
        this.shiftChangeLoading = false;
      }
    },

    // 异常截卷操作（产量报告 + 换班结转）
    async executeAbnormalRollCut() {
      // 人员判断
      if (this.pageData.operatorId === '' || this.pageData.operatorId == null) {
        this.$message.error(this.labels.pleaseSwitchOperator);
        return false;
      }

      // 基础校验
      if (this.pageData.rowCount <= 0) {
        this.$message.warning('请输入有效的排数');
        return false;
      }
      if (this.pageData.rollCount <= 0) {
        this.$message.warning('请输入有效的卷数');
        return false;
      }
      if (this.pageData.rollCount > this.pageData.rowCount) {
        this.$message.warning('卷数不能大于排数');
        return false;
      }

      // 验证排数据
      if (!this.validateRowData()) {
        return false;
      }

      // Packing List 显示时要求必填
      if (!this.validatePackingListRequired()) {
        return false;
      }

      // 校验每卷不良原因数量是否等于该卷面损数量
      if (!this.validateRollDefectQtyBySurfaceLoss()) {
        return false;
      }

      // 确认框
      try {
        await this.$confirm('确定执行异常截卷操作吗？该操作将执行产量报告。', '提示', {
          confirmButtonText: '确定',
          cancelButtonText: '取消',
          type: 'warning'
        });
      } catch (e) {
        return false; // 用户取消
      }

      try {
        const passRuleCheck = await this.checkSplitRuleBeforeAction('异常截卷')
        if (!passRuleCheck) {
          return false
        }
      } catch (error) {
        this.$message.error(error.message || '异常规则校验失败')
        return false
      }

      // 开启loading
      this.abnormalCutLoading = true;

      try {
        // ========== 第一步：执行产量报告 + 保存缓存数据 ==========
        // 计算分卷
        const rowsPerRoll = Math.floor(this.pageData.rowCount / this.pageData.rollCount);
        const remainingRows = this.pageData.rowCount % this.pageData.rollCount;

        let currentRowIndex = 0;
        const allPrintList = []; // 收集所有打印数据

        // 循环创建每一卷
        for (let rollIndex = 0; rollIndex < this.pageData.rollCount; rollIndex++) {
          const currentRollRows = rowsPerRoll + (rollIndex < remainingRows ? 1 : 0);

          // 计算当前卷的良品和不良总数
          let totalGoodQty = 0;
          let totalDefectQty = 0;
          const rollRows = [];

          // 获取当前卷的备注
          let rollRemark = '';
          let rollPackingList = '';

          // 收集当前卷的行数据
          const currentRollRowDataList = [];

          for (let i = 0; i < currentRollRows; i++) {
            const row = this.rowDataList[currentRowIndex + i];
            totalGoodQty += row.goodQty || 0;
            totalDefectQty += row.defectQty || 0;

            if (i === 0) {
              rollRemark = row.remark || '';
              rollPackingList = row.packingList || '';
            }

            rollRows.push({
              rowNumber: row.rowNumber,
              goodQty: row.goodQty || 0,
              surfaceLossQty: row.surfaceLossQty || 0,
              poorPerformanceQty: row.poorPerformanceQty || 0,
              defectQty: row.defectQty || 0,
              totalQty: row.totalQty || 0,
              packingList: row.packingList || '',
              remark: row.remark || ''
            });

            // 收集当前卷的行数据用于保存缓存
            currentRollRowDataList.push({
              rowNumber: row.rowNumber,
              goodQty: row.goodQty || 0,
              surfaceLossQty: row.surfaceLossQty || 0,
              poorPerformanceQty: row.poorPerformanceQty || 0,
              defectQty: row.defectQty || 0,
              packingList: row.packingList || '',
              remark: row.remark || ''
            });
          }

          // 构建请求数据
          const requestData = {
            ...this.pageData,
            buNo: this.scheduleData.buNo,
            rollQty: totalGoodQty,
            rollNums: 1,
            defectQty: totalDefectQty,
            rollRows: rollRows,
            rollDefectDetails: this.getRollDefectDetails(rollIndex + 1),
            packingList: rollPackingList,
            remark: rollRemark
          };

          // 调用后端创建单个卷
          const {data} = await createSplitSfdcRoll(requestData);

          if (data.code === 500) {
            throw new Error(data.msg);
          }

          // 获取当前卷返回的新卷号
          let currentNewRollNo = '';
          if (data.printList && data.printList.length > 0) {
            currentNewRollNo = data.printList[0].rollNo || '';
            // 收集打印数据
            allPrintList.push(...data.printList);
          }

          const abnormalRollData = {
            site: this.scheduleData.site,
            buNo: this.scheduleData.buNo,
            orderNo: this.scheduleData.orderNo,
            seqNo: parseInt(this.scheduleData.seqNo) || 0,
            fixtureNo: this.pageData.fixture,
            shiftFrom: this.scheduleData.shiftNo || '',
            rowCount: currentRollRows,
            rollCount: 1,
            createdBy: this.pageData.operatorId,
            currentRollNo: this.scheduleData.rollNo || '',
            newRollNo: currentNewRollNo,
            operatorId: this.pageData.operatorId,
            rowDataList: currentRollRowDataList
          };

          const {data: abnormalData} = await saveAbnormalRollData(abnormalRollData);

          if (!abnormalData || abnormalData.code !== 0) {
            console.error(`第${rollIndex + 1}卷缓存数据保存失败:`, abnormalData && abnormalData.msg);
          }

          this.$message.success(`第${rollIndex + 1}/${this.pageData.rollCount}卷创建成功`);

          currentRowIndex += currentRollRows;
        }

        // 如果有换班结转缓存数据，标记为已处理
        if (this.hasCachedData) {
          try {
            await markShiftChangeAsProcessed({
              site: this.scheduleData.site,
              orderNo: this.scheduleData.orderNo,
              seqNo: parseInt(this.scheduleData.seqNo) || 0,
              processedBy: this.pageData.operatorId
            });
            this.hasCachedData = false;
            this.cachedDataCount = 0;
          } catch (err) {
            console.error('标记换班结转数据为已处理失败:', err);
          }
        }

        this.$message.success('异常截卷操作完成！数据已保存。');

        // ========== 第二步：打印标签（和产量报告一样）==========
        if (allPrintList.length > 0) {
          await this.printLabelsWithTemplate(allPrintList);
        }

        // 放行执行完成后：回写operate_flag=Y并清理对应缓存
        try {
          await this.completeSplitRuleTodoOperationIfNeeded();
          await this.refreshSplitRuleLockStatus(false);
        } catch (completeError) {
          console.error('回写代办操作状态失败:', completeError);
          this.$message.warning(completeError.message || '回写代办操作状态失败，请联系管理员检查');
        }

        if (this.triggerPendingRuleFollowupIfNeeded()) {
          this.abnormalCutLoading = false;
          return true;
        }

        // 延时关闭弹窗
        setTimeout(() => {
          this.closeDialog();
          this.abnormalCutLoading = false;
        }, 1000);

      } catch (error) {
        console.error('异常截卷操作失败:', error);
        this.$message.error('异常截卷操作失败：' + error.message);
        this.abnormalCutLoading = false;
      }
    },

    // 表格合并行方法（备注列根据卷数合并）
    objectSpanMethod({ row, column, rowIndex, columnIndex }) {
      // 对备注、Packing List和操作列进行按卷合并
      if (column.label === '备注' || column.label === 'Packing List' || column.label === '操作') {
        const segment = this.getRollSegmentByRowIndex(rowIndex)
        if (!segment) {
          return
        }
        if (rowIndex === segment.startRow) {
          return {
            rowspan: segment.rowCount,
            colspan: 1
          }
        }
        return {
          rowspan: 0,
          colspan: 0
        }
      }
    },

    // 计算备注wrapper的样式（使用padding-top实现垂直居中）
    getRemarkWrapperStyle(rowIndex) {
      if (this.pageData.rowCount <= 0 || this.pageData.rollCount <= 0) {
        return {}
      }
      const segment = this.getRollSegmentByRowIndex(rowIndex)
      if (!segment) {
        return {}
      }
      const currentRollRows = segment.rowCount

      // 每行高度约为32px
      const rowHeight = 32
      const totalHeight = currentRollRows * rowHeight

      // textarea的实际高度约为24px（单行）
      const textareaHeight = 24

      // 计算需要的padding-top来实现垂直居中
      const paddingTop = (totalHeight - textareaHeight) / 2

      // 返回样式对象
      return {
        paddingTop: paddingTop + 'px'
      }
    },

    // ===================== 分卷优化方法结束 =====================

    // 查询固定载具列表
    queryFixedCarrierList() {
      const params = {
        site: this.scheduleData.site,
        carrierNo: this.carrierSearchData.carrierNo,
        carrierTypeName: this.carrierSearchData.carrierTypeName,
        specification: this.carrierSearchData.specification
      }
      getFixedCarrierList(params).then(({data}) => {
        if (data && data.code === 0) {
          this.carrierList = data.data
          this.carrierModelFlag = true
        } else {
          this.$message.error(data.msg || '获取固定载具列表失败')
        }
      }).catch(error => {
        this.$message.error('获取固定载具列表失败: ' + error.message)
      })
    },

    // 选中固定载具
    selectCarrier(row) {
      this.pageData.fixture = row.carrierNo
      this.carrierModelFlag = false
    },

    // 批量编辑模态框
    editBatchModel() {
      if (this.editBatchVisible) {
        this.editBatchVisible = false
      } else {
        this.editBatchVisible = true
      }
    },

    // 批量保存固定载具可用数量
    batchSaveCarrier() {
      this.saveLoading = true
      // 调用API保存
      import('@/api/yieldReport/com_separate_roll.js').then(module => {
        const { updateFixedCarrierBatch } = module
        updateFixedCarrierBatch(this.carrierList).then(({data}) => {
          if (data && data.code === 0) {
            this.$message.success('批量保存成功')
            this.editBatchVisible = false
            this.queryFixedCarrierList()
          } else {
            this.$message.error(data.msg || '批量保存失败')
          }
        }).catch(error => {
          this.$message.error('批量保存失败: ' + error.message)
        }).finally(() => {
          this.saveLoading = false
        })
      })
    },

    // 打开新增固定载具对话框
    addCarrierModal() {
      console.log(this.scheduleData)
      this.addCarrierData = {
        bu: this.scheduleData.site + '_' + this.scheduleData.buNo || '',
        site: this.scheduleData.site || '',
        buNo: this.scheduleData.buNo || '',
        carrierTypeCode: '',
        carrierTypeName: '',
        assetNo: '',
        specification: '',
        purchaseDate: null,
        currentLocation: '',
        dimensions: '',
        availableQty: null,
        maxWeight: null,
        expectedLifeCycles: null,
        expectedLifeDays: null,
        status: 1,
        remark: ''
      };
      this.addCarrierFlag = true;
    },

    // 保存新增固定载具
    saveAddCarrier() {
      this.$refs.addCarrierForm.validate((valid) => {
        if (valid) {
          this.addCarrierLoading = true;
          fixedCarrierSave(this.addCarrierData).then(({data}) => {
            if (data && data.code === 0) {
              this.$message.success('新增成功');
              this.addCarrierFlag = false;
              this.queryFixedCarrierList();
            } else {
              this.$message.error(data.msg || '新增失败');
            }
          }).catch(error => {
            this.$message.error('新增失败: ' + error.message);
          }).finally(() => {
            this.addCarrierLoading = false;
          });
        }
      });
    },

    // 打印固定载具
    printCarrier(row) {
      const LODOP = getLodop()
      if (!LODOP) {
        this.$message.error('未检测到打印控件，请安装CLodop打印控件!')
        return
      }

      try {
        // 初始化打印
        LODOP.PRINT_INIT('固定载具标签打印')

        // 设置纸张尺寸：70mm x 20mm
        LODOP.SET_PRINT_PAGESIZE(0, 700, 200, '')

        // 绘制外边框
        LODOP.ADD_PRINT_RECT('1mm', '1mm', '68mm', '18mm', 0, 1)

        // 绘制中间竖线（左右分隔）
        LODOP.ADD_PRINT_LINE('1mm', '50mm', '19mm', '50mm', 0, 1)

        // 绘制左侧横线（三行文本之间的分隔）
        LODOP.ADD_PRINT_LINE('7mm', '1mm', '7mm', '50mm', 0, 1)
        LODOP.ADD_PRINT_LINE('13mm', '1mm', '13mm', '50mm', 0, 1)

        // 左侧文字信息 - 标签条码（第一行）
        const text1 = LODOP.ADD_PRINT_TEXT('2.5mm', '2mm', '46mm', '5mm', 'NO.:' + (row.carrierNo || ''))
        LODOP.SET_PRINT_STYLEA(text1, "FontName", "Microsoft YaHei")
        LODOP.SET_PRINT_STYLEA(text1, "FontSize", 5)
        LODOP.SET_PRINT_STYLEA(text1, "Bold", 1)

        // 左侧文字信息 - 载具类型编码（第二行）
        const text2 = LODOP.ADD_PRINT_TEXT('8.5mm', '2mm', '46mm', '5mm', 'Type:' + (row.carrierTypeCode || ''))
        LODOP.SET_PRINT_STYLEA(text2, "FontName", "Microsoft YaHei")
        LODOP.SET_PRINT_STYLEA(text2, "FontSize", 5)
        LODOP.SET_PRINT_STYLEA(text2, "Bold", 1)

        // 左侧文字信息 - 载具类型名称（第三行）
        const text3 = LODOP.ADD_PRINT_TEXT('14.5mm', '2mm', '46mm', '5mm', 'TypeDesc:' + (row.carrierTypeName || ''))
        LODOP.SET_PRINT_STYLEA(text3, "FontName", "Microsoft YaHei")
        LODOP.SET_PRINT_STYLEA(text3, "FontSize", 5)
        LODOP.SET_PRINT_STYLEA(text3, "Bold", 1)

        // 右侧二维码（使用 LODOP 原生二维码）
        const qrIndex = LODOP.ADD_PRINT_BARCODE('1.5mm', '50mm', '18.5mm', '18.5mm', 'QRCode', row.carrierNo || '')
        LODOP.SET_PRINT_STYLEA(qrIndex, "QRCodeVersion", 0)
        LODOP.SET_PRINT_STYLEA(qrIndex, "QRCodeErrorLevel", "M")

        // 执行打印
        LODOP.PRINT()

      } catch (error) {
        console.error('打印失败:', error)
        this.$message.error('打印失败: ' + error.message)
      }
    },

    /*关闭modal*/
    closeDialog(){
      if (this.exceptionRuleLocked) {
        return
      }
      this.stopSplitRuleLockPolling()
      this.clearExceptionRuleVisualMeta()
      this.resetPendingRuleFollowup()
      //刷新报工的页面
      this.$emit('refreshPageData');
      //关闭当前的页面
      this.$emit('update:visible', false);
    },

    handleMainDialogBeforeClose (done) {
      if (this.exceptionRuleLocked) {
        return
      }
      done()
    },

    onDialogClosed () {
      this.stopSplitRuleLockPolling()
      this.clearExceptionRuleVisualMeta()
    },

    normalizeWarningLevel (value) {
      return String(value || '').trim()
    },

    isWarningLevelStyle () {
      const warningLevel = this.normalizeWarningLevel(this.exceptionRuleWarningLevel)
      return warningLevel === '轻微' || warningLevel === '一般'
    },

    getExceptionRuleTitleCn () {
      return this.isWarningLevelStyle() ? '过程质量预警' : '过程质量异常'
    },

    getExceptionRuleTitleLock () {
      return this.isWarningLevelStyle() ? '系统预警 / SYSTEM WARNING' : '系统锁定 / SYSTEM LOCKDOWN'
    },

    getExceptionRuleActiveText () {
      return this.isWarningLevelStyle() ? 'WARNING ACTIVE' : 'LOCKDOWN ACTIVE'
    },

    getNowDateText () {
      return this.dayjs(new Date()).format('YYYY-MM-DD')
    },

    getNowTimeText () {
      return this.dayjs(new Date()).format('HH:mm:ss')
    },

    refreshExceptionRuleClock () {
      const now = this.dayjs(new Date())
      this.exceptionRuleClockDate = now.format('YYYY-MM-DD')
      this.exceptionRuleClockTime = now.format('HH:mm:ss')
    },

    startExceptionRuleClock () {
      this.refreshExceptionRuleClock()
      if (this.exceptionRuleClockTimer) {
        return
      }
      this.exceptionRuleClockTimer = setInterval(() => {
        this.refreshExceptionRuleClock()
      }, 1000)
    },

    stopExceptionRuleClock () {
      if (this.exceptionRuleClockTimer) {
        clearInterval(this.exceptionRuleClockTimer)
        this.exceptionRuleClockTimer = null
      }
    },

    toRuleNumber (value) {
      const num = Number(value)
      return Number.isFinite(num) ? num : null
    },

    formatRuleNumber (value, scale) {
      const num = this.toRuleNumber(value)
      if (num === null) {
        return '--'
      }
      const digits = Number.isInteger(scale) && scale >= 0 ? scale : 2
      const fixed = num.toFixed(digits)
      return fixed.replace(/\.?0+$/, '')
    },

    getExceptionRuleEquipmentText () {
      return this.scheduleData.resourceDesc || this.scheduleData.resourceId || '--'
    },

    getExceptionRuleLockedTimeText () {
      return this.exceptionRuleLockedAt || `${this.getNowDateText()} ${this.getNowTimeText()}`
    },

    getExceptionRuleWorkOrderText () {
      return this.scheduleData.orderNo || '--'
    },

    getExceptionRuleSeqNoText () {
      return this.scheduleData.seqNo || '--'
    },

    formatExceptionRuleDefectRateText () {
      const text = this.formatRuleNumber(this.exceptionRuleMatchedDefectRate, 2)
      return text === '--' ? '--' : `${text}%`
    },

    formatExceptionRuleAffectedQtyText () {
      const text = this.formatRuleNumber(this.exceptionRuleMatchedTotalQty, 2)
      return text === '--' ? '--' : `${text} pcs`
    },

    formatExceptionRuleProducedQtyText () {
      const text = this.formatRuleNumber(this.scheduleData.qtyApprove, 2)
      return text === '--' ? '--' : `${text} pcs`
    },

    applyExceptionRuleVisualMeta (resultMap, refreshLockTime) {
      this.startExceptionRuleClock()
      const warningLevel = this.normalizeWarningLevel(resultMap && resultMap.warningLevel)
      if (warningLevel) {
        this.exceptionRuleWarningLevel = warningLevel
      }
      const lockedTime = String((resultMap && resultMap.lockedTime) || '').trim()
      if (lockedTime) {
        this.exceptionRuleLockedAt = lockedTime
      } else if (refreshLockTime || !this.exceptionRuleLockedAt) {
        this.exceptionRuleLockedAt = `${this.getNowDateText()} ${this.getNowTimeText()}`
      }

      if (resultMap && Object.prototype.hasOwnProperty.call(resultMap, 'matchedRollIndex')) {
        this.exceptionRuleMatchedRollIndex = resultMap.matchedRollIndex
      }
      if (resultMap && Object.prototype.hasOwnProperty.call(resultMap, 'matchedDefectRate')) {
        this.exceptionRuleMatchedDefectRate = resultMap.matchedDefectRate
      }
      if (resultMap && Object.prototype.hasOwnProperty.call(resultMap, 'matchedTotalQty')) {
        this.exceptionRuleMatchedTotalQty = resultMap.matchedTotalQty
      }
    },

    clearExceptionRuleVisualMeta () {
      this.stopExceptionRuleClock()
      this.exceptionRuleWarningLevel = ''
      this.exceptionRuleLockedAt = ''
      this.exceptionRuleMatchedRollIndex = null
      this.exceptionRuleMatchedDefectRate = null
      this.exceptionRuleMatchedTotalQty = null
      this.exceptionRuleClockDate = ''
      this.exceptionRuleClockTime = ''
    },

    buildSplitRuleStatusPayload () {
      return {
        site: this.scheduleData.site,
        buNo: this.scheduleData.buNo,
        orderNo: this.scheduleData.orderNo,
        seqNo: this.scheduleData.seqNo
      }
    },

    async refreshSplitRuleLockStatus (showUnlockHint) {
      const payload = this.buildSplitRuleStatusPayload()
      if (!payload.site || !payload.buNo || !payload.orderNo || !payload.seqNo) {
        return
      }
      const wasLocked = this.exceptionRuleLocked
      const { data } = await getSplitRuleLockStatus(payload)
      if (!data || data.code === 500) {
        return
      }
      const resultMap = data.resultMap || {}
      const locked = !!resultMap.locked
      this.exceptionRuleLocked = locked
      if (locked) {
        this.applyExceptionRuleVisualMeta(resultMap, !wasLocked)
        this.exceptionRuleLockMessage = resultMap.message || '当前异常代办尚未审核，已锁定创建分卷操作。'
        if (!wasLocked) {
          this.$emit('lockPageByExceptionRule', resultMap)
        }
        if (!this.lockStatusTimer) {
          this.startSplitRuleLockPolling()
        }
        return
      }
      this.stopSplitRuleLockPolling()
      this.exceptionRuleLockMessage = ''
      this.clearExceptionRuleVisualMeta()
      this.$emit('unlockPageByExceptionRule', resultMap)
      if (wasLocked && showUnlockHint && resultMap.bypassByAudit) {
        this.$message.success('QC已审核，已解除锁定，可继续操作。')
      }
    },

    startSplitRuleLockPolling () {
      this.stopSplitRuleLockPolling()
      this.lockStatusTimer = setInterval(() => {
        this.refreshSplitRuleLockStatus(true).catch(err => {
          console.error('轮询锁定状态失败:', err)
        })
      }, 10000)
    },

    stopSplitRuleLockPolling () {
      if (this.lockStatusTimer) {
        clearInterval(this.lockStatusTimer)
        this.lockStatusTimer = null
      }
    },

    resetPendingRuleFollowup () {
      this.pendingRuleFollowupAction = ''
      this.pendingRuleFollowupResultMap = null
    },

    triggerPendingRuleFollowupIfNeeded () {
      const action = this.pendingRuleFollowupAction
      if (!action) {
        return false
      }
      const resultMap = this.pendingRuleFollowupResultMap || {}
      this.resetPendingRuleFollowup()
      this.$emit('refreshPageData')
      this.$emit('update:visible', false)
      if (action === 'OPEN_DEFECT') {
        this.$emit('openDefectByExceptionRule', resultMap)
        return true
      }
      if (action === 'OPEN_DOWNTIME') {
        this.$emit('openDownTimeByExceptionRule', resultMap)
        return true
      }
      return false
    },

    async completeSplitRuleTodoOperationIfNeeded () {
      const payload = this.buildSplitRuleStatusPayload()
      if (!payload.site || !payload.buNo || !payload.orderNo || !payload.seqNo) {
        return
      }
      payload.operatorId = this.pageData.operatorId
      payload.functionName = this.scheduleData.functionName || ''
      const { data } = await completeSplitRuleTodoOperation(payload)
      if (data && data.code === 500) {
        throw new Error(data.msg || '回写代办操作状态失败')
      }
    },

    buildSplitRuleCheckPayload (actionName) {
      return {
        site: this.scheduleData.site,
        buNo: this.scheduleData.buNo,
        orderNo: this.scheduleData.orderNo,
        itemNo: this.scheduleData.itemNo,
        seqNo: this.scheduleData.seqNo,
        rollNo: this.scheduleData.rollNo,
        operatorId: this.pageData.operatorId,
        functionName: actionName || '',
        fixture: this.pageData.fixture || '',
        shiftNo: this.scheduleData.shiftNo || '',
        rowCount: this.pageData.rowCount || 0,
        rollCount: this.pageData.rollCount || 0,
        totalRollQty: Number(this.scheduleData.totalRollQty || 0),
        rollRows: (this.rowDataList || []).map(row => ({
          rowNumber: row.rowNumber,
          goodQty: row.goodQty || 0,
          surfaceLossQty: row.surfaceLossQty || 0,
          poorPerformanceQty: row.poorPerformanceQty || 0,
          defectQty: row.defectQty || 0,
          totalQty: row.totalQty || 0,
          packingList: row.packingList || '',
          remark: row.remark || ''
        }))
      }
    },

    async checkSplitRuleBeforeAction (actionName) {
      this.resetPendingRuleFollowup()
      const payload = this.buildSplitRuleCheckPayload(actionName)
      const { data } = await checkSplitRollExceptionRule(payload)
      if (!data || data.code === 500) {
        throw new Error((data && data.msg) || '异常规则校验失败')
      }
      const resultMap = data.resultMap || {}
      if (resultMap.bypassByAudit) {
        this.exceptionRuleLocked = false
        this.exceptionRuleLockMessage = ''
        this.clearExceptionRuleVisualMeta()
        this.stopSplitRuleLockPolling()
        this.$emit('unlockPageByExceptionRule', resultMap)
      }
      if (!resultMap.matched) {
        return true
      }

      const action = resultMap.action || 'NONE'
      const message = resultMap.message || '触发异常规则，请先处理。'
      if (action === 'OPEN_DEFECT') {
        this.$message.warning(message)
        this.pendingRuleFollowupAction = action
        this.pendingRuleFollowupResultMap = resultMap
        return true
      }
      if (action === 'OPEN_DOWNTIME') {
        this.$message.warning(message)
        this.pendingRuleFollowupAction = action
        this.pendingRuleFollowupResultMap = resultMap
        return true
      }
      if (action === 'LOCK_PAGE') {
        this.exceptionRuleLocked = true
        this.applyExceptionRuleVisualMeta(resultMap, true)
        this.exceptionRuleLockMessage = message
        this.$emit('lockPageByExceptionRule', resultMap)
        this.startSplitRuleLockPolling()
        return false
      }
      return true
    },

    /*检查材料卷号的数据*/
    checkValidQty() {
      //获取当前是的数量
      let rollQty = parseFloat(this.pageData.rollQty);
      //判断是否可以修改
      if (rollQty <= 0 || !Number.isInteger(rollQty)){
        this.$message.error(this.labels.approvedQtyMustBeInteger);
        return false;
      }
    },

    /*检查材料卷号的数据*/
    checkRollNums() {
      //获取当前是的数量
      let rollNums = parseFloat(this.pageData.rollNums);
      //判断是否是正整数
      if (rollNums <= 0 || !Number.isInteger(rollNums)){
        this.$message.error(this.labels.rollQtyMustBeInteger);
        return false;
      }
    },

    checkCreateSeparateRolllBun() {
      //人员判断
      if (this.pageData.operatorId === '' || this.pageData.operatorId == null) {
        this.$message.error(this.labels.pleaseSwitchOperator);
        return false;
      }

      // 如果有缓存数据，校验本次数据条数必须大于等于之前的数据
      if (this.hasCachedData && this.rowDataList.length < this.cachedDataCount) {
        this.$message.error(`数据条数不能减少！当前缓存数据${this.cachedDataCount}条，本次提交${this.rowDataList.length}条`);
        return false;
      }

      // 如果有缓存数据，校验缓存中带过来的数据的良品数、面损、性能不良不能小于缓存中的数据
      if (this.hasCachedData && this.cachedRowDataList.length > 0) {
        for (let i = 0; i < this.cachedRowDataList.length; i++) {
          const cachedRow = this.cachedRowDataList[i];
          const currentRow = this.rowDataList[i];

          if (currentRow) {
            // 校验良品数不能小于缓存值
            if ((currentRow.goodQty || 0) < (cachedRow.goodQty || 0)) {
              this.$message.error(`第${i + 1}排的良品数量（${currentRow.goodQty}）不能小于缓存值（${cachedRow.goodQty}）`);
              return false;
            }
            // 校验面损数量不能小于缓存值
            if ((currentRow.surfaceLossQty || 0) < (cachedRow.surfaceLossQty || 0)) {
              this.$message.error(`第${i + 1}排的面损数量（${currentRow.surfaceLossQty}）不能小于缓存值（${cachedRow.surfaceLossQty}）`);
              return false;
            }
            // 校验性能不良数量不能小于缓存值
            if ((currentRow.poorPerformanceQty || 0) < (cachedRow.poorPerformanceQty || 0)) {
              this.$message.error(`第${i + 1}排的性能不良数量（${currentRow.poorPerformanceQty}）不能小于缓存值（${cachedRow.poorPerformanceQty}）`);
              return false;
            }
          }
        }
      }

      // 开启loading
      this.yieldReportLoading = true;

      this.createSeparateRolllOperation();
    },

    /*执行创建分卷的操作*/
    async createSeparateRolllOperation() {
      // 验证排数据
      if (!this.validateRowData()) {
        this.yieldReportLoading = false;
        return false
      }

      // Packing List 显示时要求必填
      if (!this.validatePackingListRequired()) {
        this.yieldReportLoading = false;
        return false
      }

      // 校验每卷不良原因数量是否等于该卷面损数量
      if (!this.validateRollDefectQtyBySurfaceLoss()) {
        this.yieldReportLoading = false;
        return false
      }

      try {
        const passRuleCheck = await this.checkSplitRuleBeforeAction('产量报告')
        if (!passRuleCheck) {
          this.yieldReportLoading = false
          return false
        }
      } catch (error) {
        this.$message.error(error.message || '异常规则校验失败')
        this.yieldReportLoading = false
        return false
      }

      try {
        // 计算分卷
        const rowsPerRoll = Math.floor(this.pageData.rowCount / this.pageData.rollCount)
        const remainingRows = this.pageData.rowCount % this.pageData.rollCount

        let currentRowIndex = 0
        const allPrintList = []

        // 循环创建每一卷
        for (let rollIndex = 0; rollIndex < this.pageData.rollCount; rollIndex++) {
          // 计算当前卷的排数
          const currentRollRows = rowsPerRoll + (rollIndex < remainingRows ? 1 : 0)

          // 计算当前卷的良品和不良总数
          let totalGoodQty = 0
          let totalDefectQty = 0
          const rollRows = []

          // 获取当前卷的备注（第一排的备注）
          let rollRemark = ''
          let rollPackingList = ''

          for (let i = 0; i < currentRollRows; i++) {
            const row = this.rowDataList[currentRowIndex + i]
            totalGoodQty += row.goodQty || 0
            totalDefectQty += row.defectQty || 0

            // 第一排的备注作为整卷的备注
            if (i === 0) {
              rollRemark = row.remark || ''
              rollPackingList = row.packingList || ''
            }

            rollRows.push({
              rowNumber: row.rowNumber,
              goodQty: row.goodQty || 0,
              surfaceLossQty: row.surfaceLossQty || 0,
              poorPerformanceQty: row.poorPerformanceQty || 0,
              defectQty: row.defectQty || 0,
              totalQty: row.totalQty || 0,
              packingList: row.packingList || '',
              remark: row.remark || ''
            })
          }

          // 构建请求数据（每次调用rollNums固定为1）
          const requestData = {
            ...this.pageData,
            buNo: this.scheduleData.buNo,
            rollQty: totalGoodQty,  // 该卷的良品总数
            rollNums: 1,            // 固定为1
            defectQty: totalDefectQty,  // 该卷的不良总数
            rollRows: rollRows,     // 该卷包含的排数据
            rollDefectDetails: this.getRollDefectDetails(rollIndex + 1),
            packingList: rollPackingList, // 该卷的Packing List
            remark: rollRemark      // 该卷的备注
          }

          // 调用后端创建单个卷
          const {data} = await createSplitSfdcRoll(requestData)

          if (data.code === 500) {
            throw new Error(data.msg)
          }

          // 收集打印数据
          if (data.printList && data.printList.length > 0) {
            allPrintList.push(...data.printList)
          }

          // 进度提示
          this.$message.success(`第${rollIndex + 1}/${this.pageData.rollCount}卷创建成功`)

          currentRowIndex += currentRollRows
        }

        // 所有卷创建完成
        this.$message.success('创建分卷完成！')

        // 如果有缓存数据，标记为已处理
        if (this.hasCachedData) {
          try {
            await markShiftChangeAsProcessed({
              site: this.scheduleData.site,
              orderNo: this.scheduleData.orderNo,
              seqNo: parseInt(this.scheduleData.seqNo) || 0,
              processedBy: this.pageData.operatorId
            });
            // 重置缓存状态
            this.hasCachedData = false;
            this.cachedDataCount = 0;
          } catch (err) {
            console.error('标记换班结转数据为已处理失败:', err);
          }
        }

        // 打印标签（优化版：使用模板打印）
        if (allPrintList.length > 0) {
          await this.printLabelsWithTemplate(allPrintList)
        }

        // 放行执行完成后：回写operate_flag=Y并清理对应缓存
        try {
          await this.completeSplitRuleTodoOperationIfNeeded()
          await this.refreshSplitRuleLockStatus(false)
        } catch (completeError) {
          console.error('回写代办操作状态失败:', completeError)
          this.$message.warning(completeError.message || '回写代办操作状态失败，请联系管理员检查')
        }

        if (this.triggerPendingRuleFollowupIfNeeded()) {
          this.yieldReportLoading = false
          return true
        }

        // 延时关闭弹窗
        setTimeout(() =>{
          //关闭当前的页面
          this.closeDialog()
          this.yieldReportLoading = false;
        }, 1000)

      } catch (error) {
        this.$message.error('创建分卷失败: ' + error.message)
        this.yieldReportLoading = false;
      }
    },

    /**
     * 使用模板打印标签（优化版）
     * @param {Array} printList - 打印数据列表
     */
    async printLabelsWithTemplate(printList) {
      try {
        // 1. 查询物料的标签模板设置（找默认模板）
        const templateParams = {
          site: this.scheduleData.site,
          buNo: this.scheduleData.buNo,
          partNo: this.scheduleData.partNo
        };

        const {data: templateData} = await getPartLabelTemplateList(templateParams);

        if (!templateData || templateData.code !== 0 || !templateData.list || templateData.list.length === 0) {
          // 如果没有模板配置，使用原有的流转标签打印方式
          console.warn('未找到物料标签模板配置!');
          return;
        }

        // 找到默认模板（default_flag = '1'）
        let defaultTemplate = templateData.list.find(item => item.defaultFlag === '1');
        if (!defaultTemplate && templateData.list.length > 0) {
          // 如果没有设置默认模板，使用第一个
          defaultTemplate = templateData.list[0];
        }

        if (!defaultTemplate) {
          console.warn('未找到默认模板!');
          return;
        }

        const labelNo = defaultTemplate.labelNo; // A001、A002、A003

        // 2. 获取打印机（使用默认打印机）
        const LODOP = getLodop();
        if (!LODOP) {
          this.$message.warning('无法连接到打印控件，跳过打印');
          return;
        }

        // 获取默认打印机
        const printerCount = LODOP.GET_PRINTER_COUNT();
        if (printerCount === 0) {
          this.$message.warning('未检测到打印机，跳过打印');
          return;
        }

        const defaultPrinterName = LODOP.GET_PRINTER_NAME(0); // 使用第一个打印机作为默认打印机

        // 3. 调用存储过程获取打印参数
        const printDataList = [];

        for (let i = 0; i < printList.length; i++) {
          const item = printList[i];
          const params = {
            site: this.scheduleData.site,
            buNo: this.scheduleData.buNo,
            menuID: '104003006', // 过站采集功能ID
            relatedOrderNo: this.scheduleData.orderNo,
            relatedOrderLineNo: this.scheduleData.seqNo,
            documentNo: '',
            partNo: this.scheduleData.partNo,
            labelNo: labelNo,
            rollNo: item.rollNo
          };

          const {data: printData} = await callUspPartLabelTemplate(params);
          if (printData && printData.code === 0 && printData.row) {
            printDataList.push({
              ...printData.row,
              labelNo: labelNo
            });
          } else {
            console.warn(`获取卷号 ${item.rollNo} 的打印参数失败，使用原始数据`);
            // 如果获取打印参数失败，使用原始数据
            printDataList.push({
              ...item,
              labelNo: labelNo
            });
          }
        }

        // 4. 执行打印
        await this.executePrintWithTemplate(LODOP, printDataList, labelNo, defaultPrinterName);

        this.$message.success('标签打印任务已发送！');

      } catch (error) {
        console.error('模板打印失败:', error);
        // this.$message.warning('模板打印失败，使用默认流转标签打印');
        // // 降级处理：使用原有的流转标签打印方式
        // printSfdcLabel(printList);
      }
    },

    /**
     * 执行模板打印
     * @param {Object} LODOP - 打印控件对象
     * @param {Array} printDataList - 打印数据列表
     * @param {String} labelNo - 标签模板编号 (A001/A002/A003)
     * @param {String} printerName - 打印机名称
     */
    async executePrintWithTemplate(LODOP, printDataList, labelNo, printerName) {
      console.log('开始打印，标签数量:', printDataList.length, '标签数据:', printDataList);

      // 循环打印每个标签（每个标签单独打印一次）
      for (let i = 0; i < printDataList.length; i++) {
        const printData = printDataList[i];

        // 每个标签单独初始化一个打印任务
        LODOP.PRINT_INIT('分卷标签打印_' + (i + 1));

        // 设置打印模式
        LODOP.SET_PRINT_MODE("PRINT_NOCOLLATE", true);

        // 根据 labelNo 调用不同的打印方法（来自 labelPrintTemplates mixin）
        // 注意：不需要 NEWPAGE，因为每个标签是独立的打印任务
        if (labelNo === 'A001') {
          await this.printLabelA001(LODOP, printData, false);
        } else if (labelNo === 'A002') {
          this.printLabelA002(LODOP, printData, false);
        } else if (labelNo === 'A003') {
          this.printLabelA003(LODOP, printData, false);
        } else if (labelNo === 'A004') {
          this.printLabelA004(LODOP, printData, false);
        } else {
          console.warn(`未知的标签模板：${labelNo}，跳过该标签`);
          continue;
        }

        // 执行打印
        LODOP.PRINT();

        console.log(`第${i + 1}张标签已发送打印, 卷号: ${printData.rollNo}`);
      }
    },

    // 保存 默认配置 列
    async saveMultiLanguage() {
      // 保存页面 button label title 属性
      let buttons = this.buttonList;
      let labels = this.labelsList;
      await saveButtonList(buttons)
      await saveButtonList(labels)
    },

    getMultiLanguageList() {
      //首先查询当前按钮的多语言
      searchFunctionButtonList(this.queryButton).then(({data}) => {
        if (data && data.code == 0 ) {
          this.buttons = data.data
        } else {
          // saveButtonList(this.buttonList).then(({data}) => {
          // })
        }
      });
      //其次查询当前标签的多语言
      searchFunctionButtonList(this.queryLabel).then(({data}) => {
        if (data && data.code == 0 ) {
          this.labels = data.data
        } else {
          // saveButtonList(this.buttonList).then(({data}) => {
          // })
        }
      });
    },

  },
  created() {
    // this.factoryList()
    // this.getLanguageList()
  },
  beforeDestroy() {
    this.stopSplitRuleLockPolling()
    this.stopExceptionRuleClock()
  }
}

</script>

<style scoped lang="scss">
@import url('https://fonts.googleapis.com/css2?family=Barlow+Condensed:wght@400;500;600;700;800&family=JetBrains+Mono:wght@400;500;600;700&display=swap');

/*调节页面button和input的上下间距*/
.customer-css .customer-button{
  margin-top: 25px;
}

/* 固定载具清除按钮 */
.fixture-clear-btn {
  cursor: pointer;
  color: #C0C4CC;
  &:hover {
    color: #909399;
  }
}

/*调节fieldset下的样式*/
.customer-fieldset .customer-item{
  margin-top: -15px;
}

/*fieldset下table的样式*/
.customer-fieldset /deep/ .el-table__header th.is-leaf{
  line-height: 16px;
}

/deep/ .customer-tab .el-tabs__content{
  padding: 0px !important;
}

/* 良品数输入框样式 - 绿色加粗 */
.good-qty-input >>> .el-input__inner {
  font-weight: bold !important;
  color: #67c23a !important;
  font-size: 12px !important;
}

::v-deep .good-qty-input .el-input__inner {
  font-weight: bold !important;
  color: #67c23a !important;
  font-size: 12px !important;
}

/deep/ .good-qty-input .el-input__inner {
  font-weight: bold !important;
  color: #67c23a !important;
  font-size: 12px !important;
}

/* 不良数输入框样式 - 红色加粗 */
.defect-qty-input >>> .el-input__inner {
  font-weight: bold !important;
  color: #f56c6c !important;
  font-size: 12px !important;
}

::v-deep .defect-qty-input .el-input__inner {
  font-weight: bold !important;
  color: #f56c6c !important;
  font-size: 12px !important;
}

/deep/ .defect-qty-input .el-input__inner {
  font-weight: bold !important;
  color: #f56c6c !important;
  font-size: 12px !important;
}

/* 总数显示样式 */
.total-display {
  font-weight: bold;
  color: #303133;
  font-size: 12px;
}

/* 备注列单元格样式 - 使用绝对定位填满 */
.customer-dialog >>> .el-table td.remark-column,
.customer-dialog >>> .el-table td.packing-list-column {
  padding: 0 !important;
  position: relative !important;
  overflow: hidden !important;
}

.customer-dialog /deep/ .el-table td.remark-column,
.customer-dialog /deep/ .el-table td.packing-list-column {
  padding: 0 !important;
  position: relative !important;
  overflow: hidden !important;
}

/* 备注包装器 - 绝对定位填满单元格 */
.customer-dialog >>> .remark-wrapper {
  position: absolute !important;
  top: 1px !important;
  left: 1px !important;
  right: 1px !important;
  bottom: 1px !important;
  width: 100% !important;
  height: 100% !important;
  box-sizing: border-box !important;
}

.customer-dialog /deep/ .remark-wrapper {
  position: absolute !important;
  top: 1px !important;
  left: 1px !important;
  right: 1px !important;
  bottom: 1px !important;
  width: 100% !important;
  height: 100% !important;
  box-sizing: border-box !important;
}

/* 备注textarea */
.customer-dialog >>> .remark-textarea {
  width: 100% !important;
  height: 100% !important;
}

.customer-dialog >>> .remark-textarea .el-textarea__inner {
  border: none !important;
  padding: 8px 10px !important;
  border-radius: 0 !important;
  resize: none !important;
  width: 100% !important;
  height: 100% !important;
  box-sizing: border-box !important;
  overflow-y: auto !important;
}

.customer-dialog /deep/ .remark-textarea {
  width: 100% !important;
  height: 100% !important;
}

.customer-dialog /deep/ .remark-textarea .el-textarea__inner {
  border: none !important;
  padding: 8px 10px !important;
  border-radius: 0 !important;
  resize: none !important;
  width: 100% !important;
  height: 100% !important;
  box-sizing: border-box !important;
  overflow-y: auto !important;
}

.customer-dialog /deep/ .el-dialog {
  position: relative;
}

.exception-rule-mask-screen {
  --mask-accent: #e01020;
  --mask-accent-rgb: 224, 16, 32;
  --mask-subtitle: #7a1020;
  --mask-accent-dark: #b3001b;
  position: fixed;
  inset: 0;
  z-index: 4000;
  background: #0d1317;
  overflow: hidden;
  pointer-events: all;
  display: flex;
  flex-direction: column;
  font-family: 'Barlow Condensed', sans-serif;
}

.exception-rule-mask-screen.warning {
  --mask-accent: #e6a817;
  --mask-accent-rgb: 230, 168, 23;
  --mask-subtitle: #7a5c10;
  --mask-accent-dark: #a3780f;
}

.exception-rule-mask-screen.serious {
  --mask-accent: #e01020;
  --mask-accent-rgb: 224, 16, 32;
  --mask-subtitle: #7a1020;
}

.exception-rule-bg-grid {
  position: absolute;
  inset: 0;
  pointer-events: none;
  background-image:
    linear-gradient(rgba(var(--mask-accent-rgb), 0.03) 1px, transparent 1px),
    linear-gradient(90deg, rgba(var(--mask-accent-rgb), 0.03) 1px, transparent 1px);
  background-size: 48px 48px;
  z-index: 0;
}

.exception-rule-vignette {
  position: absolute;
  inset: 0;
  pointer-events: none;
  background: radial-gradient(ellipse at center, transparent 40%, rgba(0, 0, 0, 0.75) 100%);
  z-index: 0;
}

.exception-rule-scanline {
  position: absolute;
  inset: 0;
  pointer-events: none;
  overflow: hidden;
  z-index: 1;
}

.exception-rule-scanline .lines {
  position: absolute;
  inset: 0;
  background-image: repeating-linear-gradient(0deg, transparent, transparent 2px, rgba(0, 0, 0, 0.18) 2px, rgba(0, 0, 0, 0.18) 4px);
  background-size: 100% 4px;
}

.exception-rule-scanline .beam {
  position: absolute;
  left: 0;
  right: 0;
  height: 128px;
  background: linear-gradient(
    180deg,
    transparent 0%,
    rgba(var(--mask-accent-rgb), 0.035) 40%,
    rgba(var(--mask-accent-rgb), 0.055) 50%,
    rgba(var(--mask-accent-rgb), 0.035) 60%,
    transparent 100%
  );
  animation: exception-rule-scan-beam 6s linear infinite;
}

.exception-rule-corners {
  position: absolute;
  inset: 0;
  pointer-events: none;
  z-index: 2;
  color: var(--mask-accent);
}

.exception-rule-corners .corner {
  position: absolute;
  width: 80px;
  height: 80px;
}

.exception-rule-corners .corner.tl { top: 0; left: 0; }
.exception-rule-corners .corner.tr { top: 0; right: 0; }
.exception-rule-corners .corner.bl { bottom: 0; left: 0; }
.exception-rule-corners .corner.br { bottom: 0; right: 0; }

.exception-rule-corners .corner svg {
  width: 100%;
  height: 100%;
  overflow: visible;
}

.exception-rule-corners .corner.tr svg { transform: rotate(90deg); }
.exception-rule-corners .corner.bl svg { transform: rotate(-90deg); }
.exception-rule-corners .corner.br svg { transform: rotate(180deg); }

.exception-rule-corners .corner .arc {
  transform-origin: 4px 4px;
  animation: exception-rule-spin-cw 4s linear infinite;
}

.exception-rule-statusbar {
  position: relative;
  z-index: 10;
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 8px 24px;
  font-size: 12px;
  line-height: 1.2;
  border-bottom: 1px solid rgba(var(--mask-accent-rgb), 0.2);
  color: #8aafc8;
  background: rgba(8, 11, 13, 0.65);
  font-family: 'JetBrains Mono', monospace;
}

.exception-rule-statusbar .left,
.exception-rule-statusbar .right {
  display: flex;
  align-items: center;
  gap: 16px;
}

.exception-rule-statusbar .mes {
  color: var(--mask-accent);
  font-weight: 700;
  letter-spacing: 0.05em;
}

.exception-rule-statusbar .lockdown {
  color: var(--mask-accent);
  display: flex;
  align-items: center;
}

.exception-rule-statusbar .dot {
  display: inline-block;
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--mask-accent);
  margin-right: 6px;
  animation: exception-rule-blink 1s step-end infinite;
}

.exception-rule-statusbar .clock {
  color: #dde3e8;
  font-weight: 600;
}

.exception-rule-main {
  position: relative;
  z-index: 10;
  flex: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: flex-start;
  padding: 148px 32px 0;
  gap: 32px;
  min-height: 0;
}

.exception-rule-alert-icon {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 180px;
  height: 180px;
  margin-bottom: 30px;
  flex-shrink: 0;
}

.exception-rule-alert-icon .pulse-ring {
  position: absolute;
  inset: 0;
  border-radius: 50%;
  border: 2px solid var(--mask-accent);
  opacity: 0;
  animation: exception-rule-pulse-ring 2s ease-out infinite;
}

.exception-rule-alert-icon .pulse-ring.d0 { animation-delay: 0s; }
.exception-rule-alert-icon .pulse-ring.d1 { animation-delay: 0.67s; }
.exception-rule-alert-icon .pulse-ring.d2 { animation-delay: 1.33s; }

.exception-rule-alert-icon .alert-glow {
  position: absolute;
  inset: 0;
  border-radius: 50%;
  box-shadow: 0 0 40px 8px rgba(var(--mask-accent-rgb), 0.35), 0 0 80px 20px rgba(var(--mask-accent-rgb), 0.12);
  animation: exception-rule-glow-breathe 1.5s ease-in-out infinite;
}

.exception-rule-alert-icon .alert-core {
  position: relative;
  z-index: 10;
  width: 110px;
  height: 110px;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  background: radial-gradient(circle at 35% 35%, rgba(var(--mask-accent-rgb), 0.18), rgba(26, 22, 4, 0.95));
  border: 2px solid rgba(var(--mask-accent-rgb), 0.8);
  box-shadow: inset 0 0 20px rgba(var(--mask-accent-rgb), 0.3);
  color: var(--mask-accent);
  animation: exception-rule-glow-breathe 1.5s ease-in-out infinite;
}

.exception-rule-title-block {
  text-align: center;
  margin-top: 30px;
}

.exception-rule-title-cn {
  font-family: 'Barlow Condensed', sans-serif;
  font-size: 72px;
  font-weight: 800;
  letter-spacing: 0.12em;
  line-height: 1;
  color: var(--mask-accent);
  text-shadow: 0 0 40px rgba(var(--mask-accent-rgb), 0.55), 0 0 80px rgba(var(--mask-accent-rgb), 0.22);
}

.exception-rule-title-en {
  font-family: 'Barlow Condensed', sans-serif;
  margin-top: 4px;
  font-size: 30px;
  font-weight: 700;
  letter-spacing: 0.35em;
  color: var(--mask-subtitle);
}

.exception-rule-title-rule {
  margin: 12px auto 0;
  height: 1px;
  background: linear-gradient(90deg, transparent, rgba(var(--mask-accent-rgb), 0.6), transparent);
  max-width: 360px;
}

.exception-rule-title-lock {
  margin-top: 12px;
  font-family: 'Barlow Condensed', sans-serif;
  font-size: 20px;
  font-weight: 700;
  letter-spacing: 0.3em;
  text-transform: uppercase;
  color: #dde3e8;
}

.exception-rule-info-cards {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 16px;
  width: 100%;
  max-width: 768px;
}

.exception-rule-info-card {
  display: flex;
  flex-direction: column;
  gap: 4px;
  padding: 12px 16px;
  background: rgba(10, 16, 22, 0.7);
  border: 1px solid rgba(var(--mask-accent-rgb), 0.18);
}

.exception-rule-info-card .label {
  font-size: 12px;
  line-height: 1.2;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  color: #8aafc8;
  font-family: 'JetBrains Mono', monospace;
}

.exception-rule-info-card .value {
  font-family: 'Barlow Condensed', sans-serif;
  font-size: 20px;
  line-height: 1.15;
  font-weight: 700;
  letter-spacing: 0.02em;
  color: #dde3e8;
  word-break: break-all;
}

.exception-rule-info-card .value.hl {
  color: var(--mask-accent);
  text-shadow: 0 0 12px rgba(var(--mask-accent-rgb), 0.5);
  animation: exception-rule-glow-breathe 1.5s ease-in-out infinite;
}

.exception-rule-info-card.work-order-card .work-order-value-line {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: 10px;
  width: 100%;
}

.exception-rule-info-card.work-order-card .work-order-value-line .value {
  flex: 1;
  min-width: 0;
  text-align: left;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.exception-rule-info-card.work-order-card .work-order-seq {
  display: inline-block;
  min-width: 5ch;
  text-align: right;
  white-space: nowrap;
  font-family: 'Barlow Condensed', sans-serif;
  font-size: 20px;
  line-height: 1.15;
  font-weight: 700;
  letter-spacing: 0.02em;
  color: #dde3e8;
}

.exception-rule-flow-steps {
  display: flex;
  align-items: center;
  gap: 0;
  width: 100%;
  max-width: 768px;
}

.exception-rule-flow-steps .flow-step {
  flex: 1;
  text-align: center;
  position: relative;
  padding: 10px 0;
}

.exception-rule-flow-steps .flow-step .dot {
  width: 16px;
  height: 16px;
  border-radius: 50%;
  margin: 0 auto 8px;
  border: 2px solid rgba(var(--mask-accent-rgb), 0.5);
}

.exception-rule-flow-steps .flow-step.done .dot {
  background: var(--mask-accent);
  border-color: var(--mask-accent);
}

.exception-rule-flow-steps .flow-step.active .dot {
  background: transparent;
  border-color: var(--mask-accent);
  box-shadow: 0 0 8px rgba(var(--mask-accent-rgb), 0.5);
  animation: exception-rule-blink 1.2s ease-in-out infinite;
}

.exception-rule-flow-steps .flow-step .label {
  font-size: 12px;
  color: #5a7080;
  letter-spacing: 0.05em;
  font-family: 'JetBrains Mono', monospace;
}

.exception-rule-flow-steps .flow-step.done .label { color: #8aafc8; }
.exception-rule-flow-steps .flow-step.active .label {
  color: var(--mask-accent);
  font-weight: 600;
}

.exception-rule-flow-steps .flow-line {
  width: 40px;
  height: 1px;
  background: rgba(var(--mask-accent-rgb), 0.2);
  margin: 0 -4px;
  align-self: flex-start;
  margin-top: 6px;
}

.exception-rule-flow-steps .flow-line.done {
  background: rgba(var(--mask-accent-rgb), 0.5);
}

.exception-rule-bottombar {
  position: relative;
  z-index: 10;
  padding: 16px 32px;
  border-top: 1px solid rgba(var(--mask-accent-rgb), 0.2);
  background: rgba(8, 11, 13, 0.85);
}

.exception-rule-bottombar .inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  max-width: 1024px;
  margin: 0 auto;
}

.exception-rule-bottombar .left {
  display: flex;
  align-items: center;
  gap: 12px;
}

.exception-rule-bottombar .left svg {
  color: var(--mask-accent-dark);
}

.exception-rule-bottombar .left .ttl {
  font-size: 12px;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: #8aafc8;
  font-family: 'JetBrains Mono', monospace;
}

.exception-rule-quality-cards {
  display: flex;
  align-items: center;
  gap: 16px;
}

.exception-rule-quality-cards .quality-card {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 4px;
  padding: 12px 24px;
  min-width: 140px;
  border: 1px solid rgba(var(--mask-accent-rgb), 0.3);
  background: rgba(var(--mask-accent-rgb), 0.04);
}

.exception-rule-quality-cards .quality-card .qlabel {
  font-size: 11px;
  line-height: 1.2;
  font-weight: 600;
  letter-spacing: 0.15em;
  text-transform: uppercase;
  color: #8aafc8;
  font-family: 'JetBrains Mono', monospace;
}

.exception-rule-quality-cards .quality-card .qvalue {
  font-size: 22px;
  line-height: 1;
  font-weight: 700;
  color: #dde3e8;
  letter-spacing: 0.04em;
}

.exception-rule-quality-cards .quality-card .qvalue.hl {
  color: var(--mask-accent);
  text-shadow: 0 0 12px rgba(var(--mask-accent-rgb), 0.4);
}

.exception-rule-bottombar .right {
  text-align: right;
  font-size: 12px;
  line-height: 1.25;
  color: #8aafc8;
  font-family: 'JetBrains Mono', monospace;
}

.exception-rule-bottombar .right .auth {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: 4px;
  margin-top: 2px;
  color: #1e3040;
}

@keyframes exception-rule-spin-cw {
  from { transform: rotate(0deg); }
  to { transform: rotate(360deg); }
}

@keyframes exception-rule-scan-beam {
  from { top: -128px; }
  to { top: 100%; }
}

@keyframes exception-rule-pulse-ring {
  0% {
    transform: scale(0.7);
    opacity: 0.7;
  }
  100% {
    transform: scale(2.2);
    opacity: 0;
  }
}

@keyframes exception-rule-glow-breathe {
  0%, 100% { opacity: 0.8; }
  50% { opacity: 1; }
}

@keyframes exception-rule-blink {
  0%,
  100% {
    opacity: 1;
  }
  50% {
    opacity: 0;
  }
}

/* 分卷不良原因对话框 */
.roll-defect-summary {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 12px;
  padding: 8px 12px;
  background: #f5f7fa;
  border-radius: 4px;
  color: #606266;
}

.roll-defect-form /deep/ .el-form-item {
  margin-right: 12px;
}

.roll-defect-form .defect-code-label a {
  color: #409EFF;
  font-weight: 600;
  cursor: pointer;
}

.roll-defect-form /deep/ .defect-code-input .el-input__inner {
  color: #409EFF;
  font-weight: 600;
}

</style>

<style lang="scss">
/* 全局样式 - 良品数和不良数输入框颜色 */
.good-qty-input .el-input__inner {
  font-weight: bold !important;
  color: #67c23a !important;
  font-size: 16px !important;
}

.defect-qty-input .el-input__inner {
  font-weight: bold !important;
  color: #f56c6c !important;
  font-size: 16px !important;
}

/* 备注列样式 - 只针对创建分卷对话框 */
.customer-css .el-table td.remark-column,
.customer-css .el-table td.packing-list-column {
  padding: 0 !important;
  position: relative !important;
  overflow: hidden !important;
}

/* 备注包装器 - 填满整个单元格 */
.customer-css .remark-wrapper {
  position: absolute !important;
  top: 1px !important;
  left: 1px !important;
  right: 1px !important;
  bottom: 1px !important;
  width: 100% !important;
  height: 100% !important;
  box-sizing: border-box !important;
}

/* 备注textarea容器 */
.customer-css .remark-textarea {
  width: 100% !important;
  height: 100% !important;
}

.customer-css .remark-textarea .el-textarea__inner {
  border: none !important;
  padding: 8px 10px !important;
  border-radius: 0 !important;
  resize: none !important;
  width: 100% !important;
  height: 100% !important;
  box-sizing: border-box !important;
  overflow-y: auto !important;
}

</style>
