feat(contracts): embed slots admin and public endpoints
Co-Authored-By: Claude Code <noreply@anthropic.com>
This commit is contained in:
@@ -63,3 +63,10 @@ VISIT_WINDOW_REQUESTS=60
|
||||
# 每窗请求数上限——签名现算无幂等面,限速定位是误客户端缓冲,P5 速率层接防)。
|
||||
DOWNLOAD_WINDOW_REQUESTS=120
|
||||
CLEANUP_INTERVAL_MINUTES=60
|
||||
# P4b Task 1:嵌入组件(悬浮轮播 iframe)公开端点轮询参数——间隔毫秒 /
|
||||
# 连续失败上限 / 失败退避倍数(达到上限后间隔 ×倍数,成功即恢复)。默认值见
|
||||
# packages/contracts/src/constants.ts;P4b Task 4 起被 apps/viewer 嵌入页读取
|
||||
# (ETag 304 命中时零负载,A23 省流量)。
|
||||
EMBED_POLL_INTERVAL_MS=30000
|
||||
EMBED_POLL_MAX_FAILURES=5
|
||||
EMBED_POLL_BACKOFF_MULTIPLIER=5
|
||||
|
||||
@@ -45,6 +45,11 @@ tags:
|
||||
description: 照片可见性调整(单项与批量)与软删除(工作人员)
|
||||
- name: admin
|
||||
description: 管理辅助查询与账号治理(用户管理、相册交接、用户同步、用量统计)
|
||||
- name: embed-slots
|
||||
description: |
|
||||
展示位管理(P4b 悬浮轮播组件挂载点):创建、设置与相册绑定/解绑。
|
||||
权限简化决策:仅公司 admin 可管理展示位(成员授权面 P5 按需补);
|
||||
无删除端点——enabled=false 即下线(软停用,公开端随即 404)。
|
||||
- name: public
|
||||
description: 观众匿名只读(相册信息与公开照片)
|
||||
- name: interactions
|
||||
@@ -1636,6 +1641,141 @@ paths:
|
||||
'500':
|
||||
$ref: '#/components/responses/InternalError'
|
||||
|
||||
/admin/embed-slots:
|
||||
get:
|
||||
operationId: listEmbedSlots
|
||||
tags: [embed-slots]
|
||||
summary: 展示位列表
|
||||
description: |
|
||||
展示位(悬浮轮播组件挂载点)治理列表,游标分页(按 createdAt 与 ID
|
||||
稳定倒序);仅公司 admin 可用(P4b 权限简化:成员授权面 P5 按需补)。
|
||||
security:
|
||||
- bearerAuth: []
|
||||
parameters:
|
||||
- $ref: '#/components/parameters/CursorQuery'
|
||||
- name: limit
|
||||
in: query
|
||||
description: 每页条数。
|
||||
schema:
|
||||
type: integer
|
||||
minimum: 1
|
||||
maximum: 100
|
||||
default: 20
|
||||
responses:
|
||||
'200':
|
||||
description: 展示位列表页。
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/EmbedSlotList'
|
||||
'400':
|
||||
description: 查询参数校验失败(VALIDATION_FAILED;cursor/limit 非法)。
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/Error'
|
||||
'401':
|
||||
$ref: '#/components/responses/Unauthorized'
|
||||
'403':
|
||||
description: 仅 admin 可管理展示位(AUTH_FORBIDDEN)。
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/Error'
|
||||
'500':
|
||||
$ref: '#/components/responses/InternalError'
|
||||
post:
|
||||
operationId: createEmbedSlot
|
||||
tags: [embed-slots]
|
||||
summary: 创建展示位
|
||||
description: |
|
||||
创建展示位(仅 admin):服务端生成不可枚举 publicToken(嵌入代码
|
||||
data-slot 引用);初始 enabled=true、albumId=null(未绑定,公开端
|
||||
404)、configVersion=1。settings 整体缺省时按各字段缺省值落库。
|
||||
security:
|
||||
- bearerAuth: []
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/EmbedSlotCreateRequest'
|
||||
responses:
|
||||
'201':
|
||||
description: 创建后的展示位条目。
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/EmbedSlot'
|
||||
'400':
|
||||
description: 请求体校验失败(VALIDATION_FAILED;name 长度非法、settings 字段越界或取值非法)。
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/Error'
|
||||
'401':
|
||||
$ref: '#/components/responses/Unauthorized'
|
||||
'403':
|
||||
description: 仅 admin 可管理展示位(AUTH_FORBIDDEN)。
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/Error'
|
||||
'500':
|
||||
$ref: '#/components/responses/InternalError'
|
||||
|
||||
/admin/embed-slots/{id}:
|
||||
parameters:
|
||||
- $ref: '#/components/parameters/EmbedSlotId'
|
||||
patch:
|
||||
operationId: updateEmbedSlot
|
||||
tags: [embed-slots]
|
||||
summary: 更新展示位
|
||||
description: |
|
||||
展示位部分更新(仅 admin):name/enabled/settings/albumId 任一管理面
|
||||
变更均递增 configVersion 并触发 slot-state 同步事件(嵌入端配置版本
|
||||
变化即整体重置渲染)。albumId 语义:非 null 为绑定/换绑目标相册
|
||||
(相册须存在,不存在 404 ALBUM_NOT_FOUND),null 为解绑(公开端随即
|
||||
404);albumId 值本身变化(含换绑与解绑)即视为配置变更。settings
|
||||
为整体替换(提供时字段齐全)。无删除端点:enabled=false 即下线。
|
||||
security:
|
||||
- bearerAuth: []
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/EmbedSlotUpdateRequest'
|
||||
responses:
|
||||
'200':
|
||||
description: 更新后的展示位条目。
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/EmbedSlot'
|
||||
'400':
|
||||
description: 参数校验失败(VALIDATION_FAILED;name 长度非法、settings 字段越界或取值非法、空请求体)。
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/Error'
|
||||
'401':
|
||||
$ref: '#/components/responses/Unauthorized'
|
||||
'403':
|
||||
description: 仅 admin 可管理展示位(AUTH_FORBIDDEN)。
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/Error'
|
||||
'404':
|
||||
description: 展示位不存在(NOT_FOUND),或绑定目标相册不存在(ALBUM_NOT_FOUND)。
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/Error'
|
||||
'500':
|
||||
$ref: '#/components/responses/InternalError'
|
||||
|
||||
# ─────────────────────────── public ───────────────────────────
|
||||
|
||||
/public/albums/{token}:
|
||||
@@ -1763,6 +1903,72 @@ paths:
|
||||
'500':
|
||||
$ref: '#/components/responses/InternalError'
|
||||
|
||||
/public/embed-slots/{slotToken}:
|
||||
parameters:
|
||||
- $ref: '#/components/parameters/EmbedSlotToken'
|
||||
get:
|
||||
operationId: getPublicEmbedSlot
|
||||
tags: [public]
|
||||
summary: 展示位公开数据(嵌入组件数据源)
|
||||
description: |
|
||||
悬浮轮播组件的数据源(ov 域部署,匿名只读;嵌入 iframe 轮询调用):
|
||||
返回展示位绑定相册的近期已发布照片(≤20,按 publishedAt 与 ID 稳定
|
||||
倒序,小尺寸缩略图省流量)与相册摘要。lang 语义:auto(缺省)或取值
|
||||
不支持时按相册 defaultLocale 回退(不报 400,与公开相册一致)。
|
||||
|
||||
- 防探测:slotToken 不存在、展示位停用(enabled=false)或未绑定相册
|
||||
一律 404 NOT_FOUND(同码同文案,不区分原因,避免枚举探测)。
|
||||
- 条件请求(A23 省流量):200/304 响应携带强 ETag,取值为四元组
|
||||
`"{configVersion}-{photoCount}-{maxPublishedAtMs}-{maxPhotoId}"`
|
||||
(含照片条数与最新发布时间——新照片发布必变,避免仅比对实体版本
|
||||
时新照片小版本导致 304 陈旧);请求携带 If-None-Match 且匹配时
|
||||
返回 304(无响应体,仍携带 ETag)。
|
||||
security: []
|
||||
parameters:
|
||||
- name: lang
|
||||
in: query
|
||||
description: 内容语言;auto(缺省)按相册 defaultLocale,取值不支持时静默回退(不报 400)。
|
||||
schema:
|
||||
$ref: '#/components/schemas/EmbedSlotLang'
|
||||
- name: If-None-Match
|
||||
in: header
|
||||
description: 条件请求:先前响应返回的 ETag 值;匹配则返回 304。
|
||||
schema:
|
||||
type: string
|
||||
responses:
|
||||
'200':
|
||||
description: 展示位公开数据。
|
||||
headers:
|
||||
ETag:
|
||||
description: 强校验器(组成与失效语义见端点 description)。
|
||||
schema:
|
||||
type: string
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/PublicEmbedSlot'
|
||||
'304':
|
||||
description: 内容未变(If-None-Match 匹配);无响应体。
|
||||
headers:
|
||||
ETag:
|
||||
description: 当前 ETag(与匹配值一致)。
|
||||
schema:
|
||||
type: string
|
||||
'400':
|
||||
description: 查询参数校验失败(VALIDATION_FAILED;lang 取值不支持时不报错,按相册 defaultLocale 回退)。
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/Error'
|
||||
'404':
|
||||
description: 展示位不存在、已停用或未绑定相册(NOT_FOUND;不区分以避免枚举)。
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/Error'
|
||||
'500':
|
||||
$ref: '#/components/responses/InternalError'
|
||||
|
||||
# ─────────────────────────── interactions ───────────────────────────
|
||||
|
||||
/public/albums/{token}/photos/{photoId}/likes:
|
||||
@@ -2242,6 +2448,20 @@ components:
|
||||
description: 相册公开令牌(不可枚举,持有即可访问)。
|
||||
schema:
|
||||
type: string
|
||||
EmbedSlotId:
|
||||
name: id
|
||||
in: path
|
||||
required: true
|
||||
description: 展示位 ID。
|
||||
schema:
|
||||
type: string
|
||||
EmbedSlotToken:
|
||||
name: slotToken
|
||||
in: path
|
||||
required: true
|
||||
description: 展示位公开令牌(不可枚举,持有即可访问;格式见 EmbedSlot.publicToken)。
|
||||
schema:
|
||||
type: string
|
||||
CursorQuery:
|
||||
name: cursor
|
||||
in: query
|
||||
@@ -3775,6 +3995,154 @@ components:
|
||||
items:
|
||||
$ref: '#/components/schemas/UsageAlert'
|
||||
|
||||
# ── 展示位(管理端,P4b) ──
|
||||
|
||||
EmbedSlotLang:
|
||||
type: string
|
||||
description: |
|
||||
展示位内容语言(设置与公开查询共用):auto=按相册 defaultLocale,
|
||||
其余为指定语言(取值不支持时服务端静默回退相册 defaultLocale)。
|
||||
enum:
|
||||
- auto
|
||||
- zh-CN
|
||||
- en
|
||||
|
||||
EmbedSlotSettings:
|
||||
type: object
|
||||
description: |
|
||||
展示位展示设置。整体提交语义:创建时 settings 可整体缺省(各字段按
|
||||
下列缺省值落库),提供时字段齐全;更新为整体替换(未单独提交
|
||||
settings 则保持不变)。响应中字段恒齐全。
|
||||
required: [position, size, intervalMs, lang, collapsedDefault]
|
||||
properties:
|
||||
position:
|
||||
type: string
|
||||
description: 悬浮位置(宿主页面左/右侧)。
|
||||
enum:
|
||||
- left
|
||||
- right
|
||||
default: right
|
||||
size:
|
||||
type: string
|
||||
description: 组件尺寸(sm=窄屏降级档,宿主 viewport<480px 时自动降为 sm)。
|
||||
enum:
|
||||
- sm
|
||||
- md
|
||||
default: md
|
||||
intervalMs:
|
||||
type: integer
|
||||
minimum: 3000
|
||||
maximum: 30000
|
||||
description: 轮播切换间隔毫秒。
|
||||
default: 5000
|
||||
lang:
|
||||
$ref: '#/components/schemas/EmbedSlotLang'
|
||||
collapsedDefault:
|
||||
type: boolean
|
||||
description: 初始是否收起(收起后仅展示小把手,点击展开)。
|
||||
default: false
|
||||
|
||||
EmbedSlot:
|
||||
type: object
|
||||
description: |
|
||||
展示位条目(管理视角)。albumId/albumTitle 为当前绑定相册(null=未
|
||||
绑定,公开端 404);albumTitle 按相册 defaultLocale 解析(管理列表
|
||||
展示用)。任一管理面变更递增 configVersion。
|
||||
required:
|
||||
- id
|
||||
- publicToken
|
||||
- name
|
||||
- enabled
|
||||
- albumId
|
||||
- albumTitle
|
||||
- configVersion
|
||||
- settings
|
||||
- updatedAt
|
||||
properties:
|
||||
id:
|
||||
type: string
|
||||
readOnly: true
|
||||
description: 展示位 ID。
|
||||
publicToken:
|
||||
type: string
|
||||
readOnly: true
|
||||
pattern: '^[0-9a-z]{20,32}$'
|
||||
description: 展示位公开令牌(嵌入代码 data-slot 引用,不可枚举)。
|
||||
name:
|
||||
type: string
|
||||
minLength: 1
|
||||
maxLength: 64
|
||||
description: 展示位名称(管理标识)。
|
||||
enabled:
|
||||
type: boolean
|
||||
description: 是否启用;false 即下线(公开端 404,等同删除语义)。
|
||||
albumId:
|
||||
type: [string, 'null']
|
||||
readOnly: true
|
||||
description: 绑定相册 ID;未绑定为 null。
|
||||
albumTitle:
|
||||
type: [string, 'null']
|
||||
readOnly: true
|
||||
description: 绑定相册标题(按相册 defaultLocale 解析);未绑定为 null。
|
||||
configVersion:
|
||||
type: integer
|
||||
minimum: 1
|
||||
readOnly: true
|
||||
description: 配置版本(任一管理面变更递增;嵌入端据此整体重置渲染,亦为公开端 ETag 组成部分)。
|
||||
settings:
|
||||
$ref: '#/components/schemas/EmbedSlotSettings'
|
||||
updatedAt:
|
||||
type: string
|
||||
format: date-time
|
||||
readOnly: true
|
||||
description: 最近更新时间。
|
||||
|
||||
EmbedSlotList:
|
||||
allOf:
|
||||
- $ref: '#/components/schemas/CursorPageMeta'
|
||||
- type: object
|
||||
required: [items]
|
||||
properties:
|
||||
items:
|
||||
type: array
|
||||
description: 展示位条目(按 createdAt 与 ID 稳定倒序)。
|
||||
items:
|
||||
$ref: '#/components/schemas/EmbedSlot'
|
||||
|
||||
EmbedSlotCreateRequest:
|
||||
type: object
|
||||
description: 创建展示位请求;settings 可整体缺省(各字段按缺省值落库),提供时字段齐全。
|
||||
required: [name]
|
||||
properties:
|
||||
name:
|
||||
type: string
|
||||
minLength: 1
|
||||
maxLength: 64
|
||||
description: 展示位名称。
|
||||
settings:
|
||||
$ref: '#/components/schemas/EmbedSlotSettings'
|
||||
|
||||
EmbedSlotUpdateRequest:
|
||||
type: object
|
||||
description: |
|
||||
展示位部分更新请求(仅提交的字段被修改,空请求体 400)。settings 为
|
||||
整体替换(提供时字段齐全);albumId:非 null 绑定/换绑目标相册(相册
|
||||
须存在),null 解绑(公开端随即 404)——albumId 值变化即 configVersion+1。
|
||||
properties:
|
||||
name:
|
||||
type: string
|
||||
minLength: 1
|
||||
maxLength: 64
|
||||
description: 展示位名称。
|
||||
enabled:
|
||||
type: boolean
|
||||
description: 启停;false 即下线(软停用,无删除端点)。
|
||||
settings:
|
||||
$ref: '#/components/schemas/EmbedSlotSettings'
|
||||
albumId:
|
||||
type: [string, 'null']
|
||||
description: 绑定相册 ID;null 解绑。
|
||||
|
||||
# ── 公开(观众端) ──
|
||||
|
||||
SignedUrl:
|
||||
@@ -3958,6 +4326,78 @@ components:
|
||||
items:
|
||||
$ref: '#/components/schemas/PublicPhoto'
|
||||
|
||||
# ── 展示位公开数据(观众端,ov 域,P4b) ──
|
||||
|
||||
PublicEmbedAlbum:
|
||||
type: object
|
||||
description: 展示位绑定相册摘要(title 已按 lang→相册 defaultLocale 回退解析)。
|
||||
required: [publicToken, title, defaultLocale]
|
||||
properties:
|
||||
publicToken:
|
||||
type: string
|
||||
readOnly: true
|
||||
pattern: '^[0-9a-z]{20,32}$'
|
||||
description: 相册公开令牌(点击照片跳转 viewer 相册页用)。
|
||||
title:
|
||||
type: string
|
||||
readOnly: true
|
||||
description: 相册标题(实际返回语言)。
|
||||
defaultLocale:
|
||||
$ref: '#/components/schemas/Locale'
|
||||
|
||||
PublicEmbedPhoto:
|
||||
type: object
|
||||
description: |
|
||||
展示位照片条目(小尺寸缩略图省流量,与公开列表的 browse 大图区分;
|
||||
签名 URL 为短期凭证,过期后经本端点刷新)。
|
||||
required: [photoId, thumb, width, height]
|
||||
properties:
|
||||
photoId:
|
||||
type: string
|
||||
readOnly: true
|
||||
description: 照片 ID(跳转 viewer 单图定位用)。
|
||||
thumb:
|
||||
$ref: '#/components/schemas/SignedUrl'
|
||||
width:
|
||||
type: integer
|
||||
readOnly: true
|
||||
description: 缩略图宽度(像素);用于占位,减少加载跳动。
|
||||
height:
|
||||
type: integer
|
||||
readOnly: true
|
||||
description: 缩略图高度(像素)。
|
||||
|
||||
PublicEmbedSlot:
|
||||
type: object
|
||||
description: |
|
||||
展示位公开数据(嵌入组件数据源;ov 只读副本)。photos 为近期已发布
|
||||
照片,按 publishedAt 与 ID 稳定倒序,上限 20(空数组=相册暂无已发布
|
||||
照片,嵌入端展示空态卡)。album 当前恒非 null(未绑定/停用的展示位
|
||||
公开端一律 404 防探测);null 为契约前瞻保留,嵌入端按空态处理。
|
||||
required: [slotToken, configVersion, album, photos]
|
||||
properties:
|
||||
slotToken:
|
||||
type: string
|
||||
readOnly: true
|
||||
pattern: '^[0-9a-z]{20,32}$'
|
||||
description: 展示位公开令牌(回显请求路径)。
|
||||
configVersion:
|
||||
type: integer
|
||||
minimum: 1
|
||||
readOnly: true
|
||||
description: 配置版本(嵌入端变更检测:版本变化即整体重置渲染)。
|
||||
album:
|
||||
description: 绑定相册摘要;未绑定为 null(当前部署不会出现,见 schema 描述)。
|
||||
anyOf:
|
||||
- $ref: '#/components/schemas/PublicEmbedAlbum'
|
||||
- type: 'null'
|
||||
photos:
|
||||
type: array
|
||||
maxItems: 20
|
||||
description: 近期照片(publishedAt 与 ID 稳定倒序,小尺寸缩略图)。
|
||||
items:
|
||||
$ref: '#/components/schemas/PublicEmbedPhoto'
|
||||
|
||||
# ── 互动(观众端,ov 域) ──
|
||||
|
||||
DownloadVariant:
|
||||
|
||||
@@ -39,3 +39,14 @@ export const DOWNLOAD_WINDOW_REQUESTS = 120;
|
||||
export const DOWNLOAD_WINDOW_SECONDS = 60;
|
||||
/** ov 互动流水清理调度间隔分钟(like_batches/visit_requests/visit_sessions)。 */
|
||||
export const CLEANUP_INTERVAL_MINUTES = 60;
|
||||
|
||||
// ── P4b 嵌入组件(悬浮轮播)──
|
||||
// 展示位轮播 iframe 的公开端点轮询参数(ETag 304 命中时零负载;默认值可被
|
||||
// env 覆盖,登记见根 .env.example,P4b Task 4 起被 apps/viewer 嵌入页读取)。
|
||||
|
||||
/** 展示位轮询间隔毫秒(拉新照片/检测 configVersion 变化)。 */
|
||||
export const EMBED_POLL_INTERVAL_MS = 30000;
|
||||
/** 轮询连续失败上限:达到后退避(间隔 × EMBED_POLL_BACKOFF_MULTIPLIER)。 */
|
||||
export const EMBED_POLL_MAX_FAILURES = 5;
|
||||
/** 轮询失败退避倍数(连续失败达上限后拉长间隔,成功即恢复正常间隔)。 */
|
||||
export const EMBED_POLL_BACKOFF_MULTIPLIER = 5;
|
||||
|
||||
+421
@@ -760,6 +760,61 @@ export interface paths {
|
||||
patch?: never;
|
||||
trace?: never;
|
||||
};
|
||||
"/admin/embed-slots": {
|
||||
parameters: {
|
||||
query?: never;
|
||||
header?: never;
|
||||
path?: never;
|
||||
cookie?: never;
|
||||
};
|
||||
/**
|
||||
* 展示位列表
|
||||
* @description 展示位(悬浮轮播组件挂载点)治理列表,游标分页(按 createdAt 与 ID
|
||||
* 稳定倒序);仅公司 admin 可用(P4b 权限简化:成员授权面 P5 按需补)。
|
||||
*/
|
||||
get: operations["listEmbedSlots"];
|
||||
put?: never;
|
||||
/**
|
||||
* 创建展示位
|
||||
* @description 创建展示位(仅 admin):服务端生成不可枚举 publicToken(嵌入代码
|
||||
* data-slot 引用);初始 enabled=true、albumId=null(未绑定,公开端
|
||||
* 404)、configVersion=1。settings 整体缺省时按各字段缺省值落库。
|
||||
*/
|
||||
post: operations["createEmbedSlot"];
|
||||
delete?: never;
|
||||
options?: never;
|
||||
head?: never;
|
||||
patch?: never;
|
||||
trace?: never;
|
||||
};
|
||||
"/admin/embed-slots/{id}": {
|
||||
parameters: {
|
||||
query?: never;
|
||||
header?: never;
|
||||
path: {
|
||||
/** @description 展示位 ID。 */
|
||||
id: components["parameters"]["EmbedSlotId"];
|
||||
};
|
||||
cookie?: never;
|
||||
};
|
||||
get?: never;
|
||||
put?: never;
|
||||
post?: never;
|
||||
delete?: never;
|
||||
options?: never;
|
||||
head?: never;
|
||||
/**
|
||||
* 更新展示位
|
||||
* @description 展示位部分更新(仅 admin):name/enabled/settings/albumId 任一管理面
|
||||
* 变更均递增 configVersion 并触发 slot-state 同步事件(嵌入端配置版本
|
||||
* 变化即整体重置渲染)。albumId 语义:非 null 为绑定/换绑目标相册
|
||||
* (相册须存在,不存在 404 ALBUM_NOT_FOUND),null 为解绑(公开端随即
|
||||
* 404);albumId 值本身变化(含换绑与解绑)即视为配置变更。settings
|
||||
* 为整体替换(提供时字段齐全)。无删除端点:enabled=false 即下线。
|
||||
*/
|
||||
patch: operations["updateEmbedSlot"];
|
||||
trace?: never;
|
||||
};
|
||||
"/public/albums/{token}": {
|
||||
parameters: {
|
||||
query?: never;
|
||||
@@ -834,6 +889,40 @@ export interface paths {
|
||||
patch?: never;
|
||||
trace?: never;
|
||||
};
|
||||
"/public/embed-slots/{slotToken}": {
|
||||
parameters: {
|
||||
query?: never;
|
||||
header?: never;
|
||||
path: {
|
||||
/** @description 展示位公开令牌(不可枚举,持有即可访问;格式见 EmbedSlot.publicToken)。 */
|
||||
slotToken: components["parameters"]["EmbedSlotToken"];
|
||||
};
|
||||
cookie?: never;
|
||||
};
|
||||
/**
|
||||
* 展示位公开数据(嵌入组件数据源)
|
||||
* @description 悬浮轮播组件的数据源(ov 域部署,匿名只读;嵌入 iframe 轮询调用):
|
||||
* 返回展示位绑定相册的近期已发布照片(≤20,按 publishedAt 与 ID 稳定
|
||||
* 倒序,小尺寸缩略图省流量)与相册摘要。lang 语义:auto(缺省)或取值
|
||||
* 不支持时按相册 defaultLocale 回退(不报 400,与公开相册一致)。
|
||||
*
|
||||
* - 防探测:slotToken 不存在、展示位停用(enabled=false)或未绑定相册
|
||||
* 一律 404 NOT_FOUND(同码同文案,不区分原因,避免枚举探测)。
|
||||
* - 条件请求(A23 省流量):200/304 响应携带强 ETag,取值为四元组
|
||||
* `"{configVersion}-{photoCount}-{maxPublishedAtMs}-{maxPhotoId}"`
|
||||
* (含照片条数与最新发布时间——新照片发布必变,避免仅比对实体版本
|
||||
* 时新照片小版本导致 304 陈旧);请求携带 If-None-Match 且匹配时
|
||||
* 返回 304(无响应体,仍携带 ETag)。
|
||||
*/
|
||||
get: operations["getPublicEmbedSlot"];
|
||||
put?: never;
|
||||
post?: never;
|
||||
delete?: never;
|
||||
options?: never;
|
||||
head?: never;
|
||||
patch?: never;
|
||||
trace?: never;
|
||||
};
|
||||
"/public/albums/{token}/photos/{photoId}/likes": {
|
||||
parameters: {
|
||||
query?: never;
|
||||
@@ -1945,6 +2034,93 @@ export interface components {
|
||||
/** @description 告警列表(createdAt 倒序,含已解除)。 */
|
||||
alerts: components["schemas"]["UsageAlert"][];
|
||||
};
|
||||
/**
|
||||
* @description 展示位内容语言(设置与公开查询共用):auto=按相册 defaultLocale,
|
||||
* 其余为指定语言(取值不支持时服务端静默回退相册 defaultLocale)。
|
||||
* @enum {string}
|
||||
*/
|
||||
EmbedSlotLang: "auto" | "zh-CN" | "en";
|
||||
/**
|
||||
* @description 展示位展示设置。整体提交语义:创建时 settings 可整体缺省(各字段按
|
||||
* 下列缺省值落库),提供时字段齐全;更新为整体替换(未单独提交
|
||||
* settings 则保持不变)。响应中字段恒齐全。
|
||||
*/
|
||||
EmbedSlotSettings: {
|
||||
/**
|
||||
* @description 悬浮位置(宿主页面左/右侧)。
|
||||
* @default right
|
||||
* @enum {string}
|
||||
*/
|
||||
position: "left" | "right";
|
||||
/**
|
||||
* @description 组件尺寸(sm=窄屏降级档,宿主 viewport<480px 时自动降为 sm)。
|
||||
* @default md
|
||||
* @enum {string}
|
||||
*/
|
||||
size: "sm" | "md";
|
||||
/**
|
||||
* @description 轮播切换间隔毫秒。
|
||||
* @default 5000
|
||||
*/
|
||||
intervalMs: number;
|
||||
lang: components["schemas"]["EmbedSlotLang"];
|
||||
/**
|
||||
* @description 初始是否收起(收起后仅展示小把手,点击展开)。
|
||||
* @default false
|
||||
*/
|
||||
collapsedDefault: boolean;
|
||||
};
|
||||
/**
|
||||
* @description 展示位条目(管理视角)。albumId/albumTitle 为当前绑定相册(null=未
|
||||
* 绑定,公开端 404);albumTitle 按相册 defaultLocale 解析(管理列表
|
||||
* 展示用)。任一管理面变更递增 configVersion。
|
||||
*/
|
||||
EmbedSlot: {
|
||||
/** @description 展示位 ID。 */
|
||||
readonly id: string;
|
||||
/** @description 展示位公开令牌(嵌入代码 data-slot 引用,不可枚举)。 */
|
||||
readonly publicToken: string;
|
||||
/** @description 展示位名称(管理标识)。 */
|
||||
name: string;
|
||||
/** @description 是否启用;false 即下线(公开端 404,等同删除语义)。 */
|
||||
enabled: boolean;
|
||||
/** @description 绑定相册 ID;未绑定为 null。 */
|
||||
readonly albumId: string | null;
|
||||
/** @description 绑定相册标题(按相册 defaultLocale 解析);未绑定为 null。 */
|
||||
readonly albumTitle: string | null;
|
||||
/** @description 配置版本(任一管理面变更递增;嵌入端据此整体重置渲染,亦为公开端 ETag 组成部分)。 */
|
||||
readonly configVersion: number;
|
||||
settings: components["schemas"]["EmbedSlotSettings"];
|
||||
/**
|
||||
* Format: date-time
|
||||
* @description 最近更新时间。
|
||||
*/
|
||||
readonly updatedAt: string;
|
||||
};
|
||||
EmbedSlotList: components["schemas"]["CursorPageMeta"] & {
|
||||
/** @description 展示位条目(按 createdAt 与 ID 稳定倒序)。 */
|
||||
items: components["schemas"]["EmbedSlot"][];
|
||||
};
|
||||
/** @description 创建展示位请求;settings 可整体缺省(各字段按缺省值落库),提供时字段齐全。 */
|
||||
EmbedSlotCreateRequest: {
|
||||
/** @description 展示位名称。 */
|
||||
name: string;
|
||||
settings?: components["schemas"]["EmbedSlotSettings"];
|
||||
};
|
||||
/**
|
||||
* @description 展示位部分更新请求(仅提交的字段被修改,空请求体 400)。settings 为
|
||||
* 整体替换(提供时字段齐全);albumId:非 null 绑定/换绑目标相册(相册
|
||||
* 须存在),null 解绑(公开端随即 404)——albumId 值变化即 configVersion+1。
|
||||
*/
|
||||
EmbedSlotUpdateRequest: {
|
||||
/** @description 展示位名称。 */
|
||||
name?: string;
|
||||
/** @description 启停;false 即下线(软停用,无删除端点)。 */
|
||||
enabled?: boolean;
|
||||
settings?: components["schemas"]["EmbedSlotSettings"];
|
||||
/** @description 绑定相册 ID;null 解绑。 */
|
||||
albumId?: string | null;
|
||||
};
|
||||
/** @description 私有对象的短期签名 URL;不得写入持久分享链接,过期后经原入口刷新。 */
|
||||
SignedUrl: {
|
||||
/** @description 签名访问 URL。 */
|
||||
@@ -2042,6 +2218,43 @@ export interface components {
|
||||
PublicPhotoList: components["schemas"]["CursorPageMeta"] & {
|
||||
items: components["schemas"]["PublicPhoto"][];
|
||||
};
|
||||
/** @description 展示位绑定相册摘要(title 已按 lang→相册 defaultLocale 回退解析)。 */
|
||||
PublicEmbedAlbum: {
|
||||
/** @description 相册公开令牌(点击照片跳转 viewer 相册页用)。 */
|
||||
readonly publicToken: string;
|
||||
/** @description 相册标题(实际返回语言)。 */
|
||||
readonly title: string;
|
||||
defaultLocale: components["schemas"]["Locale"];
|
||||
};
|
||||
/**
|
||||
* @description 展示位照片条目(小尺寸缩略图省流量,与公开列表的 browse 大图区分;
|
||||
* 签名 URL 为短期凭证,过期后经本端点刷新)。
|
||||
*/
|
||||
PublicEmbedPhoto: {
|
||||
/** @description 照片 ID(跳转 viewer 单图定位用)。 */
|
||||
readonly photoId: string;
|
||||
thumb: components["schemas"]["SignedUrl"];
|
||||
/** @description 缩略图宽度(像素);用于占位,减少加载跳动。 */
|
||||
readonly width: number;
|
||||
/** @description 缩略图高度(像素)。 */
|
||||
readonly height: number;
|
||||
};
|
||||
/**
|
||||
* @description 展示位公开数据(嵌入组件数据源;ov 只读副本)。photos 为近期已发布
|
||||
* 照片,按 publishedAt 与 ID 稳定倒序,上限 20(空数组=相册暂无已发布
|
||||
* 照片,嵌入端展示空态卡)。album 当前恒非 null(未绑定/停用的展示位
|
||||
* 公开端一律 404 防探测);null 为契约前瞻保留,嵌入端按空态处理。
|
||||
*/
|
||||
PublicEmbedSlot: {
|
||||
/** @description 展示位公开令牌(回显请求路径)。 */
|
||||
readonly slotToken: string;
|
||||
/** @description 配置版本(嵌入端变更检测:版本变化即整体重置渲染)。 */
|
||||
readonly configVersion: number;
|
||||
/** @description 绑定相册摘要;未绑定为 null(当前部署不会出现,见 schema 描述)。 */
|
||||
album: components["schemas"]["PublicEmbedAlbum"] | null;
|
||||
/** @description 近期照片(publishedAt 与 ID 稳定倒序,小尺寸缩略图)。 */
|
||||
photos: components["schemas"]["PublicEmbedPhoto"][];
|
||||
};
|
||||
/**
|
||||
* @description 下载版本(P4a A18):browse=当前生效浏览图(水印版);
|
||||
* original=原图(需 originalDownloadEnabled 更高级开关)。
|
||||
@@ -2332,6 +2545,10 @@ export interface components {
|
||||
PhotoId: string;
|
||||
/** @description 相册公开令牌(不可枚举,持有即可访问)。 */
|
||||
AlbumPublicToken: string;
|
||||
/** @description 展示位 ID。 */
|
||||
EmbedSlotId: string;
|
||||
/** @description 展示位公开令牌(不可枚举,持有即可访问;格式见 EmbedSlot.publicToken)。 */
|
||||
EmbedSlotToken: string;
|
||||
/** @description 分页游标(上一页响应的 nextCursor)。 */
|
||||
CursorQuery: string;
|
||||
/** @description 请求语言;缺省或取值不支持时按相册 defaultLocale 回退(不报 400,响应 resolvedLocale 指示实际返回语言)。 */
|
||||
@@ -4132,6 +4349,151 @@ export interface operations {
|
||||
500: components["responses"]["InternalError"];
|
||||
};
|
||||
};
|
||||
listEmbedSlots: {
|
||||
parameters: {
|
||||
query?: {
|
||||
/** @description 分页游标(上一页响应的 nextCursor)。 */
|
||||
cursor?: components["parameters"]["CursorQuery"];
|
||||
/** @description 每页条数。 */
|
||||
limit?: number;
|
||||
};
|
||||
header?: never;
|
||||
path?: never;
|
||||
cookie?: never;
|
||||
};
|
||||
requestBody?: never;
|
||||
responses: {
|
||||
/** @description 展示位列表页。 */
|
||||
200: {
|
||||
headers: {
|
||||
[name: string]: unknown;
|
||||
};
|
||||
content: {
|
||||
"application/json": components["schemas"]["EmbedSlotList"];
|
||||
};
|
||||
};
|
||||
/** @description 查询参数校验失败(VALIDATION_FAILED;cursor/limit 非法)。 */
|
||||
400: {
|
||||
headers: {
|
||||
[name: string]: unknown;
|
||||
};
|
||||
content: {
|
||||
"application/json": components["schemas"]["Error"];
|
||||
};
|
||||
};
|
||||
401: components["responses"]["Unauthorized"];
|
||||
/** @description 仅 admin 可管理展示位(AUTH_FORBIDDEN)。 */
|
||||
403: {
|
||||
headers: {
|
||||
[name: string]: unknown;
|
||||
};
|
||||
content: {
|
||||
"application/json": components["schemas"]["Error"];
|
||||
};
|
||||
};
|
||||
500: components["responses"]["InternalError"];
|
||||
};
|
||||
};
|
||||
createEmbedSlot: {
|
||||
parameters: {
|
||||
query?: never;
|
||||
header?: never;
|
||||
path?: never;
|
||||
cookie?: never;
|
||||
};
|
||||
requestBody: {
|
||||
content: {
|
||||
"application/json": components["schemas"]["EmbedSlotCreateRequest"];
|
||||
};
|
||||
};
|
||||
responses: {
|
||||
/** @description 创建后的展示位条目。 */
|
||||
201: {
|
||||
headers: {
|
||||
[name: string]: unknown;
|
||||
};
|
||||
content: {
|
||||
"application/json": components["schemas"]["EmbedSlot"];
|
||||
};
|
||||
};
|
||||
/** @description 请求体校验失败(VALIDATION_FAILED;name 长度非法、settings 字段越界或取值非法)。 */
|
||||
400: {
|
||||
headers: {
|
||||
[name: string]: unknown;
|
||||
};
|
||||
content: {
|
||||
"application/json": components["schemas"]["Error"];
|
||||
};
|
||||
};
|
||||
401: components["responses"]["Unauthorized"];
|
||||
/** @description 仅 admin 可管理展示位(AUTH_FORBIDDEN)。 */
|
||||
403: {
|
||||
headers: {
|
||||
[name: string]: unknown;
|
||||
};
|
||||
content: {
|
||||
"application/json": components["schemas"]["Error"];
|
||||
};
|
||||
};
|
||||
500: components["responses"]["InternalError"];
|
||||
};
|
||||
};
|
||||
updateEmbedSlot: {
|
||||
parameters: {
|
||||
query?: never;
|
||||
header?: never;
|
||||
path: {
|
||||
/** @description 展示位 ID。 */
|
||||
id: components["parameters"]["EmbedSlotId"];
|
||||
};
|
||||
cookie?: never;
|
||||
};
|
||||
requestBody: {
|
||||
content: {
|
||||
"application/json": components["schemas"]["EmbedSlotUpdateRequest"];
|
||||
};
|
||||
};
|
||||
responses: {
|
||||
/** @description 更新后的展示位条目。 */
|
||||
200: {
|
||||
headers: {
|
||||
[name: string]: unknown;
|
||||
};
|
||||
content: {
|
||||
"application/json": components["schemas"]["EmbedSlot"];
|
||||
};
|
||||
};
|
||||
/** @description 参数校验失败(VALIDATION_FAILED;name 长度非法、settings 字段越界或取值非法、空请求体)。 */
|
||||
400: {
|
||||
headers: {
|
||||
[name: string]: unknown;
|
||||
};
|
||||
content: {
|
||||
"application/json": components["schemas"]["Error"];
|
||||
};
|
||||
};
|
||||
401: components["responses"]["Unauthorized"];
|
||||
/** @description 仅 admin 可管理展示位(AUTH_FORBIDDEN)。 */
|
||||
403: {
|
||||
headers: {
|
||||
[name: string]: unknown;
|
||||
};
|
||||
content: {
|
||||
"application/json": components["schemas"]["Error"];
|
||||
};
|
||||
};
|
||||
/** @description 展示位不存在(NOT_FOUND),或绑定目标相册不存在(ALBUM_NOT_FOUND)。 */
|
||||
404: {
|
||||
headers: {
|
||||
[name: string]: unknown;
|
||||
};
|
||||
content: {
|
||||
"application/json": components["schemas"]["Error"];
|
||||
};
|
||||
};
|
||||
500: components["responses"]["InternalError"];
|
||||
};
|
||||
};
|
||||
getPublicAlbum: {
|
||||
parameters: {
|
||||
query?: {
|
||||
@@ -4273,6 +4635,65 @@ export interface operations {
|
||||
500: components["responses"]["InternalError"];
|
||||
};
|
||||
};
|
||||
getPublicEmbedSlot: {
|
||||
parameters: {
|
||||
query?: {
|
||||
/** @description 内容语言;auto(缺省)按相册 defaultLocale,取值不支持时静默回退(不报 400)。 */
|
||||
lang?: components["schemas"]["EmbedSlotLang"];
|
||||
};
|
||||
header?: {
|
||||
/** @description 条件请求:先前响应返回的 ETag 值;匹配则返回 304。 */
|
||||
"If-None-Match"?: string;
|
||||
};
|
||||
path: {
|
||||
/** @description 展示位公开令牌(不可枚举,持有即可访问;格式见 EmbedSlot.publicToken)。 */
|
||||
slotToken: components["parameters"]["EmbedSlotToken"];
|
||||
};
|
||||
cookie?: never;
|
||||
};
|
||||
requestBody?: never;
|
||||
responses: {
|
||||
/** @description 展示位公开数据。 */
|
||||
200: {
|
||||
headers: {
|
||||
/** @description 强校验器(组成与失效语义见端点 description)。 */
|
||||
ETag?: string;
|
||||
[name: string]: unknown;
|
||||
};
|
||||
content: {
|
||||
"application/json": components["schemas"]["PublicEmbedSlot"];
|
||||
};
|
||||
};
|
||||
/** @description 内容未变(If-None-Match 匹配);无响应体。 */
|
||||
304: {
|
||||
headers: {
|
||||
/** @description 当前 ETag(与匹配值一致)。 */
|
||||
ETag?: string;
|
||||
[name: string]: unknown;
|
||||
};
|
||||
content?: never;
|
||||
};
|
||||
/** @description 查询参数校验失败(VALIDATION_FAILED;lang 取值不支持时不报错,按相册 defaultLocale 回退)。 */
|
||||
400: {
|
||||
headers: {
|
||||
[name: string]: unknown;
|
||||
};
|
||||
content: {
|
||||
"application/json": components["schemas"]["Error"];
|
||||
};
|
||||
};
|
||||
/** @description 展示位不存在、已停用或未绑定相册(NOT_FOUND;不区分以避免枚举)。 */
|
||||
404: {
|
||||
headers: {
|
||||
[name: string]: unknown;
|
||||
};
|
||||
content: {
|
||||
"application/json": components["schemas"]["Error"];
|
||||
};
|
||||
};
|
||||
500: components["responses"]["InternalError"];
|
||||
};
|
||||
};
|
||||
likePhotoBatch: {
|
||||
parameters: {
|
||||
query?: never;
|
||||
|
||||
Reference in New Issue
Block a user