feat(admin, miniapp): 优化数据库迁移逻辑与小程序图片资源处理

- 为后端Admin新增migration_compat工具,支持离线迁移时的基线资源检查,重构全部alembic迁移脚本适配离线模式,避免重复创建已存在的数据库表和字段
- 完善初始数据库迁移脚本,添加默认部门种子数据,新增ConciergeAdvisor详情字段从JSON到JSONB的类型转换迁移
- 小程序端新增图片资源解析工具resolveNetworkImage,实现本地静态资源到CDN的自动映射,添加图片加载容错降级机制
- 完善HeroSlide类型定义,新增actionLabel字段,优化首页轮播组件的文本渲染与错误处理逻辑
- 新增对应测试用例验证迁移路径正确性与前端数据处理逻辑
- 新增临时 brainstorm UI对比草稿与开发临时状态文件
This commit is contained in:
duanshuwen committed 2026-08-27 11:37:03 +08:00
1 parent 96bcc7c032
commit 4e04feda5b
27 files changed
+2695 -377

No files matched your search

@@ -5,12 +5,15 @@ Revises: 0016_concierge_advisors
"""
from datetime import datetime
import json
from alembic import context, op
import sqlalchemy as sa
from sqlalchemy import inspect
from sqlalchemy.dialects import postgresql
from app.migration_compat import baseline_column_names, baseline_table_names
revision = "0017_home_content"
down_revision = "0016_concierge_advisors"
@@ -142,6 +145,13 @@ SEED_WILD_ARCHIVES = (
def _create_table(table_name: str, columns: list[sa.Column]) -> None:
if is_offline_mode():
if table_name in baseline_table_names():
return
op.create_table(table_name, *columns, sa.PrimaryKeyConstraint("id"))
op.create_index(f"ix_{table_name}_isActive", table_name, ["isActive"])
op.create_index(f"ix_{table_name}_sortOrder", table_name, ["sortOrder"])
return
bind = op.get_bind()
if table_name in set(inspect(bind).get_table_names()):
return
@@ -178,6 +188,11 @@ def _seed_table(table_name: str, columns: list[sa.Column], rows: tuple[dict, ...
column_types = {column.name: column.type for column in columns}
if is_offline_mode():
available_columns = set(column_types)
if table_name in baseline_table_names():
available_columns.update(baseline_column_names(table_name))
for name, column_type in OPTIONAL_SEED_COLUMN_TYPES.items():
if name in available_columns:
column_types.setdefault(name, column_type)
else:
bind = op.get_bind()
current_columns = inspect(bind).get_columns(table_name)
@@ -200,7 +215,31 @@ def _seed_table(table_name: str, columns: list[sa.Column], rows: tuple[dict, ...
],
)
timestamp = datetime(2026, 1, 1)
op.bulk_insert(table, prepare_seed_rows(rows, seed_column_names, timestamp))
seed_rows = prepare_seed_rows(rows, seed_column_names, timestamp)
if is_offline_mode():
seed_rows = [
{
**row,
**{
name: json.dumps(row[name], ensure_ascii=False)
for name in ("detailParagraphs", "images")
if name in row
},
}
for row in seed_rows
]
for name in ("detailParagraphs", "images"):
if name in column_types:
column_types[name] = sa.Text()
table = sa.table(
table_name,
*[
sa.column(name, column_types[name])
for name in column_types
if name in seed_column_names
],
)
op.bulk_insert(table, seed_rows)
def upgrade() -> None: