快乐的昕的电脑
2025-11-24 19d6d3e4e4d807237fff95bc08dae2a4c00fdced
components/WorkOrderPrint.vue
@@ -1,490 +1,561 @@
<template>
   <view class="page wide-layout" :class="{'has-overlay': (isShowUserSelect || isShow || barcodeIsShow)}">
      <view class="status-section">
         <!-- 报工记录表部分,在标题行添加刷新按钮 -->
         <view class="report-table-wrapper">
            <view class="report-header">
               <view class="report-title">报工记录表</view>
               <view class="header-buttons">
                  <button class="refresh-btn-header" @click="refresh">刷新</button>
                  <button v-if="isGeneratingBarcode" class="reset-btn-header" @click="resetGenerateState">重置</button>
               </view>
            </view>
    <view class="page wide-layout" :class="{'has-overlay': (isShowUserSelect || isShow || barcodeIsShow)}">
        <view class="status-section">
            <!-- 报工记录表部分,在标题行添加刷新按钮 -->
            <view class="report-table-wrapper">
                <view class="report-header">
                    <view class="report-title">报工记录表</view>
                    <view class="header-buttons">
                        <button class="refresh-btn-header" @click="refresh">刷新</button>
                        <button v-if="isGeneratingBarcode" class="reset-btn-header" @click="resetGenerateState">重置</button>
                    </view>
                </view>
            <!-- 数采总产量 -->
            <view class="section-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 class="summary-row highlight-row">
                        <td>{{ nowTime }}</td>
                        <td>{{ staffDisplay || '-' }}</td>
                        <td>{{ orderNo || '-' }}</td>
                        <td>{{ order.daa003 || '-' }}</td>
                        <td>{{ planQtyDisplay }}</td>
                        <td>{{ machineNo || '-' }}</td>
                        <td>{{ order.initCjNum }}</td>
                        <td>{{ order.currentCjNum }}</td>
                        <td>{{ order.currentCjNum - order.initCjNum }}</td>
                        <td>{{ realTimeDefectiveCount }}</td>
                        <td>{{ realTimeOkCount }}</td>
                     </tr>
                  </tbody>
               </table>
            </div>
                <!-- 数采总产量 -->
                <view class="section-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>
                                <th>良品数(计算)</th>
                                <th>报工类型</th> <!-- 新增 -->
                            </tr>
                        </thead>
                        <tbody>
                            <tr class="summary-row highlight-row">
                                <td>{{ nowTime }}</td>
                                <td>{{ staffDisplay || '-' }}</td>
                                <td>{{ orderNo || '-' }}</td>
                                <td>{{ order.daa003 || '-' }}</td>
                                <td>{{ planQtyDisplay }}</td><!--计划生产数-->
                                <td>{{ order.daa008 - order.daa011 }}</td> <!-- 新增:未报工数量 -->
                                <td>{{ machineNo || '-' }}</td>
                                <td>{{ order.initCjNum }}</td>
                                <td>{{ order.currentCjNum }}</td>
                                <td>{{ order.currentCjNum - order.initCjNum }}</td>
                                <td>{{ realTimeDefectiveCount }}</td>
                                <td>{{ realTimeOkCount }}</td>
                                <td>
                                    {{ order.daa018 === '开工' ? '生产报工' : '调机报工' }}
                                </td>
                            </tr>
                        </tbody>
                    </table>
                </div>
            <!-- 历史报工记录 -->
            <view class="section-title history-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 v-for="(r, idx) in reportingHistory" :key="idx">
                        <td>{{ r.bgDate }}</td>
                        <td>{{ r.staff || '-' }}</td>
                        <td>{{ r.orderNo || '-' }}</td>
                        <td>{{ order.daa003 || '-' }}</td>
                        <td>{{ planQtyDisplay }}</td>
                        <td>{{ r.machineNo || '-' }}</td>
                        <td>{{ r.initialValue }}</td>
                        <td>{{ r.productionCount }}</td>
                        <td>{{ r.totalProduction }}</td>
                        <td>{{ r.BfQty }}</td>
                        <td>{{ r.OkQty }}</td>
                     </tr>
                     <tr v-if="!reportingHistory.length">
                        <td colspan="11" class="no-data">暂无历史报工记录</td>
                     </tr>
                  </tbody>
               </table>
            </div>
         </view>
                <!-- 历史报工记录 -->
                <view class="section-title history-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>
                                <th>报工类型</th> <!-- 新增 -->
                            </tr>
                        </thead>
                        <tbody>
                            <tr v-for="(r, idx) in reportingHistory" :key="idx">
                                <td>{{ r.bgDate }}</td>
                                <td>{{ r.staff || '-' }}</td>
                                <td>{{ r.orderNo || '-' }}</td>
                                <td>{{ order.daa003 || '-' }}</td>
                                <td>{{ planQtyDisplay }}</td>
                                <td>{{ r.machineNo || '-' }}</td>
                                <td>{{ r.initialValue }}</td>
                                <td>{{ r.productionCount }}</td>
                                <td>{{ r.totalProduction }}</td>
                                <td>{{ r.BfQty }}</td>
                                <td>{{ r.OkQty }}</td>
                                <td>{{ r.reportType || '-' }}</td> <!-- 新增 -->
                            </tr>
                            <tr v-if="!reportingHistory.length">
                                <td colspan="12" class="no-data">暂无历史报工记录</td>
                            </tr>
                        </tbody>
                    </table>
                </div>
            </view>
         <!-- 移除了原来的状态行中的按钮组 -->
         <view class="status-row">
            <!--<view class="status-box">
               <text>机台面板数:</text>
               <input v-model="productionCount" class="highlight" disabled />
            </view>
            <view class="status-box">
               <text>当前采集数:</text>
               <input v-model="calculatedCurrentCount" class="highlight" disabled />
            </view>
            <view class="operator-box">-</view>
            <view class="status-box standalone-box">
               <text>已打印条码数:</text>
               <input v-model="sQuantity" class="highlight" disabled />
            </view>
            <view class="operator-box">=</view>
            <view class="status-box">
               <text>机采不良数:</text>
               <input v-model="calculatedDefectiveCount" class="highlight" disabled />
            </view>
            <view class="status-box result-box">
               <text>已生产数:</text>
               <input v-model="calculatedTotalProduction" class="highlight" disabled />
            </view>-->
         </view>
            <!-- 移除了原来的状态行中的按钮组 -->
            <view class="status-row">
                <!--<view class="status-box">
                    <text>机台面板数:</text>
                    <input v-model="productionCount" class="highlight" disabled />
                </view>
                <view class="status-box">
                    <text>当前采集数:</text>
                    <input v-model="calculatedCurrentCount" class="highlight" disabled />
                </view>
                <view class="operator-box">-</view>
                <view class="status-box standalone-box">
                    <text>已打印条码数:</text>
                    <input v-model="sQuantity" class="highlight" disabled />
                </view>
                <view class="operator-box">=</view>
                <view class="status-box">
                    <text>机采不良数:</text>
                    <input v-model="calculatedDefectiveCount" class="highlight" disabled />
                </view>
                <view class="status-box result-box">
                    <text>已生产数:</text>
                    <input v-model="calculatedTotalProduction" class="highlight" disabled />
                </view>-->
            </view>
         <view class="flex-row gap-lg">
            <!-- 当前报工人部分 -->
            <view class="current-user-section">
               <text>当前报工人:</text>
               <text class="current-user-name">{{ staffDisplay || '未选择' }}</text>
               <button class="select-user-btn" @click="isShowUserSelect = true">选人</button>
            </view>
            <view class="flex-row gap-lg">
                <!-- 当前报工人部分 -->
                <view class="current-user-section">
                    <text>当前报工人:</text>
                    <text class="current-user-name">{{ staffDisplay || '未选择' }}</text>
                    <button class="select-user-btn" @click="isShowUserSelect = true">选人</button>
                </view>
            <!-- 不良数量部分 -->
            <view class="defective-section">
               <text>不良数量:</text>
               <input v-model="customAmount" class="inp bad-input" placeholder="请输入数量" />
            </view>
                <!-- 不良数量部分 -->
                <view class="defective-section">
                    <text>不良数量:</text>
                    <input v-model="customAmount" class="inp bad-input" placeholder="请输入数量" />
                </view>
            <!-- 确认提交按钮 -->
            <view class="submit-section">
               <button class="details-btn" @click="confirmCustomAmount">确认提交</button>
            </view>
         </view>
                <!-- 确认提交和调机报工按钮 -->
                <view class="submit-section">
                    <button class="details-btn" @click="confirmCustomAmount">确认提交</button>
                    <button class="details-btn" @click="confirmTiaojiBaogong">调机报工</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>
               <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>
               <view class="user-popup-footer">
                  <button class="clean-btn wide-btn" @click="isShowUserSelect = false">关闭</button>
               </view>
            </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>
                    <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>
                    <view class="user-popup-footer">
                        <button class="clean-btn wide-btn" @click="isShowUserSelect = false">关闭</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="bottom-section1">
                  <button class="clean-btn" type="warn" @click="deleteBarcode">关闭</button>
               </view>
               <view class="reason-section">
                  <text>报工人:</text>
                  <view class="reason-buttons">
                     <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 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="bottom-section1">
                        <button class="clean-btn" type="warn" @click="deleteBarcode">关闭</button>
                    </view>
                    <view class="reason-section">
                        <text>报工人:</text>
                        <view class="reason-buttons">
                            <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">
               <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-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>
               </uni-table>
               <view><button class="clean-btn" type="warn" @click="barcodeIsShow=false">关闭</button></view>
            </view>
         </view>
      </view>
   </view>
            <view v-if="barcodeIsShow" class="overlay">
                <view class="popup">
                    <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-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>
                    </uni-table>
                    <view><button class="clean-btn" type="warn" @click="barcodeIsShow=false">关闭</button></view>
                </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 },
      data() {
         return {
            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: '',
            /* 新增:历史报工记录数组 */
            reportingHistory: []
         }
      },
      computed: {
         //良品数实时计算
         realTimeDefectiveCount() {
            // 优先用输入框的值,否则用接口数据
            const val = Number(this.customAmount);
            if (!isNaN(val) && this.customAmount !== '') return val;
            return this.calculatedDefectiveCount;
         },
         realTimeOkCount() {
            // 良品数 = 报工数(计算) - 不良数
            const total = (this.order.currentCjNum || 0) - (this.order.initCjNum || 0);
            return total - this.realTimeDefectiveCount;
         },
         calculatedCurrentCount() { return (this.productionCount || 0) - (this.initialValue || 0); },
         calculatedTotalProduction() { return (this.kgQty || 0); }, // 若需恢复旧逻辑可用 (this.kgQty||0)+this.calculatedCurrentCount
         calculatedDefectiveCount() { return this.calculatedTotalProduction - (this.sQuantity || 0); },
         planQtyDisplay() { return this.order.planQty || this.order.planQuantity || this.order.daa008 || 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();
         // 秒级刷新;如不需动态跳秒可改为 60000
         this.nowTimeTimer = setInterval(this.updateNowTime, 1000);
      },
      beforeDestroy() { if (this.nowTimeTimer) clearInterval(this.nowTimeTimer); },
      methods: {
         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())}:${p(d.getSeconds())}`;
         },
         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;
            this.$showMessage("已重置条码生成状态");
         },
         refresh() {
            this.$sendPostRequest({
               url: "http://192.168.0.94:9095/Numerical/RefreshDevBycl",
               data: { machineNo: this.order.machineNo },
               contentType: "application/json"
            }).then(r => { r.code == 200 ? this.fetchData(true) : this.$showMessage("同步失败"); });
         },
         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);
            this.fetchData(false);
         },
         fetchData(flag) {
            if (!this.orderId && !this.orderNo) return;
            this.getOrderById();
            this.getWomdaaPrintById();
            this.getReportingHistory(); // 新增:每次刷新同步历史
            if (flag) {
               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);
                  });
            }
         },
         /* 新增:获取历史报工记录 */
         /* 修改:规范历史时间到秒 */
         getReportingHistory() {
            if (!this.orderNo) { this.reportingHistory = []; return; }
            const fmtSec = v => {
               if (!v) return '';
               // 兼容后端可能返回的不同格式
               const d = new Date(typeof v === 'string' ? v.replace(/-/g, '/') : v);
               if (isNaN(d.getTime())) return v; // 无法解析则原样返回
               const p = n => n.toString().padStart(2, '0');
               return `${d.getFullYear()}-${p(d.getMonth() + 1)}-${p(d.getDate())} ${p(d.getHours())}:${p(d.getMinutes())}:${p(d.getSeconds())}`;
            };
            this.$post({
               url: "/Womdaa/GetByBillNoBG",
               data: { billNo: this.orderNo, machineNo: this.machineNo || null }
            }).then(res => {
               const list = res?.data?.tbBillList || res?.data || [];
               this.reportingHistory = list.map(r => {
                  // 依据你数据库字段做映射(下面字段名按常见命名举例,需要按实际改)
                  return {
                     bgDate: r.bgDate || '', // 报工时间
                     staff: (r.staffNo ? (r.staffNo + ' ' + (r.staffName || '')) : (r.staffName || '')),//报工人
                     orderNo: r.billNo,//工单号
                     machineNo: r.machineNo,//机台号
                     initialValue: r.csQty ?? 0,//初始采集数
                     productionCount: r.cjQty ?? 0,//报工时采集数
                     totalProduction: (r.cjQty - r.csQty) ?? 0,//报工数(计算)
                     BfQty: r.bfQty,//不良数
                     OkQty: r.okQty//良品数(计算)
                  }
               });
            }).catch(() => { this.reportingHistory = []; });
         },
         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; }
            if (!this.staffNo) { this.$showMessage('请选择报工人'); return; }
            const staffNo = this.staffNo.split(':')[0];
            const amount = Number(this.customAmount);
            this.$post({
               url: "/MesInvItemBarcodes/AddBFToBarcodes",
               data: {
                  orderNo: this.orderNo,
                  orderId: this.orderId,
                  bf: amount,
                  staffNo: staffNo,
                  initCjNum: this.order.initCjNum,        // 初始采集数
                  currentCjNum: this.order.currentCjNum   // 报工时采集数
               }
            }).then(res => {
               if (res.status == 1) { this.$showMessage(res.message); return; }
               this.$showMessage('报废数量填写成功');
               this.fetchData(true); // 自动刷新历史
               this.customAmount = '';
            }).catch(() => this.$showMessage('报废数量填写失败,请重试'));
         },
         save() {
            if (!this.staffNo) { this.$showMessage('请选择报工人'); return; }
            uni.showToast({ title: '保存成功', icon: 'success' });
            this.getReportingHistory(); // 保存后也可刷新
         },
         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;
         }
      }
   }
    export default {
        props: { orderNo: String, orderId: Number, machineNo: String },
        data() {
            return {
                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: '',
                refreshTimer: null, // 新增:自动刷新定时器
                /* 新增:历史报工记录数组 */
                reportingHistory: []
            }
        },
        computed: {
            //良品数实时计算
            realTimeDefectiveCount() {
                // 优先用输入框的值,否则用接口数据
                const val = Number(this.customAmount);
                if (!isNaN(val) && this.customAmount !== '') return val;
                return this.calculatedDefectiveCount;
            },
            realTimeOkCount() {
                // 良品数 = 报工数(计算) - 不良数
                const total = (this.order.currentCjNum || 0) - (this.order.initCjNum || 0);
                return total - this.realTimeDefectiveCount;
            },
            calculatedCurrentCount() { return (this.productionCount || 0) - (this.initialValue || 0); },
            calculatedTotalProduction() { return (this.kgQty || 0); }, // 若需恢复旧逻辑可用 (this.kgQty||0)+this.calculatedCurrentCount
            calculatedDefectiveCount() { return this.calculatedTotalProduction - (this.sQuantity || 0); },
            planQtyDisplay() { return this.order.planQty || this.order.planQuantity || this.order.daa008 || 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();
            // 秒级刷新;如不需动态跳秒可改为 60000
            this.nowTimeTimer = setInterval(this.updateNowTime, 1000);
            // 新增:每分钟自动刷新数据(60000毫秒 = 1分钟)
            this.startAutoRefresh();
        },
        beforeDestroy() {
            if (this.nowTimeTimer) clearInterval(this.nowTimeTimer);
            // 新增:清理自动刷新定时器
            this.stopAutoRefresh();
        },
        methods: {
            // 新增:开始自动刷新
            startAutoRefresh() {
                // 先清除可能存在的旧定时器
                this.stopAutoRefresh();
                // 设置新的定时器,每分钟执行一次
                this.refreshTimer = setInterval(() => {
                    console.log('自动刷新数据...');
                    this.refresh();
                }, 60000); // 60000毫秒 = 1分钟
            },
            // 新增:停止自动刷新
            stopAutoRefresh() {
                if (this.refreshTimer) {
                    clearInterval(this.refreshTimer);
                    this.refreshTimer = 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())}:${p(d.getSeconds())}`;
            },
            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;
                this.$showMessage("已重置条码生成状态");
            },
            // 修改:在手动刷新时也重置自动刷新计时器
            refresh() {
                this.$sendPostRequest({
                    url: "http://192.168.0.94:9095/Numerical/RefreshDevBycl",
                    data: { machineNo: this.order.machineNo },
                    contentType: "application/json"
                }).then(r => {
                    if (r.code == 200) {
                        this.fetchData(true);
                        this.$showMessage("数据刷新成功");
                    } else {
                        this.$showMessage("同步失败");
                    }
                }).catch(error => {
                    console.error('刷新失败:', error);
                    this.$showMessage("刷新失败,请检查网络连接");
                });
            },
            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);
                this.fetchData(false);
            },
            fetchData(flag) {
                if (!this.orderId && !this.orderNo) return;
                this.getOrderById();
                this.getWomdaaPrintById();
                this.getReportingHistory(); // 新增:每次刷新同步历史
                if (flag) {
                    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);
                        });
                }
            },
            /* 新增:获取历史报工记录 */
            /* 修改:规范历史时间到秒 */
            getReportingHistory() {
                if (!this.orderNo) { this.reportingHistory = []; return; }
                const fmtSec = v => {
                    if (!v) return '';
                    // 兼容后端可能返回的不同格式
                    const d = new Date(typeof v === 'string' ? v.replace(/-/g, '/') : v);
                    if (isNaN(d.getTime())) return v; // 无法解析则原样返回
                    const p = n => n.toString().padStart(2, '0');
                    return `${d.getFullYear()}-${p(d.getMonth() + 1)}-${p(d.getDate())} ${p(d.getHours())}:${p(d.getMinutes())}:${p(d.getSeconds())}`;
                };
                this.$post({
                    url: "/Womdaa/GetByBillNoBG",
                    data: { billNo: this.orderNo, machineNo: this.machineNo || null }
                }).then(res => {
                    const list = res?.data?.tbBillList || res?.data || [];
                    this.reportingHistory = list.map(r => {
                        // 依据你数据库字段做映射(下面字段名按常见命名举例,需要按实际改)
                        return {
                            bgDate: r.bgDate || '', // 报工时间
                            staff: (r.staffNo ? (r.staffNo + ' ' + (r.staffName || '')) : (r.staffName || '')),//报工人
                            orderNo: r.billNo,//工单号
                            machineNo: r.machineNo,//机台号
                            initialValue: r.csQty ?? 0,//初始采集数
                            productionCount: r.cjQty ?? 0,//报工时采集数
                            totalProduction: (r.cjQty - r.csQty) ?? 0,//报工数(计算)
                            BfQty: r.bfQty,//不良数
                            OkQty: r.okQty,//良品数(计算)
                            reportType:r.remark //报工类型
                        }
                    });
                }).catch(() => { this.reportingHistory = []; });
            },
            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; }
                if (!this.staffNo) { this.$showMessage('请选择报工人'); return; }
                const staffNo = this.staffNo.split(':')[0];
                const amount = Number(this.customAmount);
                this.$post({
                    url: "/MesInvItemBarcodes/AddBFToBarcodes",
                    data: {
                        orderNo: this.orderNo,
                        orderId: this.orderId,
                        bf: amount,
                        staffNo: staffNo,
                        initCjNum: this.order.initCjNum,        // 初始采集数
                        currentCjNum: this.order.currentCjNum   // 报工时采集数
                    }
                }).then(res => {
                    if (res.status == 1) { this.$showMessage(res.message); return; }
                    this.$showMessage('报废数量填写成功');
                    this.fetchData(true); // 自动刷新历史
                    this.customAmount = '';
                }).catch(() => this.$showMessage('报废数量填写失败,请重试'));
            },
            // 新增:调机报工
            confirmTiaojiBaogong() {
                if (!this.customAmount || isNaN(Number(this.customAmount))) { this.$showMessage('请输入有效的数量'); return; }
                if (!this.staffNo) { this.$showMessage('请选择报工人'); return; }
                const staffNo = this.staffNo.split(':')[0];
                const amount = Number(this.customAmount);
                this.$post({
                    url: "/MesInvItemBarcodes/AddBFToBarcodes", // 如有调机专用接口请替换
                    data: {
                        orderNo: this.orderNo,
                        orderId: this.orderId,
                        bf: amount,
                        staffNo: staffNo,
                        initCjNum: this.order.initCjNum,
                        currentCjNum: this.order.currentCjNum,
                        type: 'tiaoji' // 可加区分字段,后端如需区分调机报工
                    }
                }).then(res => {
                    if (res.status == 1) { this.$showMessage(res.message); return; }
                    this.$showMessage('调机报工成功');
                    this.fetchData(true);
                    this.customAmount = '';
                }).catch(() => this.$showMessage('调机报工失败,请重试'));
            },
            save() {
                if (!this.staffNo) { this.$showMessage('请选择报工人'); return; }
                uni.showToast({ title: '保存成功', icon: 'success' });
                this.getReportingHistory(); // 保存后也可刷新
            },
            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>
@@ -639,7 +710,8 @@
            border: 1px solid #555;
            padding: 6px 8px;
            text-align: center;
            white-space: nowrap;
            white-space: normal; /*允许换行*/
            word-break: break-all; /*长单词 /数字也换行*/
        }
    .status-section {
@@ -751,7 +823,8 @@
        display: flex;
        align-items: center;
        gap: 14px;
        font-size: 32px;
        font-size: 36px; /* 从32px改为36px */
        font-weight: bold; /* 可选:加粗字体 */
    }
    .submit-section {
@@ -811,17 +884,18 @@
    /* 选人按钮 - 蓝色主题 */
    .select-user-btn {
        background: #007aff; /* 改为蓝色背景 */
        background: #00a2e9; /* 与提交按钮相同的蓝色 */
        color: #fff; /* 白色文字 */
        padding: 6px 22px;
        background: #eee;
        border: 1px solid #aaa;
        border-radius: 8px;
        font-size: 32px;
        border: none; /* 移除边框 */
        padding: 12px 22px; /* 调整内边距与提交按钮协调 */
        border-radius: 12px; /* 与提交按钮相同的圆角 */
        font-size: 32px; /* 保持字体大小 */
        cursor: pointer;
        transition: background 0.15s; /* 添加过渡效果 */
    }
        .select-user-btn:hover {
            background: #ddd;
            background: #008ac2;
        }
    .overlay {