Files
WonderQ-Project/WonderQ-Admin/app/serializers.py
duanshuwen c143b67275 feat(route-detail): 实现路线详情独立管理全链路功能
添加`DetailRecord`数据库模型、迁移脚本及完整的CRUD管理接口,将路线详情从玩法路线表解耦,实现独立存储。
在Admin UI的路线编辑器中集成详情配置面板,支持编辑详情文案、图片等展示内容。
完善MiniAPP路线详情页,新增导航函数、API调用及数据归一化逻辑,并添加对应单元测试。
更新所有相关文档,明确领域边界、联调流程及接口契约规范。
调整首页和玩法页的点击跳转逻辑,优先跳转路线详情页而非原需求页。
新增数值格式化工具函数优化内容展示效果。
2026-08-19 21:20:51 +08:00

148 lines
4.0 KiB
Python

from datetime import datetime
from sqlalchemy.inspection import inspect
def encode_value(value):
if isinstance(value, datetime):
return value.isoformat()
if isinstance(value, list):
return [encode_value(item) for item in value]
if isinstance(value, dict):
return {key: encode_value(item) for key, item in value.items()}
return value
def model_dict(instance, include: dict[str, object] | None = None) -> dict:
data = {column.key: encode_value(getattr(instance, column.key)) for column in inspect(instance).mapper.column_attrs}
if include:
for key, value in include.items():
data[key] = encode_value(value)
return data
def lead_dict(lead) -> dict:
return model_dict(
lead,
{"assignedUser": {"id": lead.assignedUser.id, "name": lead.assignedUser.name} if lead.assignedUser else None},
)
def public_wanfa_route_dict(route) -> dict:
return {
"id": route.id,
"title": route.title,
"subtitle": route.subtitle,
"image": route.image,
"routeCount": route.routeCount,
"demandKeyword": route.demandKeyword,
}
def public_wanfa_category_dict(category) -> dict:
return {
"id": category.id,
"label": category.label,
"routes": [public_wanfa_route_dict(route) for route in category.routes],
}
def detail_record_dict(detail) -> dict:
return model_dict(detail)
def public_detail_dict(detail) -> dict:
return {
"key": detail.key,
"eyebrow": detail.eyebrow,
"duration": detail.duration,
"title": detail.title,
"subtitle": detail.subtitle,
"intro": detail.intro,
"highlights": detail.highlights or [],
"included": detail.included or [],
"excluded": detail.excluded or [],
"notes": detail.notes or [],
"gallery": detail.gallery or [],
}
def public_home_wanfa_recommendation_dict(item) -> dict:
return {
"id": item.id,
"categoryId": item.category.id,
"label": item.category.label,
"routes": [public_wanfa_route_dict(route) for route in item.category.routes],
}
def concierge_advisor_dict(advisor) -> dict:
return model_dict(advisor)
def public_concierge_advisor_dict(advisor) -> dict:
return {
"avatar": advisor.avatar,
"name": advisor.name,
"role": advisor.role,
"details": advisor.details or [],
"qrImage": advisor.qrImage,
}
def public_home_experience_dict(item) -> dict:
return {
"id": item.id,
"badge": item.badge,
"category": item.category,
"title": item.title,
"englishTitle": item.englishTitle,
"image": item.image,
"demandKeyword": item.demandKeyword,
}
def public_home_team_building_dict(item) -> dict:
return {
"id": item.id,
"tag": item.tag,
"title": item.title,
"description": item.description,
"image": item.image,
"demandKeyword": item.demandKeyword,
}
def public_home_team_building_detail_dict(item) -> dict:
paragraphs = [
paragraph.strip()
for paragraph in (getattr(item, "detailParagraphs", None) or [])
if isinstance(paragraph, str) and paragraph.strip()
]
if not paragraphs:
paragraphs = [item.description]
return {
**public_home_team_building_dict(item),
"detailSubtitle": (getattr(item, "detailSubtitle", None) or item.description).strip(),
"detailParagraphs": paragraphs,
}
def public_home_wild_archive_dict(item) -> dict:
return {
"id": item.id,
"title": item.title,
"image": item.image,
"demandKeyword": item.demandKeyword,
"photoCount": len(item.images or [item.image]),
}
def public_home_wild_archive_detail_dict(item) -> dict:
images = [image for image in (item.images or []) if isinstance(image, str) and image.strip()]
if not images:
images = [item.image]
return {
**public_home_wild_archive_dict(item),
"images": images,
}