| | |
| | | <template> |
| | | <view class="inspection-sheet"> |
| | | <!-- 头部信息 --> |
| | | <view class="sheet-header"> |
| | | <h1>来料检验单</h1> |
| | | <view class="inspection-number">检验单号:{{formData.releaseNo}}</view> |
| | | <!--实验室送检 --> |
| | | <view style="text-align: right;" class="action-buttons"> |
| | | <a class="sysLike" v-if="this.current" @click="toSysSubmitFrom(formData.releaseNo)">实验室送检</a> |
| | | <!-- 头部信息 --> |
| | | <view class="sheet-header"> |
| | | <h1>来料检验单</h1> |
| | | <view class="inspection-number">检验单号:{{formData.releaseNo}}</view> |
| | | <!--实验室送检 --> |
| | | <view style="text-align: right;" class="action-buttons"> |
| | | <a class="sysLike" v-if="this.current" @click="toSysSubmitFrom(formData.releaseNo)">实验室送检</a> |
| | | </view> |
| | | </view> |
| | | </view> |
| | | |
| | | <!-- 基本信息区 --> |
| | | <view class="basic-info"> |
| | |
| | | <view class="info-label">不良描述:</view> |
| | | <view class="info-value">{{formData.fngDesc}}</view> |
| | | </view> |
| | | <view class="info-block" v-if="formData.newFngDesc!=null"> |
| | | <view class="info-label">上次不良:</view> |
| | | <view class="info-value">{{formData.newFngDesc}}</view> |
| | | </view> |
| | | </view> |
| | | <view class="dropdown-row"> |
| | | <view class="info-label">不良原因:</view> |
| | | <select id="defect-reason" v-model="badreason" v-if="current" @change="saveRemarksGid"> |
| | | <option value=""></option> |
| | | <option value="外观不良">外观不良</option> |
| | | <option value="尺寸不良">尺寸不良</option> |
| | | <option value="包装不良">包装不良</option> |
| | | <option value="性能不良">性能不良</option> |
| | | <option value="装配不良">装配不良</option> |
| | | <option value="安规不良">安规不良</option> |
| | | </select> |
| | | <picker v-if="current" :value="badreasonIndex" :range="badreasonOptions" @change="onBadreasonChange"> |
| | | <view class="picker-text" :class="{ 'selected': badreason }">{{ badreason || '' }}</view> |
| | | </picker> |
| | | <view v-else class="info-value">{{ badreason }}</view> |
| | | </view> |
| | | <view class="dropdown-row"> |
| | | <view class="info-label">所属车间:</view> |
| | | <select id="defect-reason" v-model="WORKSHOP" v-if="current" @change="saveRemarksGid"> |
| | | <option value=""></option> |
| | | <option value="生产一部">生产一部</option> |
| | | <option value="生产二部">生产二部</option> |
| | | <option value="注塑车间">注塑车间</option> |
| | | <option value="其他">其他</option> |
| | | </select> |
| | | <picker v-if="current" :value="workshopIndex" :range="workshopOptions" @change="onWorkshopChange"> |
| | | <view class="picker-text" :class="{ 'selected': WORKSHOP }">{{ WORKSHOP || '' }}</view> |
| | | </picker> |
| | | <view v-else class="info-value">{{ WORKSHOP }}</view> |
| | | </view> |
| | | <view class="dropdown-row"> |
| | | <view class="info-label">评审状态:</view> |
| | | <select id="defect-reason" v-model="PSTYPE" v-if="current" @change="saveRemarksGid"> |
| | | <option value=""></option> |
| | | <option value="特采/让步使用">特采/让步使用</option> |
| | | <option value="挑选/返工使用">挑选/返工使用</option> |
| | | <option value="退货">退货</option> |
| | | <option value="待判">待判</option> |
| | | </select> |
| | | <picker v-if="current" :value="pstypeIndex" :range="pstypeOptions" @change="onPstypeChange"> |
| | | <view class="picker-text" :class="{ 'selected': PSTYPE }">{{ PSTYPE || '' }}</view> |
| | | </picker> |
| | | <view v-else class="info-value">{{ PSTYPE }}</view> |
| | | </view> |
| | | <view class="info-block" style="margin-top: 10px;"> |
| | | <view class="info-label">备注:</view> |
| | | <input type="text" id="lotNo1" v-model="formData.lotNo1" |
| | | placeholder="请输入备注信息" |
| | | style="color: red; font-weight: bold;"/> |
| | | style="color: red; font-weight: bold; background-color: #fff !important; -webkit-user-select: text !important; -moz-user-select: text !important; -ms-user-select: text !important; user-select: text !important; pointer-events: auto !important; opacity: 1 !important; z-index: 1 !important;"/> |
| | | </view> |
| | | <view class="info-block" style="margin-top: 10px;"> |
| | | <view class="info-label">破坏实验数量:</view> |
| | | <view class="info-value highlight">{{formData.phsy}}</view> |
| | | <view class="info-value highlight">{{formData.PHSY || formData.phsy || ''}}</view> |
| | | </view> |
| | | |
| | | <!-- 表单上方操作按钮区 --> |
| | | <view class="top-action-buttons"> |
| | | <button class="action-btn" @click="getInspectionItems" v-if="this.current">获取检验项目</button> |
| | | <button class="action-btn" @click="openGlobalBlockHoleDialog" v-if="this.current">堵穴设置</button> |
| | | <button class="action-btn" @click="handleEmergencyRelease" v-if="this.current">紧急放行</button> |
| | | <button class="action-btn" @click="handleWithdraw" v-if="this.current">撤回</button> |
| | | </view> |
| | |
| | | <form> |
| | | <view class="form-group"> |
| | | <label class="form-label">不合格描述:</label> |
| | | <input class="form-input" type="text" v-model="remarks" /> |
| | | <input class="info-input" type="text" v-model="remarks" placeholder="请输入不合格描述" /> |
| | | </view> |
| | | |
| | | </form> |
| | |
| | | </view> |
| | | |
| | | <view v-if="destructionPopup" class="overlay"> |
| | | <view class="popup"> |
| | | <h3>破坏实验数量</h3> |
| | | <form> |
| | | <view class="form-group"> |
| | | <label class="form-label">破坏实验数量:</label> |
| | | <input class="form-input" type="text" v-model="PHSY" placeholder="留空表示清除数量" /> |
| | | <view class="popup destruction-popup"> |
| | | <h3>破坏实验</h3> |
| | | |
| | | <!-- 第一步:扫描二维码(无记录时显示) --> |
| | | <view v-if="!hasExistingRecord && !scannedMaterialInfo" class="scan-step"> |
| | | <view class="scan-icon">📷</view> |
| | | <view class="scan-title">扫描物料二维码</view> |
| | | <view class="scan-description">请扫描要用于破坏实验的物料条码</view> |
| | | <view class="scan-actions"> |
| | | <button class="scan-btn" @click="scanQRCode">开始扫描</button> |
| | | <button class="destruction-btn cancel-btn" @click="closeDestructionPopup">返回</button> |
| | | </view> |
| | | </form> |
| | | <div v-if="!isInteger" class="error-message">请输入整数值或留空</div> |
| | | <button class="updateBut" @click="editDestruction">修改</button> |
| | | <button @click="clearDestruction">清除</button> |
| | | <button @click="destructionPopup = !destructionPopup">取消</button> |
| | | </view> |
| | | |
| | | <!-- 第二步:显示扫描结果和输入数量(无记录时扫描后显示) --> |
| | | <view v-if="!hasExistingRecord && scannedMaterialInfo" class="result-step"> |
| | | <view class="scan-success-icon">✅</view> |
| | | <view class="scan-success-title">扫描成功</view> |
| | | |
| | | <!-- 显示扫描到的物料信息 --> |
| | | <view class="material-info-display"> |
| | | <view class="material-detail"> |
| | | <view class="detail-row"> |
| | | <span class="detail-label">扫描条码:</span> |
| | | <span class="detail-value barcode-value">{{ scannedMaterialInfo.itemBarcode || scannedMaterialInfo.itemNo }}</span> |
| | | </view> |
| | | <view class="detail-row"> |
| | | <span class="detail-label">物料编码:</span> |
| | | <span class="detail-value">{{ scannedMaterialInfo.itemNo }}</span> |
| | | </view> |
| | | <view class="detail-row"> |
| | | <span class="detail-label">物料名称:</span> |
| | | <span class="detail-value">{{ scannedMaterialInfo.itemName }}</span> |
| | | </view> |
| | | <view class="detail-row"> |
| | | <span class="detail-label">规格型号:</span> |
| | | <span class="detail-value">{{ scannedMaterialInfo.itemModel }}</span> |
| | | </view> |
| | | <view class="detail-row"> |
| | | <span class="detail-label">到货单号:</span> |
| | | <span class="detail-value">{{ scannedMaterialInfo.billNo }}</span> |
| | | </view> |
| | | <view class="detail-row"> |
| | | <span class="detail-label">可用数量:</span> |
| | | <span class="detail-value">{{ scannedMaterialInfo.oldQty }}</span> |
| | | </view> |
| | | </view> |
| | | </view> |
| | | |
| | | <!-- 重新设计的输入区域 --> |
| | | <view class="input-section"> |
| | | <view class="input-title">破坏实验数量</view> |
| | | <view class="input-container"> |
| | | <view class="input-box" @click="focusInput"> |
| | | <text v-if="destructionQuantity" class="input-value">{{ destructionQuantity }}</text> |
| | | <text v-else class="input-placeholder">点击输入数量</text> |
| | | </view> |
| | | </view> |
| | | <view v-if="!isInteger && destructionQuantity" class="error-tip">请输入有效的正整数</view> |
| | | </view> |
| | | |
| | | <!-- 操作按钮 --> |
| | | <view class="destruction-actions"> |
| | | <!-- 无记录时显示:确认、修改、删除、返回 --> |
| | | <template v-if="!hasExistingRecord"> |
| | | <button class="destruction-btn confirm-btn" @click="confirmDestruction" :disabled="!isInteger || !destructionQuantity">确认</button> |
| | | <button class="destruction-btn modify-btn" @click="modifyDestruction">修改</button> |
| | | <button class="destruction-btn delete-btn" @click="deleteDestruction">删除</button> |
| | | <button class="destruction-btn cancel-btn" @click="resetDestruction">返回</button> |
| | | </template> |
| | | <!-- 有记录时显示:修改、删除、返回 --> |
| | | <template v-else> |
| | | <button class="destruction-btn modify-btn" @click="modifyDestruction">修改</button> |
| | | <button class="destruction-btn delete-btn" @click="deleteDestruction">删除</button> |
| | | <button class="destruction-btn cancel-btn" @click="resetDestruction">返回</button> |
| | | </template> |
| | | </view> |
| | | </view> |
| | | |
| | | <!-- 第三步:显示已有记录信息(有记录时显示,复用扫描结果界面) --> |
| | | <view v-if="hasExistingRecord" class="result-step"> |
| | | <view class="scan-success-icon">✅</view> |
| | | <view class="scan-success-title">扫描成功</view> |
| | | |
| | | <!-- 显示扫描到的物料信息 --> |
| | | <view class="material-info-display"> |
| | | <view class="material-detail"> |
| | | <view class="detail-row"> |
| | | <span class="detail-label">扫描条码:</span> |
| | | <span class="detail-value barcode-value">{{ (scannedMaterialInfo && scannedMaterialInfo.itemBarcode) || (scannedMaterialInfo && scannedMaterialInfo.itemNo) || '' }}</span> |
| | | </view> |
| | | <view class="detail-row"> |
| | | <span class="detail-label">物料编码:</span> |
| | | <span class="detail-value">{{ (scannedMaterialInfo && scannedMaterialInfo.itemNo) || '' }}</span> |
| | | </view> |
| | | <view class="detail-row"> |
| | | <span class="detail-label">物料名称:</span> |
| | | <span class="detail-value">{{ (scannedMaterialInfo && scannedMaterialInfo.itemName) || '' }}</span> |
| | | </view> |
| | | <view class="detail-row"> |
| | | <span class="detail-label">规格型号:</span> |
| | | <span class="detail-value">{{ (scannedMaterialInfo && scannedMaterialInfo.itemModel) || '' }}</span> |
| | | </view> |
| | | <view class="detail-row"> |
| | | <span class="detail-label">到货单号:</span> |
| | | <span class="detail-value">{{ (scannedMaterialInfo && scannedMaterialInfo.billNo) || formData.lotNo }}</span> |
| | | </view> |
| | | <view class="detail-row"> |
| | | <span class="detail-label">可用数量:</span> |
| | | <span class="detail-value">{{ (scannedMaterialInfo && scannedMaterialInfo.oldQty) || '0' }}</span> |
| | | </view> |
| | | </view> |
| | | </view> |
| | | |
| | | <!-- 重新设计的输入区域 --> |
| | | <view class="input-section"> |
| | | <view class="input-title">破坏实验数量</view> |
| | | <view class="input-container"> |
| | | <view class="input-box" @click="focusInput"> |
| | | <text v-if="destructionQuantity" class="input-value">{{ destructionQuantity }}</text> |
| | | <text v-else class="input-placeholder">点击输入数量</text> |
| | | </view> |
| | | </view> |
| | | <view v-if="!isInteger && destructionQuantity" class="error-tip">请输入有效的正整数</view> |
| | | </view> |
| | | |
| | | <!-- 操作按钮 --> |
| | | <view class="destruction-actions"> |
| | | <button class="destruction-btn modify-btn" @click="modifyDestruction">修改</button> |
| | | <button class="destruction-btn delete-btn" @click="deleteDestruction">删除</button> |
| | | <button class="destruction-btn cancel-btn" @click="resetDestruction">返回</button> |
| | | </view> |
| | | </view> |
| | | </view> |
| | | </view> |
| | | |
| | | <!-- 全局堵穴设置对话框 --> |
| | | <view v-if="globalBlockHolePopup" class="overlay"> |
| | | <view class="popup global-block-hole-popup"> |
| | | <h3>全局堵穴设置</h3> |
| | | <view class="block-hole-content"> |
| | | <view class="hole-info"> |
| | | <view class="info-label">检验单号:{{ formData.releaseNo }}</view> |
| | | <view class="info-label">将应用于所有有开穴数的检验项目</view> |
| | | </view> |
| | | <view class="input-section"> |
| | | <view class="input-label">堵穴数量:</view> |
| | | <input class="info-input" type="text" v-model="globalBlockHoleInput" |
| | | placeholder="请输入1,2,3" @input="onGlobalBlockHoleInput" /> |
| | | <view v-if="globalBlockHoleError" class="error-message">{{ globalBlockHoleError }}</view> |
| | | </view> |
| | | <view class="block-hole-actions"> |
| | | <button class="block-hole-btn confirm" @click="confirmGlobalBlockHole" |
| | | :disabled="!isGlobalBlockHoleValid">确认设置</button> |
| | | <button class="block-hole-btn cancel" @click="closeGlobalBlockHoleDialog">取消</button> |
| | | </view> |
| | | </view> |
| | | </view> |
| | | </view> |
| | | |
| | | <view class="barcode"> |
| | | <u-modal :show="itemShow" title="物料明细" @confirm="drawingConfirm" @cancel="drawingCancel" |
| | | showCancelButton :z-index="1000"> |
| | | <uni-table border stripe emptyText="暂无更多数据" style="margin-left: 5px;margin-right: 5px;height: 400px;max-height: 60vh;overflow-y: auto;"> |
| | | <uni-tr> |
| | | <uni-th align="center">料号</uni-th> |
| | | <uni-th align="center" width="90">名称</uni-th> |
| | | <uni-th align="center" width="90">规格型号</uni-th> |
| | | <uni-th align="center" width="150">调取PLM图纸</uni-th> |
| | | </uni-tr> |
| | | <uni-tr v-for="(item,index) in (drawing || [])" style="height: 100px;"> |
| | | <uni-td align="center">{{item.itemNo}}</uni-td> |
| | | <uni-td align="center" style="font-size:25px;"> |
| | | <div >{{item.itemName}}</div> |
| | | </uni-td> |
| | | <uni-td align="center" style="font-size:25px;"> |
| | | <div>{{item.itemModel}}</div> |
| | | </uni-td> |
| | | <uni-td align="center" class="click-wd"> |
| | | <div @click="fetchDrawingNumber">调取图纸</div> |
| | | </uni-td> |
| | | </uni-tr> |
| | | </uni-table> |
| | | </u-modal> |
| | | </view> |
| | | |
| | | <view class="barcode"> |
| | |
| | | <uni-th align="center" width="90">能否打开文件</uni-th> |
| | | <uni-th align="center" width="150">操作(点击)</uni-th> |
| | | </uni-tr> |
| | | <uni-tr v-for="(item,index) in drawing" style="height: 100px;"> |
| | | <uni-tr v-for="(item,index) in (drawing || [])" style="height: 100px;"> |
| | | <uni-td align="center">{{item.fName}}</uni-td> |
| | | <uni-td align="center" style="font-size:25px;"> |
| | | <div v-if="item.fRelevantObject==' '" style="color: #E47470;">×</div> |
| | |
| | | <!-- 附件详情弹窗 --> |
| | | <view v-if="showAttachmentDetail" class="overlay"> |
| | | <view class="popup attachment-detail-popup"> |
| | | <h3 class="attachment-popup-title">附件详情</h3> |
| | | <div class="attachment-popup-divider"></div> |
| | | <div v-if="selectedAttachment" class="attachment-detail-content"> |
| | | <div class="attachment-detail-row"><span class="attachment-label">ID:</span><span>{{ Math.trunc(selectedAttachment.id) }}</span></div> |
| | | <div class="attachment-detail-row"><span class="attachment-label">附件名:</span><span>{{ selectedAttachment.fattach }}</span></div> |
| | | <div class="attachment-detail-row"><span class="attachment-label">类型:</span><span>{{ selectedAttachment.ftype }}</span></div> |
| | | <div class="attachment-detail-row"><span class="attachment-label">版本:</span><span>{{ selectedAttachment.fversion }}</span></div> |
| | | <div class="attachment-detail-row"><span class="attachment-label">受控日期:</span><span>{{ selectedAttachment.fdate }}</span></div> |
| | | <div class="attachment-detail-row"><span class="attachment-label">上传人:</span><span>{{ selectedAttachment.createBy }}</span></div> |
| | | <div class="attachment-detail-row"><span class="attachment-label">上传时间:</span><span>{{ selectedAttachment.createDate }}</span></div> |
| | | <div class="attachment-actions-detail"> |
| | | <button class="attachment-action-btn preview-btn" |
| | | @click="previewFtpFile(selectedAttachment)" |
| | | v-if="isPreviewable(selectedAttachment.fattach)"> |
| | | 🔍 在线预览 |
| | | </button> |
| | | <button class="attachment-action-btn download-btn" |
| | | @click="downloadAttachment(selectedAttachment)"> |
| | | 📥 下载文件 |
| | | </button> |
| | | <div class="attachment-popup-header"> |
| | | <h3 class="attachment-popup-title">附件详情</h3> |
| | | <button class="attachment-close-btn" @click="closeAttachmentDetail">返回</button> |
| | | </div> |
| | | |
| | | <div class="attachment-popup-content"> |
| | | <div v-if="selectedAttachment" class="attachment-detail-content"> |
| | | <div class="attachment-detail-header"> |
| | | <div class="file-type-badge large" :class="getFileTypeClass(selectedAttachment.fattach)"> |
| | | {{ getFileTypeIcon(selectedAttachment.fattach) }} |
| | | </div> |
| | | <div class="attachment-detail-title"> |
| | | {{ selectedAttachment.fattach }} |
| | | </div> |
| | | </div> |
| | | |
| | | <div class="attachment-detail-info"> |
| | | <div class="info-row"> |
| | | <div class="info-item"> |
| | | <text class="info-label">ID</text> |
| | | <text class="info-content">{{ Math.trunc(selectedAttachment.id) }}</text> |
| | | </div> |
| | | <div class="info-item"> |
| | | <text class="info-label">类型</text> |
| | | <text class="info-content">{{ selectedAttachment.ftype || '未知类型' }}</text> |
| | | </div> |
| | | </div> |
| | | |
| | | <div class="info-row" v-if="selectedAttachment.fversion"> |
| | | <div class="info-item"> |
| | | <text class="info-label">版本</text> |
| | | <text class="info-content">{{ selectedAttachment.fversion }}</text> |
| | | </div> |
| | | <div class="info-item" v-if="selectedAttachment.fdate"> |
| | | <text class="info-label">受控日期</text> |
| | | <text class="info-content">{{ formatDate(selectedAttachment.fdate) }}</text> |
| | | </div> |
| | | </div> |
| | | |
| | | <div class="info-row" v-if="selectedAttachment.createBy"> |
| | | <div class="info-item"> |
| | | <text class="info-label">上传人</text> |
| | | <text class="info-content">{{ selectedAttachment.createBy }}</text> |
| | | </div> |
| | | <div class="info-item" v-if="selectedAttachment.createDate"> |
| | | <text class="info-label">上传时间</text> |
| | | <text class="info-content">{{ formatDate(selectedAttachment.createDate) }}</text> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | |
| | | <div class="attachment-detail-actions"> |
| | | <button v-if="isPreviewable(selectedAttachment.fattach)" |
| | | class="btn-primary" |
| | | @click="previewFtpFile(selectedAttachment)">预览</button> |
| | | <button class="btn-success" @click="downloadAttachment(selectedAttachment)">下载</button> |
| | | </div> |
| | | </div> |
| | | <div v-else class="attachment-detail-empty"> |
| | | <div class="empty-icon">❌</div> |
| | | <div class="empty-text">暂无附件信息</div> |
| | | </div> |
| | | </div> |
| | | <div v-else class="attachment-detail-empty">暂无附件信息</div> |
| | | <button class="attachment-popup-close" @click="closeAttachmentDetail">返回附件列表</button> |
| | | </view> |
| | | </view> |
| | | <!-- 附件列表弹窗 --> |
| | | <view v-if="showAttachmentPopup" class="overlay"> |
| | | <view class="popup" style="width: 60vw; max-width: 500px;"> |
| | | <h3>附件列表</h3> |
| | | <div v-if="attachmentsLoading">加载中...</div> |
| | | <div v-else-if="attachments.length === 0">暂无附件</div> |
| | | <ul class="attachment-list" v-else> |
| | | <li v-for="item in attachments" :key="item.id"> |
| | | <div class="attachment-info"> |
| | | <span class="attachment-name" @click="showAttachmentDetailDialog(item)"> |
| | | {{ item.fattach }} |
| | | </span> |
| | | <div class="attachment-meta"> |
| | | <span class="attachment-type">{{ item.ftype || '未知类型' }}</span> |
| | | <view class="popup attachment-list-popup"> |
| | | <div class="attachment-popup-header"> |
| | | <h3 class="attachment-popup-title">附件列表</h3> |
| | | <button class="attachment-close-btn" @click="closeAttachmentPopup">关闭</button> |
| | | </div> |
| | | |
| | | <div class="attachment-popup-content"> |
| | | <div v-if="attachmentsLoading" class="attachment-loading"> |
| | | <div class="loading-spinner"></div> |
| | | <span class="loading-text">正在加载附件...</span> |
| | | </div> |
| | | |
| | | <div v-else-if="attachments.length === 0" class="attachment-empty"> |
| | | <div class="empty-icon">📁</div> |
| | | <div class="empty-text">暂无附件</div> |
| | | <div class="empty-hint">该物料暂未上传任何附件</div> |
| | | </div> |
| | | |
| | | <div v-else class="attachment-list"> |
| | | <div v-for="item in attachments" :key="item.id" class="attachment-item"> |
| | | <div class="attachment-info"> |
| | | <div class="file-type-badge" :class="getFileTypeClass(item.fattach)"> |
| | | {{ getFileTypeIcon(item.fattach) }} |
| | | </div> |
| | | <div class="attachment-details"> |
| | | <div class="attachment-name" @click="showAttachmentDetailDialog(item)"> |
| | | {{ item.fattach }} |
| | | </div> |
| | | <div class="attachment-meta"> |
| | | <span class="meta-type">{{ item.ftype || '未知类型' }}</span> |
| | | <span v-if="item.fversion" class="meta-version">v{{ item.fversion }}</span> |
| | | <span v-if="item.fdate" class="meta-date">{{ formatDate(item.fdate) }}</span> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | |
| | | <div class="attachment-actions"> |
| | | <button class="btn-secondary" @click="showAttachmentDetailDialog(item)">详情</button> |
| | | <button v-if="isPreviewable(item.fattach)" |
| | | class="btn-primary" |
| | | @click="previewFtpFile(item)">预览</button> |
| | | <button class="btn-success" @click="downloadAttachment(item)">下载</button> |
| | | </div> |
| | | </div> |
| | | <div class="attachment-actions"> |
| | | <button class="secondary-btn" @click="showAttachmentDetailDialog(item)">详情</button> |
| | | <button class="secondary-btn preview-btn" @click="previewFtpFile(item)" |
| | | v-if="isPreviewable(item.fattach)">预览</button> |
| | | <button class="secondary-btn" @click="downloadAttachment(item)">下载</button> |
| | | </div> |
| | | </li> |
| | | </ul> |
| | | <button class="attachment-popup-close" @click="closeAttachmentPopup">关闭</button> |
| | | </div> |
| | | </div> |
| | | </view> |
| | | </view> |
| | | |
| | |
| | | |
| | | <!-- 图片内容预览 --> |
| | | <view v-else-if="previewType === 'image'" class="image-preview-container"> |
| | | <image :src="previewContent" mode="widthFix" style="width: 100%; max-height: 400px;"></image> |
| | | <image |
| | | :src="previewContent" |
| | | mode="aspectFit" |
| | | class="preview-image-clickable" |
| | | @click="previewImageInPopup" |
| | | style="width: 100%; max-height: 400px; cursor: pointer;" |
| | | /> |
| | | <div class="image-zoom-hint">点击图片可放大查看</div> |
| | | </view> |
| | | |
| | | <!-- Excel 等 Office 文件提示 --> |
| | |
| | | current: true, |
| | | drawing: [], |
| | | drawingShow: false, |
| | | itemShow: false, |
| | | badreason: '', |
| | | PSTYPE: '', |
| | | WORKSHOP: '', |
| | | REMARK: '', |
| | | // picker 选项和索引 |
| | | badreasonOptions: ['', '外观不良', '尺寸不良', '包装不良', '性能不良', '装配不良', '安规不良','图纸不良'], |
| | | badreasonIndex: 0, |
| | | workshopOptions: ['', '生产一部', '生产二部', '注塑车间', '其他'], |
| | | workshopIndex: 0, |
| | | pstypeOptions: ['', '特采/让步使用', '挑选/返工使用', '退货', '待判'], |
| | | pstypeIndex: 0, |
| | | checkState: false, |
| | | writeStatu: true, |
| | | fileName:'', |
| | |
| | | destructionPopup: false, |
| | | PHSY: '', |
| | | isInteger: true, |
| | | scannedMaterialInfo: null, // 扫描到的物料信息 |
| | | destructionQuantity: '', // 破坏实验数量输入 |
| | | inputFocus: false, // 输入框焦点状态 |
| | | hasExistingRecord: false, // 是否有已存在的破坏实验记录 |
| | | attachments: [], |
| | | showAttachmentPopup: false, |
| | | attachmentsLoading: false, |
| | |
| | | previewItemNo: '', |
| | | previewType: '', // 'text', 'image', 'excel', 'unsupported' |
| | | |
| | | // 全局堵穴相关数据 |
| | | globalBlockHolePopup: false, |
| | | globalBlockHoleInput: '', |
| | | globalBlockHoleError: '', |
| | | isGlobalBlockHoleValid: false, |
| | | |
| | | } |
| | | }, |
| | | computed: { |
| | | isUnmaintainedAndNotEmergency() { |
| | | // 判断表单是否未维护且不是紧急放行 |
| | | // 未维护的条件:tableData为空或所有检验项目都未完成 |
| | | const isUnmaintained = this.tableData.length === 0 || |
| | | this.tableData.every(item => item.fcheckResu === null || item.fcheckResu === ''); |
| | | |
| | | // 不是紧急放行的条件:emergencyStatus为false |
| | | const isNotEmergency = !this.formData.emergencyStatus; |
| | | |
| | | return isUnmaintained && isNotEmergency; |
| | | } |
| | | }, |
| | | onLoad(options) { |
| | |
| | | addDefectDescription() { |
| | | // 添加不良描述的逻辑 |
| | | this.remarksPopup = !this.remarksPopup; |
| | | this.remarks = this.formData.remarks; |
| | | this.remarks = this.formData.remarks || this.remarks || ''; |
| | | console.log('打开弹窗时的remarks值:', this.remarks); |
| | | }, |
| | | |
| | | // picker 事件处理方法 |
| | | onBadreasonChange(e) { |
| | | const index = e.detail.value; |
| | | this.badreasonIndex = index; |
| | | this.badreason = this.badreasonOptions[index]; |
| | | this.saveRemarksGid('badreason'); |
| | | }, |
| | | onWorkshopChange(e) { |
| | | const index = e.detail.value; |
| | | this.workshopIndex = index; |
| | | this.WORKSHOP = this.workshopOptions[index]; |
| | | this.saveRemarksGid('WORKSHOP'); |
| | | }, |
| | | onPstypeChange(e) { |
| | | const index = e.detail.value; |
| | | this.pstypeIndex = index; |
| | | this.PSTYPE = this.pstypeOptions[index]; |
| | | this.saveRemarksGid('PSTYPE'); |
| | | }, |
| | | saveRemarksGid(fieldName) { |
| | | // 直接保存到数据库 |
| | | const requestData = { |
| | | gid: this.formData.id, |
| | | releaseNo: this.formData.releaseNo, |
| | | BLYY: this.badreason || '', |
| | | SSCJ: this.WORKSHOP || '', |
| | | PSZT: this.PSTYPE || '' |
| | | }; |
| | | console.log('发送的数据:', requestData); |
| | | console.log('badreason:', this.badreason); |
| | | console.log('WORKSHOP:', this.WORKSHOP); |
| | | console.log('PSTYPE:', this.PSTYPE); |
| | | console.log('选择的字段:', fieldName); |
| | | this.$post({ |
| | | url: "/LLJ/saveDropdownFields", |
| | | data: requestData |
| | | }).then(res => { |
| | | if (res && res.data && res.data.data && res.data.data.tbBillList && res.data.data.tbBillList.length > 0) { |
| | | // 延迟重新加载数据,确保数据库更新完成 |
| | | setTimeout(() => { |
| | | this.init(); |
| | | }, 500); |
| | | } |
| | | }).catch(err => { |
| | | console.error('保存失败:', err); |
| | | }); |
| | | }, |
| | | submitInspection() { |
| | | if (this.PSTYPE == '') { |
| | | this.writeStatu = false |
| | | } |
| | | if (this.badreason == '') { |
| | | this.writeStatu = false |
| | | } |
| | | if (this.DEPARTMENT == '') { |
| | | this.writeStatu = false |
| | | } |
| | | |
| | | // 重置验证状态 |
| | | this.writeStatu = true; |
| | | |
| | | // if (this.PSTYPE == '') { |
| | | // this.writeStatu = false |
| | | // } |
| | | // if (this.badreason == '') { |
| | | // this.writeStatu = false |
| | | // } |
| | | // 移除对未定义变量DEPARTMENT的检查 |
| | | // if (this.DEPARTMENT == '') { |
| | | // this.writeStatu = false |
| | | // } |
| | | |
| | | console.log(this.tableData) |
| | | this.checkState = false; |
| | |
| | | }) |
| | | if (this.checkState) { |
| | | |
| | | if (this.formData.fngDesc == '' || this.writeStatu == false) { |
| | | if (this.formData.fngDesc == '') { |
| | | uni.showToast({ |
| | | title: '未填写不良描述或不良原因或所属车间或评审状态', |
| | | title: '未填写不良描述', |
| | | icon: 'none' |
| | | }); |
| | | } else { |
| | |
| | | }).then(res => { |
| | | if (res.status == 0) { |
| | | |
| | | if(this.$loginInfo.account == 'PL017'){ |
| | | this.QcIssueResultDetailes = { |
| | | fbatchQty: this.formData.fbatchQty, |
| | | itemName: this.formData.itemName, |
| | | itemNo: this.formData.itemNo, |
| | | suppName: this.formData.suppName, |
| | | appicationReason: this.formData.fngDesc, |
| | | badReason: this.badreason, |
| | | remark: this.REMARK, |
| | | workShop: this.WORKSHOP, |
| | | releaseNo: this.formData.releaseNo, |
| | | staffNo: 'HMCS', |
| | | // staffNo: this.$loginInfo.account, |
| | | iqcStatus: this.PSTYPE, |
| | | department: this.DEPARTMENT, |
| | | EMERGENCY: this.formData.emergencyStatus ? "1" : "0" // 确保紧急放行状态正确传递 |
| | | }; |
| | | } |
| | | else{ |
| | | this.QcIssueResultDetailes = { |
| | | fbatchQty: this.formData.fbatchQty, |
| | | itemName: this.formData.itemName, |
| | | itemNo: this.formData.itemNo, |
| | | suppName: this.formData.suppName, |
| | | appicationReason: this.formData.fngDesc, |
| | | badReason: this.badreason, |
| | | remark: this.REMARK, |
| | | workShop: this.WORKSHOP, |
| | | releaseNo: this.formData.releaseNo, |
| | | // staffNo: 'HMCS', |
| | | staffNo: this.$loginInfo.account, |
| | | iqcStatus: this.PSTYPE, |
| | | department: this.DEPARTMENT, |
| | | EMERGENCY: this.formData.emergencyStatus ? "1" : "0" // 确保紧急放行状态正确传递 |
| | | }; |
| | | } |
| | | // 统一推送给HMCS,不管哪个账号 |
| | | this.QcIssueResultDetailes = { |
| | | fbatchQty: this.formData.fcovertQty, |
| | | itemName: (() => { |
| | | const combined = `${this.formData.itemName || ''} ${this.formData.itemModel || ''}`.trim(); |
| | | // 截断处理:超过1000字符保留前1000位 |
| | | return combined.length > 1000 ? combined.substring(0, 1000) : combined; |
| | | })(), |
| | | itemNo: this.formData.itemNo, |
| | | suppName: this.formData.suppName, |
| | | appicationReason: this.formData.fngDesc, |
| | | badReason: this.badreason, |
| | | remark: this.remarks || '', |
| | | workShop: this.WORKSHOP, |
| | | releaseNo: this.formData.releaseNo, |
| | | staffNo: 'HMCS', // 统一推送给HMCS |
| | | iqcStatus: this.PSTYPE, |
| | | department: this.WORKSHOP, // 使用WORKSHOP替代未定义的DEPARTMENT |
| | | EMERGENCY: this.formData.emergencyStatus ? "1" : "0" // 确保紧急放行状态正确传递 |
| | | }; |
| | | |
| | | console.log("提交的紧急放行状态:", this.formData.emergencyStatus ? "1" : "0"); |
| | | console.log("完整的提交数据:", this.QcIssueResultDetailes); |
| | |
| | | this.badreason = data.blyy || ''; |
| | | this.PSTYPE = data.pszt || ''; |
| | | this.WORKSHOP = data.sscj || ''; |
| | | console.log('赋值后', this.badreason, this.PSTYPE, this.WORKSHOP); |
| | | this.remarks = data.remarks || ''; // 设置remarks变量 |
| | | |
| | | // 确保PHSY字段被正确设置 |
| | | this.formData.PHSY = data.PHSY; |
| | | // 设置 picker 索引 |
| | | this.badreasonIndex = this.badreasonOptions.indexOf(this.badreason); |
| | | this.workshopIndex = this.workshopOptions.indexOf(this.WORKSHOP); |
| | | this.pstypeIndex = this.pstypeOptions.indexOf(this.PSTYPE); |
| | | |
| | | |
| | | // 确保PHSY字段被正确设置(兼容大小写) |
| | | this.formData.PHSY = data.PHSY || data.phsy; |
| | | this.PHSY = (data.PHSY || data.phsy || '').toString(); // 同时设置页面绑定的PHSY变量 |
| | | |
| | | console.log("加载的紧急放行状态:", this.formData.emergencyStatus); |
| | | this.$post({ |
| | |
| | | let tableData = res1.data.tbBillList |
| | | //当已检验个数都不为空时按照检测结构排序 |
| | | tableData.sort((a, b) => { |
| | | // 首先按Fstand排序:Fstand不为空的排在前面 |
| | | const aHasFstand = a.fstand !== null && a.fstand !== undefined; |
| | | const bHasFstand = b.fstand !== null && b.fstand !== undefined; |
| | | if (aHasFstand && !bHasFstand) { |
| | | return -1; |
| | | } else if (!aHasFstand && bHasFstand) { |
| | | return 1; |
| | | } |
| | | |
| | | // 然后按检验结果排序 |
| | | if (a.result === '合格' && b.result === '未完成') { |
| | | return -1; |
| | | } else if (a.result === '未完成' && b.result === '合格') { |
| | |
| | | url: 'SysSubmitFrom?releaseNo=' + releaseNo + '&userID=' + this.$loginInfo.account |
| | | }); |
| | | }, |
| | | editRemarks() { |
| | | // 保存不良描述 |
| | | this.$post({ |
| | | url: "/LLJ/saveRemarksGid", |
| | | data: { |
| | | gid: this.formData.id, |
| | | remarks: this.remarks || '', |
| | | releaseNo: this.formData.releaseNo |
| | | // 不再包含PHSY字段 |
| | | } |
| | | }).then(res => { |
| | | if (res.data.tbBillList > 0) { |
| | | this.formData.remarks = this.remarks; |
| | | this.remarksPopup = !this.remarksPopup; |
| | | this.$showMessage("保存成功"); |
| | | setTimeout(() => { |
| | | this.init(); |
| | | }, 2000); |
| | | } |
| | | }) |
| | | }, |
| | | |
| | | |
| | | drawingConfirm() { |
| | | this.drawingShow = false |
| | | this.imageShow = false |
| | | this.productionShow = false |
| | | this.itemShow=false |
| | | }, |
| | | drawingCancel() { |
| | | this.drawingShow = false |
| | | this.imageShow = false |
| | | this.productionShow = false |
| | | this.itemShow=false |
| | | }, |
| | | |
| | | fetchDrawingNumber() { |
| | |
| | | success: (response) => { |
| | | console.log(response) |
| | | if (response.data.data == '返回结果为空') { |
| | | _this.drawing = null |
| | | _this.drawing = [] |
| | | } else { |
| | | _this.drawing = response.data.data |
| | | // 遍历数据,判断文件后缀并添加字段 |
| | |
| | | }); |
| | | this.drawingShow = true |
| | | }, |
| | | |
| | | |
| | | |
| | | //图纸相关文档 |
| | | openDrawings(item) { |
| | |
| | | }); |
| | | }, |
| | | editRemarks() { |
| | | // 保存不良描述 |
| | | this.$post({ |
| | | url: "/LLJ/saveRemarksGid", |
| | | data: { |
| | | gid: this.formData.id, |
| | | remarks: this.remarks || '', |
| | | releaseNo: this.formData.releaseNo |
| | | // 不再包含PHSY字段 |
| | | } |
| | | }).then(res => { |
| | | if (res.data.tbBillList > 0) { |
| | | this.formData.remarks = this.remarks; |
| | | this.remarksPopup = !this.remarksPopup; |
| | | this.$showMessage("保存成功"); |
| | | // 立即重新加载数据确保同步 |
| | | setTimeout(() => { |
| | | this.init(); |
| | | }, 2000); |
| | | }, 500); |
| | | } |
| | | }).catch(err => { |
| | | console.error('保存失败:', err); |
| | | }) |
| | | }, |
| | | addDestruction() { |
| | | // 添加破坏实验的逻辑 |
| | | this.destructionPopup = !this.destructionPopup; |
| | | this.PHSY = this.formData.PHSY || ''; |
| | | this.destructionPopup = true; |
| | | |
| | | // 每次点击都查询是否已有破坏实验记录 |
| | | this.checkPhsyRecord(); |
| | | }, |
| | | |
| | | // 查询破坏实验记录是否存在 |
| | | checkPhsyRecord() { |
| | | uni.showLoading({ |
| | | title: '查询破坏实验记录...' |
| | | }); |
| | | |
| | | this.$post({ |
| | | url: "/LLJ/CheckPhsyRecord", |
| | | data: { |
| | | billNo: this.formData.lotNo, // 使用到货单号 |
| | | releaseNo: this.formData.releaseNo // 使用检验单号 |
| | | } |
| | | }).then(res => { |
| | | uni.hideLoading(); |
| | | if (res.status === 0) { |
| | | const hasRecord = res.data.exists; |
| | | if (hasRecord) { |
| | | // 有记录,显示物料信息,只显示修改、删除、返回按钮 |
| | | this.showExistingRecord(); |
| | | } else { |
| | | // 无记录,显示扫描界面 |
| | | this.showScanInterface(); |
| | | } |
| | | } else { |
| | | uni.showToast({ |
| | | title: res.message || '查询失败', |
| | | icon: 'none' |
| | | }); |
| | | this.destructionPopup = false; |
| | | } |
| | | }).catch(err => { |
| | | uni.hideLoading(); |
| | | console.error('查询破坏实验记录失败:', err); |
| | | uni.showToast({ |
| | | title: '查询失败,请重试', |
| | | icon: 'none' |
| | | }); |
| | | this.destructionPopup = false; |
| | | }); |
| | | }, |
| | | |
| | | // 显示已有记录 |
| | | showExistingRecord() { |
| | | // 设置已有记录状态 |
| | | this.hasExistingRecord = true; |
| | | // 获取破坏实验记录中的物料信息 |
| | | this.getPhsyRecordInfo(); |
| | | }, |
| | | |
| | | // 获取破坏实验记录信息 |
| | | getPhsyRecordInfo() { |
| | | uni.showLoading({ |
| | | title: '获取破坏实验记录...' |
| | | }); |
| | | |
| | | this.$post({ |
| | | url: "/LLJ/GetPhsyRecordInfo", |
| | | data: { |
| | | billNo: this.formData.lotNo, // 使用到货单号 |
| | | releaseNo: this.formData.releaseNo // 使用检验单号 |
| | | } |
| | | }).then(res => { |
| | | uni.hideLoading(); |
| | | if (res.status === 0 && res.data && res.data.tbBillList && res.data.tbBillList.length > 0) { |
| | | // 获取到破坏实验记录,设置物料信息 |
| | | const record = res.data.tbBillList[0]; |
| | | this.scannedMaterialInfo = { |
| | | itemBarcode: record.itemBarcode, |
| | | itemNo: record.itemNo, |
| | | itemName: record.itemName, |
| | | itemModel: record.itemModel, |
| | | billNo: record.billNo, |
| | | oldQty: record.yqty |
| | | }; |
| | | // 设置破坏实验数量 |
| | | this.destructionQuantity = record.cqty ? record.cqty.toString() : ''; |
| | | } else { |
| | | // 如果没有获取到详细信息,显示提示 |
| | | uni.showToast({ |
| | | title: '已存在破坏实验记录', |
| | | icon: 'none', |
| | | duration: 1500 |
| | | }); |
| | | } |
| | | }).catch(err => { |
| | | uni.hideLoading(); |
| | | console.error('获取破坏实验记录失败:', err); |
| | | uni.showToast({ |
| | | title: '获取记录失败,请重试', |
| | | icon: 'none' |
| | | }); |
| | | }); |
| | | }, |
| | | |
| | | // 显示扫描界面 |
| | | showScanInterface() { |
| | | // 设置无记录状态 |
| | | this.hasExistingRecord = false; |
| | | // 如果已经有扫描的物料信息,直接显示结果步骤 |
| | | if (this.scannedMaterialInfo) { |
| | | // 保持当前扫描信息,不重置 |
| | | return; |
| | | } |
| | | |
| | | // 如果没有扫描信息,重置所有相关数据 |
| | | this.scannedMaterialInfo = null; |
| | | this.destructionQuantity = ''; |
| | | this.isInteger = true; |
| | | }, |
| | | |
| | | // 扫描二维码 |
| | | scanQRCode() { |
| | | // #ifdef APP-PLUS |
| | | // APP环境使用uni.scanCode |
| | | uni.scanCode({ |
| | | success: (res) => { |
| | | console.log('扫描结果:', res.result); |
| | | this.processQRCodeResult(res.result); |
| | | }, |
| | | fail: (err) => { |
| | | console.error('扫描失败:', err); |
| | | uni.showToast({ |
| | | title: '扫描失败,请重试', |
| | | icon: 'none' |
| | | }); |
| | | } |
| | | }); |
| | | // #endif |
| | | |
| | | // #ifdef H5 |
| | | // H5环境提示用户手动输入 |
| | | uni.showModal({ |
| | | title: '二维码扫描', |
| | | content: 'H5环境暂不支持摄像头扫描,请输入二维码内容', |
| | | editable: true, |
| | | placeholderText: '请输入二维码内容', |
| | | success: (res) => { |
| | | if (res.confirm && res.content) { |
| | | this.processQRCodeResult(res.content); |
| | | } |
| | | } |
| | | }); |
| | | // #endif |
| | | |
| | | // #ifdef MP |
| | | // 小程序环境使用wx.scanCode |
| | | wx.scanCode({ |
| | | success: (res) => { |
| | | console.log('扫描结果:', res.result); |
| | | this.processQRCodeResult(res.result); |
| | | }, |
| | | fail: (err) => { |
| | | console.error('扫描失败:', err); |
| | | uni.showToast({ |
| | | title: '扫描失败,请重试', |
| | | icon: 'none' |
| | | }); |
| | | } |
| | | }); |
| | | // #endif |
| | | }, |
| | | |
| | | // 处理二维码扫描结果 |
| | | processQRCodeResult(qrCodeResult) { |
| | | if (!qrCodeResult) { |
| | | uni.showToast({ |
| | | title: '二维码内容为空', |
| | | icon: 'none' |
| | | }); |
| | | return; |
| | | } |
| | | |
| | | // 显示加载提示 |
| | | uni.showLoading({ |
| | | title: '查询物料信息...' |
| | | }); |
| | | |
| | | // 调用后端接口查询物料信息 |
| | | this.$post({ |
| | | url: "/LLJ/GetMaterialByBarcode", |
| | | data: { |
| | | itemBarcode: qrCodeResult, |
| | | currentBillNo: this.formData.lotNo // 传递当前检验单的到货单号 |
| | | } |
| | | }).then(res => { |
| | | uni.hideLoading(); |
| | | if (res.status === 0 && res.data && res.data.tbBillList && res.data.tbBillList.length > 0) { |
| | | // 查询成功,验证物料ID是否与检验单一致 |
| | | const scannedMaterial = res.data.tbBillList[0]; |
| | | |
| | | // 检查扫描的物料ID是否与当前检验单的物料ID一致 |
| | | if (this.formData.itemId && scannedMaterial.itemId && |
| | | this.formData.itemId.toString() !== scannedMaterial.itemId.toString()) { |
| | | // 物料ID不一致,显示错误信息 |
| | | this.scannedMaterialInfo = null; |
| | | uni.showModal({ |
| | | title: '物料不匹配', |
| | | content: '扫秒的条码不为该检验单物料,请重新扫描', |
| | | showCancel: false |
| | | }); |
| | | return; |
| | | } |
| | | |
| | | // 物料ID验证通过,显示物料信息 |
| | | this.scannedMaterialInfo = scannedMaterial; |
| | | // 保存扫描到的条码值,用于后续调用存储过程 |
| | | this.scannedMaterialInfo.itemBarcode = qrCodeResult; |
| | | uni.showToast({ |
| | | title: '查询成功', |
| | | icon: 'success' |
| | | }); |
| | | } else { |
| | | // 查询失败,显示错误信息 |
| | | this.scannedMaterialInfo = null; |
| | | uni.showModal({ |
| | | title: '查询失败', |
| | | content: res.message || '未找到对应的物料信息,请检查二维码是否正确', |
| | | showCancel: false |
| | | }); |
| | | } |
| | | }).catch(err => { |
| | | uni.hideLoading(); |
| | | console.error('查询物料信息失败:', err); |
| | | this.scannedMaterialInfo = null; |
| | | uni.showModal({ |
| | | title: '查询失败', |
| | | content: '网络错误,请检查网络连接后重试', |
| | | showCancel: false |
| | | }); |
| | | }); |
| | | }, |
| | | |
| | | // 测试输入 |
| | | testInput() { |
| | | this.destructionQuantity = '5'; |
| | | this.validateInteger(); |
| | | uni.showToast({ |
| | | title: '测试输入完成', |
| | | icon: 'success' |
| | | }); |
| | | }, |
| | | |
| | | // 点击输入框 |
| | | focusInput() { |
| | | // 使用uni-app的输入弹窗 |
| | | uni.showModal({ |
| | | title: '输入破坏实验数量', |
| | | content: `可用数量: ${this.scannedMaterialInfo.oldQty}`, |
| | | editable: true, |
| | | placeholderText: '请输入数量', |
| | | success: (res) => { |
| | | if (res.confirm && res.content) { |
| | | this.destructionQuantity = res.content; |
| | | this.validateInteger(); |
| | | } |
| | | } |
| | | }); |
| | | }, |
| | | |
| | | // 验证输入是否为整数 |
| | | validateInteger() { |
| | | if (!this.destructionQuantity) { |
| | | this.isInteger = true; |
| | | return; |
| | | } |
| | | |
| | | const value = this.destructionQuantity.toString().trim(); |
| | | // 只允许正整数 |
| | | this.isInteger = /^[1-9]\d*$/.test(value); |
| | | }, |
| | | |
| | | // 确认破坏实验 |
| | | confirmDestruction() { |
| | | if (!this.isInteger || !this.destructionQuantity) { |
| | | uni.showToast({ |
| | | title: '请输入有效的整数数量', |
| | | icon: 'none' |
| | | }); |
| | | return; |
| | | } |
| | | |
| | | // 检查扫描的物料信息是否存在 |
| | | if (!this.scannedMaterialInfo) { |
| | | uni.showToast({ |
| | | title: '请先扫描物料二维码', |
| | | icon: 'none' |
| | | }); |
| | | return; |
| | | } |
| | | |
| | | // 验证破坏实验数量不能大于可用数量 |
| | | const destructionQty = parseInt(this.destructionQuantity); |
| | | const availableQty = parseInt(this.scannedMaterialInfo.oldQty); |
| | | |
| | | if (destructionQty > availableQty) { |
| | | uni.showModal({ |
| | | title: '数量错误', |
| | | content: `破坏实验数量(${destructionQty})不能大于可用数量(${availableQty}),请重新填写或重新扫码!`, |
| | | showCancel: false |
| | | }); |
| | | return; |
| | | } |
| | | |
| | | // 显示加载提示 |
| | | uni.showLoading({ |
| | | title: '调用存储过程中...' |
| | | }); |
| | | |
| | | // 调用破坏实验存储过程 |
| | | this.$post({ |
| | | url: "/LLJ/CallPhsyUpdateProcedure", |
| | | data: { |
| | | itemBarcode: this.scannedMaterialInfo.itemBarcode || this.scannedMaterialInfo.itemNo, // 使用扫描的条码 |
| | | yqty: availableQty, // 扫码查询出来的条码数量 |
| | | cqty: destructionQty, // 填写的破坏实验数量 |
| | | billNo: this.scannedMaterialInfo.billNo, // 查询到的到货单号 |
| | | lx: 1, // 操作类型:1新增 |
| | | releaseNo: this.formData.releaseNo, // 检验单号 |
| | | itemId: this.formData.itemId // 检验单的物料ID |
| | | } |
| | | }).then(res => { |
| | | uni.hideLoading(); |
| | | |
| | | // 检查存储过程返回的结果 |
| | | if (res.status === 0) { |
| | | // 存储过程执行成功 |
| | | this.formData.PHSY = this.destructionQuantity; |
| | | this.destructionPopup = false; |
| | | this.hasExistingRecord = true; // 设置为有记录状态 |
| | | uni.showToast({ |
| | | title: '破坏实验记录保存成功', |
| | | icon: 'success', |
| | | duration: 2000 |
| | | }); |
| | | // 立即重新加载数据确保同步 |
| | | setTimeout(() => { |
| | | this.init(); |
| | | }, 500); |
| | | } else { |
| | | // 存储过程执行失败,显示错误信息 |
| | | uni.showModal({ |
| | | title: '操作失败', |
| | | content: res.message || '破坏实验记录保存失败', |
| | | showCancel: false |
| | | }); |
| | | } |
| | | }).catch(err => { |
| | | uni.hideLoading(); |
| | | console.error('调用存储过程失败:', err); |
| | | uni.showModal({ |
| | | title: '网络错误', |
| | | content: '调用存储过程失败,请检查网络连接后重试', |
| | | showCancel: false |
| | | }); |
| | | }); |
| | | }, |
| | | |
| | | // 修改破坏实验(只修改数量) |
| | | modifyDestruction() { |
| | | // 显示数量输入界面 |
| | | uni.showModal({ |
| | | title: '修改破坏实验数量', |
| | | content: '请输入新的破坏实验数量', |
| | | editable: true, |
| | | placeholderText: '请输入数量', |
| | | success: (res) => { |
| | | if (res.confirm && res.content) { |
| | | const newQuantity = parseInt(res.content); |
| | | if (isNaN(newQuantity) || newQuantity <= 0) { |
| | | uni.showToast({ |
| | | title: '请输入有效的正整数', |
| | | icon: 'none' |
| | | }); |
| | | return; |
| | | } |
| | | |
| | | // 调用修改存储过程 |
| | | this.callModifyProcedure(newQuantity); |
| | | } |
| | | } |
| | | }); |
| | | }, |
| | | |
| | | // 调用修改存储过程 |
| | | callModifyProcedure(newQuantity) { |
| | | uni.showLoading({ |
| | | title: '修改中...' |
| | | }); |
| | | |
| | | // 获取当前扫描的物料信息 |
| | | const itemBarcode = (this.scannedMaterialInfo && this.scannedMaterialInfo.itemBarcode) || |
| | | (this.scannedMaterialInfo && this.scannedMaterialInfo.itemNo) || ''; |
| | | const yqty = (this.scannedMaterialInfo && this.scannedMaterialInfo.oldQty) || 0; |
| | | |
| | | this.$post({ |
| | | url: "/LLJ/CallPhsyUpdateProcedure", |
| | | data: { |
| | | itemBarcode: itemBarcode, // 使用扫描的条码 |
| | | yqty: yqty, // 使用扫码查询出来的条码数量 |
| | | cqty: newQuantity, // 新的破坏实验数量 |
| | | billNo: this.formData.lotNo, // 到货单号 |
| | | lx: 2, // 操作类型:2修改 |
| | | releaseNo: this.formData.releaseNo, // 检验单号 |
| | | itemId: this.formData.itemId // 检验单的物料ID |
| | | } |
| | | }).then(res => { |
| | | uni.hideLoading(); |
| | | |
| | | if (res.status === 0) { |
| | | // 修改成功 |
| | | this.formData.PHSY = newQuantity.toString(); |
| | | this.PHSY = newQuantity.toString(); |
| | | this.destructionPopup = false; |
| | | |
| | | uni.showToast({ |
| | | title: '修改成功', |
| | | icon: 'success', |
| | | duration: 2000 |
| | | }); |
| | | |
| | | // 重新加载数据 |
| | | setTimeout(() => { |
| | | this.init(); |
| | | }, 500); |
| | | } else { |
| | | uni.showModal({ |
| | | title: '修改失败', |
| | | content: res.message || '修改失败', |
| | | showCancel: false |
| | | }); |
| | | } |
| | | }).catch(err => { |
| | | uni.hideLoading(); |
| | | console.error('修改失败:', err); |
| | | uni.showModal({ |
| | | title: '网络错误', |
| | | content: '修改失败,请检查网络连接后重试', |
| | | showCancel: false |
| | | }); |
| | | }); |
| | | }, |
| | | |
| | | // 删除破坏实验 |
| | | deleteDestruction() { |
| | | uni.showModal({ |
| | | title: '确认删除', |
| | | content: '确定要删除当前的破坏实验记录吗?', |
| | | success: (res) => { |
| | | if (res.confirm) { |
| | | // 调用存储过程删除记录 |
| | | this.callDeleteProcedure(); |
| | | } |
| | | } |
| | | }); |
| | | }, |
| | | |
| | | // 调用删除存储过程 |
| | | callDeleteProcedure() { |
| | | uni.showLoading({ |
| | | title: '删除中...' |
| | | }); |
| | | |
| | | // 获取当前扫描的物料信息 |
| | | const itemBarcode = (this.scannedMaterialInfo && this.scannedMaterialInfo.itemBarcode) || |
| | | (this.scannedMaterialInfo && this.scannedMaterialInfo.itemNo) || ''; |
| | | const yqty = (this.scannedMaterialInfo && this.scannedMaterialInfo.oldQty) || 0; |
| | | const cqty = parseFloat(this.destructionQuantity) || 0; // 使用当前记录的破坏数量 |
| | | |
| | | this.$post({ |
| | | url: "/LLJ/CallPhsyUpdateProcedure", |
| | | data: { |
| | | itemBarcode: itemBarcode, // 使用扫描的条码 |
| | | yqty: yqty, // 使用扫码查询出来的条码数量 |
| | | cqty: cqty, // 使用当前记录的破坏数量 |
| | | billNo: this.formData.lotNo, // 到货单号 |
| | | lx: 3, // 操作类型:3删除 |
| | | releaseNo: this.formData.releaseNo, // 检验单号 |
| | | itemId: this.formData.itemId // 检验单的物料ID |
| | | } |
| | | }).then(res => { |
| | | uni.hideLoading(); |
| | | |
| | | if (res.status === 0) { |
| | | // 删除成功 |
| | | this.scannedMaterialInfo = null; |
| | | this.destructionQuantity = ''; |
| | | this.isInteger = true; |
| | | this.formData.PHSY = ''; |
| | | this.PHSY = ''; |
| | | this.hasExistingRecord = false; |
| | | this.destructionPopup = false; |
| | | |
| | | uni.showToast({ |
| | | title: '删除成功', |
| | | icon: 'success', |
| | | duration: 2000 |
| | | }); |
| | | |
| | | // 重新加载数据 |
| | | setTimeout(() => { |
| | | this.init(); |
| | | }, 500); |
| | | } else { |
| | | uni.showModal({ |
| | | title: '删除失败', |
| | | content: res.message || '删除失败', |
| | | showCancel: false |
| | | }); |
| | | } |
| | | }).catch(err => { |
| | | uni.hideLoading(); |
| | | console.error('删除失败:', err); |
| | | uni.showModal({ |
| | | title: '网络错误', |
| | | content: '删除失败,请检查网络连接后重试', |
| | | showCancel: false |
| | | }); |
| | | }); |
| | | }, |
| | | |
| | | // 重置破坏实验(返回上一步) |
| | | resetDestruction() { |
| | | this.scannedMaterialInfo = null; |
| | | this.destructionQuantity = ''; |
| | | this.isInteger = true; |
| | | this.hasExistingRecord = false; |
| | | this.destructionPopup = false; // 直接关闭弹窗,返回到表单 |
| | | }, |
| | | |
| | | // 关闭破坏实验弹窗 |
| | | closeDestructionPopup() { |
| | | this.destructionPopup = false; |
| | | // 重置所有相关数据 |
| | | this.scannedMaterialInfo = null; |
| | | this.destructionQuantity = ''; |
| | | this.isInteger = true; |
| | | }, |
| | | |
| | | editDestruction() { |
| | | // 验证输入是否为整数 |
| | | // 验证输入是否为整数或空字符串 |
| | | if(this.PHSY === '') { |
| | | this.isInteger = true; |
| | | // 如果为空,传递空字符串,后端会处理为null |
| | | } else { |
| | | const isInteger = /^-?\d+$/.test(this.PHSY); |
| | | this.isInteger = isInteger; |
| | | if (!isInteger) { |
| | | uni.showToast({ |
| | | title: '请输入整数值或留空', |
| | | icon: 'none', |
| | | duration: 2000 |
| | | }); |
| | | return; |
| | | } |
| | | } |
| | | |
| | | // 保存破坏实验数量,并带上不良原因、所属车间、评审状态 |
| | | |
| | | // 显示加载提示 |
| | | uni.showLoading({ |
| | | title: '保存中...' |
| | | }); |
| | | |
| | | this.$post({ |
| | | url: "/LLJ/saveRemarksGid", |
| | | url: "/LLJ/savePhsyGid", |
| | | data: { |
| | | gid: this.formData.id, |
| | | releaseNo: this.formData.releaseNo, |
| | | PHSY: this.PHSY, // 可以是空字符串或有效整数 |
| | | BLYY: this.badreason, |
| | | SSCJ: this.WORKSHOP, |
| | | PSZT: this.PSTYPE |
| | | PHSY: this.PHSY |
| | | } |
| | | }).then(res => { |
| | | if (res.data.tbBillList > 0) { |
| | | // 如果输入为空,设置为null以便不显示 |
| | | uni.hideLoading(); |
| | | if (res.data && res.data.tbBillList > 0) { |
| | | this.formData.PHSY = this.PHSY === '' ? null : this.PHSY; |
| | | this.destructionPopup = false; |
| | | this.$showMessage("保存成功"); |
| | | uni.showToast({ |
| | | title: '保存成功', |
| | | icon: 'success', |
| | | duration: 2000 |
| | | }); |
| | | // 立即重新加载数据确保同步 |
| | | setTimeout(() => { |
| | | this.init(); |
| | | }, 2000); |
| | | }, 500); |
| | | } else { |
| | | uni.showToast({ |
| | | title: '保存失败', |
| | | icon: 'none', |
| | | duration: 2000 |
| | | }); |
| | | } |
| | | }).catch(err => { |
| | | uni.hideLoading(); |
| | | console.error('保存失败:', err); |
| | | uni.showToast({ |
| | | title: '保存失败,请重试', |
| | | icon: 'none', |
| | | duration: 2000 |
| | | }); |
| | | }) |
| | | }, |
| | | clearDestruction() { |
| | | // 清除破坏实验数量 |
| | | this.PHSY = ''; |
| | | // 显示加载提示 |
| | | uni.showLoading({ |
| | | title: '清除中...' |
| | | }); |
| | | |
| | | this.$post({ |
| | | url: "/LLJ/saveRemarksGid", |
| | | url: "/LLJ/savePhsyGid", |
| | | data: { |
| | | gid: this.formData.id, |
| | | releaseNo: this.formData.releaseNo, |
| | | PHSY: '', // 空字符串,后端会处理为null |
| | | BLYY: this.badreason, |
| | | SSCJ: this.WORKSHOP, |
| | | PSZT: this.PSTYPE |
| | | PHSY: '' |
| | | } |
| | | }).then(res => { |
| | | if (res.data.tbBillList > 0) { |
| | | this.formData.PHSY = null; // 确保前端也为null,不显示 |
| | | uni.hideLoading(); |
| | | if (res.data && res.data.tbBillList > 0) { |
| | | this.formData.PHSY = null; |
| | | this.PHSY = ''; |
| | | this.destructionPopup = false; |
| | | this.$showMessage("清除成功"); |
| | | uni.showToast({ |
| | | title: '清除成功', |
| | | icon: 'success', |
| | | duration: 2000 |
| | | }); |
| | | // 立即重新加载数据确保同步 |
| | | setTimeout(() => { |
| | | this.init(); |
| | | }, 2000); |
| | | }, 500); |
| | | } else { |
| | | uni.showToast({ |
| | | title: '清除失败', |
| | | icon: 'none', |
| | | duration: 2000 |
| | | }); |
| | | } |
| | | }).catch(err => { |
| | | uni.hideLoading(); |
| | | console.error('清除失败:', err); |
| | | uni.showToast({ |
| | | title: '清除失败,请重试', |
| | | icon: 'none', |
| | | duration: 2000 |
| | | }); |
| | | }) |
| | | }, |
| | | viewAttachmentInfo() { |
| | |
| | | 'ppt', 'pptx', // PowerPoint演示文稿 |
| | | 'csv' // CSV文件 |
| | | ].includes(ext); |
| | | }, |
| | | |
| | | // 获取文件类型图标 |
| | | getFileTypeIcon(filename) { |
| | | if (!filename) return '📄'; |
| | | const ext = filename.trim().split('.').pop().toLowerCase(); |
| | | const iconMap = { |
| | | 'pdf': '📕', |
| | | 'jpg': '🖼️', 'jpeg': '🖼️', 'png': '🖼️', 'gif': '🖼️', 'bmp': '🖼️', 'webp': '🖼️', |
| | | 'txt': '📝', 'log': '📝', 'md': '📝', |
| | | 'doc': '📘', 'docx': '📘', |
| | | 'xls': '📊', 'xlsx': '📊', |
| | | 'ppt': '📙', 'pptx': '📙', |
| | | 'csv': '📊', |
| | | 'zip': '📦', 'rar': '📦', '7z': '📦', |
| | | 'dwg': '🏗️', 'dxf': '🏗️' |
| | | }; |
| | | return iconMap[ext] || '📄'; |
| | | }, |
| | | |
| | | // 获取文件类型CSS类 |
| | | getFileTypeClass(filename) { |
| | | if (!filename) return 'file-unknown'; |
| | | const ext = filename.trim().split('.').pop().toLowerCase(); |
| | | const classMap = { |
| | | 'pdf': 'file-pdf', |
| | | 'jpg': 'file-image', 'jpeg': 'file-image', 'png': 'file-image', 'gif': 'file-image', 'bmp': 'file-image', 'webp': 'file-image', |
| | | 'txt': 'file-text', 'log': 'file-text', 'md': 'file-text', |
| | | 'doc': 'file-word', 'docx': 'file-word', |
| | | 'xls': 'file-excel', 'xlsx': 'file-excel', |
| | | 'ppt': 'file-powerpoint', 'pptx': 'file-powerpoint', |
| | | 'csv': 'file-excel', |
| | | 'zip': 'file-archive', 'rar': 'file-archive', '7z': 'file-archive', |
| | | 'dwg': 'file-cad', 'dxf': 'file-cad' |
| | | }; |
| | | return classMap[ext] || 'file-unknown'; |
| | | }, |
| | | |
| | | // 格式化日期 |
| | | formatDate(dateString) { |
| | | if (!dateString) return ''; |
| | | try { |
| | | const date = new Date(dateString); |
| | | return date.toLocaleDateString('zh-CN', { |
| | | year: 'numeric', |
| | | month: '2-digit', |
| | | day: '2-digit', |
| | | hour: '2-digit', |
| | | minute: '2-digit' |
| | | }); |
| | | } catch (e) { |
| | | return dateString; |
| | | } |
| | | }, |
| | | // 处理附件下载错误 |
| | | handleAttachmentError(item) { |
| | |
| | | showFilePreview(content, fileName) { |
| | | this.previewContent = content; |
| | | this.previewTitle = fileName; |
| | | this.previewItemNo = this.selectedAttachment?.itemNo || ''; |
| | | this.previewItemNo = (this.selectedAttachment && this.selectedAttachment.itemNo) || ''; |
| | | this.previewType = this.getFileType(fileName); |
| | | this.showFilePreviewPopup = true; |
| | | }, |
| | |
| | | const item = { fattach: this.previewTitle, itemNo: this.previewItemNo }; |
| | | this.downloadAttachment(item); |
| | | this.closeFilePreview(); |
| | | }, |
| | | |
| | | // 在弹窗中预览图片(放大功能) |
| | | previewImageInPopup() { |
| | | // 使用uni.previewImage API实现图片放大预览 |
| | | uni.previewImage({ |
| | | current: this.previewContent, // 当前显示图片的链接 |
| | | urls: [this.previewContent], // 需要预览的图片链接列表 |
| | | loop: false, // 是否开启图片轮播 |
| | | indicator: 'default', // 图片指示器类型 |
| | | longPressActions: { |
| | | itemList: ['发送给朋友', '保存图片', '收藏'], |
| | | success: function (data) { |
| | | console.log('选中了第' + (data.tapIndex + 1) + '个按钮'); |
| | | }, |
| | | fail: function (err) { |
| | | console.log(err.errMsg); |
| | | } |
| | | }, |
| | | success: () => { |
| | | console.log('图片预览成功'); |
| | | }, |
| | | fail: (err) => { |
| | | console.error('图片预览失败:', err); |
| | | uni.showToast({ |
| | | title: '图片预览失败', |
| | | icon: 'none' |
| | | }); |
| | | } |
| | | }); |
| | | }, |
| | | |
| | | // 预览Office文件 |
| | |
| | | } |
| | | // #endif |
| | | }, |
| | | saveRemarksGid() { |
| | | this.$post({ |
| | | url: "/LLJ/saveRemarksGid", |
| | | data: { |
| | | gid: this.formData.id, |
| | | releaseNo: this.formData.releaseNo, |
| | | BLYY: this.badreason, |
| | | SSCJ: this.WORKSHOP, |
| | | PSZT: this.PSTYPE, |
| | | PHSY: this.PHSY // 新增,保证破坏实验数不会被刷掉 |
| | | } |
| | | }).then(res => { |
| | | if (res.data.tbBillList > 0) { |
| | | this.$showMessage("自动保存成功"); |
| | | } |
| | | }); |
| | | |
| | | |
| | | // 全局堵穴相关方法 |
| | | // 检查检验项目是否有穴数 |
| | | hasHoleCount(fcheckItem) { |
| | | if (!fcheckItem) return false; |
| | | const match = fcheckItem.match(/[((](\d+)穴[))]/); |
| | | return match ? true : false; |
| | | }, |
| | | |
| | | // 获取穴数 |
| | | getHoleCount(fcheckItem) { |
| | | if (!fcheckItem) return 0; |
| | | const match = fcheckItem.match(/[((](\d+)穴[))]/); |
| | | return match ? parseInt(match[1]) : 0; |
| | | }, |
| | | |
| | | // 打开全局堵穴对话框 |
| | | openGlobalBlockHoleDialog() { |
| | | console.log('点击堵穴设置按钮'); |
| | | console.log('tableData:', this.tableData); |
| | | |
| | | // 检查是否有有开穴数的检验项目 |
| | | const hasHoleItems = this.tableData.some(item => this.hasHoleCount(item.fcheckItem)); |
| | | console.log('hasHoleItems:', hasHoleItems); |
| | | |
| | | if (!hasHoleItems) { |
| | | uni.showModal({ |
| | | title: '提示', |
| | | content: '当前检验单没有有开穴数的检验项目', |
| | | showCancel: false |
| | | }); |
| | | return; |
| | | } |
| | | |
| | | this.globalBlockHoleInput = ''; |
| | | this.globalBlockHolePopup = true; |
| | | console.log('设置globalBlockHolePopup为true'); |
| | | this.validateGlobalBlockHoleInput(); |
| | | }, |
| | | |
| | | // 关闭全局堵穴对话框 |
| | | closeGlobalBlockHoleDialog() { |
| | | this.globalBlockHolePopup = false; |
| | | this.globalBlockHoleInput = ''; |
| | | this.globalBlockHoleError = ''; |
| | | this.isGlobalBlockHoleValid = false; |
| | | }, |
| | | |
| | | |
| | | // 处理全局堵穴输入(保留原方法以防其他地方调用) |
| | | onGlobalBlockHoleInput(e) { |
| | | console.log('输入事件触发:', e); |
| | | // 兼容不同的事件格式 |
| | | const value = e.detail ? e.detail.value : e.target ? e.target.value : e; |
| | | console.log('输入值:', value); |
| | | this.globalBlockHoleInput = value; |
| | | this.validateGlobalBlockHoleInput(); |
| | | }, |
| | | |
| | | // 验证全局堵穴输入 |
| | | validateGlobalBlockHoleInput() { |
| | | const input = this.globalBlockHoleInput.trim(); |
| | | if (!input) { |
| | | this.globalBlockHoleError = ''; |
| | | this.isGlobalBlockHoleValid = false; |
| | | return; |
| | | } |
| | | |
| | | // 验证格式:1,2,3 或 1,2,3 |
| | | const blockedHoles = input.split(/[,,]/).map(s => s.trim()).filter(s => s); |
| | | |
| | | // 检查是否都是有效数字 |
| | | const isValid = blockedHoles.every(hole => { |
| | | const num = parseInt(hole); |
| | | return !isNaN(num) && num > 0; |
| | | }); |
| | | |
| | | if (!isValid) { |
| | | this.globalBlockHoleError = '请输入有效的穴号,用逗号分隔'; |
| | | this.isGlobalBlockHoleValid = false; |
| | | return; |
| | | } |
| | | |
| | | // 检查是否有重复 |
| | | const uniqueHoles = [...new Set(blockedHoles.map(h => parseInt(h)))]; |
| | | if (uniqueHoles.length !== blockedHoles.length) { |
| | | this.globalBlockHoleError = '不能输入重复的穴号'; |
| | | this.isGlobalBlockHoleValid = false; |
| | | return; |
| | | } |
| | | |
| | | this.globalBlockHoleError = ''; |
| | | this.isGlobalBlockHoleValid = true; |
| | | }, |
| | | |
| | | // 确认全局堵穴 |
| | | confirmGlobalBlockHole() { |
| | | if (!this.isGlobalBlockHoleValid) return; |
| | | |
| | | uni.showLoading({ |
| | | title: '设置堵穴中...' |
| | | }); |
| | | |
| | | // 获取所有有开穴数的检验项目 |
| | | const holeItems = this.tableData.filter(item => this.hasHoleCount(item.fcheckItem)); |
| | | |
| | | // 批量调用后端接口设置堵穴 |
| | | const promises = holeItems.map(item => { |
| | | return this.$post({ |
| | | url: "/LLJ/SetBlockedHoles", |
| | | data: { |
| | | releaseNo: this.formData.releaseNo, |
| | | blockedHoles: this.globalBlockHoleInput, |
| | | itemId: item.id |
| | | } |
| | | }); |
| | | }); |
| | | |
| | | Promise.all(promises).then(results => { |
| | | uni.hideLoading(); |
| | | |
| | | // 检查所有请求是否成功 |
| | | const failedCount = results.filter(res => res.status !== 0).length; |
| | | |
| | | if (failedCount === 0) { |
| | | uni.showToast({ |
| | | title: `成功为${holeItems.length}个检验项目设置堵穴`, |
| | | icon: 'success', |
| | | duration: 2000 |
| | | }); |
| | | |
| | | // 立即关闭对话框 |
| | | this.closeGlobalBlockHoleDialog(); |
| | | |
| | | // 立即重新加载数据确保同步 |
| | | setTimeout(() => { |
| | | this.init(); |
| | | }, 500); |
| | | } else { |
| | | uni.showModal({ |
| | | title: '部分设置失败', |
| | | content: `${failedCount}个检验项目设置失败,请重试`, |
| | | showCancel: false |
| | | }); |
| | | } |
| | | }).catch(err => { |
| | | uni.hideLoading(); |
| | | console.error('全局堵穴设置失败:', err); |
| | | uni.showModal({ |
| | | title: '网络错误', |
| | | content: '堵穴设置失败,请检查网络连接后重试', |
| | | showCancel: false |
| | | }); |
| | | }); |
| | | }, |
| | | |
| | | |
| | | } |
| | | } |
| | | </script> |
| | |
| | | box-shadow: 0 0 10px rgba(0, 0, 0, 0.1); |
| | | min-height: 100vh; |
| | | position: relative; |
| | | transition: all 0.3s ease; |
| | | } |
| | | |
| | | /* 未维护且非紧急放行表单的紫色样式 */ |
| | | .inspection-sheet.unmaintained-form { |
| | | background: linear-gradient(135deg, #f8f4ff 0%, #f0e6ff 100%); |
| | | border: 2px solid #9c27b0; |
| | | box-shadow: 0 0 20px rgba(156, 39, 176, 0.2); |
| | | } |
| | | |
| | | .inspection-sheet.unmaintained-form .sheet-header { |
| | | border-bottom: 2px solid #9c27b0; |
| | | } |
| | | |
| | | .inspection-sheet.unmaintained-form .sheet-header h1 { |
| | | color: #6a1b9a; |
| | | } |
| | | |
| | | .inspection-sheet.unmaintained-form .inspection-number { |
| | | color: #9c27b0; |
| | | } |
| | | |
| | | .inspection-sheet.unmaintained-form .material-info { |
| | | border: 1px solid #e1bee7; |
| | | background-color: rgba(156, 39, 176, 0.05); |
| | | } |
| | | |
| | | .inspection-sheet.unmaintained-form .info-label { |
| | | color: #6a1b9a; |
| | | } |
| | | |
| | | .inspection-sheet.unmaintained-form .info-value { |
| | | color: #4a148c; |
| | | } |
| | | |
| | | /* 头部样式 */ |
| | |
| | | .info-value { |
| | | color: #2c3e50; |
| | | margin-right: 20px; |
| | | } |
| | | |
| | | .picker-text { |
| | | padding: 6px 10px; |
| | | border: 1px solid #ddd; |
| | | border-radius: 4px; |
| | | background-color: white; |
| | | color: #999; |
| | | font-size: 14px; |
| | | min-height: 32px; |
| | | display: flex; |
| | | align-items: center; |
| | | max-width: 150px; |
| | | } |
| | | |
| | | .picker-text.selected { |
| | | color: #e74c3c; |
| | | font-weight: 500; |
| | | } |
| | | |
| | | .highlight { |
| | |
| | | align-items: center; |
| | | z-index: 1000; /* 提高层级,确保在固定按钮上方 */ |
| | | } |
| | | |
| | | /* 全局堵穴设置对话框需要更高的z-index */ |
| | | .global-block-hole-popup { |
| | | z-index: 1001; |
| | | } |
| | | |
| | | /* 弹窗整体美化 */ |
| | | .popup, .attachment-detail-popup { |
| | | .popup { |
| | | background: #fff; |
| | | border-radius: 16px; |
| | | box-shadow: 0 8px 32px rgba(60,60,60,0.18); |
| | |
| | | max-height: 80vh; /* 限制最大高度,避免被底部按钮遮挡 */ |
| | | overflow-y: auto; /* 内容过多时可滚动 */ |
| | | } |
| | | .attachment-popup-title { |
| | | font-size: 22px; |
| | | font-weight: 700; |
| | | color: #222; |
| | | margin-bottom: 8px; |
| | | letter-spacing: 1px; |
| | | text-align: center; |
| | | } |
| | | .attachment-popup-divider { |
| | | height: 1px; |
| | | background: linear-gradient(90deg,#e0e7ef 0%,#f5f7fa 100%); |
| | | margin-bottom: 18px; |
| | | } |
| | | |
| | | .attachment-detail-content { |
| | | margin-bottom: 18px; |
| | | } |
| | | .attachment-detail-row { |
| | | display: flex; |
| | | align-items: center; |
| | | margin-bottom: 8px; |
| | | font-size: 15px; |
| | | } |
| | | .attachment-label { |
| | | min-width: 80px; |
| | | color: #1976d2; |
| | | font-weight: 500; |
| | | margin-right: 8px; |
| | | } |
| | | .attachment-preview-area { |
| | | margin: 18px 0 8px 0; |
| | | border-radius: 10px; |
| | | background: #f8fafc; |
| | | padding: 10px; |
| | | box-shadow: 0 2px 8px rgba(60,60,60,0.06); |
| | | } |
| | | .attachment-download-area { |
| | | margin: 18px 0 8px 0; |
| | | text-align: center; |
| | | } |
| | | .attachment-download-link { |
| | | display: inline-block; |
| | | padding: 7px 18px; |
| | | background: linear-gradient(90deg,#4f8cff 0%,#1976d2 100%); |
| | | color: #fff; |
| | | border-radius: 6px; |
| | | font-weight: 500; |
| | | text-decoration: none; |
| | | transition: background 0.2s; |
| | | box-shadow: 0 2px 8px rgba(60,60,60,0.08); |
| | | } |
| | | .attachment-download-link:hover { |
| | | background: linear-gradient(90deg,#1976d2 0%,#4f8cff 100%); |
| | | } |
| | | .attachment-detail-empty { |
| | | color: #888; |
| | | text-align: center; |
| | | margin: 30px 0; |
| | | font-size: 16px; |
| | | } |
| | | .attachment-popup-close { |
| | | margin-top: 18px; |
| | | width: 100%; |
| | | background: linear-gradient(90deg,#e0e0e0 0%,#f5f7fa 100%); |
| | | color: #444; |
| | | border-radius: 8px; |
| | | font-size: 16px; |
| | | padding: 10px 0; |
| | | border: none; |
| | | font-weight: 600; |
| | | letter-spacing: 1px; |
| | | transition: background 0.2s, color 0.2s; |
| | | box-shadow: 0 2px 8px rgba(60,60,60,0.06); |
| | | } |
| | | .attachment-popup-close:hover { |
| | | background: linear-gradient(90deg,#bdbdbd 0%,#e0e0e0 100%); |
| | | color: #1976d2; |
| | | } |
| | | |
| | | /* 附件详情页面的操作按钮 */ |
| | | .attachment-actions-detail { |
| | | margin: 20px 0; |
| | | display: flex; |
| | | gap: 12px; |
| | | justify-content: center; |
| | | flex-wrap: wrap; |
| | | } |
| | | .attachment-action-btn { |
| | | padding: 10px 20px; |
| | | border: none; |
| | | border-radius: 8px; |
| | | font-size: 14px; |
| | | font-weight: 600; |
| | | cursor: pointer; |
| | | transition: all 0.3s ease; |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: center; |
| | | min-width: 120px; |
| | | box-shadow: 0 2px 4px rgba(0,0,0,0.1); |
| | | } |
| | | .attachment-action-btn.preview-btn { |
| | | background: linear-gradient(135deg, #4CAF50, #45a049); |
| | | color: white; |
| | | } |
| | | .attachment-action-btn.preview-btn:hover { |
| | | background: linear-gradient(135deg, #45a049, #3d8b40); |
| | | transform: translateY(-1px); |
| | | box-shadow: 0 4px 8px rgba(0,0,0,0.15); |
| | | } |
| | | .attachment-action-btn.download-btn { |
| | | background: linear-gradient(135deg, #2196F3, #1976D2); |
| | | color: white; |
| | | } |
| | | .attachment-action-btn.download-btn:hover { |
| | | background: linear-gradient(135deg, #1976D2, #1565C0); |
| | | transform: translateY(-1px); |
| | | box-shadow: 0 4px 8px rgba(0,0,0,0.15); |
| | | } |
| | | |
| | | /* 文件预览弹窗样式 */ |
| | |
| | | background: linear-gradient(135deg, #bdbdbd, #9e9e9e); |
| | | transform: translateY(-1px); |
| | | } |
| | | /* 列表弹窗美化(保留原有) */ |
| | | .attachment-list { |
| | | padding: 0; |
| | | /* 附件相关样式 */ |
| | | .attachment-list-popup { |
| | | width: 80vw; |
| | | max-width: 800px; |
| | | max-height: 85vh; |
| | | } |
| | | |
| | | .attachment-detail-popup { |
| | | width: 70vw; |
| | | max-width: 600px; |
| | | } |
| | | |
| | | .attachment-popup-header { |
| | | padding: 16px; |
| | | border-bottom: 1px solid #eee; |
| | | display: flex; |
| | | justify-content: space-between; |
| | | align-items: center; |
| | | background-color: white; |
| | | } |
| | | |
| | | .attachment-popup-title { |
| | | font-size: 16px; |
| | | font-weight: 600; |
| | | color: #2c3e50; |
| | | margin: 0; |
| | | list-style: none; |
| | | max-height: 300px; |
| | | } |
| | | |
| | | .attachment-close-btn { |
| | | padding: 8px 16px; |
| | | border: 1px solid #ddd; |
| | | border-radius: 4px; |
| | | background-color: white; |
| | | font-size: 14px; |
| | | transition: all 0.2s; |
| | | color: #2c3e50; |
| | | } |
| | | |
| | | .attachment-close-btn:hover { |
| | | background-color: #f8f9fa; |
| | | } |
| | | |
| | | .attachment-popup-content { |
| | | padding: 16px; |
| | | max-height: 60vh; |
| | | overflow-y: auto; |
| | | } |
| | | .attachment-list li { |
| | | |
| | | /* 加载状态 */ |
| | | .attachment-loading { |
| | | display: flex; |
| | | flex-direction: column; |
| | | align-items: center; |
| | | justify-content: center; |
| | | padding: 40px 20px; |
| | | gap: 16px; |
| | | } |
| | | |
| | | .loading-spinner { |
| | | width: 32px; |
| | | height: 32px; |
| | | border: 3px solid #f3f3f3; |
| | | border-top: 3px solid #3498db; |
| | | border-radius: 50%; |
| | | animation: spin 1s linear infinite; |
| | | } |
| | | |
| | | @keyframes spin { |
| | | 0% { transform: rotate(0deg); } |
| | | 100% { transform: rotate(360deg); } |
| | | } |
| | | |
| | | .loading-text { |
| | | font-size: 14px; |
| | | color: #7f8c8d; |
| | | } |
| | | |
| | | /* 空状态 */ |
| | | .attachment-empty { |
| | | display: flex; |
| | | flex-direction: column; |
| | | align-items: center; |
| | | justify-content: center; |
| | | padding: 40px 20px; |
| | | gap: 12px; |
| | | text-align: center; |
| | | } |
| | | |
| | | .empty-icon { |
| | | font-size: 36px; |
| | | opacity: 0.6; |
| | | } |
| | | |
| | | .empty-text { |
| | | font-size: 16px; |
| | | color: #7f8c8d; |
| | | font-weight: 500; |
| | | } |
| | | |
| | | .empty-hint { |
| | | font-size: 14px; |
| | | color: #95a5a6; |
| | | } |
| | | |
| | | /* 附件列表布局 */ |
| | | .attachment-list { |
| | | display: flex; |
| | | flex-direction: column; |
| | | gap: 16px; |
| | | } |
| | | |
| | | .attachment-item { |
| | | background-color: white; |
| | | border-radius: 8px; |
| | | box-shadow: 0 2px 10px rgba(0, 0, 0, 0.05); |
| | | overflow: hidden; |
| | | transition: all 0.3s; |
| | | border: 1px solid #eee; |
| | | } |
| | | |
| | | .attachment-item:hover { |
| | | box-shadow: 0 4px 15px rgba(0, 0, 0, 0.1); |
| | | } |
| | | |
| | | .attachment-info { |
| | | padding: 16px; |
| | | border-bottom: 1px solid #eee; |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: space-between; |
| | | padding: 12px 0; |
| | | border-bottom: 1px solid #f0f0f0; |
| | | gap: 16px; |
| | | } |
| | | .attachment-info { |
| | | flex: 1; |
| | | margin-right: 10px; |
| | | } |
| | | .attachment-name { |
| | | color: #3498db; |
| | | cursor: pointer; |
| | | font-weight: 500; |
| | | transition: color 0.2s; |
| | | display: block; |
| | | margin-bottom: 4px; |
| | | } |
| | | .attachment-name:hover { |
| | | color: #217dbb; |
| | | text-decoration: underline; |
| | | } |
| | | .attachment-meta { |
| | | font-size: 12px; |
| | | } |
| | | .attachment-type { |
| | | color: #7f8c8d; |
| | | font-style: italic; |
| | | } |
| | | .attachment-actions { |
| | | |
| | | .file-type-badge { |
| | | width: 40px; |
| | | height: 40px; |
| | | border-radius: 8px; |
| | | display: flex; |
| | | gap: 8px; |
| | | align-items: center; |
| | | justify-content: center; |
| | | font-size: 20px; |
| | | background: #f8f9fa; |
| | | border: 2px solid #e9ecef; |
| | | flex-shrink: 0; |
| | | } |
| | | .attachment-list .secondary-btn { |
| | | padding: 4px 10px; |
| | | font-size: 13px; |
| | | border-radius: 3px; |
| | | background: #f5f7fa; |
| | | color: #333; |
| | | border: 1px solid #dbe2ea; |
| | | transition: background 0.2s, color 0.2s; |
| | | |
| | | .file-type-badge.large { |
| | | width: 56px; |
| | | height: 56px; |
| | | font-size: 28px; |
| | | } |
| | | .attachment-list .secondary-btn:hover { |
| | | background: #e6f0fa; |
| | | color: #1976d2; |
| | | |
| | | .file-type-badge.file-pdf { background: #ffe6e6; border-color: #ffcccc; } |
| | | .file-type-badge.file-image { background: #e6f3ff; border-color: #cce7ff; } |
| | | .file-type-badge.file-text { background: #e6ffe6; border-color: #ccffcc; } |
| | | .file-type-badge.file-word { background: #e6f0ff; border-color: #cce0ff; } |
| | | .file-type-badge.file-excel { background: #e6ffe6; border-color: #ccffcc; } |
| | | .file-type-badge.file-powerpoint { background: #fff0e6; border-color: #ffe0cc; } |
| | | .file-type-badge.file-archive { background: #f0e6ff; border-color: #e0ccff; } |
| | | .file-type-badge.file-cad { background: #e6fff0; border-color: #ccffe0; } |
| | | .file-type-badge.file-unknown { background: #f5f5f5; border-color: #e0e0e0; } |
| | | |
| | | .attachment-details { |
| | | flex: 1; |
| | | min-width: 0; |
| | | } |
| | | .preview-btn { |
| | | background: #e8f5e8 !important; |
| | | color: #2e7d2e !important; |
| | | border-color: #a5d6a5 !important; |
| | | |
| | | .attachment-name { |
| | | font-size: 16px; |
| | | font-weight: 600; |
| | | color: #2c3e50; |
| | | cursor: pointer; |
| | | overflow: hidden; |
| | | text-overflow: ellipsis; |
| | | white-space: nowrap; |
| | | margin-bottom: 8px; |
| | | transition: color 0.2s; |
| | | } |
| | | .preview-btn:hover { |
| | | background: #d4eecc !important; |
| | | color: #1e5f1e !important; |
| | | |
| | | .attachment-name:hover { |
| | | color: #3498db; |
| | | } |
| | | .attachment-popup-close { |
| | | margin-top: 18px; |
| | | width: 100%; |
| | | background: #e0e0e0; |
| | | color: #444; |
| | | |
| | | .attachment-meta { |
| | | display: flex; |
| | | gap: 16px; |
| | | font-size: 12px; |
| | | color: #95a5a6; |
| | | } |
| | | |
| | | .meta-type { |
| | | background-color: #ecf0f1; |
| | | padding: 2px 6px; |
| | | border-radius: 10px; |
| | | color: #7f8c8d; |
| | | } |
| | | |
| | | .meta-version { |
| | | background-color: #e8f5e8; |
| | | padding: 2px 6px; |
| | | border-radius: 10px; |
| | | color: #2e7d32; |
| | | } |
| | | |
| | | .meta-date { |
| | | background-color: #fff3e0; |
| | | padding: 2px 6px; |
| | | border-radius: 10px; |
| | | color: #f57c00; |
| | | } |
| | | |
| | | .attachment-actions { |
| | | padding: 12px 16px; |
| | | border-top: 1px solid #eee; |
| | | display: flex; |
| | | gap: 8px; |
| | | background-color: #f8f9fa; |
| | | } |
| | | |
| | | /* 按钮样式 */ |
| | | .btn-secondary { |
| | | padding: 8px 16px; |
| | | border: 1px solid #ddd; |
| | | border-radius: 4px; |
| | | font-size: 15px; |
| | | padding: 8px 0; |
| | | border: none; |
| | | transition: background 0.2s; |
| | | background-color: white; |
| | | font-size: 14px; |
| | | transition: all 0.2s; |
| | | color: #2c3e50; |
| | | flex: 1; |
| | | } |
| | | .attachment-popup-close:hover { |
| | | background: #bdbdbd; |
| | | |
| | | .btn-secondary:hover { |
| | | background-color: #f8f9fa; |
| | | } |
| | | |
| | | .btn-primary { |
| | | padding: 8px 16px; |
| | | border: 1px solid #3498db; |
| | | border-radius: 4px; |
| | | background-color: #3498db; |
| | | color: white; |
| | | font-size: 14px; |
| | | transition: all 0.2s; |
| | | flex: 1; |
| | | } |
| | | |
| | | .btn-primary:hover { |
| | | background-color: #2980b9; |
| | | } |
| | | |
| | | .btn-success { |
| | | padding: 8px 16px; |
| | | border: 1px solid #2ecc71; |
| | | border-radius: 4px; |
| | | background-color: #2ecc71; |
| | | color: white; |
| | | font-size: 14px; |
| | | transition: all 0.2s; |
| | | flex: 1; |
| | | } |
| | | |
| | | .btn-success:hover { |
| | | background-color: #27ae60; |
| | | } |
| | | |
| | | /* 附件详情样式 */ |
| | | .attachment-detail-header { |
| | | display: flex; |
| | | align-items: center; |
| | | gap: 20px; |
| | | margin-bottom: 20px; |
| | | padding-bottom: 16px; |
| | | border-bottom: 1px solid #eee; |
| | | } |
| | | |
| | | .attachment-detail-title { |
| | | font-size: 18px; |
| | | font-weight: 600; |
| | | color: #2c3e50; |
| | | flex: 1; |
| | | word-break: break-all; |
| | | } |
| | | |
| | | .attachment-detail-info { |
| | | margin-bottom: 20px; |
| | | } |
| | | |
| | | .info-row { |
| | | display: flex; |
| | | margin-bottom: 12px; |
| | | gap: 16px; |
| | | } |
| | | |
| | | .info-item { |
| | | flex: 1; |
| | | } |
| | | |
| | | .info-label { |
| | | display: block; |
| | | font-size: 12px; |
| | | color: #7f8c8d; |
| | | margin-bottom: 4px; |
| | | } |
| | | |
| | | .info-content { |
| | | font-size: 14px; |
| | | color: #2c3e50; |
| | | line-height: 1.5; |
| | | } |
| | | |
| | | .attachment-detail-actions { |
| | | padding: 12px 16px; |
| | | border-top: 1px solid #eee; |
| | | display: flex; |
| | | gap: 8px; |
| | | background-color: #f8f9fa; |
| | | } |
| | | |
| | | /* 响应式设计 */ |
| | |
| | | overflow-x: auto; |
| | | } |
| | | } |
| | | |
| | | /* 图片放大预览相关样式 */ |
| | | .preview-image-clickable { |
| | | transition: transform 0.2s ease; |
| | | border-radius: 8px; |
| | | box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1); |
| | | } |
| | | |
| | | .preview-image-clickable:hover { |
| | | transform: scale(1.02); |
| | | box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15); |
| | | } |
| | | |
| | | .image-zoom-hint { |
| | | text-align: center; |
| | | margin-top: 8px; |
| | | font-size: 12px; |
| | | color: #666; |
| | | font-style: italic; |
| | | } |
| | | |
| | | .image-preview-container { |
| | | position: relative; |
| | | display: flex; |
| | | flex-direction: column; |
| | | align-items: center; |
| | | } |
| | | |
| | | /* 扫描按钮样式 */ |
| | | .scan-btn { |
| | | background: linear-gradient(135deg, #4CAF50, #45a049); |
| | | color: white; |
| | | border: none; |
| | | border-radius: 8px; |
| | | padding: 12px 20px; |
| | | font-size: 14px; |
| | | font-weight: 600; |
| | | cursor: pointer; |
| | | transition: all 0.3s ease; |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: center; |
| | | gap: 8px; |
| | | box-shadow: 0 2px 4px rgba(0,0,0,0.1); |
| | | } |
| | | |
| | | .scan-btn:hover { |
| | | background: linear-gradient(135deg, #45a049, #3d8b40); |
| | | transform: translateY(-1px); |
| | | box-shadow: 0 4px 8px rgba(0,0,0,0.15); |
| | | } |
| | | |
| | | /* 物料信息显示样式 */ |
| | | .material-info-display { |
| | | margin-top: 16px; |
| | | padding: 16px; |
| | | background: linear-gradient(135deg, #f8f9fa, #e9ecef); |
| | | border-radius: 8px; |
| | | border: 1px solid #dee2e6; |
| | | box-shadow: 0 2px 4px rgba(0,0,0,0.05); |
| | | } |
| | | |
| | | .material-info-display h4 { |
| | | margin: 0 0 12px 0; |
| | | color: #495057; |
| | | font-size: 16px; |
| | | font-weight: 600; |
| | | text-align: center; |
| | | } |
| | | |
| | | .material-detail { |
| | | display: flex; |
| | | flex-direction: column; |
| | | gap: 8px; |
| | | } |
| | | |
| | | .detail-row { |
| | | display: flex; |
| | | align-items: center; |
| | | padding: 6px 0; |
| | | border-bottom: 1px solid #e9ecef; |
| | | } |
| | | |
| | | .detail-row:last-child { |
| | | border-bottom: none; |
| | | } |
| | | |
| | | .detail-label { |
| | | min-width: 80px; |
| | | font-weight: 600; |
| | | color: #6c757d; |
| | | font-size: 14px; |
| | | } |
| | | |
| | | .detail-value { |
| | | flex: 1; |
| | | color: #212529; |
| | | font-size: 14px; |
| | | font-weight: 500; |
| | | word-break: break-all; |
| | | } |
| | | |
| | | .detail-value.barcode-value { |
| | | font-family: 'Courier New', monospace; |
| | | font-weight: 600; |
| | | color: #2c3e50; |
| | | background-color: #f8f9fa; |
| | | padding: 4px 8px; |
| | | border-radius: 4px; |
| | | border: 1px solid #dee2e6; |
| | | font-size: 13px; |
| | | letter-spacing: 0.5px; |
| | | } |
| | | |
| | | /* 破坏实验弹窗样式 */ |
| | | .destruction-popup { |
| | | width: 90vw; |
| | | max-width: 500px; |
| | | min-height: 300px; |
| | | } |
| | | |
| | | /* 扫描步骤样式 */ |
| | | .scan-step { |
| | | text-align: center; |
| | | padding: 40px 20px; |
| | | } |
| | | |
| | | /* 已有记录步骤样式 */ |
| | | .existing-record-step { |
| | | padding: 20px; |
| | | text-align: center; |
| | | } |
| | | |
| | | .existing-icon { |
| | | font-size: 48px; |
| | | text-align: center; |
| | | margin-bottom: 16px; |
| | | } |
| | | |
| | | .existing-title { |
| | | font-size: 18px; |
| | | font-weight: 600; |
| | | color: #2c3e50; |
| | | text-align: center; |
| | | margin-bottom: 12px; |
| | | } |
| | | |
| | | .existing-description { |
| | | font-size: 14px; |
| | | color: #7f8c8d; |
| | | text-align: center; |
| | | margin-bottom: 20px; |
| | | } |
| | | |
| | | /* 当前破坏实验数量显示 */ |
| | | .current-phsy-display { |
| | | margin: 20px 0; |
| | | padding: 16px; |
| | | background: linear-gradient(135deg, #f8f9fa, #e9ecef); |
| | | border-radius: 8px; |
| | | border: 1px solid #dee2e6; |
| | | box-shadow: 0 2px 4px rgba(0,0,0,0.05); |
| | | } |
| | | |
| | | .phsy-info { |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: center; |
| | | gap: 8px; |
| | | } |
| | | |
| | | .phsy-label { |
| | | font-size: 16px; |
| | | font-weight: 600; |
| | | color: #495057; |
| | | } |
| | | |
| | | .phsy-value { |
| | | font-size: 18px; |
| | | font-weight: 700; |
| | | color: #e74c3c; |
| | | background-color: #fff; |
| | | padding: 4px 12px; |
| | | border-radius: 4px; |
| | | border: 1px solid #e74c3c; |
| | | } |
| | | |
| | | .scan-icon { |
| | | font-size: 64px; |
| | | margin-bottom: 20px; |
| | | opacity: 0.8; |
| | | } |
| | | |
| | | .scan-title { |
| | | font-size: 20px; |
| | | font-weight: 600; |
| | | color: #2c3e50; |
| | | margin-bottom: 12px; |
| | | } |
| | | |
| | | .scan-description { |
| | | font-size: 14px; |
| | | color: #7f8c8d; |
| | | margin-bottom: 30px; |
| | | line-height: 1.5; |
| | | } |
| | | |
| | | /* 扫描步骤按钮布局 */ |
| | | .scan-actions { |
| | | display: flex; |
| | | gap: 12px; |
| | | justify-content: center; |
| | | align-items: center; |
| | | } |
| | | |
| | | /* 结果步骤样式 */ |
| | | .result-step { |
| | | padding: 20px; |
| | | } |
| | | |
| | | .scan-success-icon { |
| | | font-size: 48px; |
| | | text-align: center; |
| | | margin-bottom: 16px; |
| | | } |
| | | |
| | | .scan-success-title { |
| | | font-size: 18px; |
| | | font-weight: 600; |
| | | color: #27ae60; |
| | | text-align: center; |
| | | margin-bottom: 20px; |
| | | } |
| | | |
| | | /* 破坏实验操作按钮样式 */ |
| | | .destruction-actions { |
| | | display: flex; |
| | | gap: 8px; |
| | | margin-top: 24px; |
| | | justify-content: center; |
| | | flex-wrap: wrap; |
| | | } |
| | | |
| | | .destruction-btn { |
| | | padding: 10px 16px; |
| | | border: none; |
| | | border-radius: 8px; |
| | | font-size: 14px; |
| | | font-weight: 600; |
| | | cursor: pointer; |
| | | transition: all 0.3s ease; |
| | | min-width: 80px; |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: center; |
| | | flex: 1; |
| | | max-width: 120px; |
| | | } |
| | | |
| | | .destruction-btn.confirm-btn { |
| | | background: linear-gradient(135deg, #27ae60, #2ecc71); |
| | | color: white; |
| | | box-shadow: 0 2px 8px rgba(39, 174, 96, 0.3); |
| | | } |
| | | |
| | | .destruction-btn.confirm-btn:hover:not(:disabled) { |
| | | background: linear-gradient(135deg, #229954, #27ae60); |
| | | transform: translateY(-1px); |
| | | box-shadow: 0 4px 12px rgba(39, 174, 96, 0.4); |
| | | } |
| | | |
| | | .destruction-btn.confirm-btn:disabled { |
| | | background: #bdc3c7; |
| | | color: #7f8c8d; |
| | | cursor: not-allowed; |
| | | transform: none; |
| | | box-shadow: none; |
| | | } |
| | | |
| | | .destruction-btn.cancel-btn { |
| | | background: linear-gradient(135deg, #95a5a6, #7f8c8d); |
| | | color: white; |
| | | box-shadow: 0 2px 8px rgba(149, 165, 166, 0.3); |
| | | } |
| | | |
| | | .destruction-btn.cancel-btn:hover { |
| | | background: linear-gradient(135deg, #7f8c8d, #6c7b7d); |
| | | transform: translateY(-1px); |
| | | box-shadow: 0 4px 12px rgba(149, 165, 166, 0.4); |
| | | } |
| | | |
| | | .destruction-btn.modify-btn { |
| | | background: linear-gradient(135deg, #f39c12, #e67e22); |
| | | color: white; |
| | | box-shadow: 0 2px 8px rgba(243, 156, 18, 0.3); |
| | | } |
| | | |
| | | .destruction-btn.modify-btn:hover { |
| | | background: linear-gradient(135deg, #e67e22, #d35400); |
| | | transform: translateY(-1px); |
| | | box-shadow: 0 4px 12px rgba(243, 156, 18, 0.4); |
| | | } |
| | | |
| | | .destruction-btn.delete-btn { |
| | | background: linear-gradient(135deg, #e74c3c, #c0392b); |
| | | color: white; |
| | | box-shadow: 0 2px 8px rgba(231, 76, 60, 0.3); |
| | | } |
| | | |
| | | .destruction-btn.delete-btn:hover { |
| | | background: linear-gradient(135deg, #c0392b, #a93226); |
| | | transform: translateY(-1px); |
| | | box-shadow: 0 4px 12px rgba(231, 76, 60, 0.4); |
| | | } |
| | | |
| | | /* 表单输入框样式优化 */ |
| | | .form-input { |
| | | width: 100%; |
| | | padding: 12px 16px; |
| | | border: 2px solid #e9ecef; |
| | | border-radius: 8px; |
| | | font-size: 16px; |
| | | transition: border-color 0.3s ease; |
| | | box-sizing: border-box; |
| | | background-color: #fff !important; |
| | | color: #333 !important; |
| | | -webkit-appearance: none; |
| | | -moz-appearance: none; |
| | | appearance: none; |
| | | -webkit-user-select: text !important; |
| | | -moz-user-select: text !important; |
| | | -ms-user-select: text !important; |
| | | user-select: text !important; |
| | | pointer-events: auto !important; |
| | | opacity: 1 !important; |
| | | z-index: 1 !important; |
| | | } |
| | | |
| | | .form-input:focus { |
| | | border-color: #3498db; |
| | | outline: none; |
| | | box-shadow: 0 0 0 3px rgba(52, 152, 219, 0.1); |
| | | background-color: #fff; |
| | | } |
| | | |
| | | /* 简单输入框样式 - 参考SJ.vue */ |
| | | .info-input { |
| | | flex: 1; |
| | | padding: 12px 16px; |
| | | border: 2px solid #ddd; |
| | | border-radius: 6px; |
| | | background-color: white; |
| | | font-size: 16px; |
| | | width: 100%; |
| | | box-sizing: border-box; |
| | | min-height: 44px; |
| | | line-height: 1.4; |
| | | } |
| | | |
| | | .info-input:focus { |
| | | border-color: #3498db; |
| | | outline: none; |
| | | box-shadow: 0 0 0 3px rgba(52, 152, 219, 0.1); |
| | | } |
| | | |
| | | /* 输入框包装器 */ |
| | | .input-wrapper { |
| | | position: relative; |
| | | width: 100%; |
| | | } |
| | | |
| | | /* 破坏实验输入框特殊样式 */ |
| | | .destruction-input { |
| | | background-color: #fff !important; |
| | | border: 2px solid #e9ecef !important; |
| | | color: #333 !important; |
| | | font-size: 16px !important; |
| | | padding: 12px 16px !important; |
| | | width: 100% !important; |
| | | box-sizing: border-box !important; |
| | | -webkit-user-select: text !important; |
| | | -moz-user-select: text !important; |
| | | -ms-user-select: text !important; |
| | | user-select: text !important; |
| | | -webkit-appearance: none !important; |
| | | -moz-appearance: none !important; |
| | | appearance: none !important; |
| | | pointer-events: auto !important; |
| | | opacity: 1 !important; |
| | | z-index: 1 !important; |
| | | } |
| | | |
| | | .destruction-input:focus { |
| | | border-color: #3498db !important; |
| | | background-color: #fff !important; |
| | | outline: none !important; |
| | | box-shadow: 0 0 0 3px rgba(52, 152, 219, 0.1) !important; |
| | | } |
| | | |
| | | .destruction-input:disabled { |
| | | background-color: #f5f5f5 !important; |
| | | color: #999 !important; |
| | | cursor: not-allowed !important; |
| | | } |
| | | |
| | | /* uni-easyinput 样式 */ |
| | | .destruction-input-uni { |
| | | width: 100% !important; |
| | | } |
| | | |
| | | .destruction-input-uni .uni-easyinput__content { |
| | | border: 2px solid #e9ecef !important; |
| | | border-radius: 8px !important; |
| | | background-color: #fff !important; |
| | | } |
| | | |
| | | .destruction-input-uni .uni-easyinput__content-input { |
| | | font-size: 16px !important; |
| | | color: #333 !important; |
| | | padding: 12px 16px !important; |
| | | } |
| | | |
| | | /* 模拟输入框样式 */ |
| | | .fake-input { |
| | | width: 100%; |
| | | padding: 12px 16px; |
| | | border: 2px solid #e9ecef; |
| | | border-radius: 8px; |
| | | background-color: #fff; |
| | | font-size: 16px; |
| | | color: #333; |
| | | cursor: pointer; |
| | | transition: border-color 0.3s ease; |
| | | box-sizing: border-box; |
| | | min-height: 44px; |
| | | display: flex; |
| | | align-items: center; |
| | | } |
| | | |
| | | .fake-input:hover { |
| | | border-color: #3498db; |
| | | } |
| | | |
| | | .fake-input.error { |
| | | border-color: #e74c3c; |
| | | } |
| | | |
| | | .fake-input .placeholder { |
| | | color: #999; |
| | | } |
| | | |
| | | /* 简化的输入框样式 */ |
| | | .simple-input { |
| | | width: 100%; |
| | | padding: 12px 16px; |
| | | border: 2px solid #e9ecef; |
| | | border-radius: 8px; |
| | | font-size: 16px; |
| | | color: #333; |
| | | background-color: #fff; |
| | | box-sizing: border-box; |
| | | outline: none; |
| | | -webkit-appearance: none; |
| | | -moz-appearance: none; |
| | | appearance: none; |
| | | -webkit-user-select: text; |
| | | -moz-user-select: text; |
| | | -ms-user-select: text; |
| | | user-select: text; |
| | | -webkit-tap-highlight-color: transparent; |
| | | } |
| | | |
| | | .simple-input:focus { |
| | | border-color: #3498db; |
| | | -webkit-user-select: text; |
| | | -moz-user-select: text; |
| | | -ms-user-select: text; |
| | | user-select: text; |
| | | } |
| | | |
| | | /* 重新设计的输入区域样式 */ |
| | | .input-section { |
| | | margin: 20px 0; |
| | | padding: 20px; |
| | | background: #f8f9fa; |
| | | border-radius: 12px; |
| | | border: 1px solid #e9ecef; |
| | | } |
| | | |
| | | .input-title { |
| | | font-size: 16px; |
| | | font-weight: 600; |
| | | color: #2c3e50; |
| | | margin-bottom: 12px; |
| | | text-align: center; |
| | | } |
| | | |
| | | .input-container { |
| | | display: flex; |
| | | justify-content: center; |
| | | margin-bottom: 8px; |
| | | } |
| | | |
| | | .input-box { |
| | | width: 200px; |
| | | height: 50px; |
| | | border: 2px solid #3498db; |
| | | border-radius: 8px; |
| | | background-color: #fff; |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: center; |
| | | cursor: pointer; |
| | | transition: all 0.3s ease; |
| | | box-shadow: 0 2px 4px rgba(0,0,0,0.1); |
| | | } |
| | | |
| | | .input-box:hover { |
| | | border-color: #2980b9; |
| | | box-shadow: 0 4px 8px rgba(0,0,0,0.15); |
| | | transform: translateY(-1px); |
| | | } |
| | | |
| | | .input-box:active { |
| | | transform: translateY(0); |
| | | box-shadow: 0 2px 4px rgba(0,0,0,0.1); |
| | | } |
| | | |
| | | .input-value { |
| | | font-size: 18px; |
| | | font-weight: 600; |
| | | color: #2c3e50; |
| | | } |
| | | |
| | | .input-placeholder { |
| | | font-size: 16px; |
| | | color: #7f8c8d; |
| | | font-style: italic; |
| | | } |
| | | |
| | | .error-tip { |
| | | text-align: center; |
| | | color: #e74c3c; |
| | | font-size: 14px; |
| | | margin-top: 8px; |
| | | } |
| | | |
| | | .form-label { |
| | | display: block; |
| | | font-weight: 600; |
| | | color: #2c3e50; |
| | | margin-bottom: 8px; |
| | | font-size: 14px; |
| | | } |
| | | |
| | | .form-group { |
| | | margin-bottom: 20px; |
| | | } |
| | | |
| | | /* 错误信息样式 */ |
| | | .error-message { |
| | | color: #e74c3c; |
| | | font-size: 12px; |
| | | margin-top: 4px; |
| | | text-align: center; |
| | | } |
| | | |
| | | /* 堵穴相关样式 */ |
| | | .block-hole-btn { |
| | | background-color: #f39c12; |
| | | color: white; |
| | | padding: 6px 12px; |
| | | border: none; |
| | | border-radius: 4px; |
| | | cursor: pointer; |
| | | font-size: 12px; |
| | | transition: all 0.3s ease; |
| | | } |
| | | |
| | | .block-hole-btn:hover:not(.disabled) { |
| | | background-color: #e67e22; |
| | | transform: translateY(-1px); |
| | | } |
| | | |
| | | .block-hole-btn.disabled { |
| | | background-color: #bdc3c7; |
| | | color: #7f8c8d; |
| | | cursor: not-allowed; |
| | | } |
| | | |
| | | .blocked-info { |
| | | color: #e74c3c; |
| | | font-size: 12px; |
| | | margin-left: 8px; |
| | | font-weight: bold; |
| | | } |
| | | |
| | | .block-hole-popup, |
| | | .global-block-hole-popup { |
| | | width: 80vw; |
| | | max-width: 500px; |
| | | min-height: 300px; |
| | | } |
| | | |
| | | .block-hole-content { |
| | | padding: 20px; |
| | | } |
| | | |
| | | .hole-info { |
| | | margin-bottom: 20px; |
| | | padding: 15px; |
| | | background-color: #f8f9fa; |
| | | border-radius: 8px; |
| | | border: 1px solid #e9ecef; |
| | | } |
| | | |
| | | .hole-info .info-label { |
| | | font-weight: 600; |
| | | color: #495057; |
| | | margin-bottom: 8px; |
| | | display: block; |
| | | } |
| | | |
| | | .input-section { |
| | | margin-bottom: 20px; |
| | | } |
| | | |
| | | .input-label { |
| | | font-weight: 600; |
| | | color: #495057; |
| | | margin-bottom: 8px; |
| | | display: block; |
| | | } |
| | | |
| | | .block-hole-input { |
| | | width: 100%; |
| | | padding: 12px 16px; |
| | | border: 2px solid #e9ecef; |
| | | border-radius: 8px; |
| | | font-size: 16px; |
| | | transition: border-color 0.3s ease; |
| | | box-sizing: border-box; |
| | | background-color: #fff !important; |
| | | color: #333 !important; |
| | | -webkit-user-select: text !important; |
| | | -moz-user-select: text !important; |
| | | -ms-user-select: text !important; |
| | | user-select: text !important; |
| | | pointer-events: auto !important; |
| | | opacity: 1 !important; |
| | | /* 移除z-index,避免遮挡弹窗 */ |
| | | } |
| | | |
| | | .block-hole-input:focus { |
| | | border-color: #3498db; |
| | | outline: none; |
| | | box-shadow: 0 0 0 3px rgba(52, 152, 219, 0.1); |
| | | } |
| | | |
| | | .block-hole-actions { |
| | | display: flex; |
| | | gap: 12px; |
| | | justify-content: center; |
| | | margin-top: 20px; |
| | | } |
| | | |
| | | .block-hole-btn.confirm { |
| | | background: linear-gradient(135deg, #27ae60, #2ecc71); |
| | | color: white; |
| | | padding: 12px 24px; |
| | | min-width: 100px; |
| | | } |
| | | |
| | | .block-hole-btn.confirm:hover:not(:disabled) { |
| | | background: linear-gradient(135deg, #229954, #27ae60); |
| | | } |
| | | |
| | | .block-hole-btn.confirm:disabled { |
| | | background: #bdc3c7; |
| | | color: #7f8c8d; |
| | | cursor: not-allowed; |
| | | } |
| | | |
| | | .block-hole-btn.cancel { |
| | | background: linear-gradient(135deg, #95a5a6, #7f8c8d); |
| | | color: white; |
| | | padding: 12px 24px; |
| | | min-width: 100px; |
| | | } |
| | | |
| | | .block-hole-btn.cancel:hover { |
| | | background: linear-gradient(135deg, #7f8c8d, #6c7b7d); |
| | | } |
| | | |
| | | |
| | | .blocked-holes-info { |
| | | color: #e74c3c; |
| | | font-weight: bold; |
| | | margin-left: 8px; |
| | | } |
| | | </style> |