| | |
| | | <template> |
| | | <view class="page"> |
| | | <!-- 顶部显示当前系统采集生产数,打码报工数和不良数 --> |
| | | <view class="page wide-layout" :class="{'has-overlay': (isShowUserSelect || isShow || barcodeIsShow)}"> |
| | | <view class="status-section"> |
| | | <!-- 整体标题和刷新按钮 --> |
| | | <view class="header-container"> |
| | | <view class="header-title"> |
| | | <text>生产数据统计</text> |
| | | </view> |
| | | <view class="header-right"> |
| | | <view class="version-info-top"> |
| | | <text>v1.0.6</text> |
| | | </view> |
| | | <button class="refresh-btn" @click="refresh">刷新</button> |
| | | <!-- 紧急重置按钮(仅在生成状态卡住时显示) --> |
| | | <button v-if="isGeneratingBarcode" class="reset-btn" @click="resetGenerateState">重置</button> |
| | | </view> |
| | | <view class="report-table-wrapper"> |
| | | <view class="report-title">报工记录表</view> |
| | | <div class="table-scroll"> |
| | | <table class="report-table"> |
| | | <thead> |
| | | <tr> |
| | | <th>时间</th> |
| | | <th>报工人</th> |
| | | <th>工单号</th> |
| | | <th>产品名称</th> |
| | | <th>计划生产数</th> |
| | | <th>机台号</th> |
| | | <th>初始采集数</th> |
| | | <th>报工时采集数</th> |
| | | <th>报工数(计算)</th> |
| | | <th>不良数</th> |
| | | <th>良品数(计算)</th> |
| | | </tr> |
| | | </thead> |
| | | <tbody> |
| | | <tr> |
| | | <td>{{ nowTime }}</td> |
| | | <td>{{ staffDisplay || '-' }}</td> |
| | | <td>{{ orderNo || '-' }}</td> |
| | | <td>{{ order.daa003 || '-' }}</td> |
| | | <td>{{ planQtyDisplay }}</td> |
| | | <td>{{ machineNo || '-' }}</td> |
| | | <td>{{ initialValue }}</td> |
| | | <td>{{ productionCount }}</td> |
| | | <td>{{ calculatedTotalProduction }}</td> |
| | | <td>{{ calculatedDefectiveCount }}</td> |
| | | <td>{{ sQuantity }}</td> |
| | | </tr> |
| | | </tbody> |
| | | </table> |
| | | </div> |
| | | </view> |
| | | |
| | | <view class="status-row"> |
| | |
| | | <text>当前采集数:</text> |
| | | <input v-model="calculatedCurrentCount" class="highlight" disabled /> |
| | | </view> |
| | | <!-- <view class="status-box"> |
| | | <text>开工时工单已报工数:</text> |
| | | <input v-model="kgQty" class="highlight" disabled /> |
| | | </view> --> |
| | | <view class="operator-box">-</view> |
| | | <view class="status-box standalone-box"> |
| | | <text>已打印条码数:</text> |
| | |
| | | <text>已生产数:</text> |
| | | <input v-model="calculatedTotalProduction" class="highlight" disabled /> |
| | | </view> |
| | | </view> |
| | | <view class="status-row"> |
| | | <view class="status-box"> |
| | | <text>手报不良数:</text> |
| | | <input v-model="defectiveCount" class="highlight" disabled /> |
| | | </view> |
| | | <view class="status-box"> |
| | | <text>未打印条码数:</text> |
| | | <input v-model="bqty" class="highlight" disabled /> |
| | | <view class="btn-group"> |
| | | <button class="refresh-btn-inline" @click="refresh">刷新</button> |
| | | <button v-if="isGeneratingBarcode" class="reset-btn-inline" @click="resetGenerateState">重置</button> |
| | | </view> |
| | | </view> |
| | | <!-- 第一行 --> |
| | | <!-- <view class="status-row"> |
| | | <view class="status-box result-box"> |
| | | <text>当前采集数:</text> |
| | | <input v-model="calculatedCurrentCount" class="highlight" disabled /> |
| | | </view> |
| | | <view class="operator-box">=</view> |
| | | <view class="status-box"> |
| | | <text>机台面板数:</text> |
| | | <input v-model="productionCount" class="highlight" disabled /> |
| | | </view> |
| | | <view class="operator-box">-</view> |
| | | <view class="status-box"> |
| | | <text>初始值:</text> |
| | | <input v-model="initialValue" class="highlight" disabled /> |
| | | </view> |
| | | </view> --> |
| | | <!-- 第二行 --> |
| | | <!-- <view class="status-row"> |
| | | <view class="status-box result-box"> |
| | | <text>已生产数:</text> |
| | | <input v-model="calculatedTotalProduction" class="highlight" disabled /> |
| | | </view> |
| | | <view class="operator-box">=</view> |
| | | <view class="status-box"> |
| | | <text>开工时工单已报工数:</text> |
| | | <input v-model="kgQty" class="highlight" disabled /> |
| | | </view> |
| | | <view class="operator-box">+</view> |
| | | <view class="status-box"> |
| | | <text>当前采集数:</text> |
| | | <input v-model="calculatedCurrentCount" class="highlight" disabled /> |
| | | </view> |
| | | </view> --> |
| | | <!-- 第三行 --> |
| | | <!-- <view class="status-row"> |
| | | <view class="status-box result-box"> |
| | | <text>不良数:</text> |
| | | <input v-model="calculatedDefectiveCount" class="highlight" disabled /> |
| | | </view> |
| | | <view class="operator-box">=</view> |
| | | <view class="status-box"> |
| | | <text>已生产数:</text> |
| | | <input v-model="calculatedTotalProduction" class="highlight" disabled /> |
| | | </view> |
| | | <view class="operator-box">-</view> |
| | | <view class="status-box"> |
| | | <text>良品数:</text> |
| | | <input v-model="sQuantity" class="highlight" disabled /> |
| | | </view> |
| | | <view class="status-box standalone-box"> |
| | | <text>已打印条码数:</text> |
| | | <input v-model="sQuantity" class="highlight" disabled /> |
| | | </view> |
| | | </view> --> |
| | | |
| | | <view> |
| | | <view style="display: flex; flex-direction: column; flex-wrap: nowrap; align-content: flex-start;"> |
| | | <view class="form-row"> |
| | | <view class="form-item"> |
| | | <label>产品编码:</label> |
| | | <input class="inp" type="text" v-model="order.daa002" disabled="true" /> |
| | | <view class="flex-row gap-lg"> |
| | | <view class="print-section flex-grow"> |
| | | <view class="barcode-info"> |
| | | <view class="user-select"> |
| | | <text>不良数量:</text> |
| | | <input v-model="customAmount" class="inp bad-input" placeholder="请输入数量" /> |
| | | </view> |
| | | <view class="form-item"> |
| | | <label>产品名称:</label> |
| | | <!-- <input class="inp" type="text" v-model="order.daa003" disabled="true" /> --> |
| | | <superwei-combox :candidates="DAA003List" v-model="order.daa003" @select="onDaa003Change" |
| | | class="inp"></superwei-combox> |
| | | </view> |
| | | <view class="form-item"> |
| | | <label>产品规格:</label> |
| | | <input class="inp" type="text" v-model="order.daa004" disabled="true" /> |
| | | <view class="user-select"> |
| | | <button class="details-btn" @click="confirmCustomAmount">确认提交</button> |
| | | </view> |
| | | </view> |
| | | <view class="form-row"> |
| | | <view class="form-item"> |
| | | <label>图 号:</label> |
| | | <input class="inp" type="text" v-model="order.engineeringNo" disabled="true" /> |
| | | </view> |
| | | |
| | | <view class="current-user-section fill-width"> |
| | | <text>当前报工人:</text> |
| | | <text class="current-user-name">{{ staffDisplay || '未选择' }}</text> |
| | | <button class="select-user-btn" @click="isShowUserSelect = true">选人</button> |
| | | </view> |
| | | </view> |
| | | |
| | | <!-- 选人弹窗 --> |
| | | <view v-if="isShowUserSelect" class="overlay"> |
| | | <view class="popup user-select-popup"> |
| | | <!-- 搜索栏 --> |
| | | <view class="user-search-bar"> |
| | | <input v-model.trim="userSearch" |
| | | type="text" |
| | | class="user-search-input" |
| | | placeholder="输入工号或姓名搜索" |
| | | @keydown.enter.prevent /> |
| | | <button v-if="userSearch" class="user-search-clear" @click="userSearch=''">清空</button> |
| | | <view class="user-search-info"> |
| | | 匹配:{{ filteredUsers.length }} / {{ users.length }} |
| | | </view> |
| | | <view class="form-item"> |
| | | <label>材 质:</label> |
| | | <input class="inp" type="text" v-model="order.material" disabled="true" /> |
| | | </view> |
| | | <view class="user-list-scroll"> |
| | | <template v-if="filteredUsers.length"> |
| | | <view class="user-list-grid"> |
| | | <button v-for="(u, index) in filteredUsers" |
| | | :key="index" |
| | | :class="['user-list-btn', {'selected': u===staffNo}]" |
| | | @click="selectUser(u)"> |
| | | <span class="user-code">{{ u.split(':')[0] }}</span> |
| | | <span class="user-name">{{ u.split(':')[1] }}</span> |
| | | </button> |
| | | </view> |
| | | </template> |
| | | <view v-else class="no-user-result"> |
| | | 未找到匹配人员 |
| | | </view> |
| | | <view class="form-item"> |
| | | <label>颜 色:</label> |
| | | <input class="inp" type="text" v-model="order.colorName" disabled="true" /> |
| | | </view> |
| | | </view> |
| | | <view class="user-popup-footer"> |
| | | <button class="clean-btn wide-btn" @click="isShowUserSelect = false">关闭</button> |
| | | </view> |
| | | </view> |
| | | </view> |
| | | |
| | | <!-- 条码打印部分 - 中部元素在一条线上 --> |
| | | <view class="print-section"> |
| | | <view class="barcode-info"> |
| | | <view class="user-select"> |
| | | <text style="display: inline-block;float:left;margin-left: -11px;">打印条码张数:</text> |
| | | <input v-model="icount" class="inp" |
| | | style="width: 20%; height: 70px; border: 3px solid #808080; font-size: 40px; text-align: center; margin-top: 5px;" /> |
| | | </view> |
| | | |
| | | <text style="margin-left:-280px;">每张条码数量:</text> |
| | | <input class="inp" |
| | | style="width: 19%; height: 70px; border: 3px solid #808080; font-size: 40px; text-align: center; margin-top: 5px; margin-left: -38px;" |
| | | v-model="barcodeAmount" placeholder="条码数量(装箱数)" /> |
| | | |
| | | <view class="user-select"> |
| | | <button class="print-btn" @click="showPrint" :disabled="isGeneratingBarcode || printLoading" |
| | | :style="(isGeneratingBarcode || printLoading) ? 'background-color: #ccc; cursor: not-allowed;' : ''"> |
| | | {{ isGeneratingBarcode ? '生成中...' : (printLoading ? '打印中...' : '打印条码') }} |
| | | </button> |
| | | <button class="details-btn" @click="showBarcode">条码明细</button> |
| | | </view> |
| | | </view> |
| | | </view> |
| | | |
| | | <!-- 自定义数量输入行 --> |
| | | <view class="print-section" style="margin-top: 20px;"> |
| | | <view class="barcode-info"> |
| | | <view class="user-select"> |
| | | <text style="display: inline-block;float:left;margin-left: -11px;">不良数量:</text> |
| | | <input v-model="customAmount" class="inp" |
| | | style="width: 55%; height: 70px; border: 3px solid #808080; font-size: 40px; text-align: center; margin-top: 5px;" |
| | | placeholder="请输入数量" /> |
| | | </view> |
| | | |
| | | <view class="user-select" style="margin-left: 30px;"> |
| | | <button class="details-btn" @click="confirmCustomAmount">确认提交</button> |
| | | </view> |
| | | </view> |
| | | </view> |
| | | |
| | | <!-- 不良原因选择 --> |
| | | <view> |
| | | <view class="reason-section" style="margin-bottom: -16px"> |
| | | <text>点选不良备注(绑定到工单):</text> |
| | | <view class="reason-buttons" style="font-size: 23px;"> |
| | | <button v-for="(reason, index) in badReasons" :key="index" |
| | | :class="{'reason-btn': true, 'selected': selectedReasons.includes(reason)}" |
| | | @click="toggleReason(reason)" v-text="reason"></button> |
| | | </view> |
| | | </view> |
| | | </view> |
| | | |
| | | <!-- 底部保存和取消按钮 --> |
| | | <view class="bottom-section"> |
| | | <button class="save-btn" @click="save">保存并生效</button> |
| | | <button class="cancel-btn" @click="cancel">取消</button> |
| | | </view> |
| | | |
| | | <!-- 保留旧弹窗 --> |
| | | <view v-if="isShow" class="overlay"> |
| | | <view class="popup"> |
| | | <view class="barcode-info"> |
| | | <!-- <view class="user-select"> |
| | | <text>已打印条码数:</text> |
| | | <input v-model="sQuantity" class="highlight" disabled /> |
| | | </view> |
| | | <view class="user-select"> |
| | | <text>未打印条码数:</text> |
| | | <input v-model="bqty" class="highlight" disabled /> |
| | | </view> --> |
| | | |
| | | <view class="user-select1"> |
| | | <text style="float: left; display: inline-block;">打印条码张数:</text> |
| | | <input v-model="icount" class="inp5" disabled="true" /> |
| | | </view> |
| | | <view class="user-select2"> |
| | | <text style="float: left;">每张条码数量:</text> |
| | | <input class="inp6" disabled="true" v-model="barcodeAmount" placeholder="条码数量(装箱数)" /> |
| | | </view> |
| | | |
| | | <view class="form-row"> |
| | | <!--<kk-printer defaultText="打印条码" class="print-btn" ref="kkprinter" :user="staffNo" |
| | | :bufferData="bufferData" @onPrint="onPrint" @onPrintSuccess="onPrintSuccess" |
| | | @onPrintFail="onPrintFail"> |
| | | </kk-printer>--> |
| | | </view> |
| | | </view> |
| | | <view class="bottom-section1"> |
| | | <!-- <button class="clean-btn" type="primary" @click="cleanUser">关闭</button> --> |
| | | <button class="clean-btn" type="warn" @click="deleteBarcode">取消打印</button> |
| | | <button class="print-btn" |
| | | style="width: 48%; padding: 1.5vh; color: white; font-size: 1.5vw; border: none; text-align: center; cursor: pointer; border-radius: 0.5vw;" |
| | | @click="printTest" :loading="printLoading" :disabled="printLoading || isGeneratingBarcode" |
| | | :style="(printLoading || isGeneratingBarcode) ? 'background-color: #ccc; cursor: not-allowed;' : ''"> |
| | | {{ isGeneratingBarcode ? '生成中...' : (printLoading ? '打印中...' : '打印条码') }} |
| | | </button> |
| | | <button class="clean-btn" type="warn" @click="deleteBarcode">关闭</button> |
| | | </view> |
| | | <view class="reason-section"> |
| | | <text>报工人:</text> |
| | | <view class="reason-buttons"> |
| | | <button v-for="(reason, index) in users" :key="index" |
| | | :class="{'reason-btn': true, 'selected': user === reason}" @click="toggleUser(reason)" |
| | | v-text="reason"></button> |
| | | <button v-for="(u,index) in users" :key="index" |
| | | :class="{'reason-btn':true,'selected': user===u}" |
| | | @click="toggleUser(u)"> |
| | | {{ formatUser(u) }} |
| | | </button> |
| | | </view> |
| | | </view> |
| | | </view> |
| | | </view> |
| | | |
| | | <!-- 展示条码明细 --> |
| | | <view v-if="barcodeIsShow" class="overlay"> |
| | | <view class="popup"> |
| | | <!-- <view class="barcode-info"> --> |
| | | <uni-table ref="table" border stripe emptyText="暂无更多数据" class="table1"> |
| | | <uni-tr> |
| | | <uni-th align="center" style="font-size: 40px;">生成时间</uni-th> |
| | | <uni-th align="center" style="width:39%;font-size: 40px;">条码</uni-th> |
| | | <uni-th align="center" style="font-size: 40px;">报工人</uni-th> |
| | | <uni-th align="center" style="font-size: 40px;">报工数量</uni-th> |
| | | <uni-th align="center" style="font-size:40px;">生成时间</uni-th> |
| | | <uni-th align="center" style="width:39%;font-size:40px;">条码</uni-th> |
| | | <uni-th align="center" style="font-size:40px;">报工人</uni-th> |
| | | <uni-th align="center" style="font-size:40px;">报工数量</uni-th> |
| | | </uni-tr> |
| | | <uni-tr v-for="(item, index) in reportingList" :key="index"> |
| | | <uni-td align="center"> |
| | | <input type="text" v-model="item.bgDate" style="width: 26vh;" /> |
| | | </uni-td> |
| | | <uni-td align="center"> |
| | | <input v-model="item.itemNoCade" style="width: 40vh;" /> |
| | | </uni-td> |
| | | <uni-td align="center"> |
| | | <input v-model="item.staffName" /> |
| | | </uni-td> |
| | | <uni-td align="center"> |
| | | <input v-model="item.okQty" /> |
| | | </uni-td> |
| | | <uni-tr v-for="(item,index) in reportingList" :key="index"> |
| | | <uni-td align="center"><input type="text" v-model="item.bgDate" style="width:26vh;" /></uni-td> |
| | | <uni-td align="center"><input v-model="item.itemNoCade" style="width:40vh;" /></uni-td> |
| | | <uni-td align="center"><input v-model="item.staffName" /></uni-td> |
| | | <uni-td align="center"><input v-model="item.okQty" /></uni-td> |
| | | </uni-tr> |
| | | </uni-table> |
| | | <!-- </view> --> |
| | | <view> |
| | | <button class="clean-btn" type="warn" @click="barcodeIsShow = false">关闭</button> |
| | | </view> |
| | | <view><button class="clean-btn" type="warn" @click="barcodeIsShow=false">关闭</button></view> |
| | | </view> |
| | | </view> |
| | | </view> |
| | |
| | | </template> |
| | | |
| | | <script> |
| | | import { |
| | | printTemplate3 |
| | | } from "../utils/printTemplate"; |
| | | import { printTemplate3 } from "../utils/printTemplate"; |
| | | |
| | | export default { |
| | | props: { |
| | | orderNo: String, |
| | | orderId: Number, |
| | | machineNo: String |
| | | }, |
| | | props: { orderNo: String, orderId: Number, machineNo: String }, |
| | | data() { |
| | | return { |
| | | currentUser: '', // 默认当前用户 |
| | | barcodeAmount: '', // 输入的条码数量 |
| | | users: [], // 用户列表 |
| | | userForm: [], |
| | | staff: [], |
| | | user: {}, |
| | | badReasons: [], // 不良原因 |
| | | itemsNgname: [], |
| | | selectedReasons: [], // 存储选中的不良原因 |
| | | productionCount: 0, // 当前系统采集生产数 |
| | | printedCount: 0, // 当前已打码报工数 |
| | | defectiveCount: 0, // 不良数 |
| | | order: {}, |
| | | icount: 1, // 默认为1,避免为0或null |
| | | bqty: 0, |
| | | sQuantity: 0, |
| | | kgQty: 0, |
| | | initialValue: 0, |
| | | qqty: 0, |
| | | ngStaid: 0, |
| | | bufferData: '', |
| | | dataToPrint: [], |
| | | isLoading: false, // 新的加载状态 |
| | | but: false, |
| | | DAA003List: [], |
| | | lineList: [], |
| | | isShow: false, // 控制打印条码按钮的显示 |
| | | barcodeIsShow: false, |
| | | barcodeList: [], |
| | | staffNo: '', |
| | | printStr: '', |
| | | |
| | | printMac: '', |
| | | bluetoothSocket: {}, // 蓝牙连接 |
| | | device: '', |
| | | uuid: '', |
| | | printNum: 1, |
| | | |
| | | reportingList: [], |
| | | |
| | | printLoading: false, |
| | | customAmount: '', |
| | | |
| | | // 新增防重复请求相关变量 |
| | | isGeneratingBarcode: false, // 是否正在生成条码 |
| | | lastGenerateTime: 0, // 上次生成条码的时间戳 |
| | | generateRequestId: null // 当前生成请求的唯一ID |
| | | }; |
| | | }, |
| | | computed: { |
| | | // 计算当前采集数,确保不会出现NaN或undefined |
| | | calculatedCurrentCount() { |
| | | const production = this.productionCount || 0; |
| | | const initial = this.initialValue || 0; |
| | | return production - initial; |
| | | }, |
| | | // 计算已生产总数 |
| | | calculatedTotalProduction() { |
| | | const kgQty = this.kgQty || 0; |
| | | const currentCount = this.calculatedCurrentCount; |
| | | // 当开工时工单已报工数为0时,直接使用当前采集数的值 |
| | | //return kgQty === 0 ? currentCount : kgQty + currentCount; |
| | | return kgQty + currentCount |
| | | }, |
| | | // 计算不良数 |
| | | calculatedDefectiveCount() { |
| | | const totalProduction = this.calculatedTotalProduction; |
| | | // const totalProduction = this.productionCount; |
| | | const goodCount = this.sQuantity || 0; |
| | | return totalProduction - goodCount; |
| | | isShowUserSelect: false, |
| | | currentUser: '', |
| | | barcodeAmount: '', |
| | | users: [], userForm: [], staff: [], user: {}, |
| | | productionCount: 0, printedCount: 0, defectiveCount: 0, order: {}, |
| | | icount: 1, bqty: 0, sQuantity: 0, kgQty: 0, initialValue: 0, qqty: 0, |
| | | ngStaid: 0, bufferData: '', dataToPrint: [], isLoading: false, but: false, |
| | | DAA003List: [], lineList: [], isShow: false, barcodeIsShow: false, barcodeList: [], |
| | | staffNo: '', printStr: '', printMac: '', bluetoothSocket: {}, device: '', uuid: '', |
| | | printNum: 1, reportingList: [], printLoading: false, customAmount: '', |
| | | isGeneratingBarcode: false, lastGenerateTime: 0, generateRequestId: null, |
| | | nowTimeTimer: null, nowTime: '', |
| | | // 新增:搜索关键字 |
| | | userSearch: '' |
| | | } |
| | | }, |
| | | components: {}, |
| | | mounted() { |
| | | // this.fetchData(false); // Initial fetch |
| | | // this.timer = setInterval(this.fetchData, 180000); // Call fetchData every 5 minutes |
| | | computed: { |
| | | calculatedCurrentCount() { return (this.productionCount || 0) - (this.initialValue || 0); }, |
| | | calculatedTotalProduction() { return (this.kgQty || 0) + this.calculatedCurrentCount; }, |
| | | calculatedDefectiveCount() { return this.calculatedTotalProduction - (this.sQuantity || 0); }, |
| | | planQtyDisplay() { return this.order.planQty || this.order.planQuantity || this.order.daa007 || this.order.daa010 || 0; }, |
| | | staffDisplay() { |
| | | if (!this.staffNo) return ''; |
| | | const segs = this.staffNo.split(':'); |
| | | return segs.length > 1 ? `${segs[0]} ${segs[1]}` : this.staffNo; |
| | | }, |
| | | // 新增:过滤后的用户列表 |
| | | filteredUsers() { |
| | | if (!this.userSearch) return this.users; |
| | | const kw = this.userSearch.trim().toLowerCase(); |
| | | return this.users.filter(u => u.toLowerCase().includes(kw)); |
| | | } |
| | | }, |
| | | created() { |
| | | // 初始化数据,确保所有数值型变量有默认值 |
| | | this.initializeData(); |
| | | this.fetchData(true); |
| | | this.init(); |
| | | this.getXS0101(); |
| | | this.updateNowTime(); |
| | | this.nowTimeTimer = setInterval(this.updateNowTime, 60000); |
| | | }, |
| | | beforeDestroy() { if (this.nowTimeTimer) clearInterval(this.nowTimeTimer); }, |
| | | methods: { |
| | | // 初始化所有数值型变量,避免null或undefined |
| | | initializeData() { |
| | | this.productionCount = 0; |
| | | this.printedCount = 0; |
| | | this.defectiveCount = 0; |
| | | this.icount = 1; |
| | | this.bqty = 0; |
| | | this.sQuantity = 0; |
| | | this.kgQty = 0; |
| | | this.initialValue = 0; |
| | | this.qqty = 0; |
| | | |
| | | // 初始化防重复状态 |
| | | this.isGeneratingBarcode = false; |
| | | this.lastGenerateTime = 0; |
| | | this.generateRequestId = null; |
| | | formatUser(u) { |
| | | if (!u) return ''; |
| | | const segs = u.split(':'); |
| | | return segs.length > 1 ? `${segs[0]} ${segs[1]}` : u; |
| | | }, |
| | | |
| | | // 手动重置防重复状态(紧急情况下使用) |
| | | selectUser(u) { this.staffNo = u; this.isShowUserSelect = false; this.userSearch = ''; }, |
| | | updateNowTime() { |
| | | const d = new Date(), p = n => n.toString().padStart(2, '0'); |
| | | this.nowTime = `${d.getFullYear()}-${p(d.getMonth() + 1)}-${p(d.getDate())} ${p(d.getHours())}:${p(d.getMinutes())}`; |
| | | }, |
| | | initializeData() { |
| | | this.productionCount = this.printedCount = this.defectiveCount = 0; |
| | | this.icount = 1; this.bqty = 0; this.sQuantity = 0; this.kgQty = 0; |
| | | this.initialValue = 0; this.qqty = 0; |
| | | this.isGeneratingBarcode = false; this.lastGenerateTime = 0; this.generateRequestId = null; |
| | | }, |
| | | resetGenerateState() { |
| | | this.isGeneratingBarcode = false; |
| | | this.generateRequestId = null; |
| | | this.lastGenerateTime = 0; |
| | | console.log("已手动重置条码生成状态"); |
| | | this.isGeneratingBarcode = false; this.generateRequestId = null; this.lastGenerateTime = 0; |
| | | this.$showMessage("已重置条码生成状态"); |
| | | }, |
| | | refresh() { |
| | | this.$sendPostRequest({ |
| | | url: "http://192.168.0.94:9095/Numerical/RefreshDev", |
| | | data: { |
| | | machineNo: this.order.machineNo |
| | | }, |
| | | data: { machineNo: this.order.machineNo }, |
| | | contentType: "application/json" |
| | | }).then(res1 => { |
| | | if (res1.code == 200) { |
| | | this.fetchData(true); // 重新请求数据 |
| | | } else { |
| | | this.$showMessage("同步失败"); |
| | | } |
| | | }); |
| | | |
| | | }).then(r => { r.code == 200 ? this.fetchData(true) : this.$showMessage("同步失败"); }); |
| | | }, |
| | | printTest() { |
| | | if (!this.staffNo) { |
| | | this.$showMessage("请选择报工人"); |
| | | return; |
| | | } |
| | | |
| | | try { |
| | | // 在调用onPrint前清空数据 |
| | | // 这样可以确保每次打印都是从零开始 |
| | | this.dataToPrint = []; |
| | | this.bufferData = ''; |
| | | this.onPrint(); |
| | | |
| | | this.$showMessage('正在打印,请稍等!'); |
| | | this.printLoading = true; |
| | | |
| | | this.printNum = 1; |
| | | setTimeout(() => { |
| | | this.doPrint(); |
| | | this.printLoading = false; |
| | | console.log("调用打印"); |
| | | }, 2000); |
| | | } catch (e) { |
| | | this.onPrintFail(); |
| | | console.log(e); |
| | | } |
| | | |
| | | }, |
| | | doPrint() { //printNum:打印次数 |
| | | var mac_address = uni.getStorageSync('printMac'); |
| | | console.log("打印机地址" + mac_address); |
| | | console.log('打印开始'); |
| | | console.log("打印参数" + this.bufferData); |
| | | |
| | | if (!mac_address) { |
| | | this.$showMessage('请选择蓝牙打印机'); |
| | | this.printLoading = false; |
| | | return false; |
| | | } |
| | | |
| | | // 检查Android版本并使用对应的打印方法 |
| | | // const androidVersion = this.getAndroidVersion(); |
| | | // console.log('Android版本:', androidVersion); |
| | | |
| | | // if (androidVersion >= 12) { |
| | | // return this.doPrintForAndroid12Plus(mac_address); |
| | | // } else { |
| | | return this.doPrintForAndroidLegacy(mac_address); |
| | | // } |
| | | }, |
| | | |
| | | // Android 12+ 版本的蓝牙打印方法 |
| | | doPrintForAndroid12Plus(mac_address) { |
| | | try { |
| | | console.log('使用Android 12+兼容的蓝牙打印方法'); |
| | | |
| | | // 检查蓝牙权限 |
| | | if (!this.checkBluetoothPermissions()) { |
| | | this.$showMessage('蓝牙权限不足,请检查应用权限设置'); |
| | | this.printLoading = false; |
| | | return false; |
| | | } |
| | | |
| | | var main = plus.android.runtimeMainActivity(); |
| | | var BluetoothManager = plus.android.importClass("android.bluetooth.BluetoothManager"); |
| | | var Context = plus.android.importClass("android.content.Context"); |
| | | |
| | | // 获取BluetoothManager |
| | | var bluetoothManager = main.getSystemService(Context.BLUETOOTH_SERVICE); |
| | | var bluetoothAdapter = bluetoothManager.getAdapter(); |
| | | |
| | | if (!bluetoothAdapter) { |
| | | this.$showMessage('设备不支持蓝牙'); |
| | | this.printLoading = false; |
| | | return false; |
| | | } |
| | | |
| | | if (!bluetoothAdapter.isEnabled()) { |
| | | this.$showMessage('请先开启蓝牙'); |
| | | this.printLoading = false; |
| | | return false; |
| | | } |
| | | |
| | | // 获取配对设备 |
| | | var pairedDevices = bluetoothAdapter.getBondedDevices(); |
| | | var targetDevice = null; |
| | | |
| | | // 查找目标设备 |
| | | var iterator = pairedDevices.iterator(); |
| | | while (iterator.hasNext()) { |
| | | var device = iterator.next(); |
| | | if (device.getAddress().equals(mac_address)) { |
| | | targetDevice = device; |
| | | break; |
| | | } |
| | | } |
| | | |
| | | if (!targetDevice) { |
| | | this.$showMessage('未找到配对的打印机设备'); |
| | | this.printLoading = false; |
| | | return false; |
| | | } |
| | | |
| | | // 创建蓝牙连接 |
| | | var UUID = plus.android.importClass("java.util.UUID"); |
| | | var uuid = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB"); |
| | | var bluetoothSocket = targetDevice.createRfcommSocketToServiceRecord(uuid); |
| | | |
| | | // 连接设备 |
| | | try { |
| | | bluetoothSocket.connect(); |
| | | console.log('蓝牙连接成功'); |
| | | |
| | | // 发送打印数据 |
| | | var outputStream = bluetoothSocket.getOutputStream(); |
| | | var bytes = plus.android.invoke(this.bufferData, 'getBytes', 'gbk'); |
| | | outputStream.write(bytes); |
| | | outputStream.flush(); |
| | | |
| | | // 关闭连接 |
| | | outputStream.close(); |
| | | bluetoothSocket.close(); |
| | | |
| | | console.log("打印成功"); |
| | | this.cleanUser(); |
| | | this.onPrintSuccess(); |
| | | return true; |
| | | |
| | | } catch (connectError) { |
| | | console.error('蓝牙连接失败:', connectError); |
| | | |
| | | // 尝试fallback方法 |
| | | try { |
| | | bluetoothSocket.close(); |
| | | // 使用反射获取hidden方法 |
| | | var createRfcommSocket = targetDevice.getClass().getMethod("createRfcommSocket", |
| | | plus.android.importClass("java.lang.Integer").TYPE); |
| | | bluetoothSocket = createRfcommSocket.invoke(targetDevice, 1); |
| | | |
| | | bluetoothSocket.connect(); |
| | | console.log('使用fallback方法连接成功'); |
| | | |
| | | var outputStream = bluetoothSocket.getOutputStream(); |
| | | var bytes = plus.android.invoke(this.bufferData, 'getBytes', 'gbk'); |
| | | outputStream.write(bytes); |
| | | outputStream.flush(); |
| | | |
| | | outputStream.close(); |
| | | bluetoothSocket.close(); |
| | | |
| | | this.cleanUser(); |
| | | this.onPrintSuccess(); |
| | | return true; |
| | | |
| | | } catch (fallbackError) { |
| | | console.error('Fallback方法也失败:', fallbackError); |
| | | this.$showMessage('蓝牙连接失败,请检查打印机状态'); |
| | | this.printLoading = false; |
| | | return false; |
| | | } |
| | | } |
| | | |
| | | } catch (error) { |
| | | console.error('Android 12+ 蓝牙打印错误:', error); |
| | | this.$showMessage('打印失败: ' + error.message); |
| | | this.printLoading = false; |
| | | return false; |
| | | } |
| | | }, |
| | | |
| | | // Android 11及以下版本的蓝牙打印方法(保持原有逻辑) |
| | | doPrintForAndroidLegacy(mac_address) { |
| | | try { |
| | | console.log('使用传统蓝牙打印方法'); |
| | | |
| | | var device = null, |
| | | BAdapter = null, |
| | | BluetoothAdapter = null, |
| | | uuid = null, |
| | | main = null, |
| | | bluetoothSocket = null; |
| | | |
| | | main = plus.android.runtimeMainActivity(); |
| | | BluetoothAdapter = plus.android.importClass("android.bluetooth.BluetoothAdapter"); |
| | | let UUID = plus.android.importClass("java.util.UUID"); |
| | | uuid = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB"); |
| | | BAdapter = BluetoothAdapter.getDefaultAdapter(); |
| | | |
| | | if (!BAdapter) { |
| | | this.$showMessage('设备不支持蓝牙'); |
| | | this.printLoading = false; |
| | | return false; |
| | | } |
| | | |
| | | device = BAdapter.getRemoteDevice(mac_address); |
| | | plus.android.importClass(device); |
| | | bluetoothSocket = device.createInsecureRfcommSocketToServiceRecord(uuid); |
| | | plus.android.importClass(bluetoothSocket); |
| | | |
| | | if (!bluetoothSocket.isConnected()) { |
| | | console.log('检测到设备未连接,尝试连接....'); |
| | | bluetoothSocket.connect(); |
| | | } |
| | | |
| | | console.log('设备已连接'); |
| | | if (bluetoothSocket.isConnected()) { |
| | | var outputStream = bluetoothSocket.getOutputStream(); |
| | | plus.android.importClass(outputStream); |
| | | var bytes = plus.android.invoke(this.bufferData, 'getBytes', 'gbk'); |
| | | outputStream.write(bytes); |
| | | outputStream.flush(); |
| | | device = null //这里关键 |
| | | bluetoothSocket.close(); //必须关闭蓝牙连接否则意外断开的话打印错误 |
| | | console.log("打印机连接状态:111"); |
| | | this.cleanUser(); |
| | | this.onPrintSuccess(); |
| | | return true; |
| | | } else { |
| | | console.log("打印机连接状态:222"); |
| | | this.printLoading = false; |
| | | return false; |
| | | } |
| | | } catch (error) { |
| | | console.error('传统蓝牙打印错误:', error); |
| | | this.$showMessage('打印失败: ' + error.message); |
| | | this.printLoading = false; |
| | | return false; |
| | | } |
| | | }, |
| | | |
| | | // 获取Android版本号 |
| | | getAndroidVersion() { |
| | | try { |
| | | var Build = plus.android.importClass("android.os.Build"); |
| | | return Build.VERSION.SDK_INT; |
| | | } catch (error) { |
| | | console.error('获取Android版本失败:', error); |
| | | return 30; // 默认返回Android 11的API Level |
| | | } |
| | | }, |
| | | |
| | | // 检查蓝牙权限(Android 12+需要) |
| | | checkBluetoothPermissions() { |
| | | try { |
| | | const androidVersion = this.getAndroidVersion(); |
| | | |
| | | // Android 12以下版本不需要新权限 |
| | | if (androidVersion < 31) { // Android 12 = API 31 |
| | | return true; |
| | | } |
| | | |
| | | var main = plus.android.runtimeMainActivity(); |
| | | var PackageManager = plus.android.importClass("android.content.pm.PackageManager"); |
| | | var ContextCompat = plus.android.importClass("androidx.core.content.ContextCompat"); |
| | | |
| | | // Android 12+ 需要的权限 |
| | | var permissions = [ |
| | | "android.permission.BLUETOOTH_CONNECT", |
| | | "android.permission.BLUETOOTH_SCAN" |
| | | ]; |
| | | |
| | | var missingPermissions = []; |
| | | for (var i = 0; i < permissions.length; i++) { |
| | | var permission = permissions[i]; |
| | | var granted = ContextCompat.checkSelfPermission(main, permission); |
| | | if (granted !== PackageManager.PERMISSION_GRANTED) { |
| | | console.log('权限未授予:', permission); |
| | | missingPermissions.push(permission); |
| | | } |
| | | } |
| | | |
| | | if (missingPermissions.length > 0) { |
| | | // 尝试请求权限 |
| | | this.requestBluetoothPermissions(missingPermissions); |
| | | return false; |
| | | } |
| | | |
| | | return true; |
| | | } catch (error) { |
| | | console.error('权限检查失败:', error); |
| | | // 如果检查失败,假设权限已授予(可能是老版本Android) |
| | | return true; |
| | | } |
| | | }, |
| | | |
| | | // 请求蓝牙权限 |
| | | requestBluetoothPermissions(permissions) { |
| | | try { |
| | | var main = plus.android.runtimeMainActivity(); |
| | | var ActivityCompat = plus.android.importClass("androidx.core.app.ActivityCompat"); |
| | | |
| | | console.log('请求蓝牙权限:', permissions); |
| | | |
| | | // 将JavaScript数组转换为Java数组 |
| | | var javaPermissions = plus.android.newObject("java.lang.String", permissions.length); |
| | | for (var i = 0; i < permissions.length; i++) { |
| | | javaPermissions[i] = permissions[i]; |
| | | } |
| | | |
| | | // 请求权限 |
| | | ActivityCompat.requestPermissions(main, javaPermissions, 1001); |
| | | |
| | | // 显示提示信息 |
| | | this.$showMessage('正在请求蓝牙权限,请在系统弹窗中允许权限后重试'); |
| | | |
| | | } catch (error) { |
| | | console.error('请求权限失败:', error); |
| | | this.$showMessage('无法请求蓝牙权限,请手动在设置中开启应用的蓝牙权限'); |
| | | } |
| | | }, |
| | | init() { |
| | | console.log("设置蓝牙"); |
| | | try { |
| | | // 检查Android版本并使用对应的初始化方法 |
| | | const androidVersion = this.getAndroidVersion(); |
| | | |
| | | if (androidVersion >= 12) { |
| | | this.initForAndroid12Plus(); |
| | | } else { |
| | | this.initForAndroidLegacy(); |
| | | } |
| | | } catch (err) { |
| | | console.error("蓝牙初始化异常!", err); |
| | | } |
| | | }, |
| | | |
| | | // Android 12+ 版本的蓝牙初始化 |
| | | initForAndroid12Plus() { |
| | | try { |
| | | console.log("使用Android 12+兼容的蓝牙初始化"); |
| | | |
| | | var main = plus.android.runtimeMainActivity(); |
| | | var BluetoothManager = plus.android.importClass("android.bluetooth.BluetoothManager"); |
| | | var Context = plus.android.importClass("android.content.Context"); |
| | | var UUID = plus.android.importClass("java.util.UUID"); |
| | | |
| | | this.uuid = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB"); |
| | | |
| | | // 获取BluetoothManager和Adapter |
| | | var bluetoothManager = main.getSystemService(Context.BLUETOOTH_SERVICE); |
| | | var bluetoothAdapter = bluetoothManager.getAdapter(); |
| | | |
| | | if (bluetoothAdapter && bluetoothAdapter.isDiscovering()) { |
| | | bluetoothAdapter.cancelDiscovery(); // 停止扫描 |
| | | } |
| | | |
| | | let printMac1 = uni.getStorageSync('printMac'); |
| | | this.printMac = printMac1; |
| | | console.log("打印机地址" + this.printMac); |
| | | |
| | | var address_mac = this.printMac ? this.printMac : "DC:1D:30:91:06:52"; |
| | | console.log("status:" + address_mac); |
| | | |
| | | if (bluetoothAdapter) { |
| | | this.device = bluetoothAdapter.getRemoteDevice(address_mac); |
| | | plus.android.importClass(this.device); |
| | | console.log("Android 12+ 蓝牙初始化成功"); |
| | | } |
| | | |
| | | } catch (err) { |
| | | console.error("Android 12+ 蓝牙初始化失败:", err); |
| | | // 如果失败,尝试使用传统方法 |
| | | this.initForAndroidLegacy(); |
| | | } |
| | | }, |
| | | |
| | | // Android 11及以下版本的蓝牙初始化(保持原有逻辑) |
| | | initForAndroidLegacy() { |
| | | try { |
| | | console.log("使用传统蓝牙初始化方法"); |
| | | |
| | | var main = plus.android.runtimeMainActivity(); |
| | | var BluetoothAdapter = plus.android.importClass("android.bluetooth.BluetoothAdapter"); |
| | | var UUID = plus.android.importClass("java.util.UUID"); |
| | | |
| | | this.uuid = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB"); |
| | | var BAdapter = BluetoothAdapter.getDefaultAdapter(); |
| | | |
| | | if (BAdapter) { |
| | | BAdapter.cancelDiscovery(); // 停止扫描 |
| | | } |
| | | |
| | | let printMac1 = uni.getStorageSync('printMac'); |
| | | this.printMac = printMac1; |
| | | console.log("打印机地址" + this.printMac); |
| | | |
| | | var address_mac = this.printMac ? this.printMac : "DC:1D:30:91:06:52"; |
| | | console.log("status:" + address_mac); |
| | | |
| | | if (BAdapter) { |
| | | this.device = BAdapter.getRemoteDevice(address_mac); |
| | | plus.android.importClass(this.device); |
| | | |
| | | this.bluetoothSocket = this.device.createInsecureRfcommSocketToServiceRecord(this.uuid); |
| | | plus.android.importClass(this.bluetoothSocket); |
| | | console.log("传统蓝牙初始化成功"); |
| | | } |
| | | |
| | | } catch (err) { |
| | | console.error("传统蓝牙初始化失败:", err); |
| | | } |
| | | }, |
| | | |
| | | onDaa003Change(event) { |
| | | |
| | | let orde = this.lineList[this.DAA003List.indexOf(event)]; |
| | | |
| | | this.orderId = orde.id; |
| | | this.orderNo = orde.daa001; |
| | | |
| | | //切换为新的id |
| | | onDaa003Change(v) { |
| | | let o = this.lineList[this.DAA003List.indexOf(v)]; |
| | | this.orderId = o.id; this.orderNo = o.daa001; |
| | | uni.setStorageSync('machine', this.machineNo); |
| | | uni.setStorageSync('orderId', this.orderId); |
| | | uni.setStorageSync('orderNo', this.orderNo); |
| | | uni.setStorageSync('engineeringNo', this.order.engineeringNo); |
| | | |
| | | this.fetchData(false); |
| | | }, |
| | | fetchData(flag) { |
| | | // let machine = uni.getStorageSync('machine'); |
| | | // let orderId = uni.getStorageSync('orderId'); |
| | | // let orderNo = uni.getStorageSync('orderNo'); |
| | | |
| | | // if (orderId) { |
| | | // this.orderId = orderId; |
| | | // } else { |
| | | // if (!this.orderId) { |
| | | // this.orderId = uni.getStorageSync('id'); |
| | | // } |
| | | |
| | | // } |
| | | |
| | | // if (orderNo) { |
| | | // this.orderNo = orderNo; |
| | | // } else { |
| | | // if (!this.orderNo) { |
| | | // this.orderNo = uni.getStorageSync('daa001'); |
| | | // } |
| | | // } |
| | | |
| | | // if (machine) { |
| | | // this.machineNo = machine; |
| | | // } else { |
| | | // if (!this.machineNo) { |
| | | // this.machineNo = uni.getStorageSync('machineNo'); |
| | | // } |
| | | // } |
| | | |
| | | if (!this.orderId && !this.orderNo) { |
| | | return; |
| | | } |
| | | |
| | | if (!this.orderId && !this.orderNo) return; |
| | | this.getOrderById(); |
| | | this.getMesItemsNgname(); |
| | | |
| | | this.getWomdaaPrintById(); |
| | | this.findByOrderId(); |
| | | |
| | | if (flag) { |
| | | this.$post({ |
| | | url: "/Womdaa/GetWomdaasByShow", |
| | | data: { |
| | | machineNo: this.machineNo |
| | | } |
| | | }).then(res => { |
| | | this.lineList = res.data.tbBillList; |
| | | this.DAA003List = res.data.tbBillList.map(item => item.daa003); |
| | | }) |
| | | } |
| | | |
| | | }, |
| | | formatDate(date) { |
| | | if (!date) return ''; |
| | | |
| | | try { |
| | | let year = date.getFullYear(); // 获取年份 |
| | | let month = String(date.getMonth() + 1).padStart(2, '0'); // 获取月份并补零 |
| | | let day = String(date.getDate()).padStart(2, '0'); // 获取日期并补零 |
| | | return `${year}-${month}-${day}`; // 返回格式化后的字符串 |
| | | } catch (error) { |
| | | console.error("日期格式化错误:", error); |
| | | return ''; |
| | | } |
| | | }, |
| | | // 切换选中的不良原因 |
| | | toggleReason(reason) { |
| | | if (!reason) return; |
| | | |
| | | if (this.selectedReasons.includes(reason)) { |
| | | this.selectedReasons = this.selectedReasons.filter(r => r !== reason); |
| | | } else { |
| | | this.selectedReasons.push(reason); |
| | | } |
| | | }, |
| | | toggleUser(user) { |
| | | if (!user) return; |
| | | |
| | | this.user = this.user === user ? null : user; |
| | | this.staffNo = user; |
| | | }, |
| | | showPrint() { |
| | | // 防重复点击检查 - 生成中或打印中都不允许 |
| | | if (this.isGeneratingBarcode) { |
| | | this.$showMessage('正在生成条码,请稍等...'); |
| | | return; |
| | | } |
| | | |
| | | if (this.printLoading) { |
| | | this.$showMessage('正在打印条码,请稍等...'); |
| | | return; |
| | | } |
| | | |
| | | // 防抖检查:2秒内不允许重复操作 |
| | | const currentTime = Date.now(); |
| | | if (currentTime - this.lastGenerateTime < 2000) { |
| | | this.$showMessage('操作过于频繁,请稍等再试'); |
| | | return; |
| | | } |
| | | |
| | | if (this.icount > 6) { |
| | | this.$showMessage('条码数量不能超过6张'); |
| | | return; |
| | | } |
| | | |
| | | this.isShow = true; |
| | | |
| | | //this.printBarcode(); |
| | | this.getXS0101(); |
| | | |
| | | this.user = ""; |
| | | |
| | | this.staffNo = null; |
| | | }, |
| | | showBarcode() { |
| | | |
| | | |
| | | this.$post({ |
| | | url: "/MesStaff/GetMesReportingList", |
| | | data: { |
| | | orderNo: this.orderNo, |
| | | } |
| | | }).then(res => { |
| | | this.reportingList = res.data.tbBillList; |
| | | this.barcodeIsShow = true; |
| | | }); |
| | | }, |
| | | // 打印条码报工 |
| | | printBarcode() { |
| | | // 防重复请求检查 |
| | | if (this.isGeneratingBarcode) { |
| | | this.$showMessage('正在生成条码,请稍等...'); |
| | | return; |
| | | } |
| | | |
| | | if (!this.barcodeAmount) { |
| | | this.isShow = false; |
| | | this.$showMessage('请输入条码数量'); |
| | | return; |
| | | } |
| | | |
| | | if (this.bqty == 0) { |
| | | this.isShow = false; |
| | | this.$showMessage('可打印数量为0'); |
| | | return; |
| | | } |
| | | |
| | | if (this.bqty < this.barcodeAmount) { |
| | | this.isShow = false; |
| | | this.$showMessage('打印数量不能大于可打印数量'); |
| | | return; |
| | | } |
| | | |
| | | if (this.icount * this.barcodeAmount > this.bqty) { |
| | | this.isShow = false; |
| | | this.$showMessage('打印总数超过可打印总数'); |
| | | return; |
| | | } |
| | | |
| | | // 设置生成状态锁定 |
| | | this.isGeneratingBarcode = true; |
| | | this.lastGenerateTime = Date.now(); |
| | | |
| | | // 生成唯一请求ID,用于防重 |
| | | this.generateRequestId = `${this.orderNo}_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`; |
| | | |
| | | console.log('开始生成条码,请求ID:', this.generateRequestId); |
| | | |
| | | // 添加超时机制:15秒后自动释放锁定 |
| | | const timeoutId = setTimeout(() => { |
| | | if (this.isGeneratingBarcode) { |
| | | console.log('条码生成超时,释放锁定'); |
| | | this.isGeneratingBarcode = false; |
| | | this.$showMessage('生成条码超时,请重试'); |
| | | } |
| | | }, 15000); |
| | | |
| | | this.$post({ |
| | | url: "/MesInvItemBarcodes/AddItemToBarcodes", |
| | | data: { |
| | | printQty: this.barcodeAmount, |
| | | orderNo: this.orderNo, |
| | | orderId: this.orderId, |
| | | user: this.user, |
| | | count: this.icount, |
| | | requestId: this.generateRequestId // 传递请求ID到后端用于防重 |
| | | }, |
| | | showLoading: true, |
| | | showLoadingTitle: "正在生成条码..." |
| | | }).then(res => { |
| | | // 清除超时定时器 |
| | | clearTimeout(timeoutId); |
| | | |
| | | // 注意:这里不立即释放 isGeneratingBarcode,要等到打印完成才释放 |
| | | // this.isGeneratingBarcode = false; // 移除这行,在 cleanUser() 中重置 |
| | | |
| | | if (res.status == 1) { |
| | | this.$showMessage(res.message); |
| | | this.isShow = false; |
| | | // 如果生成失败,重置状态 |
| | | this.isGeneratingBarcode = false; |
| | | this.generateRequestId = null; |
| | | return; |
| | | } |
| | | this.dataToPrint = res.data.tbBillList; |
| | | // this.getXS0101(); |
| | | |
| | | let printCommands = []; |
| | | |
| | | console.log("接口返回的条数" + this.dataToPrint.length); |
| | | |
| | | let user = this.staffNo; |
| | | |
| | | for (let i = 0; i < this.dataToPrint.length; i++) { |
| | | let _printData = { |
| | | strp1: this.dataToPrint[i].out12, |
| | | strp2: this.dataToPrint[i].out2, |
| | | strp3: this.dataToPrint[i].out6, |
| | | strp4: this.dataToPrint[i].out1, |
| | | strp5: this.dataToPrint[i].out11, |
| | | strp6: this.dataToPrint[i].out8, |
| | | strp7: this.dataToPrint[i].out9, |
| | | strp8: this.dataToPrint[i].out12, |
| | | strp9: this.dataToPrint[i].out7, |
| | | strp10: user, |
| | | } |
| | | let printCmd = printTemplate3(_printData); |
| | | printCommands.push(printCmd); |
| | | } |
| | | this.bufferData = printCommands.join('\n'); |
| | | |
| | | console.log('条码生成成功,请求ID:', this.generateRequestId); |
| | | }).catch(error => { |
| | | // 网络错误时也要释放锁定 |
| | | clearTimeout(timeoutId); |
| | | this.isGeneratingBarcode = false; |
| | | this.generateRequestId = null; |
| | | |
| | | console.error('条码生成失败:', error); |
| | | this.$showMessage('网络异常,条码生成失败,请重试'); |
| | | }); |
| | | }, |
| | | onPrint() { |
| | | |
| | | this.printBarcode(); |
| | | }, |
| | | |
| | | onPrintSuccess() { |
| | | this.getOrderById(); |
| | | this.findByOrderId(); |
| | | // this.updateBarcodeAmount(); |
| | | this.getWomdaaPrintById(); |
| | | |
| | | // 清空打印数据 |
| | | this.bufferData = ''; |
| | | this.dataToPrint = []; |
| | | |
| | | // 清空报工人数据 |
| | | this.staffNo = null; |
| | | this.user = ''; |
| | | |
| | | // 重置防重复状态(打印成功后完全重置) |
| | | this.isGeneratingBarcode = false; |
| | | this.generateRequestId = null; |
| | | |
| | | console.log("打印成功,已重置防重复状态"); |
| | | }, |
| | | onPrintFail() { |
| | | console.log("重连失败"); |
| | | this.printLoading = false; |
| | | |
| | | // 重置防重复状态(打印失败后也要重置) |
| | | this.isGeneratingBarcode = false; |
| | | this.generateRequestId = null; |
| | | |
| | | console.log("打印失败,已重置防重复状态"); |
| | | }, |
| | | |
| | | updateBarcodeAmount() { |
| | | if (this.dataToPrint.length == 0) { |
| | | return; |
| | | } |
| | | |
| | | let barcodes = this.dataToPrint.map(s => s.out12); |
| | | |
| | | this.$post({ |
| | | url: "/MesInvItemBarcodes/UpdateBarcodeAmount", |
| | | data: { |
| | | barcodes: barcodes, |
| | | user: this.staffNo |
| | | } |
| | | }).then(res => { |
| | | console.log("更新条码数量成功"); |
| | | }) |
| | | }, |
| | | |
| | | deleteBarcode() { |
| | | |
| | | // 关闭弹窗 |
| | | this.isShow = false; |
| | | |
| | | // 取消打印时完全重置防重复状态 |
| | | this.isGeneratingBarcode = false; |
| | | this.generateRequestId = null; |
| | | |
| | | // 清空打印数据 |
| | | this.bufferData = ''; |
| | | this.dataToPrint = []; |
| | | |
| | | // 清空报工人相关数据 |
| | | this.staffNo = null; |
| | | this.user = ''; |
| | | |
| | | // 重置打印条码数据 |
| | | this.barcodeAmount = ''; |
| | | this.icount = 1; |
| | | |
| | | // 清空staff数据 |
| | | this.staff = null; |
| | | |
| | | console.log("已清空报工人和打印数据,重置防重复状态"); |
| | | |
| | | if (this.dataToPrint.length == 0) { |
| | | return; |
| | | } |
| | | |
| | | |
| | | |
| | | // let barcodes = this.dataToPrint.map(s => s.out12); |
| | | // this.$post({ |
| | | // url: "/MesInvItemBarcodes/DeleteBarcode", |
| | | // data: { |
| | | // barcodes: barcodes, |
| | | // } |
| | | // }).then(res => { |
| | | // console.log("删除条码成功"); |
| | | // }) |
| | | }, |
| | | cleanUser() { |
| | | this.isShow = false; |
| | | |
| | | this.printLoading = false; |
| | | |
| | | // 打印结束后重置生成状态,允许下次生成 |
| | | this.isGeneratingBarcode = false; |
| | | this.generateRequestId = null; |
| | | |
| | | console.log("打印结束,已重置生成状态"); |
| | | }, |
| | | // 保存操作 |
| | | save() { |
| | | console.log('保存成功'); |
| | | let ids = []; |
| | | |
| | | this.selectedReasons.forEach(s => { |
| | | let id = this.itemsNgname[this.badReasons.indexOf(s)].id; |
| | | ids.push(id); |
| | | }); |
| | | |
| | | if (ids.length <= 0) { |
| | | return |
| | | } |
| | | |
| | | let ngids = ids.join(","); |
| | | |
| | | //MesOrderSta |
| | | this.$post({ |
| | | url: "/MesOrderSta/UpdateNg", |
| | | data: { |
| | | ngId: ngids, |
| | | staId: this.ngStaid |
| | | } |
| | | }).then(res => { |
| | | if (res.data.tbBillList) { |
| | | uni.showToast({ |
| | | title: '保存成功', |
| | | icon: 'success', |
| | | this.$post({ url: "/Womdaa/GetWomdaasByShow", data: { machineNo: this.machineNo } }) |
| | | .then(res => { |
| | | this.lineList = res.data.tbBillList; |
| | | this.DAA003List = res.data.tbBillList.map(i => i.daa003); |
| | | }); |
| | | this.getOrderById(); |
| | | this.getWomdaaPrintById(); |
| | | this.findByOrderId(); |
| | | } |
| | | }); |
| | | |
| | | }, |
| | | // 取消操作 |
| | | cancel() { |
| | | console.log('取消操作'); |
| | | uni.showToast({ |
| | | title: '取消操作', |
| | | icon: 'none', |
| | | }); |
| | | }, |
| | | getOrderById() { |
| | | this.$post({ |
| | | url: "/Womdaa/GetWomdaaById", |
| | | data: { |
| | | orderId: this.orderId, |
| | | orderNo: this.orderNo |
| | | } |
| | | }).then(res => { |
| | | this.order = res.data.tbBillList; |
| | | this.printedCount = res.data.tbBillList.bgqty; |
| | | this.defectiveCount = res.data.tbBillList.blQty; |
| | | this.productionCount = this.order.todayOutput; |
| | | |
| | | if (!this.order.todayOutput) { |
| | | this.productionCount = 0; |
| | | } |
| | | |
| | | if (!this.defectiveCount) { |
| | | this.defectiveCount = 0; |
| | | } |
| | | |
| | | if (!this.printedCount) { |
| | | this.printedCount = 0; |
| | | } |
| | | |
| | | //this.defectiveCount = this.productionCount - this.sQuantity; |
| | | }) |
| | | }, |
| | | getMesItemsNgname() { |
| | | this.$post({ |
| | | url: "/MesItemsNgname/GetMesItemsNgname", |
| | | }).then(res => { |
| | | this.itemsNgname = res.data.tbBillList; |
| | | this.badReasons = this.itemsNgname.map(s => s.ngName); |
| | | }); |
| | | }, |
| | | getXS0101() { |
| | | this.$post({ |
| | | url: "/MesStaff/GetAllXS0101", |
| | | }).then(res => { |
| | | this.staff = res.data.tbBillList; |
| | | this.users = this.staff.map(s => s.staffNo + ":" + s.staffName); |
| | | }); |
| | | }, |
| | | getWomdaaPrintById() { |
| | | // 添加错误处理和数据校验 |
| | | try { |
| | | this.$post({ |
| | | url: "/Womdaa/GetWomdaaPrintById", |
| | | data: { |
| | | orderId: this.orderId |
| | | } |
| | | }).then(res => { |
| | | // 检查响应数据是否存在且格式正确 |
| | | if (!res || !res.data || !res.data.tbBillList) { |
| | | console.error('获取打印数据失败: 响应数据格式错误'); |
| | | return; |
| | | } |
| | | |
| | | const data = res.data.tbBillList; |
| | | |
| | | // 直接赋值bqty,不使用默认值 |
| | | this.bqty = data.bqty; |
| | | this.icount = 1; // 固定为1 |
| | | this.sQuantity = data.sQuantity || 0; |
| | | this.initialValue = data.initialValue || 0; |
| | | this.kgQty = data.kgQty || 0; |
| | | this.barcodeAmount = data.qqty || 0; |
| | | |
| | | // 只有当bqty不为null且不为undefined且等于0时才执行Completed |
| | | if (this.bqty !== null && this.bqty !== undefined && this.bqty === 0) { |
| | | console.log('数量为0,执行完成操作'); |
| | | this.Completed(); |
| | | } |
| | | |
| | | }).catch(err => { |
| | | console.error('获取打印数据失败:', err); |
| | | }); |
| | | } catch (error) { |
| | | console.error('执行getWomdaaPrintById时发生错误:', error); |
| | | } |
| | | }, |
| | | Completed() { |
| | | this.$post({ |
| | | url: "/MesOrderSta/Completed", |
| | | data: { |
| | | orderId: this.orderId, |
| | | orderNo: this.orderNo |
| | | } |
| | | }).then(res1 => { |
| | | |
| | | }) |
| | | }, |
| | | findByOrderId() { |
| | | this.$post({ |
| | | url: "/MesOrderSta/FindByOrderNo", |
| | | data: { |
| | | orderId: this.orderId, |
| | | orderNo: this.orderNo |
| | | } |
| | | }).then(res => { |
| | | |
| | | // 从接口获取的已选择原因 |
| | | let str = res.data.tbBillList.ngId; |
| | | |
| | | this.ngStaid = res.data.tbBillList.id; |
| | | |
| | | if (!str) { |
| | | return; |
| | | } |
| | | |
| | | let ids = str.split(","); |
| | | |
| | | // 使用 map 和 filter 提取对应的 ngName |
| | | let preSelectedReasons = ids.map(id => { |
| | | // 查找对应的对象 |
| | | let matchedItem = this.itemsNgname.find(item => item.id == id); |
| | | return matchedItem ? matchedItem.ngName : null; // 如果找到,返回 ngName;否则返回 null |
| | | }).filter(ngName => ngName !== null); // 过滤掉 null 值 |
| | | |
| | | // 设置已选中的不良原因 |
| | | this.selectedReasons = this.badReasons.filter(reason => preSelectedReasons.includes(reason)); |
| | | }); |
| | | toggleUser(u) { |
| | | if (!u) return; |
| | | this.user = this.user === u ? null : u; |
| | | this.staffNo = this.user; |
| | | }, |
| | | confirmCustomAmount() { |
| | | // 检查输入是否为有效数字 |
| | | if (!this.customAmount || isNaN(Number(this.customAmount))) { |
| | | this.$showMessage('请输入有效的数量'); |
| | | return; |
| | | } |
| | | |
| | | // 将自定义数量应用到系统中 |
| | | let amount = Number(this.customAmount); |
| | | console.log('应用自定义数量:', amount); |
| | | |
| | | // 这里可以根据需要调用API或更新相关数据 |
| | | if (!this.customAmount || isNaN(Number(this.customAmount))) { this.$showMessage('请输入有效的数量'); return; } |
| | | const amount = Number(this.customAmount); |
| | | this.$post({ |
| | | url: "/MesInvItemBarcodes/AddBFToBarcodes", |
| | | data: { |
| | | orderNo: this.orderNo, |
| | | orderId: this.orderId, |
| | | bf: amount |
| | | } |
| | | data: { orderNo: this.orderNo, orderId: this.orderId, bf: amount } |
| | | }).then(res => { |
| | | if (res.status == 1) { |
| | | this.$showMessage(res.message); |
| | | return; |
| | | } |
| | | if (res.status == 1) { this.$showMessage(res.message); return; } |
| | | this.$showMessage('报废数量填写成功'); |
| | | // 重新获取数据以更新显示 |
| | | this.fetchData(true); |
| | | // 清空输入框 |
| | | this.customAmount = ''; |
| | | }).catch(err => { |
| | | console.error('报废数量填写失败:', err); |
| | | this.$showMessage('报废数量填写失败,请重试'); |
| | | }); |
| | | }).catch(() => this.$showMessage('报废数量填写失败,请重试')); |
| | | }, |
| | | save() { |
| | | if (!this.staffNo) { this.$showMessage('请选择报工人'); return; } |
| | | uni.showToast({ title: '保存成功', icon: 'success' }); |
| | | }, |
| | | cancel() { uni.showToast({ title: '取消操作', icon: 'none' }); }, |
| | | getOrderById() { |
| | | this.$post({ url: "/Womdaa/GetWomdaaById", data: { orderId: this.orderId, orderNo: this.orderNo } }) |
| | | .then(res => { |
| | | this.order = res.data.tbBillList; |
| | | this.printedCount = res.data.tbBillList.bgqty || 0; |
| | | this.defectiveCount = res.data.tbBillList.blQty || 0; |
| | | this.productionCount = this.order.todayOutput || 0; |
| | | }); |
| | | }, |
| | | getXS0101() { |
| | | this.$post({ url: "/MesStaff/GetAllXS0101" }) |
| | | .then(res => { |
| | | this.staff = res.data.tbBillList; |
| | | this.users = this.staff.map(s => s.staffNo + ":" + s.staffName); |
| | | }); |
| | | }, |
| | | getWomdaaPrintById() { |
| | | this.$post({ url: "/Womdaa/GetWomdaaPrintById", data: { orderId: this.orderId } }) |
| | | .then(res => { |
| | | if (!res?.data?.tbBillList) return; |
| | | const d = res.data.tbBillList; |
| | | this.bqty = d.bqty; |
| | | this.icount = 1; |
| | | this.sQuantity = d.sQuantity || 0; |
| | | this.initialValue = d.initialValue || 0; |
| | | this.kgQty = d.kgQty || 0; |
| | | this.barcodeAmount = d.qqty || 0; |
| | | if (this.bqty === 0) this.Completed(); |
| | | }).catch(() => { }); |
| | | }, |
| | | Completed() { |
| | | this.$post({ url: "/MesOrderSta/Completed", data: { orderId: this.orderId, orderNo: this.orderNo } }); |
| | | }, |
| | | init() { |
| | | try { |
| | | const v = this.getAndroidVersion(); |
| | | v >= 12 ? this.initForAndroid12Plus() : this.initForAndroidLegacy(); |
| | | } catch (e) { console.error(e); } |
| | | }, |
| | | getAndroidVersion() { |
| | | try { var Build = plus.android.importClass("android.os.Build"); return Build.VERSION.SDK_INT; } |
| | | catch { return 30; } |
| | | }, |
| | | initForAndroid12Plus() { |
| | | try { |
| | | var main = plus.android.runtimeMainActivity(); |
| | | var BluetoothManager = plus.android.importClass("android.bluetooth.BluetoothManager"); |
| | | var Context = plus.android.importClass("android.content.Context"); |
| | | var UUID = plus.android.importClass("java.util.UUID"); |
| | | this.uuid = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB"); |
| | | var mgr = main.getSystemService(Context.BLUETOOTH_SERVICE); |
| | | var adp = mgr.getAdapter(); |
| | | if (adp && adp.isDiscovering()) adp.cancelDiscovery(); |
| | | this.printMac = uni.getStorageSync('printMac'); |
| | | var mac = this.printMac || "DC:1D:30:91:06:52"; |
| | | if (adp) { |
| | | this.device = adp.getRemoteDevice(mac); |
| | | plus.android.importClass(this.device); |
| | | } |
| | | } catch (e) { this.initForAndroidLegacy(); } |
| | | }, |
| | | initForAndroidLegacy() { |
| | | try { |
| | | var BluetoothAdapter = plus.android.importClass("android.bluetooth.BluetoothAdapter"); |
| | | var UUID = plus.android.importClass("java.util.UUID"); |
| | | this.uuid = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB"); |
| | | var BAdapter = BluetoothAdapter.getDefaultAdapter(); |
| | | if (BAdapter) BAdapter.cancelDiscovery(); |
| | | this.printMac = uni.getStorageSync('printMac'); |
| | | var mac = this.printMac || "DC:1D:30:91:06:52"; |
| | | if (BAdapter) { |
| | | this.device = BAdapter.getRemoteDevice(mac); |
| | | plus.android.importClass(this.device); |
| | | this.bluetoothSocket = this.device.createInsecureRfcommSocketToServiceRecord(this.uuid); |
| | | plus.android.importClass(this.bluetoothSocket); |
| | | } |
| | | } catch (e) { } |
| | | }, |
| | | deleteBarcode() { |
| | | this.isShow = false; |
| | | this.isGeneratingBarcode = false; |
| | | this.generateRequestId = null; |
| | | this.bufferData = ''; this.dataToPrint = []; |
| | | this.staffNo = null; this.user = ''; this.barcodeAmount = ''; this.icount = 1; this.staff = null; |
| | | } |
| | | } |
| | | }; |
| | | } |
| | | </script> |
| | | |
| | | <style scoped> |
| | | /* 页面样式 */ |
| | | .page { |
| | | padding: 2vh; |
| | | padding: 1.2vh 2vw; |
| | | display: flex; |
| | | flex-direction: column; |
| | | justify-content: space-between; |
| | | box-sizing: border-box; |
| | | } |
| | | |
| | | .top-right { |
| | | position: absolute; |
| | | top: -25px; |
| | | right: 50px; |
| | | z-index: 1000; |
| | | .wide-layout { |
| | | max-width: 1600px; |
| | | margin: 0 auto; |
| | | } |
| | | |
| | | .refresh-btn { |
| | | /* padding: 10px; */ |
| | | float: right; |
| | | background-color: #00A2E9; |
| | | color: white; |
| | | border: none; |
| | | font-size: 32px; |
| | | border-radius: 15px; |
| | | margin-top: -23px; |
| | | padding-left: 25px; |
| | | padding-right: 25px; |
| | | margin-top: -32px; |
| | | margin-bottom: 49px; |
| | | .page.has-overlay .status-section > :not(.overlay) { |
| | | pointer-events: none; |
| | | } |
| | | |
| | | /* 状态行样式 */ |
| | | .page.has-overlay .status-section > .overlay { |
| | | pointer-events: auto; |
| | | } |
| | | |
| | | .report-table-wrapper { |
| | | margin-bottom: 12px; |
| | | } |
| | | |
| | | .table-scroll { |
| | | overflow-x: auto; |
| | | } |
| | | |
| | | .report-title { |
| | | font-size: 24px; |
| | | font-weight: 600; |
| | | text-align: center; |
| | | margin: 0 0 8px; |
| | | } |
| | | |
| | | .report-table { |
| | | min-width: 1080px; |
| | | width: 100%; |
| | | border-collapse: collapse; |
| | | font-size: 14px; |
| | | background: #fff; |
| | | } |
| | | |
| | | .report-table th, .report-table td { |
| | | border: 1px solid #555; |
| | | padding: 6px 8px; |
| | | text-align: center; |
| | | white-space: nowrap; |
| | | } |
| | | |
| | | .status-section { |
| | | display: flex; |
| | | flex-direction: column; |
| | | margin-bottom: 3vh; |
| | | padding-top: 14px; |
| | | gap: 10px; |
| | | } |
| | | |
| | | .status-row { |
| | | display: flex; |
| | | justify-content: space-around; |
| | | margin-bottom: 20px; |
| | | flex-wrap: wrap; |
| | | align-items: center; |
| | | gap: 10px; |
| | | background: #f9f9f9; |
| | | padding: 10px 14px; |
| | | border-radius: 8px; |
| | | box-shadow: 0 1px 4px rgba(0,0,0,.06); |
| | | } |
| | | |
| | | .status-box { |
| | |
| | | align-items: center; |
| | | } |
| | | |
| | | .refresh-container { |
| | | display: flex; |
| | | flex-direction: column; |
| | | align-items: flex-end; |
| | | .result-box { |
| | | background: #f0f8ff; |
| | | padding: 4px 12px; |
| | | border-radius: 6px; |
| | | border-left: 5px solid #007aff; |
| | | } |
| | | |
| | | input.highlight { |
| | | width: 10vw; |
| | | font-weight: 700; |
| | | width: 9vw; |
| | | min-width: 110px; |
| | | font-weight: 600; |
| | | border: none; |
| | | background-color: #FFD700; |
| | | background: #fff; |
| | | text-align: center; |
| | | font-size: 1.5vw; |
| | | font-size: 18px; |
| | | padding: 6px 0; |
| | | border-radius: 6px; |
| | | box-shadow: inset 0 1px 3px rgba(0,0,0,.12); |
| | | } |
| | | |
| | | .form-row { |
| | | .operator-box { |
| | | display: flex; |
| | | justify-content: space-between; |
| | | margin-bottom: 3vh; |
| | | flex-wrap: nowrap; |
| | | justify-content: center; |
| | | align-items: center; |
| | | font-size: 28px; |
| | | font-weight: bold; |
| | | color: #007aff; |
| | | margin: 0 6px; |
| | | } |
| | | |
| | | .form-item { |
| | | width: 30%; |
| | | .btn-group { |
| | | margin-left: auto; |
| | | display: flex; |
| | | align-items: center; |
| | | gap: 12px; |
| | | } |
| | | |
| | | .refresh-btn-inline, .reset-btn-inline { |
| | | transition: .15s; |
| | | } |
| | | |
| | | .refresh-btn-inline { |
| | | background: #00A2E9; |
| | | color: #fff; |
| | | border: none; |
| | | font-size: 18px; |
| | | border-radius: 10px; |
| | | padding: 8px 30px; |
| | | } |
| | | |
| | | .refresh-btn-inline:hover { |
| | | background: #0086c0; |
| | | } |
| | | |
| | | .reset-btn-inline { |
| | | background: #ff6b6b; |
| | | color: #fff; |
| | | border: none; |
| | | font-size: 16px; |
| | | border-radius: 10px; |
| | | padding: 8px 18px; |
| | | } |
| | | |
| | | .reset-btn-inline:hover { |
| | | background: #e94d4d; |
| | | } |
| | | |
| | | .flex-row { |
| | | display: flex; |
| | | flex-wrap: wrap; |
| | | gap: 20px; |
| | | align-items: flex-start; |
| | | } |
| | | |
| | | .flex-grow { |
| | | flex: 1 1 540px; |
| | | } |
| | | |
| | | .gap-lg { |
| | | gap: 30px; |
| | | } |
| | | |
| | | .print-section { |
| | | |
| | | padding: 1vh; |
| | | border-radius: 1vw; |
| | | margin-bottom: 2vh; |
| | | display: flex; |
| | | flex-wrap: wrap; |
| | | align-items: center; |
| | | flex-direction: row; |
| | | align-content: stretch; |
| | | justify-content: flex-start; |
| | | padding: 6px 0 14px; |
| | | margin-bottom: 0; |
| | | flex: 1; |
| | | } |
| | | |
| | | .barcode-info { |
| | | display: flex; |
| | | flex-wrap: wrap; |
| | | align-items: flex-start; |
| | | gap: 2vw; |
| | | flex-direction: row; |
| | | flex-wrap: nowrap; |
| | | align-content: flex-start; |
| | | justify-content: flex-start; |
| | | gap: 30px; |
| | | } |
| | | |
| | | .inp { |
| | | width: 65%; |
| | | padding: 1vh; |
| | | margin-top: -13px; |
| | | font-size: 1.3vw; |
| | | padding: 8px; |
| | | font-size: 16px; |
| | | border: 1px solid #808080; |
| | | border-radius: 0.5vw; |
| | | border-radius: 8px; |
| | | box-sizing: border-box; |
| | | } |
| | | |
| | | .barcode-info text { |
| | | font-size: 2.5vw |
| | | } |
| | | |
| | | input { |
| | | padding: 1vh; |
| | | font-size: 1.5vw; |
| | | width: 10vw; |
| | | border-radius: 0.5vw; |
| | | height: 2.4em; |
| | | } |
| | | |
| | | .print-btn { |
| | | display: inline-block; |
| | | padding: 1.5vh; |
| | | background-color: #e93c00eb; |
| | | color: white; |
| | | font-size: 1.5vw; |
| | | border: none; |
| | | cursor: pointer; |
| | | border-radius: 1vw; |
| | | margin-left: 30px; |
| | | .bad-input { |
| | | width: 320px; |
| | | max-width: 100%; |
| | | height: 66px; |
| | | border: 3px solid #808080; |
| | | font-size: 34px; |
| | | text-align: center; |
| | | } |
| | | |
| | | .details-btn { |
| | | display: inline-block; |
| | | padding: 1.5vh; |
| | | background-color: #00a2e9; |
| | | color: white; |
| | | font-size: 1.5vw; |
| | | padding: 12px 34px; |
| | | background: #00a2e9; |
| | | color: #fff; |
| | | font-size: 20px; |
| | | border: none; |
| | | cursor: pointer; |
| | | border-radius: 1vw; |
| | | margin-left: 50px; |
| | | border-radius: 12px; |
| | | } |
| | | |
| | | /* 不良原因选择 */ |
| | | .reason-section { |
| | | margin-bottom: 3vh; |
| | | } |
| | | .details-btn:hover { |
| | | background: #008ac2; |
| | | } |
| | | |
| | | .reason-buttons { |
| | | display: grid; |
| | | grid-template-columns: repeat(5, 1fr); |
| | | gap: 1vw; |
| | | } |
| | | |
| | | .reason-btn { |
| | | padding: 0.5vh; |
| | | background-color: #808080; |
| | | color: white; |
| | | font-size: 1.3vw; |
| | | border: none; |
| | | border-radius: 0.5vw; |
| | | cursor: pointer; |
| | | } |
| | | |
| | | .reason-btn.selected { |
| | | background-color: #FFD700; |
| | | color: black; |
| | | } |
| | | |
| | | /* 底部保存和取消按钮 */ |
| | | .bottom-section { |
| | | .current-user-section { |
| | | display: flex; |
| | | justify-content: space-between; |
| | | margin-top: 2vh; |
| | | align-items: center; |
| | | font-size: 18px; |
| | | border: 1.5px solid #f00; |
| | | border-radius: 10px; |
| | | padding: 14px 22px; |
| | | background: #fff; |
| | | gap: 14px; |
| | | } |
| | | |
| | | .bottom-section1 { |
| | | display: flex; |
| | | justify-content: space-around; |
| | | margin-bottom: 2vh; |
| | | padding: 2vh 1vw; |
| | | .fill-width { |
| | | flex: 0 1 380px; |
| | | } |
| | | |
| | | .save-btn, |
| | | .cancel-btn { |
| | | width: 48%; |
| | | padding: 1.5vh; |
| | | background-color: #00A2E9; |
| | | color: white; |
| | | font-size: 1.5vw; |
| | | border: none; |
| | | text-align: center; |
| | | cursor: pointer; |
| | | border-radius: 0.5vw; |
| | | .current-user-name { |
| | | font-weight: bold; |
| | | font-size: 22px; |
| | | } |
| | | |
| | | .clean-btn { |
| | | width: 48%; |
| | | padding: 1.5vh; |
| | | color: white; |
| | | font-size: 1.5vw; |
| | | border: none; |
| | | text-align: center; |
| | | cursor: pointer; |
| | | border-radius: 0.5vw; |
| | | background-color: #007aff; |
| | | .select-user-btn { |
| | | padding: 6px 22px; |
| | | background: #eee; |
| | | border: 1px solid #aaa; |
| | | border-radius: 8px; |
| | | font-size: 16px; |
| | | } |
| | | |
| | | .user-select1 { |
| | | float: left; |
| | | display: inline-block; |
| | | margin-top: 17px; |
| | | } |
| | | |
| | | .user-select2 { |
| | | margin-top: 17px; |
| | | margin-left: -10px; |
| | | } |
| | | |
| | | .user-select { |
| | | /* margin-right: 2vw; */ |
| | | font-size: 1.5vw; |
| | | } |
| | | |
| | | .form-item label { |
| | | float: left; |
| | | margin-top: -5px; |
| | | font-size: 1.5vw; |
| | | /* Larger font for labels */ |
| | | display: inline-block; |
| | | margin-bottom: 0.5vh; |
| | | color: #333; |
| | | } |
| | | .select-user-btn:hover { |
| | | background: #ddd; |
| | | } |
| | | |
| | | .overlay { |
| | | position: fixed; |
| | |
| | | left: 0; |
| | | width: 100%; |
| | | height: 100%; |
| | | background-color: rgba(0, 0, 0, 0.5); |
| | | background: rgba(0,0,0,.45); |
| | | display: flex; |
| | | justify-content: center; |
| | | align-items: center; |
| | | z-index: 1000; |
| | | } |
| | | |
| | | .popup { |
| | | background-color: #fff; |
| | | background: #fff; |
| | | padding: 2vh; |
| | | border: 1px solid #ccc; |
| | | box-shadow: 0 0 10px rgba(0, 0, 0, 0.1); |
| | | width: 70vw; |
| | | box-shadow: 0 0 14px rgba(0,0,0,.12); |
| | | width: 72vw; |
| | | max-width: 1400px; |
| | | height: 70vh; |
| | | font-size: 1.6vw; |
| | | /* 设置弹框的最大高度 */ |
| | | font-size: 1.4vw; |
| | | max-height: 80vh; |
| | | /* 启用纵向滚动条 */ |
| | | overflow-y: auto; |
| | | /* 设置弹框的外观 */ |
| | | border-radius: 12px; |
| | | z-index: 1001; |
| | | } |
| | | |
| | | .user-select-popup { |
| | | width: 860px; |
| | | max-width: 80vw; |
| | | height: auto; |
| | | min-height: 480px; |
| | | padding: 0; |
| | | display: flex; |
| | | flex-direction: column; |
| | | } |
| | | /* 搜索条样式 */ |
| | | .user-search-bar { |
| | | display: flex; |
| | | align-items: center; |
| | | gap: 12px; |
| | | padding: 18px 32px 0 32px; |
| | | background: #fff; |
| | | flex-wrap: wrap; |
| | | } |
| | | |
| | | .user-search-input { |
| | | flex: 1 1 260px; |
| | | padding: 10px 14px; |
| | | font-size: 16px; |
| | | border: 1px solid #bbb; |
| | | border-radius: 8px; |
| | | /* Increased font size within popups */ |
| | | outline: none; |
| | | } |
| | | |
| | | .inp5 { |
| | | float: left; |
| | | margin-top: 0px; |
| | | width: 20%; |
| | | text-align: center; |
| | | font-size: 45px; |
| | | border: 0px; |
| | | border-radius: 1.5vw; |
| | | background-color: #e5d3a0; |
| | | .user-search-input:focus { |
| | | border-color: #007aff; |
| | | box-shadow: 0 0 0 2px rgba(0,122,255,.15); |
| | | } |
| | | |
| | | .user-search-clear { |
| | | padding: 10px 18px; |
| | | background: #ff9f43; |
| | | color: #fff; |
| | | border: none; |
| | | border-radius: 8px; |
| | | font-size: 14px; |
| | | cursor: pointer; |
| | | } |
| | | |
| | | .inp6 { |
| | | float: left; |
| | | width: 22%; |
| | | text-align: center; |
| | | font-size: 45px; |
| | | border: 0px; |
| | | border-radius: 1.5vw; |
| | | background-color: #e5d3a0; |
| | | display: inline-block; |
| | | .user-search-clear:hover { |
| | | background: #ff8920; |
| | | } |
| | | |
| | | .user-search-info { |
| | | font-size: 14px; |
| | | color: #555; |
| | | } |
| | | |
| | | .user-list-scroll { |
| | | flex: 1 1 auto; |
| | | overflow-y: auto; |
| | | padding: 24px 32px 0 32px; |
| | | } |
| | | |
| | | .user-list-grid { |
| | | display: grid; |
| | | grid-template-columns: repeat(auto-fill,minmax(150px,1fr)); |
| | | gap: 24px 24px; |
| | | } |
| | | |
| | | .user-list-btn { |
| | | display: flex; |
| | | flex-direction: column; |
| | | justify-content: center; |
| | | align-items: center; |
| | | gap: 6px; |
| | | padding: 16px 10px; |
| | | height: 120px; |
| | | font-size: 18px; |
| | | background: #00a2e9; |
| | | color: #fff; |
| | | border: none; |
| | | border-radius: 10px; |
| | | cursor: pointer; |
| | | box-sizing: border-box; |
| | | word-break: break-word; |
| | | } |
| | | |
| | | .user-list-btn .user-code { |
| | | font-weight: 600; |
| | | font-size: 18px; |
| | | } |
| | | |
| | | .user-list-btn .user-name { |
| | | font-size: 16px; |
| | | } |
| | | |
| | | .user-list-btn.selected { |
| | | background: #0072c9; |
| | | box-shadow: 0 0 0 3px rgba(255,255,255,.6) inset; |
| | | } |
| | | |
| | | .user-list-btn:hover { |
| | | background: #008ed0; |
| | | } |
| | | |
| | | .no-user-result { |
| | | padding: 40px 0; |
| | | text-align: center; |
| | | font-size: 18px; |
| | | color: #666; |
| | | } |
| | | |
| | | .user-popup-footer { |
| | | flex-shrink: 0; |
| | | padding: 22px 32px 32px 32px; |
| | | background: #fff; |
| | | text-align: center; |
| | | } |
| | | |
| | | .clean-btn { |
| | | width: 48%; |
| | | padding: 1.6vh; |
| | | color: #fff; |
| | | font-size: 1.4vw; |
| | | border: none; |
| | | text-align: center; |
| | | cursor: pointer; |
| | | border-radius: .6vw; |
| | | background: #007aff; |
| | | } |
| | | |
| | | .clean-btn.wide-btn { |
| | | width: 60%; |
| | | font-size: 20px; |
| | | } |
| | | |
| | | .clean-btn:hover { |
| | | background: #0062c9; |
| | | } |
| | | |
| | | .reason-section { |
| | | margin: 14px 0 18px; |
| | | } |
| | | |
| | | .reason-buttons { |
| | | display: grid; |
| | | grid-template-columns: repeat(5,1fr); |
| | | gap: 12px; |
| | | } |
| | | |
| | | .reason-btn { |
| | | padding: 10px 6px; |
| | | background: #808080; |
| | | color: #fff; |
| | | font-size: 14px; |
| | | border: none; |
| | | border-radius: 8px; |
| | | cursor: pointer; |
| | | } |
| | | |
| | | .reason-btn.selected { |
| | | background: #FFD700; |
| | | color: #000; |
| | | } |
| | | |
| | | .bottom-section { |
| | | display: flex; |
| | | justify-content: space-between; |
| | | margin-top: 16px; |
| | | gap: 16px; |
| | | } |
| | | |
| | | .save-btn, .cancel-btn { |
| | | flex: 1; |
| | | padding: 16px 0; |
| | | background: #00A2E9; |
| | | color: #fff; |
| | | font-size: 20px; |
| | | border: none; |
| | | border-radius: 10px; |
| | | } |
| | | |
| | | .save-btn:hover, .cancel-btn:hover { |
| | | background: #0086c0; |
| | | } |
| | | |
| | | .table1 { |
| | | width: 100%; |
| | | border-spacing: 3px; |
| | | } |
| | | |
| | | .table2 { |
| | | background-color: bisque; |
| | | @media (max-width:1400px) { |
| | | input.highlight { |
| | | font-size: 16px; |
| | | } |
| | | |
| | | } |
| | | .user-list-btn { |
| | | height: 110px; |
| | | font-size: 16px; |
| | | } |
| | | |
| | | .top-refresh-container { |
| | | display: flex; |
| | | justify-content: flex-end; |
| | | align-items: center; |
| | | margin-bottom: 15px; |
| | | } |
| | | |
| | | .version-info-top { |
| | | text-align: right; |
| | | font-size: 13px; |
| | | color: #000; |
| | | margin-right: 10px; |
| | | } |
| | | |
| | | .operator-box { |
| | | display: flex; |
| | | justify-content: center; |
| | | align-items: center; |
| | | font-size: 36px; |
| | | font-weight: bold; |
| | | margin: 0 10px; |
| | | color: #333; |
| | | } |
| | | |
| | | .header-container { |
| | | display: flex; |
| | | justify-content: space-between; |
| | | align-items: center; |
| | | margin-bottom: 20px; |
| | | padding: 10px 15px; |
| | | background-color: #f2f2f2; |
| | | border-radius: 10px; |
| | | box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1); |
| | | } |
| | | |
| | | .header-title { |
| | | font-size: 24px; |
| | | font-weight: bold; |
| | | color: #333; |
| | | } |
| | | |
| | | .header-right { |
| | | display: flex; |
| | | align-items: center; |
| | | } |
| | | |
| | | .top-refresh-container { |
| | | display: flex; |
| | | justify-content: flex-end; |
| | | align-items: center; |
| | | margin-bottom: 15px; |
| | | } |
| | | |
| | | .version-info-top { |
| | | text-align: right; |
| | | font-size: 13px; |
| | | color: #666; |
| | | margin-right: 10px; |
| | | } |
| | | |
| | | .status-row { |
| | | display: flex; |
| | | justify-content: flex-start; |
| | | align-items: center; |
| | | margin-bottom: 20px; |
| | | background-color: #f9f9f9; |
| | | padding: 15px; |
| | | border-radius: 8px; |
| | | box-shadow: 0 1px 3px rgba(0, 0, 0, 0.05); |
| | | } |
| | | |
| | | .status-box { |
| | | display: flex; |
| | | align-items: center; |
| | | padding: 0 10px; |
| | | } |
| | | |
| | | .result-box { |
| | | background-color: #f0f8ff; |
| | | padding: 5px 15px; |
| | | border-radius: 6px; |
| | | border-left: 4px solid #007aff; |
| | | } |
| | | |
| | | input.highlight { |
| | | width: 10vw; |
| | | font-weight: 700; |
| | | border: none; |
| | | background-color: #fff; |
| | | text-align: center; |
| | | font-size: 1.5vw; |
| | | padding: 8px; |
| | | border-radius: 4px; |
| | | box-shadow: inset 0 1px 3px rgba(0, 0, 0, 0.1); |
| | | } |
| | | |
| | | .operator-box { |
| | | display: flex; |
| | | justify-content: center; |
| | | align-items: center; |
| | | font-size: 36px; |
| | | font-weight: bold; |
| | | margin: 0 15px; |
| | | color: #007aff; |
| | | width: 40px; |
| | | height: 40px; |
| | | line-height: 40px; |
| | | text-align: center; |
| | | } |
| | | |
| | | .refresh-btn { |
| | | background-color: #007aff; |
| | | color: white; |
| | | border: none; |
| | | font-size: 18px; |
| | | border-radius: 6px; |
| | | padding: 8px 20px; |
| | | transition: background-color 0.3s; |
| | | } |
| | | |
| | | .refresh-btn:active { |
| | | background-color: #0062cc; |
| | | } |
| | | |
| | | .reset-btn { |
| | | background-color: #ff6b6b; |
| | | color: white; |
| | | border: none; |
| | | font-size: 18px; |
| | | border-radius: 6px; |
| | | padding: 8px 15px; |
| | | margin-left: 10px; |
| | | transition: background-color 0.3s; |
| | | } |
| | | |
| | | .reset-btn:active { |
| | | background-color: #e55555; |
| | | } |
| | | |
| | | .non-calc-row { |
| | | border-top: 1px dashed #ccc; |
| | | margin-top: 30px; |
| | | padding-top: 20px; |
| | | position: relative; |
| | | } |
| | | |
| | | .divider-label { |
| | | position: absolute; |
| | | top: -12px; |
| | | left: 30px; |
| | | background-color: #fff; |
| | | padding: 0 15px; |
| | | font-size: 16px; |
| | | color: #777; |
| | | } |
| | | |
| | | .standalone-box { |
| | | background-color: #f5f5f5; |
| | | padding: 8px 15px; |
| | | border-radius: 6px; |
| | | margin-right: 20px; |
| | | } |
| | | |
| | | .confirm-row { |
| | | display: flex; |
| | | justify-content: space-between; |
| | | align-items: center; |
| | | margin-top: 10px; |
| | | } |
| | | |
| | | .input-group { |
| | | display: flex; |
| | | align-items: center; |
| | | } |
| | | |
| | | .custom-input { |
| | | width: 60%; |
| | | padding: 1vh; |
| | | font-size: 1.5vw; |
| | | border: 1px solid #808080; |
| | | border-radius: 0.5vw; |
| | | } |
| | | |
| | | .confirm-btn { |
| | | padding: 1.5vh; |
| | | background-color: #00A2E9; |
| | | color: white; |
| | | font-size: 1.5vw; |
| | | border: none; |
| | | cursor: pointer; |
| | | border-radius: 0.5vw; |
| | | } |
| | | |
| | | .custom-amount-section { |
| | | margin-top: 20px; |
| | | } |
| | | |
| | | .custom-amount-container { |
| | | display: flex; |
| | | align-items: center; |
| | | } |
| | | |
| | | .custom-amount-label { |
| | | margin-right: 10px; |
| | | font-size: 1.5vw; |
| | | } |
| | | |
| | | .custom-amount-input { |
| | | width: 60%; |
| | | padding: 1vh; |
| | | font-size: 1.5vw; |
| | | border: 1px solid #808080; |
| | | border-radius: 0.5vw; |
| | | } |
| | | |
| | | .custom-amount-row { |
| | | margin-top: 20px; |
| | | .reason-btn { |
| | | font-size: 12px; |
| | | } |
| | | } |
| | | </style> |