feat: 前后端全量开发 v0.2
后端: - 客户模块 CRUD+搜索 (api/services/repositories 分层) - 合同模块: FG单号规则/意向单转正式单/订单创建自动快照客户信息 - 优化下料: FFD首递减装箱算法(利用率统计/余料/未排入清单) 前端 (Vue3+TS+Element Plus): - 7页面: 登录/工作台/订单中心/合同/客户/样板库/优化下料 - 自研二维窗型画布渲染器: 解析drawing_data渲染玻璃区域/外框/ 扇开向标记/尺寸标注, 支持缩放平移复位 - 样板库与订单联动(用此样板下单自动带图纸) - axios统一envelope拦截/登录守卫/付费墙提示 工程: - SPA history 回退路由, 构建产物挂载后端 - 全接口回归 6/6 通过
This commit is contained in:
@@ -0,0 +1,85 @@
|
||||
"""合同路由:意向单/正式单管理。"""
|
||||
from fastapi import APIRouter
|
||||
from pydantic import BaseModel, Field
|
||||
|
||||
from huamenchuang.core.deps import CurrentUser, DbSession
|
||||
from huamenchuang.core.response import fail, ok, paginated
|
||||
from huamenchuang.repositories.contract_repo import status_label
|
||||
from huamenchuang.services.contract_service import ContractService
|
||||
|
||||
router = APIRouter(prefix="/contracts", tags=["合同"])
|
||||
|
||||
|
||||
class ContractBody(BaseModel):
|
||||
customer_id: int | None = None
|
||||
customer_name: str = ""
|
||||
phone: str = ""
|
||||
address: str = ""
|
||||
area: float = 0
|
||||
count: int = 0
|
||||
money: float = 0
|
||||
note: str = ""
|
||||
|
||||
|
||||
class ConvertBody(BaseModel):
|
||||
contract_id: int
|
||||
|
||||
|
||||
def _to_out(c) -> dict:
|
||||
return {
|
||||
"id": c.id, "contract_no": c.contract_no, "customer_id": c.customer_id,
|
||||
"customer_name": c.customer_name, "phone": c.phone, "address": c.address,
|
||||
"area": float(c.area), "count": c.count, "money": float(c.money),
|
||||
"status": c.status, "status_label": status_label(c.status),
|
||||
"sign_status": c.sign_status, "note": c.note,
|
||||
"created_at": str(c.created_at), "updated_at": str(c.updated_at),
|
||||
}
|
||||
|
||||
|
||||
@router.post("")
|
||||
async def create_contract(body: ContractBody, user: CurrentUser, db: DbSession):
|
||||
"""创建合同(默认意向单)。"""
|
||||
contract = await ContractService(db).create(user, body.model_dump())
|
||||
return ok(data=_to_out(contract), message="创建成功")
|
||||
|
||||
|
||||
@router.get("")
|
||||
async def list_contracts(user: CurrentUser, db: DbSession, page: int = 1,
|
||||
page_size: int = 15, keyword: str = "", status: int | None = None):
|
||||
"""合同分页列表(结构对齐目标站 {"contracts": {...}})。"""
|
||||
items, total = await ContractService(db).repo.search(
|
||||
user.company_id, page, page_size, keyword, status)
|
||||
return ok(data={"contracts": paginated(
|
||||
[_to_out(c) for c in items], page, page_size, total)})
|
||||
|
||||
|
||||
@router.put("/{contract_id}")
|
||||
async def update_contract(contract_id: int, body: ContractBody, user: CurrentUser, db: DbSession):
|
||||
"""编辑合同。"""
|
||||
try:
|
||||
c = await ContractService(db).update(user, contract_id, body.model_dump())
|
||||
except KeyError as e:
|
||||
return fail(str(e))
|
||||
return ok(data=_to_out(c), message="更新成功")
|
||||
|
||||
|
||||
@router.post("/convert")
|
||||
async def convert_contract(body: ConvertBody, user: CurrentUser, db: DbSession):
|
||||
"""意向单转正式单(对齐目标站 convert-contract/)。"""
|
||||
try:
|
||||
c = await ContractService(db).convert_to_formal(user, body.contract_id)
|
||||
except KeyError as e:
|
||||
return fail(str(e))
|
||||
except ValueError as e:
|
||||
return fail(str(e))
|
||||
return ok(data=_to_out(c), message="已转为正式单")
|
||||
|
||||
|
||||
@router.delete("/{contract_id}")
|
||||
async def delete_contract(contract_id: int, user: CurrentUser, db: DbSession):
|
||||
"""删除合同。"""
|
||||
try:
|
||||
await ContractService(db).delete(user, contract_id)
|
||||
except KeyError as e:
|
||||
return fail(str(e))
|
||||
return ok(message="删除成功")
|
||||
Reference in New Issue
Block a user