feat: P0-3 打印模板体系(区块化模板CRUD+打印中心重构)
This commit is contained in:
@@ -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="模板已删除")
|
||||
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user