2026-05-17-production-management.md 34 KB

生产管理模块 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: Implement 7 production management modules (耗材管理、试剂管理、SOP文档、工艺工序分类、工艺产出物类型、耗材包管理、工艺库管理) with backend API + frontend UI, following existing codebase patterns exactly. 工艺路线配置 deferred to next iteration.

Architecture: FastAPI backend with flat-function CRUD (no service layer), Vue 3 + Element Plus frontend with standard list page template. Batch 1 (5 simple CRUD modules) has no dependencies. Batch 2 (耗材包+工艺库) depends on Batch 1. All modules share a new API route file app/api/production.py and frontend route group under /production.

Tech Stack: Python 3.9 / FastAPI / SQLAlchemy / Pydantic v2 (backend); Vue 3 / TypeScript / Element Plus / Tailwind CSS 4 (frontend)

Design Spec: docs/superpowers/specs/2026-05-17-production-management-design.md

Key Reference Files (READ FIRST):

  • Backend CRUD pattern: backend/app/crud/item_unit.py — canonical simple CRUD
  • Backend API pattern: backend/app/api/admin.py (item-unit section, lines 968-1059)
  • Backend model pattern: backend/app/models/models.py (class BizItemUnit)
  • Frontend standard list: web-admin/src/views/system/unit/index.vue — canonical list page
  • Frontend API pattern: web-admin/src/api/admin.ts (fetchXxxList/fetchCreateXxx/fetchUpdateXxx/fetchDeleteXxx)
  • Frontend router: web-admin/src/router/modules/sqxp.ts
  • Upload pattern: web-admin/src/api/business.ts (fetchUploadAttachment)

File Structure

Backend (create/modify)

File Action Purpose
docs/sql/production.sql CREATE All 11 tables DDL + menu INSERT statements
backend/app/models/models.py MODIFY Add 11 model classes at end of file
backend/app/crud/consumable.py CREATE 耗材 CRUD
backend/app/crud/reagent.py CREATE 试剂 CRUD
backend/app/crud/sop_document.py CREATE SOP文档 CRUD
backend/app/crud/process_category.py CREATE 工艺工序分类 CRUD
backend/app/crud/output_type.py CREATE 工艺产出物类型 CRUD
backend/app/crud/consumable_pack.py CREATE 耗材包 CRUD (主表+明细)
backend/app/crud/process.py CREATE 工艺库 CRUD (主表+3子表)
backend/app/api/production.py CREATE All 7 modules API routes
backend/app/api/__init__.py MODIFY Import + export production_router
backend/app/main.py MODIFY Import + register production_router

Frontend (create/modify)

File Action Purpose
web-admin/src/api/production.ts CREATE All 7 modules API functions
web-admin/src/router/modules/sqxp.ts MODIFY Add 生产管理 route group
web-admin/src/views/production/consumable/index.vue CREATE 耗材管理标准列表页
web-admin/src/views/production/reagent/index.vue CREATE 试剂管理标准列表页
web-admin/src/views/production/sop/index.vue CREATE SOP文档列表页(含附件上传)
web-admin/src/views/production/process-category/index.vue CREATE 工艺工序分类标准列表页
web-admin/src/views/production/output-type/index.vue CREATE 工艺产出物类型标准列表页
web-admin/src/views/production/consumable-pack/index.vue CREATE 耗材包管理列表页(含明细子表)
web-admin/src/views/production/process/index.vue CREATE 工艺库管理列表页(Tab式编辑)

Task 1: SQL DDL + Menu Entries

Files:

  • Create: docs/sql/production.sql

  • [ ] Step 1: Create the SQL DDL file with all 11 tables and menu entries

Create docs/sql/production.sql with the complete DDL. All tables follow project conventions: id VARCHAR(64) UUID, business fields first, then public fields (tenant_no through del_flag), ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci.

Tables to create:

  1. biz_consumable — consumable_code, consumable_name, spec_model, standard_usage, description
  2. biz_reagent — reagent_code, reagent_name, spec, standard_usage, unit, description
  3. biz_sop_document — sop_code, sop_name, version_no, sop_attachments
  4. biz_process_category — category_code, category_name
  5. biz_output_type — type_code, type_name
  6. biz_consumable_pack — pack_code, pack_name, usage_scene, pack_type, status
  7. biz_consumable_pack_item — pack_id, consumable_code, consumable_name, spec_model, standard_usage, remark
  8. biz_process — process_code, category_id, process_name, description, equipment_name, estimated_duration, sop_ids
  9. biz_process_reagent — process_id, reagent_code, reagent_name, spec, standard_usage, unit, is_key_material
  10. biz_process_consumable — process_id, consumable_code, consumable_name, spec_model, standard_usage, is_required, remark
  11. biz_process_output — process_id, output_type_id, output_name, output_barcode

Also include INSERT statements for sys_menu:

  • Top-level menu "生产管理" under Web root (parent_id pointing to the Web menu root, which has id='1')
  • 7 child menu items, each with appropriate menu_code (e.g., production:consumable:list, production:reagent:list, etc.)

Verification: File contains valid SQL, all tables have public fields, all tables use VARCHAR(64) for id, charset utf8mb4.

  • Step 2: Commit
git add docs/sql/production.sql
git commit -m "feat: add production management SQL DDL and menu entries"

Task 2: Backend Models (11 SQLAlchemy models)

Files:

  • Modify: backend/app/models/models.py (append at end)
  • Modify: backend/app/models/__init__.py (re-export new models)

  • [ ] Step 1: Add 11 model classes to models.py

Append after the last class in backend/app/models/models.py. Follow the exact pattern of BizItemUnit:

  • Inherit from Base (from app.core.database)
  • All columns use Column(...) with explicit types
  • Public fields in exact order: tenant_no, order_num, remark, create_by, create_dept_id, create_time, update_by, update_time, del_flag
  • create_time uses default=datetime.now, update_time uses default=datetime.now, onupdate=datetime.now
  • del_flag uses SmallInteger with default=0

Models:

  • BizConsumable → biz_consumable
  • BizReagent → biz_reagent
  • BizSopDocument → biz_sop_document
  • BizProcessCategory → biz_process_category
  • BizOutputType → biz_output_type
  • BizConsumablePack → biz_consumable_pack
  • BizConsumablePackItem → biz_consumable_pack_item
  • BizProcess → biz_process
  • BizProcessReagent → biz_process_reagent
  • BizProcessConsumable → biz_process_consumable
  • BizProcessOutput → biz_process_output

  • [ ] Step 2: Re-export in backend/app/models/__init__.py

Add all 11 new classes to the imports and __all__ list.

  • Step 3: Verify

Run: cd backend && source venv/bin/activate && python -c "from app.models.models import BizConsumable, BizReagent, BizSopDocument, BizProcessCategory, BizOutputType, BizConsumablePack, BizConsumablePackItem, BizProcess, BizProcessReagent, BizProcessConsumable, BizProcessOutput; print('All models imported OK')"

  • Step 4: Commit
git add backend/app/models/
git commit -m "feat: add 11 production management SQLAlchemy models"

Task 3: Backend CRUD — Batch 1 (5 simple modules)

Files:

  • Create: backend/app/crud/consumable.py
  • Create: backend/app/crud/reagent.py
  • Create: backend/app/crud/sop_document.py
  • Create: backend/app/crud/process_category.py
  • Create: backend/app/crud/output_type.py

Each CRUD file follows the EXACT pattern from backend/app/crud/item_unit.py:

  1. _row_to_dict(obj) — returns dict with camelCase keys
  2. list_xxx(db, *, page, page_size, keyword, tenant_no) — paginated list with keyword search + tenant filter + soft-delete filter
  3. get_xxx(db, id) — single record by id with del_flag=0 check
  4. xxx_code_exists(db, code, tenant_no, exclude_id=None) — uniqueness check on code field
  5. create_xxx(db, *, ...fields..., tenant_no, user_id) — validate + create with generate_uuid()
  6. update_xxx(db, id, *, ...fields..., user_id) — validate + update
  7. soft_delete_xxx(db, id) — set del_flag=1
  8. total_pages(total, page_size) — pagination helper
  • Step 1: Create backend/app/crud/consumable.py

Fields: consumable_code, consumable_name, spec_model, standard_usage, description Keyword search on: consumable_code, consumable_name

  • Step 2: Create backend/app/crud/reagent.py

Fields: reagent_code, reagent_name, spec, standard_usage, unit, description Keyword search on: reagent_code, reagent_name

  • Step 3: Create backend/app/crud/sop_document.py

Fields: sop_code, sop_name, version_no, sop_attachments Keyword search on: sop_code, sop_name NOTE: sop_attachments stores comma-separated URLs, returned as-is in _row_to_dict

  • Step 4: Create backend/app/crud/process_category.py

Fields: category_code, category_name Keyword search on: category_code, category_name

  • Step 5: Create backend/app/crud/output_type.py

Fields: type_code, type_name Keyword search on: type_code, type_name

  • Step 6: Verify all CRUD modules import correctly

Run: cd backend && source venv/bin/activate && python -c "from app.crud import consumable, reagent, sop_document, process_category, output_type; print('All CRUD modules OK')"

  • Step 7: Commit
git add backend/app/crud/consumable.py backend/app/crud/reagent.py backend/app/crud/sop_document.py backend/app/crud/process_category.py backend/app/crud/output_type.py
git commit -m "feat: add batch 1 CRUD modules (consumable, reagent, sop, process-category, output-type)"

Task 4: Backend CRUD — Batch 2 (耗材包 + 工艺库)

Files:

  • Create: backend/app/crud/consumable_pack.py
  • Create: backend/app/crud/process.py

耗材包 CRUD (主表+明细)

  • Step 1: Create backend/app/crud/consumable_pack.py

This module needs:

  • BizConsumablePack main table CRUD (list, get, create, update, soft_delete)
  • BizConsumablePackItem detail table CRUD
  • Create: Accept main fields + list of items. Generate UUID for pack, then create each item with pack_id.
  • Update: Accept main fields + list of items. Update main record, then delete existing items + re-insert (simple replace strategy).
  • Get detail: Return main record + list of child items (_row_to_dict for main includes items: [...])
  • Soft delete: Also soft-delete all child items (set their del_flag=1)
  • _row_to_dict for main includes: pack items as nested list

_row_to_dict for pack item:

{
    "id": item.id,
    "packId": item.pack_id,
    "consumableCode": item.consumable_code,
    "consumableName": item.consumable_name,
    "specModel": item.spec_model,
    "standardUsage": item.standard_usage,
    "remark": item.remark or "",
}

工艺库 CRUD (主表+3个子表)

  • Step 2: Create backend/app/crud/process.py

This module needs:

  • BizProcess main table CRUD
  • BizProcessReagent sub-table CRUD
  • BizProcessConsumable sub-table CRUD
  • BizProcessOutput sub-table CRUD
  • Create: Accept main fields + 3 lists (reagents, consumables, outputs). Generate UUID for process, then create each sub-record with process_id.
  • Update: Replace strategy — update main, delete+re-insert all sub-records.
  • Get detail: Return main record + 3 nested lists.
  • Soft delete: Also soft-delete all child records.

_row_to_dict for process includes:

{
    "id": ...,
    "processCode": ...,
    "categoryId": ...,
    "processName": ...,
    "description": ...,
    "equipmentName": ...,
    "estimatedDuration": ...,
    "sopIds": ...,
    # ... public fields ...
    "reagents": [reagent_row_to_dict(r) for r in reagents],
    "consumables": [consumable_row_to_dict(c) for c in consumables],
    "outputs": [output_row_to_dict(o) for o in outputs],
}
  • Step 3: Verify

Run: cd backend && source venv/bin/activate && python -c "from app.crud import consumable_pack, process; print('Batch 2 CRUD OK')"

  • Step 4: Commit
git add backend/app/crud/consumable_pack.py backend/app/crud/process.py
git commit -m "feat: add batch 2 CRUD modules (consumable-pack, process)"

Task 5: Backend API Routes + Registration

Files:

  • Create: backend/app/api/production.py
  • Modify: backend/app/api/__init__.py
  • Modify: backend/app/main.py

  • [ ] Step 1: Create backend/app/api/production.py

Follow the exact pattern from backend/app/api/admin.py (item-units section).

Structure:

from fastapi import APIRouter, Depends, Query
from pydantic import BaseModel, ConfigDict, Field
from sqlalchemy.orm import Session
from typing import Any, Optional, List

from app.core.database import get_db
from app.core.menu_guard import require_admin_or_super_admin, require_menu_code
from app.core.response import success_response, error_response
from app.crud import consumable as consumable_svc
from app.crud import reagent as reagent_svc
from app.crud import sop_document as sop_document_svc
from app.crud import process_category as process_category_svc
from app.crud import output_type as output_type_svc
from app.crud import consumable_pack as consumable_pack_svc
from app.crud import process as process_svc
from app.models.models import SysUser

router = APIRouter(prefix="/web/admin", tags=["生产管理"])

def _get_tenant_no(db: Session, user: dict) -> str:
    # Same pattern as admin.py
    ...

Endpoints to create (7 modules × 4 CRUD operations = 28 endpoints):

Module List (GET) Create (POST) Update (PUT) Delete (DELETE)
耗材 /consumables /consumables /consumables/{id} /consumables/{id}
试剂 /reagents /reagents /reagents/{id} /reagents/{id}
SOP /sop-documents /sop-documents /sop-documents/{id} /sop-documents/{id}
工序分类 /process-categories /process-categories /process-categories/{id} /process-categories/{id}
产出物类型 /output-types /output-types /output-types/{id} /output-types/{id}
耗材包 /consumable-packs /consumable-packs /consumable-packs/{id} /consumable-packs/{id}
工艺库 /processes /processes /processes/{id} /processes/{id}

Additional list-only endpoints needed by dropdowns:

  • GET /reagers/all — all reagents (no pagination, for dropdown in process form)
  • GET /consumables/all — all consumables (for dropdown in pack/process form)
  • GET /sop-documents/all — all SOP docs (for multi-select in process form)
  • GET /process-categories/all — all categories (for dropdown)
  • GET /output-types/all — all output types (for dropdown)
  • GET /consumable-packs/{id}/items — pack items (for importing into process)

Request body patterns:

Simple CRUD (耗材 as example):

class ConsumableCreateBody(BaseModel):
    model_config = ConfigDict(populate_by_name=True)
    consumable_code: str = Field(..., alias="consumableCode")
    consumable_name: str = Field(..., alias="consumableName")
    spec_model: Optional[str] = Field(None, alias="specModel")
    standard_usage: Optional[str] = Field(None, alias="standardUsage")
    description: Optional[str] = None
    order_num: Optional[int] = Field(0, alias="orderNum")
    remark: Optional[str] = None

耗材包 Create/Update (includes items):

class PackItemInput(BaseModel):
    model_config = ConfigDict(populate_by_name=True)
    consumable_code: Optional[str] = Field(None, alias="consumableCode")
    consumable_name: Optional[str] = Field(None, alias="consumableName")
    spec_model: Optional[str] = Field(None, alias="specModel")
    standard_usage: Optional[str] = Field(None, alias="standardUsage")
    remark: Optional[str] = None

class ConsumablePackCreateBody(BaseModel):
    model_config = ConfigDict(populate_by_name=True)
    pack_code: str = Field(..., alias="packCode")
    pack_name: str = Field(..., alias="packName")
    usage_scene: Optional[str] = Field(None, alias="usageScene")
    pack_type: Optional[str] = Field(None, alias="packType")
    status: Optional[str] = "1"
    order_num: Optional[int] = Field(0, alias="orderNum")
    remark: Optional[str] = None
    items: List[PackItemInput] = []

工艺库 Create/Update (includes 3 sub-lists):

class ProcessReagentInput(BaseModel):
    model_config = ConfigDict(populate_by_name=True)
    reagent_code: Optional[str] = Field(None, alias="reagentCode")
    reagent_name: Optional[str] = Field(None, alias="reagentName")
    spec: Optional[str] = None
    standard_usage: Optional[str] = Field(None, alias="standardUsage")
    unit: Optional[str] = None
    is_key_material: Optional[str] = Field("0", alias="isKeyMaterial")

class ProcessConsumableInput(BaseModel):
    model_config = ConfigDict(populate_by_name=True)
    consumable_code: Optional[str] = Field(None, alias="consumableCode")
    consumable_name: Optional[str] = Field(None, alias="consumableName")
    spec_model: Optional[str] = Field(None, alias="specModel")
    standard_usage: Optional[str] = Field(None, alias="standardUsage")
    is_required: Optional[str] = Field("1", alias="isRequired")
    remark: Optional[str] = None

class ProcessOutputInput(BaseModel):
    model_config = ConfigDict(populate_by_name=True)
    output_type_id: Optional[str] = Field(None, alias="outputTypeId")
    output_name: Optional[str] = Field(None, alias="outputName")
    output_barcode: Optional[str] = Field(None, alias="outputBarcode")

class ProcessCreateBody(BaseModel):
    model_config = ConfigDict(populate_by_name=True)
    process_code: str = Field(..., alias="processCode")
    category_id: Optional[str] = Field(None, alias="categoryId")
    process_name: str = Field(..., alias="processName")
    description: Optional[str] = None
    equipment_name: Optional[str] = Field(None, alias="equipmentName")
    estimated_duration: Optional[str] = Field(None, alias="estimatedDuration")
    sop_ids: Optional[str] = Field(None, alias="sopIds")
    order_num: Optional[int] = Field(0, alias="orderNum")
    remark: Optional[str] = None
    reagents: List[ProcessReagentInput] = []
    consumables: List[ProcessConsumableInput] = []
    outputs: List[ProcessOutputInput] = []

Auth patterns:

  • List endpoints: Depends(require_menu_code("production:xxx:list"))
  • Write endpoints: Depends(require_admin_or_super_admin)
  • "All" dropdown endpoints: Depends(require_admin_or_super_admin) (lightweight, no pagination)

  • [ ] Step 2: Register router in backend/app/api/__init__.py

Add:

from app.api.production import router as production_router

Add production_router to __all__.

  • Step 3: Register router in backend/app/main.py

Add import and:

app.include_router(production_router, prefix=settings.API_V1_PREFIX)
  • Step 4: Verify backend starts

Run: cd backend && source venv/bin/activate && python -c "from app.main import app; routes = [r.path for r in app.routes]; prod = [r for r in routes if 'consumable' in r or 'reagent' in r or 'sop-document' in r or 'process-categor' in r or 'output-type' in r or 'consumable-pack' in r or 'processes' in r]; print(f'Production routes: {len(prod)}'); print(prod[:10])"

Expected: 28+ production routes registered.

  • Step 5: Commit
git add backend/app/api/production.py backend/app/api/__init__.py backend/app/main.py
git commit -m "feat: add production management API routes (7 modules, 28 endpoints)"

Task 6: Frontend API Functions

Files:

  • Create: web-admin/src/api/production.ts

  • [ ] Step 1: Create web-admin/src/api/production.ts

Follow the pattern from web-admin/src/api/admin.ts. Use request.get/post/put/del with params for JSON body and data for FormData.

For each of the 7 modules, define 4 API functions (list, create, update, delete). Also define "all" functions for dropdown data.

import request from '@/utils/http'

// ==================== 耗材管理 ====================
export function fetchConsumableList(params?: { page?: number; pageSize?: number; keyword?: string }) {
  return request.get<{ list: any[]; total: number; page: number; pageSize: number; totalPages: number }>({
    url: '/web/admin/consumables', params
  })
}
export function fetchAllConsumables() {
  return request.get<any[]>({ url: '/web/admin/consumables/all' })
}
export function fetchCreateConsumable(data: Record<string, any>) {
  return request.post({ url: '/web/admin/consumables', params: data })
}
export function fetchUpdateConsumable(id: string, data: Record<string, any>) {
  return request.put({ url: `/web/admin/consumables/${id}`, params: data })
}
export function fetchDeleteConsumable(id: string) {
  return request.del({ url: `/web/admin/consumables/${id}` })
}

// ==================== 试剂管理 ====================
// (same pattern: fetchReagentList, fetchAllReagents, fetchCreateReagent, fetchUpdateReagent, fetchDeleteReagent)

// ==================== SOP文档 ====================
// (same pattern: fetchSopList, fetchAllSopDocuments, fetchCreateSop, fetchUpdateSop, fetchDeleteSop)

// ==================== 工艺工序分类 ====================
// (same pattern: fetchProcessCategoryList, fetchAllProcessCategories, fetchCreateProcessCategory, ...)

// ==================== 工艺产出物类型 ====================
// (same pattern: fetchOutputTypeList, fetchAllOutputTypes, fetchCreateOutputType, ...)

// ==================== 耗材包管理 ====================
// (same pattern, but create/update body includes items array)

// ==================== 工艺库管理 ====================
// (same pattern, but create/update body includes reagents, consumables, outputs arrays)

Important convention from codebase: POST/PUT use params for JSON body, showSuccessMessage: true is NOT needed (messages shown in page component).

  • Step 2: Commit
git add web-admin/src/api/production.ts
git commit -m "feat: add production management frontend API functions"

Task 7: Frontend Routes + Menu

Files:

  • Modify: web-admin/src/router/modules/sqxp.ts

  • [ ] Step 1: Add production route group to sqxp.ts

Add a new top-level route entry. Use a unique ID (e.g., '90000000000000000000000000000001'). Follow the existing pattern of other top-level groups.

{
  id: '90000000000000000000000000000001',
  name: 'ProductionManagement',
  path: '/production',
  component: '/index/index',
  meta: { title: '生产管理', icon: 'ri:factory-line', keepAlive: false, roles: ['admin'] },
  children: [
    {
      id: '90000000000000000000000000000010',
      name: 'ProductionConsumable',
      path: 'consumable',
      component: '/production/consumable/index',
      meta: { title: '耗材管理', keepAlive: true, menuCode: 'production:consumable:list' }
    },
    {
      id: '90000000000000000000000000000020',
      name: 'ProductionReagent',
      path: 'reagent',
      component: '/production/reagent/index',
      meta: { title: '试剂管理', keepAlive: true, menuCode: 'production:reagent:list' }
    },
    {
      id: '90000000000000000000000000000030',
      name: 'ProductionSop',
      path: 'sop',
      component: '/production/sop/index',
      meta: { title: 'SOP文档', keepAlive: true, menuCode: 'production:sop:list' }
    },
    {
      id: '90000000000000000000000000000040',
      name: 'ProductionProcessCategory',
      path: 'process-category',
      component: '/production/process-category/index',
      meta: { title: '工艺工序分类', keepAlive: true, menuCode: 'production:process-category:list' }
    },
    {
      id: '90000000000000000000000000000050',
      name: 'ProductionOutputType',
      path: 'output-type',
      component: '/production/output-type/index',
      meta: { title: '工艺产出物类型', keepAlive: true, menuCode: 'production:output-type:list' }
    },
    {
      id: '90000000000000000000000000000060',
      name: 'ProductionConsumablePack',
      path: 'consumable-pack',
      component: '/production/consumable-pack/index',
      meta: { title: '耗材包管理', keepAlive: true, menuCode: 'production:consumable-pack:list' }
    },
    {
      id: '90000000000000000000000000000070',
      name: 'ProductionProcess',
      path: 'process',
      component: '/production/process/index',
      meta: { title: '工艺库管理', keepAlive: true, menuCode: 'production:process:list' }
    }
  ]
}

NOTE: Add this to sqxpAdminRoutes array in sqxp.ts. Icon only on top-level (sidebar convention).

  • Step 2: Commit
git add web-admin/src/router/modules/sqxp.ts
git commit -m "feat: add production management frontend routes"

Task 8: Frontend Pages — Batch 1 (5 simple CRUD pages)

Files:

  • Create: web-admin/src/views/production/consumable/index.vue
  • Create: web-admin/src/views/production/reagent/index.vue
  • Create: web-admin/src/views/production/sop/index.vue
  • Create: web-admin/src/views/production/process-category/index.vue
  • Create: web-admin/src/views/production/output-type/index.vue

All 5 pages follow the exact same pattern as web-admin/src/views/system/unit/index.vue (327 lines). Read that file first and replicate its structure.

Common page structure:

page-container
  page-head (h1 title + description)
  panel
    panel-top (title-bar-heading with green vertical bar)
    filter-block (keyword search + search/reset buttons)
    list-toolbar (selected count + add button)
    list-body/list-wrap (el-table with columns + pagination)
    el-dialog (add/edit form, label-position="top", form-grid-2)

Per-page differences:

  • Step 1: Create 耗材管理 page (production/consumable/index.vue)

defineOptions({ name: 'ProductionConsumable' })

  • Table columns: 耗材编码, 耗材名称, 规格型号, 标准用量, 描述, 创建时间, 操作
  • Search keyword searches on: consumableCode, consumableName
  • Form fields: consumableCode (required), consumableName (required), specModel, standardUsage, description, remark
  • API: fetchConsumableList, fetchCreateConsumable, fetchUpdateConsumable, fetchDeleteConsumable from @/api/production

  • [ ] Step 2: Create 试剂管理 page (production/reagent/index.vue)

defineOptions({ name: 'ProductionReagent' })

  • Table columns: 试剂编码, 试剂名称, 规格, 标准用量, 单位, 描述, 创建时间, 操作
  • Form fields: reagentCode (required), reagentName (required), spec, standardUsage, unit (el-select dropdown from item-unit API), description, remark
  • Special: "单位" field is an el-select that loads options from fetchAllItemUnits() (import from @/api/admin)
  • API: fetchReagentList, fetchCreateReagent, fetchUpdateReagent, fetchDeleteReagent from @/api/production

  • [ ] Step 3: Create SOP文档 page (production/sop/index.vue)

defineOptions({ name: 'ProductionSop' })

  • Table columns: SOP编号, SOP文档名称, 版本号, 附件数, 创建时间, 操作
  • Form fields: sopCode (required), sopName (required), versionNo, sopAttachments (file upload card)
  • Special: File upload using the card layout pattern from ProtocolFormDialog.vue:
    • Use el-upload with :auto-upload="false", @change="handleFileChange"
    • Upload via fetchUploadAttachment(formData) from @/api/business
    • Store comma-separated URLs in sopAttachments field
    • Display attachment count in table
  • API: fetchSopList, fetchCreateSop, fetchUpdateSop, fetchDeleteSop from @/api/production

  • [ ] Step 4: Create 工艺工序分类 page (production/process-category/index.vue)

defineOptions({ name: 'ProductionProcessCategory' })

  • Table columns: 分类编码, 分类名称, 创建时间, 操作
  • Form fields: categoryCode (required), categoryName (required), remark
  • Simplest page — identical to unit template
  • API: fetchProcessCategoryList, fetchCreateProcessCategory, fetchUpdateProcessCategory, fetchDeleteProcessCategory from @/api/production

  • [ ] Step 5: Create 工艺产出物类型 page (production/output-type/index.vue)

defineOptions({ name: 'ProductionOutputType' })

  • Table columns: 类型编码, 类型名称, 创建时间, 操作
  • Form fields: typeCode (required), typeName (required), remark
  • Same pattern as 工序分类 — very simple
  • API: fetchOutputTypeList, fetchCreateOutputType, fetchUpdateOutputType, fetchDeleteOutputType from @/api/production

  • [ ] Step 6: Verify all 5 pages load

Run: cd web-admin && pnpm build 2>&1 | tail -5 Expected: Build succeeds with no errors.

  • Step 7: Commit
git add web-admin/src/views/production/
git commit -m "feat: add batch 1 frontend pages (consumable, reagent, sop, process-category, output-type)"

Task 9: Frontend Page — 耗材包管理

Files:

  • Create: web-admin/src/views/production/consumable-pack/index.vue

  • [ ] Step 1: Create 耗材包管理 page

defineOptions({ name: 'ProductionConsumablePack' })

List page: Standard template with additional columns:

  • Table columns: 编号, 名称, 使用场景, 类型(display dict: bzhcb=标准耗材包, zdyhcb=自定义耗材包), 状态(el-switch or tag: 1=启用, 0=停用), 创建时间, 操作

Add/Edit dialog: Larger dialog with 2 sections:

  1. 基本信息: packCode, packName, usageScene, packType (el-radio-group: bzhcb/zdyhcb), status (el-switch), remark
  2. 耗材明细: Embedded el-table inside the dialog for managing pack items:
    • Each row: consumableCode, consumableName, specModel, standardUsage, remark
    • "添加耗材" button opens a sub-dialog to select from consumable list (use fetchAllConsumables() dropdown or table select)
    • After selecting, auto-fill code/name/spec from the consumable record
    • Row-level delete button
    • Inline editing for standardUsage

Data flow:

  • On dialog open (edit mode): Load pack detail which includes items array
  • On save: Submit main fields + items array together to create/update API

  • [ ] Step 2: Verify page loads

Run: cd web-admin && pnpm build 2>&1 | tail -5

  • Step 3: Commit
git add web-admin/src/views/production/consumable-pack/
git commit -m "feat: add consumable pack management frontend page"

Task 10: Frontend Page — 工艺库管理

Files:

  • Create: web-admin/src/views/production/process/index.vue

  • [ ] Step 1: Create 工艺库管理 page

defineOptions({ name: 'ProductionProcess' })

List page: Standard template:

  • Table columns: 工序代码, 工序名称, 工序分类(resolve from category map), 描述, 设备名称, 预估耗时, 创建时间, 操作
  • On load: also fetch all categories, SOP docs for display resolution

Add/Edit dialog: Wide dialog (width="900px") with el-tabs:

  • Tab 1 — 基本信息: processCode, categoryId (el-select from fetchAllProcessCategories), processName, description, equipmentName, estimatedDuration, sopIds (el-select multiple from fetchAllSopDocuments), remark
  • Tab 2 — 试剂关联: el-table with rows:
    • Columns: reagentCode, reagentName, spec, standardUsage, unit, isKeyMaterial (el-switch/checkbox)
    • "添加试剂" button → select from reagent dropdown (fetchAllReagents), auto-fill code/name/spec/usage/unit
    • User can modify standardUsage and isKeyMaterial
    • Row delete button
  • Tab 3 — 耗材关联: el-table with rows:
    • Columns: consumableCode, consumableName, specModel, standardUsage, isRequired (el-switch), remark
    • Two add modes:
    • "添加耗材" button → select from consumable dropdown
    • "从耗材包导入" button → select pack (el-select from fetchAllConsumablePacks), then load pack items and merge into table
    • Row delete button
  • Tab 4 — 产出物: el-table with rows:
    • Columns: outputTypeId (display resolved name), outputName, outputBarcode
    • "添加产出物" button → row with el-select for output type + input for name
    • Row delete button

Data flow:

  • On dialog open (edit mode): Load process detail which includes reagents/consumables/outputs arrays
  • On tab switch: No special action needed (all data in local reactive state)
  • On save: Collect all 4 sections' data and submit together

Key considerations:

  • Load dropdown data (categories, reagents, consumables, SOP docs, output types, consumable packs) when dialog opens
  • Use onMounted or dialog open handler to pre-fetch reference data
  • Display category name in table by maintaining a category map {id: name}

  • [ ] Step 2: Verify page loads

Run: cd web-admin && pnpm build 2>&1 | tail -5

  • Step 3: Commit
git add web-admin/src/views/production/process/
git commit -m "feat: add process library management frontend page"

Task 11: Final Verification

  • Step 1: Full frontend build

Run: cd web-admin && pnpm build Expected: Exit code 0, no errors.

  • Step 2: Backend import check

Run: cd backend && source venv/bin/activate && python -c "from app.main import app; print('Backend OK')"

  • Step 3: Manual smoke test (if dev server available)
  1. Start backend: cd backend && ./start-local.sh
  2. Start frontend: cd web-admin && pnpm dev
  3. Navigate to each of the 7 pages under 生产管理 sidebar
  4. Test CRUD on each page (add, edit, delete, search)
  5. Test dropdown loading on 试剂 (unit dropdown), 工艺库 (category/reagent/consumable/SOP/output dropdowns)
  6. Test file upload on SOP文档
  7. Test耗材包 item management (add/remove items)
  8. Test工艺库 tab management (add/remove reagents, consumables, outputs)

Dependency Graph

Task 1 (SQL)
    ↓
Task 2 (Models)
    ↓
Task 3 (CRUD Batch 1) ← independent from Task 6/7
    ↓
Task 4 (CRUD Batch 2)
    ↓
Task 5 (API Routes) ← depends on Task 3 + 4
    ↓
Task 6 (Frontend API) ← independent, can parallel with Task 5
Task 7 (Frontend Routes) ← independent, can parallel with Task 5
    ↓
Task 8 (Frontend Batch 1) ← depends on Task 5 + 6 + 7
    ↓
Task 9 (Frontend 耗材包) ← depends on Task 5 + 6 + 7
Task 10 (Frontend 工艺库) ← depends on Task 5 + 6 + 7 + 8 (needs dropdowns from batch 1)
    ↓
Task 11 (Final Verification) ← depends on all above

Parallelization opportunities:

  • Tasks 6 + 7 can run in parallel with Task 5
  • Tasks 8 + 9 can run in parallel (both depend on Task 5+6+7)
  • Task 10 should wait for Task 8 (needs dropdown APIs working)