ForgeFlow-ERP/docs/superpowers/plans/2026-06-13-warehouse-paper-form-unification-phase1.md
2026-06-14 16:23:27 +08:00

9.7 KiB
Raw Blame History

Warehouse Paper Form Unification Phase 1 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: Make warehouse operation documents use one cohesive paper-form visual language, starting with the production-ledger controlled inbound forms that currently mix modern web controls into the paper sheet.

Architecture: Keep all business state, computed values, validation, and submit payloads in InventoryLedgerView.vue unchanged. Introduce paper-specific wrappers/classes around the existing controls so selectors, selected-lot tables, live summaries, remarks, and settle controls visually belong to the same document grid as the approved “客料入库单”. Avoid global restyling of .form-field, .double-field, .table-wrap, or shared controls used outside paper documents.

Tech Stack: Vue 3 SFC, Vite, project CSS in frontend/src/styles/main.css, Node built-in test runner.


File Structure

  • Modify frontend/src/views/InventoryLedgerView.vue: convert the generic warehouse drawers production-ledger controlled inbound branch to paper-specific markup while preserving existing bindings and branch conditions.
  • Modify frontend/src/styles/main.css: add reusable paper document classes for control grids, inline summary rows, source-lot selector/table panels, and settle confirmation rows.
  • Modify frontend/src/views/InventoryLedgerView.test.js: add regression coverage that production surplus/scrap inbound forms use the paper-specific classes and that the old naked modern classes are not the only visual contract.

Design Direction

  • Aesthetic: “工业纸质单据”.
  • Purpose: Support fast warehouse entry while making each operation feel like a formal business document, not a demo web form.
  • Differentiation anchor: Thick ledger grid lines, label/value cells, stamped meta strips, and paper-native control panels.
  • DFII: 13. Impact 4, fit 5, feasibility 5, performance 4, consistency risk 5. This is strong because it reuses the approved客料入库 visual system, but must be scoped to avoid touching unrelated app forms.

Task 1: Lock The Regression Tests

Files:

  • Modify: frontend/src/views/InventoryLedgerView.test.js

  • Read: frontend/src/views/InventoryLedgerView.vue

  • Read: frontend/src/styles/main.css

  • Step 1: Add paper-form assertions for production-ledger controlled inbound

Add a test that checks the generic drawer contains production-ledger paper classes and keeps the old branch visually wrapped:

it("wraps production-ledger controlled inbound forms in the shared paper control language", () => {
  assert.match(source, /warehouse-paper-control-grid/);
  assert.match(source, /warehouse-paper-source-lot-panel/);
  assert.match(source, /warehouse-paper-source-lot-table/);
  assert.match(source, /warehouse-paper-inline-summary/);
  assert.match(source, /warehouse-paper-settle-panel/);
  assert.match(source, /warehouse-paper-settle-toggle/);
  assert.match(source, /warehouse-paper-settle-grid/);
  assert.match(source, /warehouse-paper-settle-remark/);
  assert.match(mainCss, /\.warehouse-document-section-grid > \.warehouse-paper-control-grid\s*\{[\s\S]*grid-column: 1 \/ -1;/);
  assert.match(mainCss, /\.warehouse-paper-control-grid\s*\{[\s\S]*grid-template-columns: repeat\(4, minmax\(0, 1fr\)\);/);
  assert.match(mainCss, /\.warehouse-paper-source-lot-table/);
  assert.match(mainCss, /\.warehouse-paper-settle-toggle/);
});
  • Step 2: Run the test and confirm it fails before implementation

Run:

cd frontend
node --test src/views/InventoryLedgerView.test.js

Expected before implementation: failure mentioning one or more missing warehouse-paper-* classes.

Task 2: Convert Production Controlled Inbound Markup

Files:

  • Modify: frontend/src/views/InventoryLedgerView.vue

  • Step 1: Replace the naked production work-order block

Replace the isProductionWorkOrderControlledInbound stack-form block with paper-grid fields:

<div v-if="isProductionWorkOrderControlledInbound" class="warehouse-paper-control-grid warehouse-paper-control-grid-compact">
  <label class="warehouse-paper-field warehouse-paper-field-wide">
    <span>{{ isReworkScrapInbound ? "返工工单" : "生产台账" }}</span>
    <select v-model.number="genericForm.work_order_id" required @change="applyGenericWorkOrder">
      <option disabled value="">{{ isReworkScrapInbound ? "请选择返工工单" : "请选择生产台账" }}</option>
      <option v-for="workOrder in genericWorkOrderOptions" :key="workOrder.work_order_id" :value="workOrder.work_order_id">
        {{ formatWorkOrderLedgerOption(workOrder, activeOperation?.bizType) }}
      </option>
    </select>
  </label>

  <template v-if="selectedGenericWorkOrder">
    <article class="warehouse-paper-summary-card warehouse-paper-summary-card-wide">
      <span>产品</span>
      <strong>{{ selectedGenericWorkOrder.product_code }} · {{ selectedGenericWorkOrder.product_name }}</strong>
    </article>
    <article class="warehouse-paper-summary-card">
      <span>材料库存批次号</span>
      <strong>{{ selectedGenericWorkOrder.source_lot_summary || selectedGenericWorkOrder.material_lot_no || "-" }}</strong>
    </article>
    <article v-if="isProductionScrapInbound" class="warehouse-paper-summary-card">
      <span>库外未闭环重量</span>
      <strong>{{ formatWeight(selectedGenericWorkOrder.outside_weight_kg || selectedGenericWorkOrder.limits?.max_scrap_inbound_weight_kg) }}</strong>
    </article>
    <article v-if="isProductionSurplusInbound" class="warehouse-paper-summary-card">
      <span>库外未闭环重量</span>
      <strong>{{ formatWeight(selectedGenericWorkOrder.outside_weight_kg || selectedGenericWorkOrder.limits?.max_surplus_inbound_weight_kg) }}</strong>
    </article>
  </template>
</div>
  • Step 2: Convert the core fields to a paper grid

Replace the main double-field and triple-field groups in the generic drawer with warehouse-paper-control-grid, using the existing exact conditions and v-models. Keep field order: item, warehouse, location, measure basis, weight, quantity, unit cost.

  • Step 3: Wrap source-lot selector and tables in paper panels

Keep StockLotTagSelect unchanged, but place it inside:

<div v-if="usesGenericSourceLotSelector" class="warehouse-paper-source-lot-panel">
  <div class="warehouse-paper-source-lot-heading">
    <span>来源库存批次号</span>
    <strong>{{ genericSourceLotSelectPlaceholder }}</strong>
  </div>
  <StockLotTagSelect ... />
</div>

For selected lot tables, keep the same columns and inputs but add warehouse-paper-source-lot-table to the wrapping table container so CSS can remove the ordinary web-card feel.

  • Step 4: Convert summaries and settle controls

Replace inventory-live-summary display with warehouse-paper-inline-summary, and replace work-order-settle-panel / work-order-settle-toggle with paper-specific classes. Keep genericForm.settle_work_order, deviation values, and genericForm.settle_remark unchanged.

Task 3: Add Paper-Specific CSS

Files:

  • Modify: frontend/src/styles/main.css

  • Step 1: Add grid spanning rules

Add the new paper containers beside existing .warehouse-paper-grid rules:

.warehouse-document-section-grid > .warehouse-paper-control-grid,
.warehouse-document-section-grid > .warehouse-paper-source-lot-panel,
.warehouse-document-section-grid > .warehouse-paper-source-lot-table,
.warehouse-document-section-grid > .warehouse-paper-inline-summary,
.warehouse-document-section-grid > .warehouse-paper-settle-panel {
  grid-column: 1 / -1;
}
  • Step 2: Reuse approved paper field and summary cells

Make .warehouse-paper-control-grid visually match .warehouse-paper-grid, with four columns on desktop, two on tablet, and one on mobile. Make .warehouse-paper-control-grid-compact allow summary cards to live in the same grid.

  • Step 3: Style selector/table/settle panels as document rows

Style:

.warehouse-paper-source-lot-panel
.warehouse-paper-source-lot-heading
.warehouse-paper-source-lot-table
.warehouse-paper-inline-summary
.warehouse-paper-settle-panel
.warehouse-paper-settle-toggle
.warehouse-paper-settle-grid
.warehouse-paper-settle-remark

They should use document borders, paper backgrounds, Songti/Simsun value text where appropriate, and no floating modern-card shadows.

Task 4: Verify

Files:

  • Test: frontend/src/views/InventoryLedgerView.test.js

  • Build: frontend/package.json

  • Step 1: Run focused view tests

Run:

cd frontend
node --test src/views/InventoryLedgerView.test.js

Expected: all tests pass.

  • Step 2: Run production build

Run:

cd frontend
npm run build

Expected: Vite build succeeds. Existing chunk-size warning is acceptable if it remains the same non-blocking warning.

  • Step 3: Browser verification

Open http://localhost:5173/inventory-ledger, then inspect:

  • 原材料库 · 客料入库 remains unchanged and approved.
  • 原材料库 · 生产余料入库 uses the same paper-grid visual language.
  • The source-lot multi-select, selected-lot table, remark field, and “该批材料余料结单” no longer look like separate modern web cards pasted onto paper.
  • Existing submit button and drawer behavior still work.

Self-Review

  • Spec coverage: covers the users requested recommended approach by converting the most visible mixed-UI warehouse document first and creating reusable paper classes for subsequent warehouse forms.
  • Placeholder scan: no TBD/TODO/implement-later placeholders.
  • Type consistency: class names in tests, markup, and CSS use the same warehouse-paper-* prefix.