|
|
<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>
|