12 KiB
市场物料库「我的物料领用记录」实施计划
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: 采用复用模式 - 页面 = 标题 + Tab组件(mineOnly prop),复用现有 MaterialUsageTab 组件,新增后端 API /web/admin/my-material-usages
Tech Stack: Vue 3 + Element Plus (前端) | FastAPI + SQLAlchemy (后端)
任务清单
Task 1: 后端 - 新增 Pydantic Schema
Files:
- Modify:
backend/app/schemas/material.py
Steps:
- Step 1: 读取现有 schema 文件了解结构
读取 backend/app/schemas/material.py 查看现有的 MaterialUsage 相关 schema 定义。
- Step 2: 添加查询参数 Schema
在 material.py 中添加:
from pydantic import BaseModel, Field
from typing import Optional
class MyMaterialUsageQuery(BaseModel):
keyword: Optional[str] = Field(None, description="关键词搜索")
material_id: Optional[str] = Field(None, description="物料ID")
material_type: Optional[str] = Field(None, description="物料类型")
change_type: Optional[str] = Field(None, description="变动类型")
start_time: Optional[str] = Field(None, description="开始日期 YYYY-MM-DD")
end_time: Optional[str] = Field(None, description="结束日期 YYYY-MM-DD")
- Step 3: 添加响应字段
在 MaterialUsage 或创建新的 MaterialUsageResponse 添加 requisition_status 字段:
class MaterialUsageResponse(BaseModel):
# ... 现有字段 ...
requisition_status: Optional[str] = Field(None, description="领用状态: open/closed")
- Step 4: Commit
git add backend/app/schemas/material.py
git commit -m "feat(market): 新增 MyMaterialUsageQuery schema"
Task 2: 后端 - 新增 CRUD 方法
Files:
- Modify:
backend/app/crud/material.py
Steps:
- Step 1: 读取现有 CRUD 文件
读取 backend/app/crud/material.py 查看现有的 material_usage 相关 CRUD 方法。
- Step 2: 添加 get_my_usages 方法
在 material.py CRUD 文件中添加:
async def get_my_usages(
db: AsyncSession,
current_user_id: str,
tenant_no: str,
page: int = 1,
page_size: int = 10,
keyword: Optional[str] = None,
material_id: Optional[str] = None,
material_type: Optional[str] = None,
change_type: Optional[str] = None,
start_time: Optional[str] = None,
end_time: Optional[str] = None,
) -> Tuple[List[dict], int]:
"""
获取当前用户的物料领用记录(手动出库记录)
Args:
current_user_id: 当前用户ID(用于筛选领用人)
其他筛选参数...
Returns:
(记录列表, 总数)
"""
# 参考现有 material_usage 的查询逻辑
# 额外添加条件:
# - source_type = 'manual_out'
# - receiver = current_user_name 或与 current_user_id 关联的领用人
# 按 create_time DESC 排序
- Step 3: Commit
git add backend/app/crud/material.py
git commit -m "feat(market): 新增 get_my_usages CRUD 方法"
Task 3: 后端 - 新增 API 路由
Files:
- Create:
backend/app/api/market.py - Modify:
backend/app/api/__init__.py - Modify:
backend/app/main.py
Steps:
- Step 1: 创建 market.py 路由文件
创建 backend/app/api/market.py:
from fastapi import APIRouter, Depends, Query
from sqlalchemy.ext.asyncio import AsyncSession
from typing import Optional
from app.core.security import get_current_user
from app.database import get_db
from app.schemas.material import MyMaterialUsageQuery
from app.crud.material import get_my_usages
router = APIRouter(prefix="/market", tags=["market"])
@router.get("/my-material-usages")
async def get_my_material_usage_list(
page: int = Query(1, ge=1),
page_size: int = Query(10, ge=1, le=100),
keyword: Optional[str] = Query(None),
material_id: Optional[str] = Query(None),
material_type: Optional[str] = Query(None),
change_type: Optional[str] = Query(None),
start_time: Optional[str] = Query(None),
end_time: Optional[str] = Query(None),
current_user: dict = Depends(get_current_user),
db: AsyncSession = Depends(get_db),
):
"""获取当前用户的物料领用记录"""
# 获取当前用户信息
user_id = current_user.get("user_id")
user_name = current_user.get("user_name")
tenant_no = current_user.get("tenant_no")
records, total = await get_my_usages(
db=db,
current_user_id=user_id,
user_name=user_name,
tenant_no=tenant_no,
page=page,
page_size=page_size,
keyword=keyword,
material_id=material_id,
material_type=material_type,
change_type=change_type,
start_time=start_time,
end_time=end_time,
)
return {
"list": records,
"total": total,
"page": page,
"pageSize": page_size,
}
- Step 2: 注册路由到 __init__.py
在 backend/app/api/__init__.py 中添加:
from app.api.market import router as market_router
# 在 api_router 列表中添加
api_router.include_router(market_router)
- Step 3: 确保 main.py 中调用 __init__.py
确认 backend/app/main.py 中的 include_router(api_router) 包含了 __init__.py 中注册的路由。
- Step 4: Commit
git add backend/app/api/market.py backend/app/api/__init__.py backend/app/main.py
git commit -m "feat(market): 新增市场模块 API 路由"
Task 4: 前端 - 新增 API 函数
Files:
- Modify:
web-admin/src/api/material-usage.ts
Steps:
- Step 1: 读取现有 API 文件
读取 web-admin/src/api/material-usage.ts 了解现有结构和 MaterialUsage 类型定义。
- Step 2: 添加 fetchMyMaterialUsageList 函数
在 material-usage.ts 中添加:
export async function fetchMyMaterialUsageList(params: {
page: number
pageSize: number
keyword?: string
materialId?: string
materialType?: string
changeType?: string
startTime?: string
endTime?: string
}): Promise<{ list: MaterialUsage[]; total: number }> {
return request.get('/web/admin/my-material-usages', { params })
}
- Step 3: 确保 MaterialUsage 类型包含 requisitionStatus
检查 MaterialUsage 类型定义,如需要则添加:
export interface MaterialUsage {
// ... 现有字段 ...
requisitionStatus?: 'open' | 'closed'
}
- Step 4: Commit
git add web-admin/src/api/material-usage.ts
git commit -m "feat(market): 新增 fetchMyMaterialUsageList API"
Task 5: 前端 - 修改 MaterialUsageTab 支持 mineOnly
Files:
- Modify:
web-admin/src/views/cell-storage/material/MaterialUsageTab.vue
Steps:
- Step 1: 读取现有 MaterialUsageTab.vue
读取 web-admin/src/views/cell-storage/material/MaterialUsageTab.vue 了解当前实现。
- Step 2: 添加 mineOnly prop
在 <script setup> 中添加:
const props = withDefaults(
defineProps<{
mineOnly?: boolean
}>(),
{
mineOnly: false
}
)
- Step 3: 修改 loadData 函数支持 mineOnly
async function loadData() {
loading.value = true
try {
const params: Record<string, any> = {
page: pagination.page,
pageSize: pagination.pageSize
}
// ... 现有参数构建 ...
const res = props.mineOnly
? await fetchMyMaterialUsageList(params)
: await fetchMaterialUsageList(params)
tableData.value = res.list || []
pagination.total = res.total ?? 0
} finally {
loading.value = false
}
}
- Step 4: 导入 fetchMyMaterialUsageList
import {
fetchMaterialUsageList,
fetchMaterialUsage,
fetchMarkMaterialUsageFullyUsed,
fetchMyMaterialUsageList // 新增
} from '@/api/material-usage'
- Step 5: 修改变动类型下拉选项(mineOnly 时不显示入库)
在模板中找到变动类型选择器:
<el-select v-model="searchForm.changeType" placeholder="全部" clearable>
<el-option v-if="!mineOnly" label="入库" value="in" /> <!-- 修改:添加 v-if="!mineOnly" -->
<el-option label="出库" value="out" />
<el-option label="任务使用" value="use" />
<el-option label="废弃" value="discard" />
</el-select>
- Step 6: 添加使用状态列
在表格中(变动类型列之后或适当位置)添加:
<el-table-column
v-if="mineOnly"
label="使用状态"
min-width="100"
align="center"
header-align="center"
>
<template #default="{ row }">
<template v-if="isManualOutRow(row)">
<el-tag v-if="row.requisitionStatus === 'closed'" type="success" size="small">
已使用完
</el-tag>
<el-tag v-else type="info" size="small">
使用中
</el-tag>
</template>
<span v-else>—</span>
</template>
</el-table-column>
- Step 7: 隐藏领用人列(mineOnly 时不显示)
找到领用人列,添加 v-if:
<el-table-column
v-if="!mineOnly" <!-- 添加此条件 -->
label="领用人"
...
>
- Step 8: Commit
git add web-admin/src/views/cell-storage/material/MaterialUsageTab.vue
git commit -m "feat(market): MaterialUsageTab 支持 mineOnly 模式"
Task 6: 前端 - 新建页面
Files:
- Create:
web-admin/src/views/cell-storage/my-material-usage/index.vue
Steps:
- Step 1: 参考生产物料库页面创建
参考 web-admin/src/views/production/my-production-material-usage/index.vue 创建:
<!-- 市场物料库 — 我的物料领用记录 -->
<template>
<div class="page-container">
<section class="panel">
<div class="panel-top">
<h2 class="title-bar-heading">我的物料领用记录</h2>
</div>
<MaterialUsageTab mine-only />
</section>
</div>
</template>
<script setup lang="ts">
import MaterialUsageTab from '../material/MaterialUsageTab.vue'
defineOptions({ name: 'MarketMaterialMyUsage' })
</script>
- Step 2: Commit
git add web-admin/src/views/cell-storage/my-material-usage/index.vue
git commit -m "feat(market): 新增我的物料领用记录页面"
Task 7: 前端 - 添加路由配置
Files:
- Modify:
web-admin/src/router/modules/sqxp.ts
Steps:
- Step 1: 读取路由文件找到市场基础信息菜单位置
在 sqxp.ts 中找到市场物料库的路由配置,添加同级菜单项。
- Step 2: 添加路由配置
在市场物料库路由的同级添加:
{
path: 'my-material-usage',
component: '/cell-storage/my-material-usage/index',
meta: {
title: '我的物料领用记录',
icon: 'List',
menuCode: 'biz:material:myUsage'
}
}
注意:需要添加到市场基础信息菜单分组下。
- Step 3: Commit
git add web-admin/src/router/modules/sqxp.ts
git commit -m "feat(market): 添加我的物料领用记录路由"
Task 8: 验证测试
Steps:
- Step 1: 启动后端服务
cd backend && ./start-local.sh
或确认后端服务已运行。
- Step 2: 启动前端服务
cd web-admin && pnpm dev
- Step 3: 手动测试
- 登录系统
- 访问「市场基础信息 → 我的物料领用记录」
- 验证列表正确加载当前用户的出库记录
- 点击「标记已使用完」按钮
- 验证状态变为"已使用完"
- Step 4: Commit 最终改动
如果测试通过,提交所有剩余改动。
验收清单
- 后端 API
/web/admin/my-material-usages返回正确数据 - 菜单「市场基础信息 → 我的物料领用记录」可正常访问
- 列表仅显示当前用户的物料出库记录
- 变动类型筛选正常(mineOnly 模式不显示入库选项)
- 「使用状态」列正确显示"已使用完"/"使用中"
- 点击「标记已使用完」后,状态正确更新
- 查看详情弹窗正常显示