34 KiB
Continuous Die Changeover Count Implementation Plan
For agentic workers: REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (
- [ ]) syntax for tracking.
Goal: Add the special stamping method 连续模, require/report 换料次数 for continuous die report items, and carry it through worker reporting, admin review, records, manager dashboard, and Excel export.
Architecture: Treat 连续模 as a special stamping method recognized by exact trimmed text, parallel to 清洗 but without changing normal work-time, device, beat, workload, lock, or wage rules. Store 换料次数 on production_report_items because it belongs to one product/process detail, not the whole report. Keep product 冲压方式 free-text with two suggested values, so field usage remains flexible for current shop-floor terms.
Tech Stack: FastAPI, SQLAlchemy, Pydantic, MySQL, openpyxl, WeChat Mini Program WXML/WXSS/JS.
File Map
Backend:
- Create:
/Users/souplearn/Gitlab/app/JhHardwareWRS_BackPoint/app/services/continuous_die.py - Create:
/Users/souplearn/Gitlab/app/JhHardwareWRS_BackPoint/scripts/migrate_continuous_die_changeover_count.py - Modify:
/Users/souplearn/Gitlab/app/JhHardwareWRS_BackPoint/app/models.py - Modify:
/Users/souplearn/Gitlab/app/JhHardwareWRS_BackPoint/app/schemas.py - Modify:
/Users/souplearn/Gitlab/app/JhHardwareWRS_BackPoint/app/services/serializers.py - Modify:
/Users/souplearn/Gitlab/app/JhHardwareWRS_BackPoint/app/routers/reports.py - Modify:
/Users/souplearn/Gitlab/app/JhHardwareWRS_BackPoint/app/routers/reviews.py - Modify:
/Users/souplearn/Gitlab/app/JhHardwareWRS_BackPoint/app/routers/dashboard.py - Modify:
/Users/souplearn/Gitlab/app/JhHardwareWRS_BackPoint/app/services/excel_export.py - Test:
/Users/souplearn/Gitlab/app/JhHardwareWRS_BackPoint/tests/test_continuous_die.py
Frontend:
- Modify:
/Users/souplearn/Gitlab/app/JhHardwareWRS/utils/api.js - Modify:
/Users/souplearn/Gitlab/app/JhHardwareWRS/pages/manageProducts/manageProducts.js - Modify:
/Users/souplearn/Gitlab/app/JhHardwareWRS/pages/manageProducts/manageProducts.wxml - Modify:
/Users/souplearn/Gitlab/app/JhHardwareWRS/pages/manageProducts/manageProducts.wxss - Modify:
/Users/souplearn/Gitlab/app/JhHardwareWRS/pages/deviceQr/deviceQr.wxml - Modify:
/Users/souplearn/Gitlab/app/JhHardwareWRS/pages/deviceQr/deviceQr.wxss - Modify:
/Users/souplearn/Gitlab/app/JhHardwareWRS/pages/reportForm/reportForm.js - Modify:
/Users/souplearn/Gitlab/app/JhHardwareWRS/pages/reportForm/reportForm.wxml - Modify:
/Users/souplearn/Gitlab/app/JhHardwareWRS/pages/reportForm/reportForm.wxss - Modify:
/Users/souplearn/Gitlab/app/JhHardwareWRS/pages/review/review.js - Modify:
/Users/souplearn/Gitlab/app/JhHardwareWRS/pages/review/review.wxml - Modify:
/Users/souplearn/Gitlab/app/JhHardwareWRS/pages/review/review.wxss - Modify:
/Users/souplearn/Gitlab/app/JhHardwareWRS/pages/records/records.wxml - Modify:
/Users/souplearn/Gitlab/app/JhHardwareWRS/pages/records/records.wxss - Modify:
/Users/souplearn/Gitlab/app/JhHardwareWRS/pages/dashboard/dashboard.wxml - Modify:
/Users/souplearn/Gitlab/app/JhHardwareWRS/pages/dashboard/dashboard.wxss - Modify:
/Users/souplearn/Gitlab/app/JhHardwareWRS/pages/reportResult/reportResult.js - Modify:
/Users/souplearn/Gitlab/app/JhHardwareWRS/pages/reportResult/reportResult.wxml - Modify:
/Users/souplearn/Gitlab/app/JhHardwareWRS/pages/reportResult/reportResult.wxss
Important non-goal:
- Do not include
换料次数in参考工资yet. Current wage formula is成品数量 * 工序单价; there is no maintained换料单价, so calculating extra pay now would require a hidden hard-coded price. This task only records and exports the count for later wage integration.
Task 1: Backend Continuous Die Recognition And Schema Field
Files:
-
Create:
/Users/souplearn/Gitlab/app/JhHardwareWRS_BackPoint/app/services/continuous_die.py -
Modify:
/Users/souplearn/Gitlab/app/JhHardwareWRS_BackPoint/app/models.py -
Modify:
/Users/souplearn/Gitlab/app/JhHardwareWRS_BackPoint/app/schemas.py -
Create:
/Users/souplearn/Gitlab/app/JhHardwareWRS_BackPoint/scripts/migrate_continuous_die_changeover_count.py -
Test:
/Users/souplearn/Gitlab/app/JhHardwareWRS_BackPoint/tests/test_continuous_die.py -
Step 1: Write the helper test
Add this to /Users/souplearn/Gitlab/app/JhHardwareWRS_BackPoint/tests/test_continuous_die.py:
from app.services.continuous_die import (
CONTINUOUS_DIE_STAMPING_METHOD,
is_continuous_die_stamping_method,
)
def test_continuous_die_stamping_method_is_trimmed_exact_match():
assert CONTINUOUS_DIE_STAMPING_METHOD == "连续模"
assert is_continuous_die_stamping_method("连续模") is True
assert is_continuous_die_stamping_method(" 连续模 ") is True
assert is_continuous_die_stamping_method("连续模具") is False
assert is_continuous_die_stamping_method("清洗") is False
assert is_continuous_die_stamping_method(None) is False
- Step 2: Run the new test and verify it fails
Run:
cd /Users/souplearn/Gitlab/app/JhHardwareWRS_BackPoint
.venv/bin/python -m pytest tests/test_continuous_die.py -q
Expected: FAIL because app.services.continuous_die does not exist.
- Step 3: Create the backend helper
Create /Users/souplearn/Gitlab/app/JhHardwareWRS_BackPoint/app/services/continuous_die.py:
CONTINUOUS_DIE_STAMPING_METHOD = "连续模"
def clean_text(value: str | None) -> str:
return str(value or "").strip()
def is_continuous_die_stamping_method(value: str | None) -> bool:
return clean_text(value) == CONTINUOUS_DIE_STAMPING_METHOD
def is_continuous_die_product(product) -> bool:
return bool(product) and is_continuous_die_stamping_method(getattr(product, "stamping_method", None))
def is_continuous_die_item(item) -> bool:
return is_continuous_die_stamping_method(getattr(item, "stamping_method", None))
- Step 4: Add the DB model field
In /Users/souplearn/Gitlab/app/JhHardwareWRS_BackPoint/app/models.py, add this field to ProductionReportItem immediately after process_unit_price_yuan:
changeover_count: Mapped[float] = mapped_column(Numeric(12, 2), nullable=False, default=0)
- Step 5: Add the migration script
Create /Users/souplearn/Gitlab/app/JhHardwareWRS_BackPoint/scripts/migrate_continuous_die_changeover_count.py:
from sqlalchemy import text
from app.database import engine
def main() -> None:
with engine.begin() as conn:
exists = conn.execute(
text(
"""
SELECT COUNT(*)
FROM information_schema.columns
WHERE table_schema = DATABASE()
AND table_name = 'production_report_items'
AND column_name = 'changeover_count'
"""
)
).scalar()
if not exists:
conn.execute(
text(
"""
ALTER TABLE production_report_items
ADD COLUMN changeover_count DECIMAL(12, 2) NOT NULL DEFAULT 0
AFTER process_unit_price_yuan
"""
)
)
print("migrate_continuous_die_changeover_count done")
if __name__ == "__main__":
main()
- Step 6: Add schema fields
In /Users/souplearn/Gitlab/app/JhHardwareWRS_BackPoint/app/schemas.py, add these exact fields to the existing classes:
# class MoldNameOut
is_continuous_die: bool = False
# class ProductOption
is_continuous_die: bool = False
# class ReportDraftItem
changeover_count: float = 0
is_continuous_die: bool = False
# class ReportDraftBlock
is_continuous_die: bool = False
# class ReportSubmitItem
changeover_count: float = Field(default=0, ge=0)
is_continuous_die: bool = False
# class ReportItemOut
changeover_count: float = 0
is_continuous_die: bool = False
# class ReportItemCorrection
changeover_count: float | None = Field(default=None, ge=0)
# class DeviceQrOut
is_continuous_die: bool = False
# class DashboardRow
changeover_count: float = 0
is_continuous_die: bool = False
- Step 7: Run the helper test
Run:
cd /Users/souplearn/Gitlab/app/JhHardwareWRS_BackPoint
.venv/bin/python -m pytest tests/test_continuous_die.py -q
Expected: PASS.
Task 2: Backend Report Flow, Review Flow, Dashboard, And Export
Files:
-
Modify:
/Users/souplearn/Gitlab/app/JhHardwareWRS_BackPoint/app/services/serializers.py -
Modify:
/Users/souplearn/Gitlab/app/JhHardwareWRS_BackPoint/app/routers/reports.py -
Modify:
/Users/souplearn/Gitlab/app/JhHardwareWRS_BackPoint/app/routers/reviews.py -
Modify:
/Users/souplearn/Gitlab/app/JhHardwareWRS_BackPoint/app/routers/dashboard.py -
Modify:
/Users/souplearn/Gitlab/app/JhHardwareWRS_BackPoint/app/services/excel_export.py -
Test:
/Users/souplearn/Gitlab/app/JhHardwareWRS_BackPoint/tests/test_continuous_die.py -
Step 1: Extend backend serialization tests
Append this test to /Users/souplearn/Gitlab/app/JhHardwareWRS_BackPoint/tests/test_continuous_die.py:
from types import SimpleNamespace
from app.services.serializers import product_option
def test_product_option_marks_continuous_die():
product = SimpleNamespace(
attendance_point_name="嘉恒",
project_no="P001",
product_name="测试产品",
profile_no=None,
material_code=None,
material_name=None,
supplier=None,
product_net_weight_kg=None,
product_gross_weight_kg=None,
scrap_loss_rate=None,
waste_price_yuan_per_kg=None,
device_no="",
process_name="1",
stamping_method=" 连续模 ",
operator_count=1,
process_unit_price_yuan=0,
standard_beat=10,
standard_workload=0,
)
option = product_option(product)
assert option.stamping_method == " 连续模 "
assert option.is_continuous_die is True
assert option.is_cleaning is False
- Step 2: Run the test and verify it fails
Run:
cd /Users/souplearn/Gitlab/app/JhHardwareWRS_BackPoint
.venv/bin/python -m pytest tests/test_continuous_die.py -q
Expected: FAIL because ProductOption is not yet populated with is_continuous_die.
- Step 3: Update serializers
In /Users/souplearn/Gitlab/app/JhHardwareWRS_BackPoint/app/services/serializers.py:
Add import:
from app.services.continuous_die import is_continuous_die_item, is_continuous_die_product
Update product_option:
def product_option(product: Product) -> ProductOption:
data = product_out(product).model_dump()
data["is_misc"] = is_misc_product(product)
data["is_multi_person"] = is_multi_person_product(product)
data["is_continuous_die"] = is_continuous_die_product(product)
return ProductOption(**data)
Update report_out item serialization so every ReportItemOut includes:
changeover_count=as_float(item.changeover_count),
is_continuous_die=is_continuous_die_item(item),
Update correction maps so changeover_count is treated as numeric:
numeric_fields = {
"operator_count",
"process_unit_price_yuan",
"good_qty",
"defect_qty",
"scrap_qty",
"changeover_count",
}
- Step 4: Update report draft and submit
In /Users/souplearn/Gitlab/app/JhHardwareWRS_BackPoint/app/routers/reports.py:
Add import:
from app.services.continuous_die import is_continuous_die_item, is_continuous_die_product
When building ReportDraftBlock, compute:
block_is_continuous_die = any(option.is_continuous_die for option in options)
Set:
is_continuous_die=block_is_continuous_die,
When building ReportDraftItem, set:
changeover_count=0,
is_continuous_die=is_continuous_die_product(first) if first else False,
When submitting normal report items, compute:
item_is_continuous_die = is_continuous_die_product(product) or is_continuous_die_item(item)
changeover_count = as_float(item.changeover_count)
if not item_is_continuous_die:
changeover_count = 0
if changeover_count < 0:
raise HTTPException(status_code=400, detail="换料次数不能为负数")
Inside each ProductionReportItem( constructor in normal report submission, add this keyword argument:
changeover_count=changeover_count,
In cleaning submit path, set:
changeover_count=0,
- Step 5: Update admin review
In /Users/souplearn/Gitlab/app/JhHardwareWRS_BackPoint/app/routers/reviews.py:
Add import:
from app.services.continuous_die import is_continuous_die_item, is_continuous_die_product
In _snapshot, include:
"changeover_count": float(item.changeover_count or 0),
When product correction changes an item, set:
item.changeover_count = item.changeover_count if is_continuous_die_product(product) else 0
When applying item corrections, add:
if correction.changeover_count is not None:
next_changeover_count = as_float(correction.changeover_count)
if next_changeover_count < 0:
raise HTTPException(status_code=400, detail="换料次数不能为负数")
if not is_continuous_die_item(item):
next_changeover_count = 0
if next_changeover_count != as_float(item.changeover_count):
item.changeover_count = next_changeover_count
has_correction = True
In system auto-submit validation, continuous die follows normal production validation; do not skip device or quantity validation.
- Step 6: Update dashboard aggregation
In /Users/souplearn/Gitlab/app/JhHardwareWRS_BackPoint/app/routers/dashboard.py:
Add import:
from app.services.continuous_die import is_continuous_die_item, is_continuous_die_product
Add correction label:
"changeover_count": "换料次数",
Inside each item loop:
is_continuous_die = is_continuous_die_item(item) or is_continuous_die_product(product)
Initialize group fields:
"changeover_count": 0.0,
"is_continuous_die": is_continuous_die,
Accumulate:
group["changeover_count"] += as_float(item.changeover_count)
group["is_continuous_die"] = group["is_continuous_die"] or is_continuous_die
Set DashboardRow fields:
changeover_count=round2(group["changeover_count"]),
is_continuous_die=group["is_continuous_die"],
- Step 7: Update Excel export
In /Users/souplearn/Gitlab/app/JhHardwareWRS_BackPoint/app/services/excel_export.py, add 换料次数 after 冲压方式:
"冲压方式",
"换料次数",
"操作人数",
Add the row value:
row.stamping_method,
row.changeover_count,
row.operator_count,
Add report flag:
if getattr(row, "is_continuous_die", False):
report_flags.append("连续模")
Leave reference_wage as-is:
# reference_wage remains good_qty * process_unit_price_yuan until a changeover unit price is maintained.
- Step 8: Run backend tests
Run:
cd /Users/souplearn/Gitlab/app/JhHardwareWRS_BackPoint
.venv/bin/python -m pytest tests/test_continuous_die.py tests/test_metrics.py tests/test_review_corrections.py -q
Expected: all selected tests PASS.
Task 3: Frontend API Normalization
Files:
-
Modify:
/Users/souplearn/Gitlab/app/JhHardwareWRS/utils/api.js -
Step 1: Add frontend continuous die helpers
Near the existing cleaning helper in /Users/souplearn/Gitlab/app/JhHardwareWRS/utils/api.js, add:
const CONTINUOUS_DIE_STAMPING_METHOD = '连续模'
const isContinuousDieStampingMethod = value => String(value || '').trim() === CONTINUOUS_DIE_STAMPING_METHOD
const isContinuousDieRow = row => (
!!row && (
!!row.is_continuous_die
|| !!row.isContinuousDie
|| isContinuousDieStampingMethod(row.stamping_method || row.stampingMethod)
)
)
- Step 2: Add continuous die to product and mold mapping
In toCamelProduct, add:
isContinuousDie: isContinuousDieRow(row),
In toCamelMoldOption, add:
isContinuousDie: !!row.is_continuous_die || isContinuousDieRow(row),
- Step 3: Add continuous die to report item mapping
In toCamelReportItem, add:
const isContinuousDie = isContinuousDieRow(row)
Return these fields:
isContinuousDie,
changeoverCount: row.changeover_count === null || row.changeover_count === undefined ? 0 : Number(row.changeover_count || 0),
Add correction display:
correctionPair(corrections, 'changeover_count', '换料次数', row.changeover_count || 0),
- Step 4: Add continuous die to draft mapping and submit payload
In emptyDraftItem, optionToDraftItem, and apiDraftItemToCamel, add:
isContinuousDie: false,
changeoverCount: '',
changeoverCountError: false,
For product-derived items:
isContinuousDie: option ? !!option.isContinuousDie : false,
changeoverCount: '',
In toSubmitPayload, add:
changeover_count: item.isContinuousDie ? Number(item.changeoverCount || 0) : 0,
is_continuous_die: !!item.isContinuousDie,
- Step 5: Add dashboard mapping
In listDashboardReports row mapping, add:
isContinuousDie: isContinuousDieRow(row),
changeoverCount: row.changeover_count || 0,
- Step 6: Export helpers
At the bottom module export object, export:
isContinuousDieStampingMethod,
isContinuousDieRow,
Task 4: Product List Input Suggestions And Continuous Die Watermark
Files:
-
Modify:
/Users/souplearn/Gitlab/app/JhHardwareWRS/pages/manageProducts/manageProducts.js -
Modify:
/Users/souplearn/Gitlab/app/JhHardwareWRS/pages/manageProducts/manageProducts.wxml -
Modify:
/Users/souplearn/Gitlab/app/JhHardwareWRS/pages/manageProducts/manageProducts.wxss -
Step 1: Add product page state and handlers
In data, add:
stampingMethodSuggestions: ['清洗', '连续模'],
stampingSuggestionVisible: false,
In onInput, trim stamping method only on save, not while typing. Add:
if (field === 'stampingMethod') {
this.setData({
stampingSuggestionVisible: false,
[`form.${field}`]: value,
})
return
}
Add handlers:
onStampingFocus() {
this.setData({ stampingSuggestionVisible: true })
},
chooseStampingSuggestion(e) {
const value = e.currentTarget.dataset.value
this.setData({
'form.stampingMethod': value,
stampingSuggestionVisible: false,
})
},
hideStampingSuggestion() {
setTimeout(() => {
this.setData({ stampingSuggestionVisible: false })
}, 150)
},
In save, normalize before validation:
form.stampingMethod = String(form.stampingMethod || '').trim()
Keep this rule unchanged except for trimming:
if (['清洗', '处理杂活'].includes(form.stampingMethod)) {
form.standardBeat = 0
}
Continuous die must still show and require standard beat.
- Step 2: Update product page WXML
Replace the 冲压方式 input block with:
<view class="form-item stamping-field">
<text class="label">冲压方式</text>
<input
class="input"
value="{{form.stampingMethod}}"
data-field="stampingMethod"
bindfocus="onStampingFocus"
bindblur="hideStampingSuggestion"
bindinput="onInput"
placeholder="可输入,或选择清洗/连续模"
/>
<view wx:if="{{stampingSuggestionVisible}}" class="stamping-suggestion-panel">
<view
wx:for="{{stampingMethodSuggestions}}"
wx:key="*this"
class="stamping-suggestion-option"
data-value="{{item}}"
catchtap="chooseStampingSuggestion"
>{{item}}</view>
</view>
</view>
On product cards, add:
<text wx:if="{{item.isContinuousDie}}" class="continuous-die-stamp {{item.isCleaning || item.isMisc || item.isMultiPerson ? 'lower-product-stamp' : ''}}">连续模</text>
- Step 3: Add product page CSS
Add styles to /Users/souplearn/Gitlab/app/JhHardwareWRS/pages/manageProducts/manageProducts.wxss:
.stamping-field {
position: relative;
}
.stamping-suggestion-panel {
position: absolute;
left: 0;
right: 0;
top: 112rpx;
z-index: 20;
background: #fff;
border: 1rpx solid #d9e2f2;
border-radius: 8rpx;
box-shadow: 0 12rpx 32rpx rgba(16, 35, 72, 0.12);
overflow: hidden;
}
.stamping-suggestion-option {
padding: 22rpx 24rpx;
font-size: 28rpx;
color: #1f2a44;
border-bottom: 1rpx solid #eef2f7;
}
.stamping-suggestion-option:last-child {
border-bottom: 0;
}
.continuous-die-stamp {
position: absolute;
right: 24rpx;
top: 24rpx;
transform: rotate(12deg);
color: #c26b00;
border: 2rpx solid rgba(194, 107, 0, 0.55);
border-radius: 6rpx;
padding: 6rpx 12rpx;
font-size: 24rpx;
font-weight: 700;
background: rgba(255, 244, 224, 0.88);
}
Task 5: Worker Reporting Form
Files:
-
Modify:
/Users/souplearn/Gitlab/app/JhHardwareWRS/pages/reportForm/reportForm.js -
Modify:
/Users/souplearn/Gitlab/app/JhHardwareWRS/pages/reportForm/reportForm.wxml -
Modify:
/Users/souplearn/Gitlab/app/JhHardwareWRS/pages/reportForm/reportForm.wxss -
Step 1: Add validation for changeover count
In validateDraft, after raw material batch validation and before quantity validation, add:
if (item.isContinuousDie) {
const text = String(item.changeoverCount || '').trim()
const value = Number(text)
if (!text || !Number.isInteger(value) || value < 0) {
this.setData({
[`draft.deviceBlocks[${blockIndex}].items[${itemIndex}].changeoverCountError`]: true,
})
wx.showToast({
title: `${blockDisplay(block)}请填写非负整数换料次数`,
icon: 'none',
})
return false
}
}
Add a generic input handler or reuse onQtyInput with data-field="changeoverCount":
if (field === 'changeoverCount') {
this.setData({
[`draft.deviceBlocks[${blockIndex}].items[${itemIndex}].changeoverCountError`]: false,
})
}
- Step 2: Add WXML field
Inside each non-misc report item, place this between 材料库存批次号 and the readonly product grid:
<view wx:if="{{reportItem.isContinuousDie}}" class="form-item">
<text class="label">换料次数</text>
<input
class="input number-input {{reportItem.changeoverCountError ? 'field-error' : ''}}"
type="number"
value="{{reportItem.changeoverCount}}"
placeholder="请输入换料次数"
data-block-index="{{blockIndex}}"
data-item-index="{{itemIndex}}"
data-field="changeoverCount"
bindinput="onQtyInput"
/>
</view>
Add watermarks:
<text wx:if="{{reportItem.isContinuousDie}}" class="continuous-item-stamp {{reportItem.isMultiPerson ? 'lower-item-stamp' : ''}}">连续模</text>
- Step 3: Add report form CSS
In /Users/souplearn/Gitlab/app/JhHardwareWRS/pages/reportForm/reportForm.wxss, add:
.continuous-item-stamp {
position: absolute;
right: 20rpx;
top: 20rpx;
transform: rotate(12deg);
padding: 6rpx 12rpx;
border-radius: 6rpx;
border: 2rpx solid rgba(194, 107, 0, 0.55);
color: #b45f00;
background: rgba(255, 244, 224, 0.9);
font-size: 22rpx;
font-weight: 700;
}
.lower-item-stamp {
top: 72rpx;
}
Task 6: Admin Review, Records, Dashboard, QR, And Result UI
Files:
-
Modify:
/Users/souplearn/Gitlab/app/JhHardwareWRS/pages/review/review.js -
Modify:
/Users/souplearn/Gitlab/app/JhHardwareWRS/pages/review/review.wxml -
Modify:
/Users/souplearn/Gitlab/app/JhHardwareWRS/pages/review/review.wxss -
Modify:
/Users/souplearn/Gitlab/app/JhHardwareWRS/pages/records/records.wxml -
Modify:
/Users/souplearn/Gitlab/app/JhHardwareWRS/pages/records/records.wxss -
Modify:
/Users/souplearn/Gitlab/app/JhHardwareWRS/pages/dashboard/dashboard.wxml -
Modify:
/Users/souplearn/Gitlab/app/JhHardwareWRS/pages/dashboard/dashboard.wxss -
Modify:
/Users/souplearn/Gitlab/app/JhHardwareWRS/pages/deviceQr/deviceQr.wxml -
Modify:
/Users/souplearn/Gitlab/app/JhHardwareWRS/pages/deviceQr/deviceQr.wxss -
Modify:
/Users/souplearn/Gitlab/app/JhHardwareWRS/pages/reportResult/reportResult.js -
Modify:
/Users/souplearn/Gitlab/app/JhHardwareWRS/pages/reportResult/reportResult.wxml -
Modify:
/Users/souplearn/Gitlab/app/JhHardwareWRS/pages/reportResult/reportResult.wxss -
Step 1: Review page JS
In makeEditItem, include:
isContinuousDie: !!detail.isContinuousDie,
changeoverCount: detail.changeoverCount || 0,
changeoverCountError: false,
In productToEditItem, after product replacement:
isContinuousDie: !!product.isContinuousDie,
changeoverCount: product.isContinuousDie ? (item.changeoverCount || 0) : 0,
In restoreProduct, carry:
isContinuousDie: product.isContinuousDie === undefined ? original.isContinuousDie : product.isContinuousDie,
changeoverCount: product.isContinuousDie ? (item.changeoverCount || 0) : 0,
In onItemInput, recalculate only quantity fields as today, but allow changeoverCount to update and clear error:
if (field === 'changeoverCount') {
updates[`rows[${reportIndex}].editItems[${itemIndex}].changeoverCountError`] = false
}
In approve, validate:
const invalidChangeoverItemIndex = (row.editItems || []).findIndex(item => {
if (!item.isContinuousDie) {
return false
}
const value = Number(item.changeoverCount)
return !Number.isInteger(value) || value < 0
})
if (invalidChangeoverItemIndex >= 0) {
const reportIndex = this.data.rows.findIndex(item => String(item.id) === String(id))
this.setData({
[`rows[${reportIndex}].editItems[${invalidChangeoverItemIndex}].changeoverCountError`]: true,
})
wx.showToast({ title: '请填写非负整数换料次数', icon: 'none' })
return
}
In approve patch item corrections, include:
changeover_count: item.isContinuousDie ? Number(item.changeoverCount || 0) : 0,
- Step 2: Review page WXML
Add report-level watermark:
<text wx:if="{{item.hasContinuousDie}}" class="continuous-die-watermark {{item.isSystemAutoSubmitted || item.isVoided || item.isModified || item.hasMisc || item.isCleaning || item.hasMultiPerson ? 'lower-watermark' : ''}}">连续模</text>
Add detail-level watermark:
<text wx:if="{{detail.isContinuousDie}}" class="detail-continuous-stamp">连续模</text>
Add display under non-cleaning/non-misc detail metrics:
<view wx:if="{{detail.isContinuousDie}}">
<text class="label">换料次数</text>
<text class="value">{{detail.changeoverCount || 0}}</text>
</view>
Add editable field in the review form grid:
<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>
In product replacement modal cards, add:
<text wx:if="{{item.isContinuousDie}}" class="continuous-die-watermark product-select-stamp">连续模</text>
- Step 3: Records page
In /Users/souplearn/Gitlab/app/JhHardwareWRS/pages/records/records.wxml, add report and detail watermarks plus a detail metric:
<text wx:if="{{item.hasContinuousDie}}" class="continuous-die-watermark {{item.isSystemAutoSubmitted || item.isVoided || item.isModified || item.hasMisc || item.isCleaning || item.hasMultiPerson ? 'lower-watermark' : ''}}">连续模</text>
<text wx:if="{{detail.isContinuousDie}}" class="detail-continuous-stamp">连续模</text>
<view wx:if="{{detail.isContinuousDie}}">
<text class="label">换料次数</text>
<text class="value">{{detail.changeoverCount || 0}}</text>
</view>
- Step 4: Dashboard page
In /Users/souplearn/Gitlab/app/JhHardwareWRS/pages/dashboard/dashboard.wxml, add:
<text wx:if="{{item.isContinuousDie}}" class="continuous-die-watermark {{item.isSystemAutoSubmitted || item.isVoided || item.correctionPairs.length || item.isMisc || item.isCleaning || item.isMultiPerson ? 'lower-watermark' : ''}}">连续模</text>
<view wx:if="{{item.isContinuousDie}}">
<text class="label">换料次数</text>
<text class="value">{{item.changeoverCount || 0}}</text>
</view>
- Step 5: QR page
In /Users/souplearn/Gitlab/app/JhHardwareWRS/pages/deviceQr/deviceQr.wxml, add tags in single-select and batch-select rows:
<text wx:if="{{item.isContinuousDie}}" class="mold-option-tag continuous-tag">连续模</text>
- Step 6: Report result page
In /Users/souplearn/Gitlab/app/JhHardwareWRS/pages/reportResult/reportResult.js, include item result fields:
isContinuousDie: !!item.isContinuousDie,
changeoverCount: item.changeoverCount || 0,
In /Users/souplearn/Gitlab/app/JhHardwareWRS/pages/reportResult/reportResult.wxml, add:
<text wx:if="{{result.isContinuousDie}}" class="result-continuous-stamp">连续模</text>
<view wx:if="{{result.isContinuousDie}}">
<text class="label">换料次数</text>
<text class="value">{{result.changeoverCount || 0}}</text>
</view>
- Step 7: Shared CSS pattern
Add orange continuous die styles to each page CSS touched in this task:
.continuous-die-watermark,
.detail-continuous-stamp,
.result-continuous-stamp {
position: absolute;
right: 24rpx;
top: 24rpx;
transform: rotate(12deg);
padding: 6rpx 12rpx;
border-radius: 6rpx;
border: 2rpx solid rgba(194, 107, 0, 0.55);
color: #b45f00;
background: rgba(255, 244, 224, 0.9);
font-size: 22rpx;
font-weight: 700;
}
.continuous-tag {
color: #b45f00;
background: #fff4e0;
}
Use the class names shown in this task's WXML snippets. If a page already has .lower-watermark, use that existing class for vertical offset; otherwise add only the continuous die classes shown above.
Task 7: Manual Verification And Release Steps
Files:
-
Verify changed frontend files above.
-
Verify backend files above.
-
Step 1: Run backend migration locally
Run:
cd /Users/souplearn/Gitlab/app/JhHardwareWRS_BackPoint
.venv/bin/python scripts/migrate_continuous_die_changeover_count.py
Expected output:
migrate_continuous_die_changeover_count done
- Step 2: Run backend tests
Run:
cd /Users/souplearn/Gitlab/app/JhHardwareWRS_BackPoint
.venv/bin/python -m pytest tests/test_continuous_die.py tests/test_metrics.py tests/test_review_corrections.py -q
Expected: all tests PASS.
- Step 3: Product list verification
Manual test in WeChat devtools:
-
Open 产品清单.
-
Click 新增产品.
-
Click 冲压方式 input.
-
Verify suggestions show only
清洗and连续模. -
Select
连续模. -
Verify 标准节拍 is still visible and required.
-
Save a product with
冲压方式= 连续模including spaces. -
Reopen the product and verify it is recognized as
连续模. -
Verify product card shows orange
连续模watermark. -
Step 4: Worker reporting verification
Manual test:
-
Scan a normal single-person
连续模product QR. -
Start work.
-
Finish work.
-
In 下班报工, verify the product card shows
连续模watermark. -
Verify
换料次数input appears between材料库存批次号and product readonly information. -
Try submitting empty value. Expected: toast
请填写非负整数换料次数. -
Enter
2, fill production quantity and device, submit. -
Verify result page shows
换料次数 2. -
Step 5: Admin review verification
Manual test:
-
Open 报工审核.
-
Expand the continuous die report.
-
Verify detail card shows
连续模watermark and换料次数. -
Change
换料次数from2to3. -
Approve.
-
Reopen record and verify:
- Card has
更改watermark. - Correction display shows
换料次数 2 -> 3. - Work time, standard workload, actual beat still recalculate from time and quantity only.
- Card has
-
Step 6: Manager dashboard and export verification
Manual test:
-
Open 经理报工看板.
-
Find the approved continuous die row.
-
Verify orange
连续模watermark. -
Verify
换料次数 3displays. -
Export Excel.
-
Verify first sheet has
换料次数column. -
Verify the row has
报工标记=连续模. -
Verify
参考工资remains成品数量 * 工序单价, without adding changeover pay. -
Step 7: QR verification
Manual test:
-
Open 模具二维码.
-
Search the continuous die product.
-
Verify single-select and batch modal rows show
连续模tag. -
Generate QR.
-
Verify bottom annotation includes product name / process / stamping method; for continuous die it includes
连续模. -
Step 8: Server release
Backend release order:
cd /software/JhHardwareWRS_BackPoint
git pull
.venv/bin/python scripts/migrate_continuous_die_changeover_count.py
If backend is running with reload, verify logs show reload. If not, restart the backend service.
Frontend release:
- Upload WeChat mini-program version after devtools verification.
- This feature needs frontend release because worker/admin/manager pages all need new visible fields.
Self-Review
Spec coverage:
连续模special judgment by trimmed exact stamping method: Task 1 and Task 3.- Product
冲压方式remains free input with suggested清洗and连续模: Task 4. - Continuous die watermark in product list, QR, report, review, records, dashboard, result: Tasks 4 and 6.
- Worker report requires
换料次数: Task 5. - Admin review displays and can edit
换料次数: Task 6 plus backend Task 2. - Manager dashboard and Excel export carry
换料次数: Task 2 and Task 6. - Dashboard aggregation sums
换料次数: Task 2. - No forced dictionary-maintenance page: preserved by Task 4.
- Wage calculation is not changed because no changeover unit price exists: File Map non-goal and Task 7.
Placeholder scan:
- No unresolved placeholder markers remain.
- Every modified behavior has a concrete file target and exact code shape or verification step.
Type consistency:
- Backend snake_case:
changeover_count,is_continuous_die. - Frontend camelCase:
changeoverCount,isContinuousDie. - Display label:
换料次数.