JhHardwareWRS/pages/review/review.wxml
2026-07-25 21:12:17 +08:00

352 lines
20 KiB
Plaintext

<scroll-view
class="page safe-bottom"
scroll-y
type="list"
scroll-top="{{scrollTop}}"
scroll-anchoring="{{true}}"
refresher-enabled
refresher-triggered="{{refreshing}}"
bindscroll="onScroll"
bindrefresherrefresh="onPullDownRefresh"
>
<view class="header">
<view class="review-header-row">
<view class="review-header-main">
<text class="title">报工审核</text>
<text class="subtitle">复核并校正员工上报数据后通过</text>
</view>
<view class="top-action-group">
<view class="void-filter-switch">
<text>过滤作废</text>
<switch checked="{{filterVoided}}" color="#1463ff" bindchange="onFilterVoidedChange" />
</view>
<button class="btn mini secondary detail-toggle" bindtap="toggleDetails">
{{detailExpandedAll ? '收起明细' : '展开明细'}}
</button>
</view>
</view>
</view>
<view wx:if="{{!rows.length}}" class="list-empty">暂无待审核报工</view>
<view
wx:for="{{rows}}"
wx:key="id"
wx:for-index="reportIndex"
id="review-report-{{item.id}}"
class="card review-card {{item.isSystemAutoSubmitted ? 'system-auto' : ''}} {{item.isVoided ? 'voided' : ''}} {{detailExpandedAll || expandedReportId == item.id ? 'expanded' : ''}}"
data-id="{{item.id}}"
bindtap="toggleReportDetail"
>
<text wx:if="{{item.hasOverLimit}}" class="over-limit-watermark {{item.watermarkClasses.overLimit}}">超额</text>
<text wx:if="{{item.isVoided}}" class="voided-watermark {{item.watermarkClasses.state}}">作废</text>
<text wx:elif="{{item.isModified}}" class="modified-watermark {{item.watermarkClasses.state}}">更改</text>
<text wx:if="{{item.isSystemAutoSubmitted}}" class="timeout-watermark {{item.watermarkClasses.timeout}}">{{item.autoSubmitReason || '超时-系统自动提交'}}</text>
<text wx:if="{{item.isCleaning}}" class="cleaning-watermark {{item.watermarkClasses.cleaning}}">清洗</text>
<text wx:if="{{item.hasMisc}}" class="misc-watermark {{item.watermarkClasses.misc}}">包含杂活</text>
<text wx:if="{{item.hasMultiPerson}}" class="multi-person-watermark {{item.watermarkClasses.multiPerson}}">多人协作</text>
<text wx:if="{{item.hasContinuousDie}}" class="continuous-die-watermark {{item.watermarkClasses.continuousDie}}">连续模</text>
<view class="row">
<view class="row-left">
<text class="value">{{item.employeeName}} · {{item.reportDate}}</text>
<text class="subtitle">考勤点 {{item.attendancePointName || '-'}}</text>
<text class="subtitle">{{item.timeRangeText}}</text>
<text class="subtitle">{{item.metrics.shiftDistributionText || ''}}</text>
<text wx:if="{{item.allocationSummaryText}}" class="allocation-summary">归属拆分:{{item.allocationSummaryText}}</text>
</view>
<text class="pill {{item.status === 'approved' ? 'success' : 'warn'}}">{{item.statusName}}</text>
</view>
<view wx:if="{{detailExpandedAll || expandedReportId == item.id}}" catchtap="noop">
<view class="divider"></view>
<view wx:if="{{!item.isCleaning && !item.isVoided && item.canEdit}}" class="review-edit-panel">
<text class="panel-title">上下班时间校正</text>
<view class="time-grid">
<picker mode="date" value="{{item.editStartDate}}" data-report-index="{{reportIndex}}" data-field="editStartDate" bindchange="onReportFieldChange">
<view class="picker compact-picker">{{item.editStartDate || '上班日期'}}</view>
</picker>
<picker mode="time" value="{{item.editStartTime}}" data-report-index="{{reportIndex}}" data-field="editStartTime" bindchange="onReportFieldChange">
<view class="picker compact-picker">{{item.editStartTime || '上班时间'}}</view>
</picker>
<picker mode="date" value="{{item.editEndDate}}" data-report-index="{{reportIndex}}" data-field="editEndDate" bindchange="onReportFieldChange">
<view class="picker compact-picker">{{item.editEndDate || '下班日期'}}</view>
</picker>
<picker mode="time" value="{{item.editEndTime}}" data-report-index="{{reportIndex}}" data-field="editEndTime" bindchange="onReportFieldChange">
<view class="picker compact-picker">{{item.editEndTime || '下班时间'}}</view>
</picker>
</view>
</view>
<view class="item-list">
<view wx:for="{{item.editItems}}" wx:key="id" wx:for-item="detail" wx:for-index="itemIndex" class="detail-line {{detail.isMultiPerson || detail.isContinuousDie ? 'marked-detail-line' : ''}} {{detail.isMultiPerson && detail.isContinuousDie ? 'stacked-detail-line' : ''}}">
<text wx:if="{{detail.isMultiPerson}}" class="detail-multi-stamp">多人协作</text>
<text wx:if="{{detail.isContinuousDie}}" class="detail-continuous-stamp {{detail.isMultiPerson ? 'lower-detail-stamp' : ''}}">连续模</text>
<text class="detail-title">{{detail.deviceNo}} · {{detail.productName}} / {{detail.process || '-'}} / {{detail.stampingMethod || '-'}}</text>
<text class="muted">考勤点 {{detail.attendancePointName || item.attendancePointName || '-'}}</text>
<text wx:if="{{detail.isMisc}}" class="muted">处理杂活 · {{detail.workTimeText}}</text>
<text wx:elif="{{detail.isCleaning}}" class="muted">工序 {{detail.process || '-'}} · 冲压方式 {{detail.stampingMethod || '-'}} · 清洗数量 {{detail.goodQty}}</text>
<text wx:else class="muted">工序 {{detail.process || '-'}} · 冲压方式 {{detail.stampingMethod || '-'}} · 成品 {{detail.goodQty}} · 不良 {{detail.defectQty}}</text>
<text wx:if="{{!detail.isCleaning && !detail.isMisc}}" class="muted">材料库存批次号 {{detail.rawMaterialBatchNo || '-'}}</text>
<view wx:if="{{!detail.isCleaning && !detail.isMisc && detail.deviceSegments.length && !item.isVoided && item.canEdit}}" class="device-time-inline">
<text class="panel-title device-time-title">换模具时间校正</text>
<view
wx:for="{{detail.deviceSegments}}"
wx:key="id"
wx:for-item="segment"
wx:for-index="segmentIndex"
class="device-time-row"
>
<view class="device-time-main">
<text class="value">{{segment.label}} · {{segment.displayName}}</text>
<text class="subtitle">原记录 {{segment.scannedAtText}}</text>
</view>
<view class="device-time-pickers">
<picker mode="date" value="{{segment.editScanDate}}" data-report-index="{{reportIndex}}" data-item-index="{{itemIndex}}" data-segment-index="{{segmentIndex}}" data-field="editScanDate" bindchange="onDeviceSegmentFieldChange">
<view class="picker compact-picker">{{segment.editScanDate || '日期'}}</view>
</picker>
<picker mode="time" value="{{segment.editScanTime}}" data-report-index="{{reportIndex}}" data-item-index="{{itemIndex}}" data-segment-index="{{segmentIndex}}" data-field="editScanTime" bindchange="onDeviceSegmentFieldChange">
<view class="picker compact-picker">{{segment.editScanTime || '时间'}}</view>
</picker>
</view>
</view>
</view>
<view wx:if="{{detail.isMisc}}" class="detail-metric-grid">
<view>
<text class="label">工时</text>
<text class="value">{{detail.workTimeText}}</text>
</view>
<view>
<text class="label">杂活事项</text>
<text class="value">{{detail.remark || '待备注'}}</text>
</view>
</view>
<view wx:elif="{{detail.isCleaning}}" class="detail-metric-grid">
<view>
<text class="label">清洗数量</text>
<text class="value">{{detail.goodQty}}</text>
</view>
<view>
<text class="label">工时</text>
<text class="value">{{detail.workTimeText}}</text>
</view>
</view>
<view wx:else class="detail-metric-grid">
<view>
<text class="label">工时</text>
<text class="value">{{detail.workTimeText}}</text>
</view>
<view>
<text class="label">成品 / 标准工作量</text>
<text class="value {{detail.workloadCompareClass}}">
{{detail.goodQty}} / {{detail.standardWorkload}}
<text wx:if="{{detail.workloadReason}}" class="metric-reason">{{detail.workloadReason}}</text>
</text>
</view>
<view>
<text class="label">实际节拍</text>
<text class="value {{detail.beatCompareClass}}">
{{detail.actualBeat}} 秒
<text wx:if="{{detail.beatReason}}" class="metric-reason">{{detail.beatReason}}</text>
</text>
</view>
<view>
<text class="label">标准节拍</text>
<text class="value">{{detail.standardBeat}} 秒</text>
</view>
<view wx:if="{{detail.isContinuousDie}}">
<text class="label">换料次数</text>
<text class="value">{{detail.changeoverCount || 0}}</text>
</view>
</view>
<view wx:if="{{detail.hasOverLimitNotice}}" class="over-limit-panel {{detail.hasOverLimit ? 'danger' : 'warn'}}">
<text class="over-limit-title">{{detail.hasOverLimit ? '超额' : '无法校验'}}</text>
<text class="over-limit-text">{{detail.overLimitReason || '-'}}</text>
<view class="over-limit-grid">
<text>本次消耗 {{detail.overLimitCurrentReportQtyText}}</text>
<text>累计消耗 {{detail.overLimitCurrentCumulativeQtyText}}</text>
<text wx:if="{{detail.hasOverLimitMaxReportableQty}}">最大可报 {{detail.overLimitMaxReportableQtyText}}</text>
<text wx:if="{{detail.hasOverLimitPreviousGoodQty}}">前序可用 {{detail.overLimitPreviousGoodQtyText}}</text>
</view>
</view>
<view wx:if="{{detail.isMisc && !item.isVoided && item.canEdit}}" class="review-edit-panel misc-remark-panel">
<text class="panel-title">杂活事项备注</text>
<textarea
class="input misc-remark-input"
value="{{detail.remark}}"
placeholder="请输入处理杂活事项,便于经理监督留痕"
data-report-index="{{reportIndex}}"
data-item-index="{{itemIndex}}"
data-field="remark"
bindinput="onItemInput"
/>
</view>
<view wx:if="{{!detail.isMisc && !item.isVoided && item.canEdit}}" class="form-grid review-form-grid">
<view class="form-item">
<text class="label">设备号</text>
<picker
wx:if="{{detail.equipmentOptions.length}}"
mode="selector"
range="{{detail.equipmentOptions}}"
range-key="deviceNo"
value="{{detail.deviceIndex}}"
data-report-index="{{reportIndex}}"
data-item-index="{{itemIndex}}"
bindchange="onDeviceChange"
>
<view class="device-select-control {{detail.deviceError ? 'field-error' : ''}}">
<text class="device-select-text">{{detail.deviceNo || (detail.isCleaning ? '请选择清洗设备号' : '请选择冲压设备号')}}</text>
<text class="device-select-action">选择</text>
</view>
</picker>
<view wx:else class="readonly {{detail.deviceError ? 'field-error' : ''}}">暂无可选设备</view>
</view>
<view class="form-item full-span product-correction-row">
<text class="label">产品/工序更正</text>
<view class="product-correction-actions">
<button class="btn primary full" data-report-index="{{reportIndex}}" data-item-index="{{itemIndex}}" bindtap="openProductModal">更正产品</button>
<button class="btn secondary full" data-report-index="{{reportIndex}}" data-item-index="{{itemIndex}}" bindtap="restoreProduct">恢复</button>
</view>
</view>
<view class="form-item full-span">
<text class="label">产品名称</text>
<view class="readonly product-readonly">{{detail.projectNo}} · {{detail.productName}}</view>
</view>
<view class="form-item">
<text class="label">工序</text>
<view class="readonly product-readonly">{{detail.process || '未填写工序'}}</view>
</view>
<view class="form-item">
<text class="label">冲压方式</text>
<view class="readonly product-readonly">{{detail.stampingMethod || '-'}}</view>
</view>
<view wx:if="{{detail.isContinuousDie}}" class="form-item">
<text class="label">换料次数</text>
<input
class="input number-input {{detail.changeoverCountError ? 'field-error' : ''}}"
type="number"
value="{{detail.changeoverCount}}"
data-report-index="{{reportIndex}}"
data-item-index="{{itemIndex}}"
data-field="changeoverCount"
bindinput="onItemInput"
/>
</view>
<view class="form-item">
<text class="label">{{detail.isCleaning ? '清洗数量' : '成品数量'}}</text>
<input
class="input number-input"
type="digit"
value="{{detail.goodQty}}"
data-report-index="{{reportIndex}}"
data-item-index="{{itemIndex}}"
data-field="goodQty"
bindinput="onItemInput"
/>
</view>
<view wx:if="{{!detail.isCleaning}}" class="form-item">
<text class="label">不良数量</text>
<input
class="input number-input"
type="digit"
value="{{detail.defectQty}}"
data-report-index="{{reportIndex}}"
data-item-index="{{itemIndex}}"
data-field="defectQty"
bindinput="onItemInput"
/>
</view>
</view>
</view>
</view>
<view wx:if="{{!item.isVoided && item.canEdit}}" class="review-edit-panel review-remark-panel">
<text class="panel-title">审核备注</text>
<textarea
class="input review-remark-input"
value="{{item.editReviewRemark}}"
placeholder="请输入本条报工的审核备注"
maxlength="500"
data-report-index="{{reportIndex}}"
data-field="editReviewRemark"
bindinput="onReportFieldChange"
/>
</view>
<view wx:elif="{{item.reviewRemark}}" class="review-edit-panel review-remark-panel">
<text class="panel-title">审核备注</text>
<text class="readonly-text">{{item.reviewRemark}}</text>
</view>
<view wx:if="{{(!item.isVoided && (item.canEdit || item.canVoid)) || (item.isVoided && item.canUnvoid)}}" class="button-row review-action-row">
<button wx:if="{{!item.isVoided && item.canEdit}}" class="btn primary review-action-btn" data-id="{{item.id}}" bindtap="approve">{{item.status === 'approved' ? '保存更改' : '校正并审核通过'}}</button>
<button wx:if="{{!item.isVoided && item.canVoid}}" class="btn danger review-action-btn" data-id="{{item.id}}" catchtap="voidReport">作废</button>
<button wx:if="{{item.isVoided && item.canUnvoid}}" class="btn secondary review-action-btn" data-id="{{item.id}}" catchtap="unvoidReport">撤销作废</button>
</view>
</view>
</view>
<view class="button-row pager-row" wx:if="{{rows.length && !focusReportId}}">
<button class="btn secondary pager-nav" bindtap="prevPage" disabled="{{page <= 1}}">上一页</button>
<view class="page-jump-control">
<input class="page-jump-input" type="number" confirm-type="done" value="{{pageInput}}" bindinput="onPageInput" bindconfirm="jumpToPage" />
<text class="page-total-label">/ {{totalPages}}</text>
<text class="page-jump-action" bindtap="jumpToPage">跳</text>
</view>
<button class="btn secondary pager-nav" bindtap="nextPage" disabled="{{page >= totalPages}}">下一页</button>
</view>
</scroll-view>
<view wx:if="{{productModalVisible}}" class="modal-mask product-select-mask" catchtap="closeProductModal">
<view class="modal-panel product-select-panel" catchtap="noop">
<view class="modal-head">
<view>
<text class="modal-title">产品清单</text>
<text class="modal-subtitle">选择正确的产品、工序和冲压方式后替换当前报工明细</text>
</view>
<button class="btn mini secondary modal-close" bindtap="closeProductModal">关闭</button>
</view>
<input
class="input product-select-search"
value="{{productModalKeyword}}"
placeholder="搜索产品、物料、供应商、工序、冲压方式"
bindinput="onProductModalKeywordInput"
/>
<view wx:if="{{!productModalRows.length && !productModalLoading}}" class="list-empty">暂无可替换产品</view>
<view wx:for="{{productModalRows}}" wx:key="uniqueKey" wx:for-index="productIndex" class="card product-select-card">
<view class="row">
<view class="row-left">
<text class="value">{{item.productName}}</text>
<text class="subtitle">考勤点 {{item.attendancePointName || '-'}}</text>
<text class="subtitle">{{item.projectNo}} · {{item.materialCode || '-'}}</text>
<text class="subtitle">工序 {{item.processDisplay || item.process || '-'}} · 冲压方式 {{item.stampingMethod || '-'}}</text>
<text class="subtitle">物料名称 {{item.materialName || '-'}}</text>
</view>
<text class="pill primary">{{item.processDisplay || item.process || '工序'}}</text>
<text wx:if="{{item.isCleaning}}" class="cleaning-watermark product-select-stamp">清洗</text>
<text wx:if="{{item.isMisc}}" class="misc-watermark product-select-stamp">杂活</text>
<text wx:if="{{item.isMultiPerson}}" class="multi-person-watermark product-select-stamp">多人协作</text>
<text wx:if="{{item.isContinuousDie}}" class="continuous-die-watermark product-select-stamp">连续模</text>
</view>
<view class="divider"></view>
<view wx:if="{{!item.isCleaning && !item.isMisc}}" class="row">
<text class="muted">标准节拍 {{item.standardBeat}} 秒</text>
</view>
<button class="btn primary full product-replace-btn" data-index="{{productIndex}}" bindtap="replaceProductFromModal">替换</button>
</view>
<view class="button-row pager-row product-select-pager" wx:if="{{productModalRows.length}}">
<button class="btn secondary pager-nav" bindtap="productModalPrevPage" disabled="{{productModalPage <= 1}}">上一页</button>
<view class="page-jump-control">
<input class="page-jump-input" type="number" confirm-type="done" value="{{productModalPageInput}}" bindinput="onProductModalPageInput" bindconfirm="jumpProductModalPage" />
<text class="page-total-label">/ {{productModalTotalPages}}</text>
<text class="page-jump-action" bindtap="jumpProductModalPage">跳</text>
</view>
<button class="btn secondary pager-nav" bindtap="productModalNextPage" disabled="{{productModalPage >= productModalTotalPages}}">下一页</button>
</view>
</view>
</view>