feat: add map image site module
This commit is contained in:
@@ -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()
|
||||
|
||||
@@ -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],
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user