Merge pull request 'feat:新增演示' (#13) from feat/0.3.0 into main
my-v0-server / deploy (push) Successful in 49s
my-v0-server / deploy (push) Successful in 49s
Reviewed-on: #13
This commit was merged in pull request #13.
This commit is contained in:
@@ -41,6 +41,8 @@ SCREEN_MAX_MB=10
|
||||
# 回收站里的大屏保留多少天,超过后自动彻底删除
|
||||
TRASH_RETENTION_DAYS=30
|
||||
THUMBNAIL_DIR=data/thumbnails
|
||||
# 未登录演示:展示这个用户 ID 名下的大屏(用该账号登录后在编辑器里做即可);留空则没有演示数据
|
||||
DEMO_OWNER_ID=
|
||||
|
||||
# 模型写的单条数据查询的超时(秒)
|
||||
DATA_QUERY_TIMEOUT=10
|
||||
|
||||
+45
-3
@@ -2,17 +2,59 @@
|
||||
|
||||
from typing import Annotated, Any
|
||||
|
||||
from fastapi import APIRouter, Query
|
||||
from fastapi import APIRouter, Query, Response
|
||||
from fastapi.responses import FileResponse
|
||||
|
||||
from app.api.screens import Service
|
||||
from app.api.screens import Service, thumbnail_url
|
||||
from app.common.response import ApiResponse, success_response
|
||||
from app.config import settings
|
||||
from app.core.exceptions import BizException
|
||||
from app.schemas.saved_screen import PublicScreen
|
||||
from app.schemas.saved_screen import (
|
||||
DemoScreen,
|
||||
DemoScreenList,
|
||||
PublicScreen,
|
||||
PublishBrief,
|
||||
)
|
||||
from app.services.screens import LIVE_VARS_MAX_CHARS, public_page
|
||||
|
||||
router = APIRouter(prefix="/public", tags=["Public"])
|
||||
|
||||
# 演示数据的条数上限和浏览器缓存时长(秒)
|
||||
DEMO_LIMIT = 20
|
||||
DEMO_CACHE_SECONDS = 60
|
||||
|
||||
|
||||
@router.get("/demo/screens")
|
||||
async def list_demo_screens(
|
||||
service: Service, response: Response
|
||||
) -> ApiResponse[DemoScreenList]:
|
||||
"""未登录演示:演示账号(DEMO_OWNER_ID)下的大屏,页面去掉数据源 headers;没配账号时为空"""
|
||||
owner_id = settings.demo_owner_id
|
||||
if owner_id is None:
|
||||
return success_response(DemoScreenList(items=[]))
|
||||
records = await service.list_demo(owner_id, DEMO_LIMIT)
|
||||
response.headers["Cache-Control"] = f"public, max-age={DEMO_CACHE_SECONDS}"
|
||||
return success_response(
|
||||
DemoScreenList(
|
||||
items=[
|
||||
DemoScreen(
|
||||
screen_id=record.screen_id,
|
||||
name=record.name,
|
||||
page=public_page(record.page),
|
||||
thumbnail_url=thumbnail_url(record.thumbnail),
|
||||
revision=record.revision,
|
||||
updated_at=record.updated_at,
|
||||
publish=None
|
||||
if record.publish is None
|
||||
else PublishBrief.model_validate(
|
||||
record.publish.model_dump(exclude={"revision"})
|
||||
),
|
||||
)
|
||||
for record in records
|
||||
]
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
@router.get("/screens/{share_id}")
|
||||
async def get_public_screen(
|
||||
|
||||
@@ -133,6 +133,13 @@ class Settings:
|
||||
)
|
||||
)
|
||||
|
||||
# 演示账号的用户 ID:未登录访问时展示这个账号下的大屏,不配置则没有演示数据
|
||||
demo_owner_id: int | None = field(
|
||||
default_factory=lambda: (
|
||||
int(value) if (value := os.getenv("DEMO_OWNER_ID", "").strip()) else None
|
||||
)
|
||||
)
|
||||
|
||||
# 模型写的单条数据查询的超时(秒)
|
||||
data_query_timeout: float = field(
|
||||
default_factory=lambda: float(os.getenv("DATA_QUERY_TIMEOUT", "10"))
|
||||
|
||||
@@ -109,6 +109,22 @@ class ScreenDetail(BaseModel):
|
||||
publish: PublishBrief | None
|
||||
|
||||
|
||||
class DemoScreen(BaseModel):
|
||||
"""未登录演示用的大屏:带页面,前端据此在内存里还原一份可随意修改的大屏列表"""
|
||||
|
||||
screen_id: str
|
||||
name: str
|
||||
page: dict[str, Any]
|
||||
thumbnail_url: str | None
|
||||
revision: int
|
||||
updated_at: datetime
|
||||
publish: PublishBrief | None
|
||||
|
||||
|
||||
class DemoScreenList(BaseModel):
|
||||
items: list[DemoScreen]
|
||||
|
||||
|
||||
class ScreenSaved(BaseModel):
|
||||
revision: int
|
||||
updated_at: datetime
|
||||
|
||||
@@ -428,6 +428,21 @@ class ScreenService:
|
||||
deleted=deleted,
|
||||
)
|
||||
|
||||
async def list_demo(self, owner_id: int, limit: int) -> list[ScreenRecord]:
|
||||
"""演示账号下没删除的大屏(最近修改在前),带页面"""
|
||||
summaries, _ = await self._store.search(
|
||||
owner_id,
|
||||
keyword=None,
|
||||
status=None,
|
||||
sort="updated_at",
|
||||
descending=True,
|
||||
limit=limit,
|
||||
offset=0,
|
||||
deleted=False,
|
||||
)
|
||||
records = [await self._store.get(item.screen_id, owner_id) for item in summaries]
|
||||
return [record for record in records if record is not None]
|
||||
|
||||
async def copy_screen(self, screen_id: str, owner_id: int, name: str | None) -> str:
|
||||
"""只复制草稿和封面,不复制发布状态和历史"""
|
||||
source = await self.get(screen_id, owner_id)
|
||||
|
||||
Reference in New Issue
Block a user