feat: add map image site module

This commit is contained in:
duanshuwen
2026-07-02 08:57:49 +08:00
parent a47b4b5dd0
commit 7b329907f9
5 changed files with 221 additions and 8 deletions

View File

@@ -21,6 +21,7 @@ from ..models import (
Destination,
HeroSlide,
Lead,
MapImage,
MediaAsset,
Product,
ProductImage,
@@ -62,6 +63,16 @@ SITE_CONFIG_MODULES = {
"none_to_empty": set(),
"create_defaults": {"isHot": False},
},
"map": {
"model": MapImage,
"entity": "map_image",
"primary": "image",
"fields": {"image", "isActive"},
"none_to_empty": set(),
"create_defaults": {},
"ordered": False,
"singleton": True,
},
"themes": {
"model": ThemeCard,
"entity": "theme_card",
@@ -302,14 +313,32 @@ def hero_slide_admin_dict(item: HeroSlide) -> dict:
}
def map_image_admin_dict(item: MapImage) -> dict:
return {
"id": item.id,
"image": item.image or None,
"isActive": item.isActive,
"createdAt": encode_value(item.createdAt),
"updatedAt": encode_value(item.updatedAt),
}
def site_item_dict(module: str, item) -> dict:
if module == "heroSlides":
return hero_slide_admin_dict(item)
if module == "map":
return map_image_admin_dict(item)
return destination_dict(item) if module == "destinations" else model_dict(item)
def module_items(db: Session, model) -> list:
return db.scalars(select(model).order_by(model.sortOrder.asc())).all()
def module_items(db: Session, config: dict) -> list:
model = config["model"]
stmt = select(model)
if config.get("ordered", True):
stmt = stmt.order_by(model.sortOrder.asc())
else:
stmt = stmt.order_by(model.createdAt.asc())
return db.scalars(stmt).all()
def normalize_site_sort_orders(items: list) -> None:
@@ -328,7 +357,7 @@ def site_create_payload(module: str, config: dict, body: SiteConfigPatchIn, db:
for field, value in config["create_defaults"].items():
payload.setdefault(field, value)
payload["isActive"] = payload.get("isActive", True)
if payload.get("sortOrder") is None:
if config.get("ordered", True) and payload.get("sortOrder") is None:
payload["sortOrder"] = next_site_sort_order(db, config["model"])
if module == "destinations":
slug = clean_site_value(payload.get("slug"))
@@ -491,6 +520,10 @@ def admin_site_config(_user: AdminUser = Depends(require_admin), db: Session = D
for item in db.scalars(select(HeroSlide).order_by(HeroSlide.sortOrder.asc())).all()
],
"destinations": [destination_dict(item) for item in destinations],
"map": [
map_image_admin_dict(item)
for item in db.scalars(select(MapImage).order_by(MapImage.createdAt.asc())).all()
],
"themes": [
model_dict(item)
for item in db.scalars(select(ThemeCard).order_by(ThemeCard.sortOrder.asc())).all()
@@ -511,6 +544,8 @@ def create_site_config(
db: Session = Depends(get_db),
):
config = site_module(module)
if config.get("singleton") and module_items(db, config):
site_config_error(409, "地图图片已存在", "MAP_IMAGE_ALREADY_EXISTS", {"module": module})
item = config["model"](**site_create_payload(module, config, body, db))
db.add(item)
db.flush()
@@ -529,7 +564,9 @@ def reorder_site_config(
db: Session = Depends(get_db),
):
config = site_module(module)
items = module_items(db, config["model"])
if not config.get("ordered", True):
site_config_error(400, "模块不支持排序", "MODULE_CONFIG_REORDER_UNSUPPORTED", {"module": module})
items = module_items(db, config)
current_ids = [item.id for item in items]
requested_ids = body.itemIds
if len(set(requested_ids)) != len(requested_ids) or set(requested_ids) != set(current_ids):
@@ -590,7 +627,8 @@ def delete_site_config(
before = site_item_dict(module, item)
db.delete(item)
db.flush()
normalize_site_sort_orders(module_items(db, config["model"]))
if config.get("ordered", True):
normalize_site_sort_orders(module_items(db, config))
result = {"id": item_id}
audit(db, get_actor_id(request), "delete", config["entity"], item_id, result, before)
db.commit()

View File

@@ -1,6 +1,6 @@
from sqlalchemy import select
from sqlalchemy.orm import Session, selectinload
from ..models import Campaign, CtaBanner, Destination, HeroSlide, Product, ThemeCard
from ..models import Campaign, CtaBanner, Destination, HeroSlide, MapImage, Product, ThemeCard
from ..serializers import destination_dict, model_dict
@@ -14,21 +14,25 @@ ROUTE_SECTION_LABELS = [
def site_config(db: Session, active_only: bool, include_public_extras: bool = True) -> dict:
hero_stmt = select(HeroSlide).order_by(HeroSlide.sortOrder.asc())
destination_stmt = select(Destination).options(selectinload(Destination.aliases)).order_by(Destination.sortOrder.asc())
map_stmt = select(MapImage).order_by(MapImage.createdAt.asc())
theme_stmt = select(ThemeCard).order_by(ThemeCard.sortOrder.asc())
cta_stmt = select(CtaBanner).order_by(CtaBanner.sortOrder.asc())
if active_only:
hero_stmt = hero_stmt.where(HeroSlide.isActive.is_(True))
destination_stmt = destination_stmt.where(Destination.isActive.is_(True))
map_stmt = map_stmt.where(MapImage.isActive.is_(True))
theme_stmt = theme_stmt.where(ThemeCard.isActive.is_(True))
cta_stmt = cta_stmt.where(CtaBanner.isActive.is_(True))
hero_slides = db.scalars(hero_stmt).all()
destinations = db.scalars(destination_stmt).all()
map_images = db.scalars(map_stmt).all()
themes = db.scalars(theme_stmt).all()
cta_banners = db.scalars(cta_stmt).all()
result = {
"heroSlides": [model_dict(item) for item in hero_slides],
"destinations": [destination_dict(item) for item in destinations],
"map": [model_dict(item) for item in map_images],
"themes": [model_dict(item) for item in themes],
"ctaBanners": [model_dict(item) for item in cta_banners],
}