feat(miniprogram): split driver plan copy product into three lines
Make copy-to-group text easier to scan: 产品信息 / 计划数量 / 实际数量 as separate lines. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
1 parent
36d27416d3
commit
c626023250
2 files changed
+211
-8
No files matched your search
@@ -0,0 +1,201 @@
|
||||
# 司机运输计划单「复制发群」产品行拆分 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:** 将小程序司机运输计划单「复制发群」中每个产品由单行紧凑格式改为三行(产品信息 / 计划数量 / 实际数量),多产品组间不空行。
|
||||
|
||||
**Architecture:** 仅改 `miniprogram/utils/plDriverPlanCopy.js`:`formatProductLine` 改为返回三行字符串数组;`appendInfoSection` 展开 push。头信息、区块顺序、空站/无产品边界、`copyDriverPlanToClipboard` 不变。用一次性 Node 断言脚本验证后删除。
|
||||
|
||||
**Tech Stack:** uni-app 小程序工具 JS(ES module)、Node 临时校验。
|
||||
|
||||
**Spec:** `docs/superpowers/specs/2026-10-13-mini-pl-driver-plan-copy-product-lines-design.md`
|
||||
|
||||
---
|
||||
|
||||
## File map
|
||||
|
||||
| 文件 | 动作 | 职责 |
|
||||
|------|------|------|
|
||||
| `miniprogram/utils/plDriverPlanCopy.js` | Modify | 产品三行输出;导出签名不变 |
|
||||
| `/tmp` 临时校验脚本 | Create→Delete | Node 断言定稿示例 |
|
||||
|
||||
---
|
||||
|
||||
### Task 1: 改产品行为三行
|
||||
|
||||
**Files:**
|
||||
- Modify: `miniprogram/utils/plDriverPlanCopy.js`
|
||||
|
||||
- [x] **Step 1: 更新规格注释;将 `formatProductLine` 改为返回三行数组;`appendInfoSection` 展开 push**
|
||||
|
||||
把文件顶部规格注释改为指向新 design。替换产品格式化与追加逻辑为:
|
||||
|
||||
```js
|
||||
/**
|
||||
* 司机运输计划单「复制发群」纯文本(不含附件)
|
||||
* 规格:docs/superpowers/specs/2026-10-13-mini-pl-driver-plan-copy-product-lines-design.md
|
||||
* (头信息/区块/边界继承 2026-10-12 enrich 设计)
|
||||
*/
|
||||
|
||||
// ... 保留 DASH、FIELD_GAP、stopTypeOf、customerNameOf、textOrDash、
|
||||
// formatQtyWithUnit、planQtyOf、actualQtyOf 不变 ...
|
||||
|
||||
/** 产品三行:产品信息 / 计划数量 / 实际数量 */
|
||||
function formatProductLines(product) {
|
||||
const name = textOrDash(product?.productName ?? product?.product_name)
|
||||
const model = textOrDash(product?.model)
|
||||
const pack = textOrDash(product?.packageSpec ?? product?.package_spec)
|
||||
const unit = product?.unit
|
||||
const planPart = formatQtyWithUnit(planQtyOf(product), unit)
|
||||
const actualPart = formatQtyWithUnit(actualQtyOf(product), unit)
|
||||
return [
|
||||
`- 产品信息:${name}${FIELD_GAP}${model}${FIELD_GAP}${pack}`,
|
||||
`- 计划数量:${planPart}`,
|
||||
`- 实际数量:${actualPart}`
|
||||
]
|
||||
}
|
||||
|
||||
function appendInfoSection(lines, title, stops) {
|
||||
lines.push(title)
|
||||
if (!stops.length) {
|
||||
lines.push(DASH)
|
||||
return
|
||||
}
|
||||
stops.forEach((stop) => {
|
||||
lines.push(`${customerNameOf(stop)}:`)
|
||||
const products = Array.isArray(stop?.products) ? stop.products : []
|
||||
if (!products.length) {
|
||||
lines.push(`- ${DASH}`)
|
||||
return
|
||||
}
|
||||
products.forEach((product) => {
|
||||
formatProductLines(product).forEach((line) => lines.push(line))
|
||||
})
|
||||
})
|
||||
}
|
||||
```
|
||||
|
||||
其余 `buildDriverPlanCopyText` / `copyDriverPlanToClipboard` 保持不变。删除旧的 `formatProductLine`。
|
||||
|
||||
- [x] **Step 2: 一次性 Node 断言(通过后删除脚本)**
|
||||
|
||||
```bash
|
||||
cat > /tmp/check-driver-plan-copy-lines.mjs << 'EOF'
|
||||
import { buildDriverPlanCopyText } from './miniprogram/utils/plDriverPlanCopy.js'
|
||||
|
||||
const page = {
|
||||
copySeqNo: 128,
|
||||
planNo: 'YSJH20260409001',
|
||||
licensePlate: '沪A12345',
|
||||
stops: [
|
||||
{
|
||||
stopType: 'delivery',
|
||||
customerName: '甲客户',
|
||||
products: [
|
||||
{ productName: '工业酒精', model: '95%', packageSpec: '吨桶', planQty: 12, actualQty: 11.9, unit: '吨' }
|
||||
]
|
||||
},
|
||||
{
|
||||
stopType: 'delivery',
|
||||
customerName: '乙客户',
|
||||
products: [
|
||||
{ productName: '工业酒精', model: '95%', packageSpec: '吨桶', planQty: 8, actualQty: 7.9, unit: '吨' },
|
||||
{ productName: '甲醇', model: '99.9%', packageSpec: '吨桶', planQty: 2, actualQty: 2, unit: '吨' }
|
||||
]
|
||||
},
|
||||
{
|
||||
stopType: 'load',
|
||||
customerName: '某某化工厂',
|
||||
products: [
|
||||
{ productName: '工业酒精', model: '95%', packageSpec: '吨桶', planQty: 20, actualQty: 19.8, unit: '吨' },
|
||||
{ productName: '甲醇', model: '99.9%', packageSpec: '吨桶', planQty: 2, actualQty: 2, unit: '吨' }
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
const expected = [
|
||||
'序号:128',
|
||||
'计划编号:YSJH20260409001',
|
||||
'车辆:沪A12345',
|
||||
'送货信息:',
|
||||
'甲客户:',
|
||||
'- 产品信息:工业酒精 95% 吨桶',
|
||||
'- 计划数量:12 吨',
|
||||
'- 实际数量:11.9 吨',
|
||||
'乙客户:',
|
||||
'- 产品信息:工业酒精 95% 吨桶',
|
||||
'- 计划数量:8 吨',
|
||||
'- 实际数量:7.9 吨',
|
||||
'- 产品信息:甲醇 99.9% 吨桶',
|
||||
'- 计划数量:2 吨',
|
||||
'- 实际数量:2 吨',
|
||||
'装货信息:',
|
||||
'某某化工厂:',
|
||||
'- 产品信息:工业酒精 95% 吨桶',
|
||||
'- 计划数量:20 吨',
|
||||
'- 实际数量:19.8 吨',
|
||||
'- 产品信息:甲醇 99.9% 吨桶',
|
||||
'- 计划数量:2 吨',
|
||||
'- 实际数量:2 吨'
|
||||
].join('\n')
|
||||
|
||||
const actual = buildDriverPlanCopyText(page)
|
||||
if (actual !== expected) {
|
||||
console.error('MISMATCH\n--- actual ---\n' + actual + '\n--- expected ---\n' + expected)
|
||||
process.exit(1)
|
||||
}
|
||||
|
||||
const emptyish = buildDriverPlanCopyText({ planNo: 'X', stops: [] })
|
||||
const emptyExpected = [
|
||||
'序号:—',
|
||||
'计划编号:X',
|
||||
'车辆:—',
|
||||
'送货信息:',
|
||||
'—',
|
||||
'装货信息:',
|
||||
'—'
|
||||
].join('\n')
|
||||
if (emptyish !== emptyExpected) {
|
||||
console.error('EMPTY MISMATCH\n' + emptyish)
|
||||
process.exit(1)
|
||||
}
|
||||
|
||||
console.log('OK')
|
||||
EOF
|
||||
# 在仓库根目录执行;若相对 import 失败则改用 file:// 绝对路径
|
||||
cd /Users/zlwu/work/00code/shanxia2.0 && node --input-type=module -e "
|
||||
import { buildDriverPlanCopyText } from './miniprogram/utils/plDriverPlanCopy.js'
|
||||
" 2>/dev/null || true
|
||||
```
|
||||
|
||||
推荐在仓库根直接跑内嵌断言(路径相对仓库根):
|
||||
|
||||
```bash
|
||||
cd /Users/zlwu/work/00code/shanxia2.0
|
||||
node --input-type=module <<'EOF'
|
||||
import { buildDriverPlanCopyText } from './miniprogram/utils/plDriverPlanCopy.js'
|
||||
# ... 同上 page / expected / emptyish 断言 ...
|
||||
EOF
|
||||
```
|
||||
|
||||
Expected stdout: `OK`
|
||||
|
||||
- [x] **Step 3: Commit**
|
||||
|
||||
```bash
|
||||
git add miniprogram/utils/plDriverPlanCopy.js docs/superpowers/plans/2026-10-13-mini-pl-driver-plan-copy-product-lines.md
|
||||
git commit -m "feat(miniprogram): split driver plan copy product into three lines"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Spec coverage checklist
|
||||
|
||||
| Spec 项 | Task |
|
||||
|---------|------|
|
||||
| D1 只改 plDriverPlanCopy.js | Task 1 |
|
||||
| D2 多产品不空行 | Task 1 `formatProductLines` 连续 push |
|
||||
| D3 formatProductLine→三行 | Task 1 |
|
||||
| D4 / D5 空值与无产品 `- —` | 既有 `appendInfoSection` + `textOrDash` |
|
||||
| 定稿实例 | Task 1 Step 2 |
|
||||
@@ -1,6 +1,7 @@
|
||||
/**
|
||||
* 司机运输计划单「复制发群」纯文本(不含附件)
|
||||
* 规格:docs/superpowers/specs/2026-10-12-mini-pl-driver-plan-copy-text-enrich-design.md
|
||||
* 规格:docs/superpowers/specs/2026-10-13-mini-pl-driver-plan-copy-product-lines-design.md
|
||||
* (头信息/区块/边界继承 2026-10-12 enrich 设计)
|
||||
*/
|
||||
|
||||
const DASH = '—'
|
||||
@@ -41,18 +42,19 @@ function actualQtyOf(product) {
|
||||
return null
|
||||
}
|
||||
|
||||
/** 产品紧凑行:- 名称 型号 包装 计划数量:… 实际数量:… */
|
||||
function formatProductLine(product) {
|
||||
/** 产品三行:产品信息 / 计划数量 / 实际数量(组间不空行) */
|
||||
function formatProductLines(product) {
|
||||
const name = textOrDash(product?.productName ?? product?.product_name)
|
||||
const model = textOrDash(product?.model)
|
||||
const pack = textOrDash(product?.packageSpec ?? product?.package_spec)
|
||||
const unit = product?.unit
|
||||
const planPart = formatQtyWithUnit(planQtyOf(product), unit)
|
||||
const actualPart = formatQtyWithUnit(actualQtyOf(product), unit)
|
||||
return (
|
||||
`- ${name}${FIELD_GAP}${model}${FIELD_GAP}${pack}` +
|
||||
`${FIELD_GAP}计划数量:${planPart}${FIELD_GAP}实际数量:${actualPart}`
|
||||
)
|
||||
return [
|
||||
`- 产品信息:${name}${FIELD_GAP}${model}${FIELD_GAP}${pack}`,
|
||||
`- 计划数量:${planPart}`,
|
||||
`- 实际数量:${actualPart}`
|
||||
]
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -74,7 +76,7 @@ function appendInfoSection(lines, title, stops) {
|
||||
return
|
||||
}
|
||||
products.forEach((product) => {
|
||||
lines.push(formatProductLine(product))
|
||||
formatProductLines(product).forEach((line) => lines.push(line))
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user