8a8ad8a18d
P4a Task 1 契约扩展批次(36 → 51 operations,gen/redocly/枚举同步守护绿):
- photos:POST /albums/{albumId}/photos/hide-batch(photoIds 1..200,逐项
BatchHideResult {photoId, ok, code?},部分成功语义,A16);
- admin:POST /admin/albums/{albumId}/transfer(owner 交接,历史上传人不动,
keepAsCollaborator,A17);
- albums:POST/GET /albums/{albumId}/watermark-jobs(WatermarkConfig 版本化
+ 历史重生成任务 state/progress/total/failed,原子切换、原图永不覆盖,
A18/A20);
- interactions:GET /public/albums/{token}/photos/{photoId}/download
(variant=browse|original 两级开关校验;**新增错误码 DOWNLOAD_DISABLED**,
errors.ts 与 Error enum 两侧同步,A18);
- admin 账号治理:GET /admin/users 统一为 listAdminUsers 双模式 + PATCH
/admin/users/{userId} 与 reset-password / activate / deactivate;
- admin 用户同步:GET /admin/user-sync/{status,runs,errors} + POST runs
手动补拉(互斥复用进行中批次,A29);
- admin 用量:GET /admin/usage/summary + PUT thresholds(null 清除、
即刻重评估,A23)。
偏差登记①——/admin/users 路径冲突(P1b lookupUsersByAccount):P4a 决策
统一为双模式端点(前缀模式沿用 P1b 语义与任何已认证工作人员可用;管理
列表模式 query/status 过滤 + 游标 + 仅 admin),响应统一 AdminUserList
(AdminUser 字段超集,游标元信息随行)。消费方同步:admin 邀请搜索
(fetchLookupUsers/类型镜像,行为不变)与 api 过渡实现(仍仅前缀模式、
limit 对齐 1..100 缺省 20;管理列表模式与仅 admin 判定随 Task 6 落地,
users-lookup e2e 已按统一形状修订)。
偏差登记②——apps/mobile 手写镜像未随本次更新:其邀请流程仍按旧 3 字段
投影消费(AdminUserList 为超集,运行时兼容,mobile IT 不经该路径);列
为 P4a 跟进项,仅当其 e2e 破坏时处理。
Co-Authored-By: Claude Code <noreply@anthropic.com>
124 lines
4.5 KiB
TypeScript
124 lines
4.5 KiB
TypeScript
/**
|
||
* 相册域接口(对齐 @photo/contracts:albums/assets/members/categories/photos
|
||
* 与 /admin/users 账号前缀查询)
|
||
*
|
||
* - 列表端点均为游标分页(cursor + limit;nextCursor 为 null 表示到底)
|
||
* - 更新为 PATCH 部分语义;translations 数组全量替换
|
||
* - 204 端点(移除成员/删除分类/删除照片)无响应体
|
||
* - 资产直传 PUT 走 staging 预签名 URL(裸 fetch,不带会话头),见
|
||
* views/albums 内的上传组件
|
||
*/
|
||
import request from '@/utils/http'
|
||
|
||
/** 相册列表(管理视角:当前用户可见,创建时间倒序) */
|
||
export function fetchAlbumList(params: { cursor?: string; limit?: number }) {
|
||
return request.get<Api.Album.ListResponse>({ url: '/v1/albums', params })
|
||
}
|
||
|
||
/** 相册详情(完整配置 + 多语言内容 + 分类) */
|
||
export function fetchAlbum(albumId: string) {
|
||
return request.get<Api.Album.Detail>({ url: `/v1/albums/${albumId}` })
|
||
}
|
||
|
||
/** 创建相册(创建者自动成为 owner 成员) */
|
||
export function fetchCreateAlbum(data: Api.Album.CreatePayload) {
|
||
return request.post<Api.Album.Detail>({ url: '/v1/albums', data })
|
||
}
|
||
|
||
/** 更新相册(部分更新;translations 全量替换,须含 defaultLocale 条目) */
|
||
export function fetchUpdateAlbum(albumId: string, data: Api.Album.UpdatePayload) {
|
||
return request.patch<Api.Album.Detail>({ url: `/v1/albums/${albumId}`, data })
|
||
}
|
||
|
||
/** 初始化资产上传(banner/cover/logo;返回 staging 直传凭证) */
|
||
export function fetchInitAlbumAsset(albumId: string, data: Api.Album.AssetInitPayload) {
|
||
return request.post<Api.Album.AssetInitResponse>({
|
||
url: `/v1/albums/${albumId}/assets`,
|
||
data
|
||
})
|
||
}
|
||
|
||
/** 完成资产上传核验(幂等;返回短期签名 URL,即预览/刷新入口) */
|
||
export function fetchCompleteAlbumAsset(albumId: string, assetId: string) {
|
||
return request.post<Api.Album.AssetCompleteResponse>({
|
||
url: `/v1/albums/${albumId}/assets/${assetId}/complete`
|
||
})
|
||
}
|
||
|
||
/** 成员列表(含 owner) */
|
||
export function fetchAlbumMembers(albumId: string, params: { cursor?: string; limit?: number }) {
|
||
return request.get<Api.Album.MemberListResponse>({
|
||
url: `/v1/albums/${albumId}/members`,
|
||
params
|
||
})
|
||
}
|
||
|
||
/** 添加成员(按用户 ID;重复添加 409 MEMBER_CONFLICT) */
|
||
export function fetchAddAlbumMember(albumId: string, userId: string) {
|
||
return request.post<Api.Album.Member>({
|
||
url: `/v1/albums/${albumId}/members`,
|
||
data: { userId, role: 'collaborator' }
|
||
})
|
||
}
|
||
|
||
/** 移除成员(owner 不可移除 403;目标不存在幂等 204) */
|
||
export function fetchRemoveAlbumMember(albumId: string, userId: string) {
|
||
return request.del<void>({ url: `/v1/albums/${albumId}/members/${userId}` })
|
||
}
|
||
|
||
/** 账号前缀查询(邀请协作者前置;≥2 字符,激活用户;P4a 契约统一 AdminUserList) */
|
||
export function fetchLookupUsers(accountPrefix: string, limit = 10) {
|
||
return request.get<Api.Album.UserLookupListResponse>({
|
||
url: '/v1/admin/users',
|
||
params: { accountPrefix, limit },
|
||
showErrorMessage: false
|
||
})
|
||
}
|
||
|
||
/** 创建分类 */
|
||
export function fetchCreateCategory(albumId: string, data: Api.Album.CategoryCreatePayload) {
|
||
return request.post<Api.Album.Category>({
|
||
url: `/v1/albums/${albumId}/categories`,
|
||
data
|
||
})
|
||
}
|
||
|
||
/** 更新分类(translations 全量替换) */
|
||
export function fetchUpdateCategory(categoryId: string, data: Api.Album.CategoryUpdatePayload) {
|
||
return request.patch<Api.Album.Category>({ url: `/v1/categories/${categoryId}`, data })
|
||
}
|
||
|
||
/** 删除分类(204;分类下有照片时服务端 400 拒绝) */
|
||
export function fetchDeleteCategory(categoryId: string) {
|
||
return request.del<void>({ url: `/v1/categories/${categoryId}` })
|
||
}
|
||
|
||
/** 管理照片列表(全状态可见 + uploader 脱敏;uploadedAt 倒序游标) */
|
||
export function fetchAlbumPhotos(
|
||
albumId: string,
|
||
params: {
|
||
visibility?: Api.Album.PhotoVisibility
|
||
categoryId?: string
|
||
cursor?: string
|
||
limit?: number
|
||
}
|
||
) {
|
||
return request.get<Api.Album.AdminPhotoListResponse>({
|
||
url: `/v1/albums/${albumId}/photos`,
|
||
params
|
||
})
|
||
}
|
||
|
||
/** 调整照片可见性(仅 hidden ↔ published) */
|
||
export function fetchUpdatePhotoVisibility(photoId: string, visibility: 'hidden' | 'published') {
|
||
return request.patch<Api.Album.AdminPhoto>({
|
||
url: `/v1/photos/${photoId}`,
|
||
data: { visibility }
|
||
})
|
||
}
|
||
|
||
/** 软删除照片(204;deleted 为员工侧终态) */
|
||
export function fetchDeletePhoto(photoId: string) {
|
||
return request.del<void>({ url: `/v1/photos/${photoId}` })
|
||
}
|