feat: 新增客片案例与团队共创模块,重构玩法与配置

- 新增客片案例全流程功能,包含前台页面、管理端配置、后端API、数据库迁移与文档
- 新增团队共创详情页面与对应接口
- 重构玩法模块:将静态playData替换为动态API获取,拆分类型定义到playTypes.ts
- 优化vite构建配置与环境变量处理,调整详情页操作栏文案
- 更新全量相关文档与配图,新增客片案例、团队共创API文档
- 新增测试用例,完善数据归一化逻辑
- 调整路由配置与环境变量示例文件
This commit is contained in:
duanshuwen committed 2026-08-19 20:23:04 +08:00
1 parent cda8069630
commit 7ba92f3c5d
76 files changed
+7970 -137

No files matched your search

+99 -2
View File
@@ -1,11 +1,21 @@
from fastapi import APIRouter, Depends, HTTPException, status
from sqlalchemy import select
from sqlalchemy.orm import Session
from sqlalchemy.orm import Session, selectinload
from .shared import site_config
from ..auth import create_customer_token, require_customer
from ..database import get_db
from ..models import Customer, Lead
from ..models import ConciergeAdvisor, Customer, HomeExperience, HomeTeamBuilding, HomeWanfaRecommendation, HomeWildArchive, Lead, WanfaCategory
from ..schemas import LeadCreateIn, PhoneLoginIn
from ..serializers import (
public_concierge_advisor_dict,
public_home_experience_dict,
public_home_team_building_dict,
public_home_team_building_detail_dict,
public_home_wanfa_recommendation_dict,
public_home_wild_archive_detail_dict,
public_home_wild_archive_dict,
public_wanfa_category_dict,
)
from ..wechat import WechatApiError, WechatConfigError, exchange_phone_code
@@ -33,6 +43,93 @@ def get_site_config(db: Session = Depends(get_db)):
return site_config(db, active_only=True)
@router.get("/api/public/wanfa/categories")
def get_public_wanfa_categories(db: Session = Depends(get_db)):
categories = db.scalars(
select(WanfaCategory)
.options(selectinload(WanfaCategory.routes))
.order_by(WanfaCategory.sortOrder.asc())
).all()
return {"categories": [public_wanfa_category_dict(category) for category in categories]}
@router.get("/api/public/concierge/advisors")
def get_public_concierge_advisors(db: Session = Depends(get_db)):
advisors = db.scalars(
select(ConciergeAdvisor)
.where(ConciergeAdvisor.isActive.is_(True))
.order_by(ConciergeAdvisor.sortOrder.asc())
).all()
return {"advisors": [public_concierge_advisor_dict(advisor) for advisor in advisors]}
@router.get("/api/public/home")
def get_public_home(db: Session = Depends(get_db)):
experiences = db.scalars(
select(HomeExperience)
.where(HomeExperience.isActive.is_(True))
.order_by(HomeExperience.sortOrder.asc())
).all()
team_buildings = db.scalars(
select(HomeTeamBuilding)
.where(HomeTeamBuilding.isActive.is_(True))
.order_by(HomeTeamBuilding.sortOrder.asc())
).all()
wild_archives = db.scalars(
select(HomeWildArchive)
.where(HomeWildArchive.isActive.is_(True))
.order_by(HomeWildArchive.sortOrder.asc())
).all()
play_recommendations = db.scalars(
select(HomeWanfaRecommendation)
.options(selectinload(HomeWanfaRecommendation.category).selectinload(WanfaCategory.routes))
.where(HomeWanfaRecommendation.isActive.is_(True))
.order_by(HomeWanfaRecommendation.sortOrder.asc())
).all()
return {
"experiences": [public_home_experience_dict(item) for item in experiences],
"teamBuildings": [public_home_team_building_dict(item) for item in team_buildings],
"wildArchives": [public_home_wild_archive_dict(item) for item in wild_archives],
"playRecommendations": [public_home_wanfa_recommendation_dict(item) for item in play_recommendations],
}
@router.get("/api/public/home/team-buildings/{team_building_id}")
def get_public_team_building(team_building_id: str, db: Session = Depends(get_db)):
team_building = db.scalar(
select(HomeTeamBuilding).where(
HomeTeamBuilding.id == team_building_id,
HomeTeamBuilding.isActive.is_(True),
)
)
if not team_building:
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="团队共创不存在")
return public_home_team_building_detail_dict(team_building)
@router.get("/api/public/home/wild-archives")
def list_public_wild_archives(db: Session = Depends(get_db)):
archives = db.scalars(
select(HomeWildArchive)
.where(HomeWildArchive.isActive.is_(True))
.order_by(HomeWildArchive.sortOrder.asc())
).all()
return {"items": [public_home_wild_archive_dict(item) for item in archives]}
@router.get("/api/public/home/wild-archives/{archive_id}")
def get_public_wild_archive(archive_id: str, db: Session = Depends(get_db)):
archive = db.scalar(
select(HomeWildArchive).where(
HomeWildArchive.id == archive_id,
HomeWildArchive.isActive.is_(True),
)
)
if not archive:
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="客片案例不存在")
return public_home_wild_archive_detail_dict(archive)
@router.post("/api/public/auth/phone-login")
def phone_login(body: PhoneLoginIn, db: Session = Depends(get_db)):
try: