chore: initialize mini program frontend

This commit is contained in:
souplearn
2026-06-24 15:19:14 +08:00
commit fa73a3c184
96 changed files with 20561 additions and 0 deletions
+110
View File
@@ -0,0 +1,110 @@
const api = require('../../utils/api')
Page({
data: {
report: null,
},
async onLoad(options) {
try {
const report = await api.getReport(options.reportId)
this.setData({
report: {
...report,
itemResults: this.buildItemResults(report),
},
})
} catch (error) {
wx.showToast({ title: error.message, icon: 'none' })
}
},
round1(value) {
return Math.round(Number(value || 0) * 10) / 10
},
round2(value) {
return Math.round(Number(value || 0) * 100) / 100
},
buildCompareText(rate, fastLabel, slowLabel) {
return `${rate > 0 ? slowLabel : fastLabel}${Math.abs(this.round1(rate))}%`
},
buildWorkloadText(rate) {
return `${rate >= 0 ? '工作量大于标准工作量' : '工作量小于标准工作量'}${Math.abs(this.round1(rate))}%`
},
buildItemResults(report) {
return (report.items || []).map((item, index) => {
if (item.isMisc) {
return {
key: `${item.id || index}`,
title: '处理杂活',
subtitle: `考勤点 ${item.attendancePointName || report.attendancePointName || '-'} · 工序 ${item.process || '-'} · 冲压方式 ${item.stampingMethod || '-'}`,
goodQty: 0,
defectQty: 0,
workTimeText: item.workTimeText || '-',
resultText: '处理杂活工时已提交管理员审核,杂活事项由管理员备注留痕',
goodResult: true,
isMisc: true,
isMultiPerson: !!item.isMultiPerson,
isContinuousDie: !!item.isContinuousDie,
changeoverCount: item.changeoverCount || 0,
}
}
if (item.isCleaning) {
return {
key: `${item.id || index}`,
title: `清洗 · ${item.displayName || item.productName || '-'}`,
subtitle: `考勤点 ${item.attendancePointName || report.attendancePointName || '-'} · 项目 ${item.projectNo || '-'} · 工序 ${item.process || '-'} · 冲压方式 ${item.stampingMethod || '-'}`,
goodQty: this.round2(item.goodQty || 0),
defectQty: 0,
resultText: `清洗数量 ${this.round2(item.goodQty || 0)},已提交管理员审核`,
goodResult: true,
isCleaning: true,
isMultiPerson: !!item.isMultiPerson,
isContinuousDie: !!item.isContinuousDie,
changeoverCount: item.changeoverCount || 0,
}
}
const goodQty = Number(item.goodQty || 0)
const defectQty = Number(item.defectQty || 0)
const outputQty = goodQty + defectQty
const actualBeat = outputQty > 0 ? Number(item.allocatedMinutes || 0) * 60 / outputQty : 0
const standardBeat = Number(item.standardBeat || 0)
const standardWorkload = api.calculateStandardWorkload(item.allocatedMinutes, standardBeat) || Number(item.standardWorkload || 0)
const paceRate = standardBeat > 0 ? (actualBeat - standardBeat) / standardBeat * 100 : 0
const workloadRate = standardWorkload > 0 ? (goodQty - standardWorkload) / standardWorkload * 100 : 0
const paceText = this.buildCompareText(paceRate, '节拍快于标准节拍', '节拍慢于标准节拍')
const workloadText = this.buildWorkloadText(workloadRate)
const overStandardAbnormal = paceRate < -30 || workloadRate > 30
const underStandardAbnormal = paceRate > 0 || workloadRate < 0
const abnormal = overStandardAbnormal || underStandardAbnormal
const goodResult = !abnormal
const suffix = overStandardAbnormal
? '数据明显超出标准,请自我核对一下是不是报工时填错。'
: (goodResult ? '今天真的很棒呢!' : '后续需要加油喽!')
return {
key: `${item.id || index}`,
title: `${item.deviceNo || '-'} · ${item.displayName || item.productName || '-'}`,
subtitle: `考勤点 ${item.attendancePointName || report.attendancePointName || '-'} · 项目 ${item.projectNo || '-'} · 工序 ${item.process || '-'} · 冲压方式 ${item.stampingMethod || '-'}`,
actualBeat: this.round2(actualBeat),
standardBeat: this.round2(standardBeat),
goodQty: this.round2(goodQty),
defectQty: this.round2(defectQty),
standardWorkload: this.round1(standardWorkload),
resultText: `今日${paceText},今日${workloadText},${suffix}`,
goodResult,
overStandardAbnormal: abnormal,
isMultiPerson: !!item.isMultiPerson,
isContinuousDie: !!item.isContinuousDie,
changeoverCount: item.changeoverCount || 0,
}
})
},
goRecords() {
wx.redirectTo({
url: '/pages/records/records',
})
},
goHome() {
wx.reLaunch({
url: '/pages/index/index',
})
},
})
+4
View File
@@ -0,0 +1,4 @@
{
"navigationStyle": "custom",
"disableSwipeBack": true
}
+74
View File
@@ -0,0 +1,74 @@
<view class="page safe-bottom result-page">
<view class="result-nav">
<text class="result-nav-title">报工结果</text>
</view>
<view class="header">
<text class="title">报工成功</text>
<text class="subtitle">已提交管理员审核</text>
</view>
<block wx:if="{{report}}">
<view class="card">
<text wx:if="{{report.hasMisc}}" class="misc-watermark">包含杂活</text>
<text wx:if="{{report.hasMultiPerson}}" class="multi-person-watermark {{report.hasMisc ? 'lower-watermark' : ''}}">多人协作</text>
<text wx:if="{{report.hasContinuousDie}}" class="continuous-die-watermark {{report.hasMisc || report.hasMultiPerson ? 'lower-watermark' : ''}} {{report.hasMisc && report.hasMultiPerson ? 'third-watermark' : ''}}">连续模</text>
<text class="label">报工日期</text>
<text class="value">{{report.reportDate}}</text>
<text class="subtitle">考勤点 {{report.attendancePointName || '-'}}</text>
<text class="subtitle">{{report.metrics.shiftDistributionText}}</text>
<view class="divider"></view>
<view
wx:for="{{report.itemResults}}"
wx:key="key"
wx:for-item="result"
class="result-item {{result.goodResult ? 'good' : (result.overStandardAbnormal ? 'danger' : 'warn')}} {{result.isMultiPerson || result.isContinuousDie ? 'marked-result' : ''}} {{result.isMultiPerson && result.isContinuousDie ? 'stacked-result' : ''}}"
>
<text wx:if="{{result.isMultiPerson}}" class="result-multi-stamp">多人协作</text>
<text wx:if="{{result.isContinuousDie}}" class="result-continuous-stamp {{result.isMultiPerson ? 'lower-result-stamp' : ''}}">连续模</text>
<text class="result-title">{{result.title}}</text>
<text class="result-subtitle">{{result.subtitle}}</text>
<text class="result-text">{{result.resultText}}</text>
<view wx:if="{{result.isMisc}}" class="result-metrics">
<view>
<text class="label">工时</text>
<text class="value">{{result.workTimeText}}</text>
</view>
</view>
<view wx:elif="{{result.isCleaning}}" class="result-metrics">
<view>
<text class="label">清洗数量</text>
<text class="value">{{result.goodQty}}</text>
</view>
</view>
<view wx:else class="result-metrics">
<view>
<text class="label">实际节拍</text>
<text class="value">{{result.actualBeat}} 秒/件</text>
</view>
<view>
<text class="label">标准节拍</text>
<text class="value">{{result.standardBeat}} 秒/件</text>
</view>
<view>
<text class="label">成品数量</text>
<text class="value">{{result.goodQty}}</text>
</view>
<view>
<text class="label">标准工作量</text>
<text class="value">{{result.standardWorkload}}</text>
</view>
<view wx:if="{{result.isContinuousDie}}">
<text class="label">换料次数</text>
<text class="value">{{result.changeoverCount || 0}}</text>
</view>
</view>
</view>
</view>
<view class="button-row">
<button class="btn secondary full" bindtap="goRecords">查看记录</button>
<button class="btn primary full" bindtap="goHome">返回首页</button>
</view>
</block>
</view>
+125
View File
@@ -0,0 +1,125 @@
.result-page {
padding-top: 0;
}
.result-nav {
position: relative;
z-index: 2;
display: flex;
align-items: center;
justify-content: center;
height: 176rpx;
margin: 0 -24rpx 22rpx;
padding-top: 88rpx;
border-bottom: 1rpx solid rgba(213, 222, 235, 0.9);
background: rgba(247, 248, 250, 0.96);
box-sizing: border-box;
}
.result-nav-title {
color: #111827;
font-size: 34rpx;
font-weight: 700;
line-height: 1;
}
.result-item {
position: relative;
display: block;
margin-top: 18rpx;
padding: 20rpx;
border-radius: 16rpx;
box-sizing: border-box;
}
.result-item.marked-result {
padding-top: 62rpx;
}
.result-item.stacked-result {
padding-top: 104rpx;
}
.result-item .result-multi-stamp {
position: absolute;
right: 16rpx;
top: 14rpx;
padding: 6rpx 12rpx;
border: 2rpx solid rgba(217, 119, 6, 0.62);
border-radius: 10rpx;
color: rgba(154, 74, 5, 0.88);
background: rgba(255, 247, 232, 0.92);
font-size: 22rpx;
font-weight: 900;
line-height: 1;
}
.result-continuous-stamp {
position: absolute;
right: 16rpx;
top: 14rpx;
padding: 6rpx 12rpx;
border: 2rpx solid rgba(217, 119, 6, 0.62);
border-radius: 10rpx;
color: rgba(154, 74, 5, 0.88);
background: rgba(255, 247, 232, 0.92);
font-size: 22rpx;
font-weight: 900;
line-height: 1;
}
.result-continuous-stamp.lower-result-stamp {
top: 56rpx;
}
.result-item.good {
border: 1rpx solid #bfe8d4;
background: #eefaf4;
color: #087443;
}
.result-item.warn {
border: 1rpx solid #f7d7a8;
background: #fff7e8;
color: #9a4a05;
}
.result-item.danger {
border: 1rpx solid #f1b4b2;
background: #fff1f0;
color: #b42318;
}
.result-title {
display: block;
color: #162232;
font-size: 28rpx;
font-weight: 800;
line-height: 1.35;
}
.result-subtitle {
display: block;
margin-top: 8rpx;
color: #667085;
font-size: 24rpx;
font-weight: 600;
line-height: 1.4;
}
.result-text {
display: block;
margin-top: 16rpx;
font-size: 32rpx;
font-weight: 700;
line-height: 1.55;
}
.result-metrics {
display: grid;
grid-template-columns: repeat(2, minmax(0, 1fr));
gap: 14rpx 18rpx;
margin-top: 18rpx;
padding-top: 18rpx;
border-top: 1rpx solid rgba(102, 112, 133, 0.16);
}