feat: P0-3 打印模板体系(区块化模板CRUD+打印中心重构)

This commit is contained in:
HHY
2026-09-25 03:13:38 -07:00
parent 3d0f43d567
commit 87f9869829
8 changed files with 360 additions and 28 deletions
+92
View File
@@ -0,0 +1,92 @@
"""打印模板路由:订单打印模板 CRUD(对齐目标站 order_format 语义)。"""
import json
from fastapi import APIRouter
from pydantic import BaseModel, Field
from sqlalchemy import select
from huamenchuang.core.deps import CurrentUser, DbSession
from huamenchuang.core.response import fail, ok
from huamenchuang.models.extend import OrderFormat
router = APIRouter(prefix="/order-formats", tags=["打印模板"])
BLOCK_TYPES = ("title", "info", "image", "table", "sign")
TABLE_KINDS = ("process", "bom")
class FormatBody(BaseModel):
name: str = Field(min_length=1, max_length=64)
order_type: int = Field(default=0, ge=0, le=1)
blocks: list[dict] = Field(default_factory=list, description="模板区块列表")
is_default: int = Field(default=0, ge=0, le=1)
def _validate_blocks(blocks: list[dict]) -> str | None:
for b in blocks:
if b.get("type") not in BLOCK_TYPES:
return f"不支持的区块类型: {b.get('type')}"
if b.get("type") == "table" and b.get("kind") not in TABLE_KINDS:
return "table 区块需要 kind: process/bom"
return None
def _to_out(f: OrderFormat) -> dict:
return {"id": f.id, "name": f.name, "order_type": f.order_type,
"blocks": json.loads(f.blocks or "[]"), "is_default": f.is_default, "sort": f.sort}
@router.get("")
async def list_formats(user: CurrentUser, db: DbSession):
stmt = (select(OrderFormat).where(OrderFormat.company_id == user.company_id)
.order_by(OrderFormat.sort, OrderFormat.id))
rows = list((await db.execute(stmt)).scalars())
return ok(data=[_to_out(r) for r in rows])
@router.post("")
async def create_format(body: FormatBody, user: CurrentUser, db: DbSession):
err = _validate_blocks(body.blocks)
if err:
return fail(err)
fmt = OrderFormat(company_id=user.company_id,
name=body.name, order_type=body.order_type,
blocks=json.dumps(body.blocks, ensure_ascii=False),
is_default=body.is_default)
if body.is_default: # 唯一默认
for other in (await db.execute(select(OrderFormat).where(
OrderFormat.company_id == user.company_id))).scalars():
other.is_default = 0
db.add(fmt)
await db.flush()
return ok(data=_to_out(fmt), message="模板已创建")
@router.put("/{format_id}")
async def update_format(format_id: int, body: FormatBody, user: CurrentUser, db: DbSession):
fmt = await db.get(OrderFormat, format_id)
if fmt is None or fmt.company_id != user.company_id:
return fail("模板不存在")
err = _validate_blocks(body.blocks)
if err:
return fail(err)
fmt.name = body.name
fmt.order_type = body.order_type
fmt.blocks = json.dumps(body.blocks, ensure_ascii=False)
if body.is_default:
for other in (await db.execute(select(OrderFormat).where(
OrderFormat.company_id == user.company_id))).scalars():
other.is_default = 0
fmt.is_default = 1
else:
fmt.is_default = 0
return ok(data=_to_out(fmt), message="模板已更新")
@router.delete("/{format_id}")
async def delete_format(format_id: int, user: CurrentUser, db: DbSession):
fmt = await db.get(OrderFormat, format_id)
if fmt is None or fmt.company_id != user.company_id:
return fail("模板不存在")
await db.delete(fmt)
return ok(message="模板已删除")
+2
View File
@@ -7,6 +7,7 @@ from huamenchuang.api import (
contracts,
customers,
optimize,
order_format,
orders,
platform,
quote,
@@ -25,6 +26,7 @@ api_router.include_router(windoor.router)
api_router.include_router(optimize.router)
api_router.include_router(quote.router)
api_router.include_router(script.router)
api_router.include_router(order_format.router)
api_router.include_router(warehouse.router)
api_router.include_router(business.router)
api_router.include_router(platform.router)