library-picturebook-activity/frontend/src/api/public.ts

530 lines
14 KiB
TypeScript
Raw Normal View History

import axios from "axios"
// 公众端专用 axios 实例
const publicApi = axios.create({
baseURL: import.meta.env.VITE_API_BASE_URL || "/api",
timeout: 15000,
})
// 请求拦截器
publicApi.interceptors.request.use((config) => {
const token = localStorage.getItem("public_token")
if (token) {
config.headers.Authorization = `Bearer ${token}`
}
return config
})
// 响应拦截器
publicApi.interceptors.response.use(
(response) => {
// 后端返回格式:{ code: 200, message: "success", data: xxx }
// 当 data 为 null 时,直接返回 null
if (response.data) {
return response.data.data !== undefined ? response.data.data : response.data
}
return response.data
},
(error) => {
if (error.response?.status === 401) {
localStorage.removeItem("public_token")
localStorage.removeItem("public_user")
// 如果在公众端页面,跳转到公众端登录
if (window.location.pathname.startsWith("/p/")) {
window.location.href = "/p/login"
}
}
return Promise.reject(error)
},
)
// ==================== 认证 ====================
export interface PublicRegisterParams {
username: string
password: string
nickname: string
phone?: string
city?: string
}
export interface PublicLoginParams {
username: string
password: string
}
export interface PublicUser {
id: number
username: string
nickname: string
phone: string | null
city: string | null
avatar: string | null
tenantId: number
tenantCode: string
userSource: string
userType: "adult" | "child"
parentUserId: number | null
roles: string[]
permissions: string[]
children?: any[]
childrenCount?: number
}
export interface LoginResponse {
token: string
user: PublicUser
}
export const publicAuthApi = {
register: (data: PublicRegisterParams): Promise<LoginResponse> =>
publicApi.post("/public/auth/register", data),
login: (data: PublicLoginParams): Promise<LoginResponse> =>
publicApi.post("/public/auth/login", data),
}
// ==================== 个人信息 ====================
export const publicProfileApi = {
getProfile: (): Promise<PublicUser> => publicApi.get("/public/mine/profile"),
updateProfile: (data: {
nickname?: string
city?: string
avatar?: string
gender?: string
}) => publicApi.put("/public/mine/profile", data),
}
// ==================== 子女管理 ====================
export interface Child {
id: number
parentId: number
name: string
gender: string | null
birthday: string | null
grade: string | null
city: string | null
schoolName: string | null
avatar: string | null
}
export interface CreateChildParams {
name: string
gender?: string
birthday?: string
grade?: string
city?: string
schoolName?: string
}
export const publicChildrenApi = {
list: (): Promise<Child[]> => publicApi.get("/public/mine/children"),
create: (data: CreateChildParams): Promise<Child> =>
publicApi.post("/public/mine/children", data),
get: (id: number): Promise<Child> =>
publicApi.get(`/public/mine/children/${id}`),
update: (id: number, data: Partial<CreateChildParams>): Promise<Child> =>
publicApi.put(`/public/mine/children/${id}`, data),
delete: (id: number) => publicApi.delete(`/public/mine/children/${id}`),
}
// ==================== 子女独立账号管理 ====================
export interface CreateChildAccountParams {
username: string
password: string
nickname: string
gender?: string
birthday?: string
city?: string
avatar?: string
relationship?: string
}
export interface ChildAccount {
id: number
username: string
nickname: string
avatar: string | null
gender: string | null
birthday: string | null
city: string | null
status: string
userType: string
createTime: string
relationship: string | null
controlMode: string
}
export const publicChildAccountApi = {
// 家长为子女创建独立账号
create: (data: CreateChildAccountParams): Promise<any> =>
publicApi.post("/public/children/create-account", data),
// 获取子女账号列表
list: (): Promise<ChildAccount[]> =>
publicApi.get("/public/children/accounts"),
// 家长切换到子女身份
switchToChild: (childUserId: number): Promise<LoginResponse> =>
publicApi.post("/public/auth/switch-child", { childUserId }),
// 更新子女账号信息
update: (id: number, data: {
nickname?: string
password?: string
gender?: string
birthday?: string
city?: string
avatar?: string
controlMode?: string
}): Promise<any> =>
publicApi.put(`/public/children/accounts/${id}`, data),
// 子女查看家长信息
getParentInfo: (): Promise<{
parentId: number
nickname: string
avatar: string | null
relationship: string | null
} | null> =>
publicApi.get("/public/mine/parent-info"),
}
// ==================== 活动 ====================
export interface PublicActivity {
id: number
contestName: string
contestType: string
contestState: string
status: string
startTime: string
endTime: string
coverUrl: string | null
posterUrl: string | null
registerStartTime: string
registerEndTime: string
submitStartTime: string
submitEndTime: string
submitRule: string
reviewStartTime: string
reviewEndTime: string
organizers: any
visibility: string
resultState: string
resultPublishTime: string | null
content: string
address: string | null
contactName: string | null
contactPhone: string | null
contactQrcode: string | null
coOrganizers: any
sponsors: any
registerState: string
workType: string
workRequirement: string
}
/** 公众端活动详情(含公告、附件等扩展字段) */
export interface PublicActivityNotice {
id: number
title: string
content: string
noticeType?: string
publishTime?: string
createTime?: string
}
export interface PublicActivityAttachment {
id: number
fileName: string
fileUrl: string
fileType?: string
format?: string
size?: string
}
export interface PublicActivityDetail extends PublicActivity {
/** 兼容旧字段;详情正文以后端 content 为准 */
description?: string
notices?: PublicActivityNotice[]
attachments?: PublicActivityAttachment[]
ageMin?: number
ageMax?: number
targetCities?: string[]
}
/** 公众端公示成果行(无报名账号等敏感字段) */
export interface PublicActivityResultItem {
id: number
workNo: string | null
title: string | null
rank: number | null
finalScore: number | string | null
awardName: string | null
participantName: string
}
export const publicActivitiesApi = {
list: (params?: {
page?: number
pageSize?: number
keyword?: string
contestType?: string
}): Promise<{ list: PublicActivity[]; total: number }> =>
publicApi.get("/public/activities", { params }),
detail: (id: number): Promise<PublicActivityDetail> =>
publicApi.get(`/public/activities/${id}`),
register: (
id: number,
data: { participantType: "self" | "child"; childId?: number },
) => publicApi.post(`/public/activities/${id}/register`, data),
getMyRegistration: (id: number) =>
publicApi.get<{
id: number
contestId: number
userId: number
registrationType: string
registrationState: string
registrationTime: string
hasSubmittedWork: boolean
workCount: number
} | null>(`/public/activities/${id}/my-registration`),
submitWork: (
id: number,
data: {
registrationId: number
userWorkId?: number
title?: string
description?: string
files?: string[]
previewUrl?: string
attachments?: { fileName: string; fileUrl: string; fileType?: string; size?: string }[]
},
) => publicApi.post(`/public/activities/${id}/submit-work`, data),
/** 公示成果分页(仅 resultState=published 的活动;无需登录) */
getPublishedResults: (
id: number,
params?: { page?: number; pageSize?: number },
): Promise<{
list: PublicActivityResultItem[]
total: number
page: number
pageSize: number
}> => publicApi.get(`/public/activities/${id}/results`, { params }),
}
// ==================== 我的报名 ====================
export const publicMineApi = {
registrations: (params?: { page?: number; pageSize?: number }) =>
2026-04-03 18:47:42 +08:00
publicApi.get("/public/activities/mine/registrations", { params }),
}
// ==================== 点赞 & 收藏 ====================
export const publicInteractionApi = {
like: (workId: number) =>
publicApi.post(`/public/works/${workId}/like`),
favorite: (workId: number) =>
publicApi.post(`/public/works/${workId}/favorite`),
getInteraction: (workId: number) =>
publicApi.get(`/public/works/${workId}/interaction`),
batchStatus: (workIds: number[]) =>
publicApi.post("/public/works/batch-interaction", { workIds }),
myFavorites: (params?: { page?: number; pageSize?: number }) =>
publicApi.get("/public/mine/favorites", { params }),
}
// ==================== 用户作品库 ====================
export interface UserWork {
id: number
userId: number
title: string
coverUrl: string | null
description: string | null
visibility: string
status: string
reviewNote: string | null
originalImageUrl: string | null
voiceInputUrl: string | null
textInput: string | null
aiMeta: any
viewCount: number
likeCount: number
favoriteCount: number
commentCount: number
shareCount: number
publishTime: string | null
createTime: string
modifyTime: string
pages?: UserWorkPage[]
tags?: Array<{ tag: { id: number; name: string; category: string } }>
creator?: { id: number; nickname: string; avatar: string | null; username: string }
_count?: { pages: number; likes: number; favorites: number; comments: number }
}
export interface UserWorkPage {
id: number
workId: number
pageNo: number
imageUrl: string | null
text: string | null
audioUrl: string | null
}
export const publicUserWorksApi = {
// 创建作品
create: (data: {
title: string
coverUrl?: string
description?: string
visibility?: string
originalImageUrl?: string
voiceInputUrl?: string
textInput?: string
aiMeta?: any
pages?: Array<{ pageNo: number; imageUrl?: string; text?: string; audioUrl?: string }>
tagIds?: number[]
}): Promise<UserWork> => publicApi.post("/public/works", data),
// 我的作品列表
list: (params?: {
page?: number
pageSize?: number
status?: string
keyword?: string
}): Promise<{ list: UserWork[]; total: number }> =>
publicApi.get("/public/works", { params }),
// 作品详情
detail: (id: number): Promise<UserWork> =>
publicApi.get(`/public/works/${id}`),
// 更新作品
update: (id: number, data: {
title?: string
description?: string
coverUrl?: string
visibility?: string
tagIds?: number[]
}): Promise<UserWork> => publicApi.put(`/public/works/${id}`, data),
// 删除作品
delete: (id: number) => publicApi.delete(`/public/works/${id}`),
// 发布作品(进入审核)
publish: (id: number) => publicApi.post(`/public/works/${id}/publish`),
// 获取绘本分页
getPages: (id: number): Promise<UserWorkPage[]> =>
publicApi.get(`/public/works/${id}/pages`),
// 保存绘本分页
savePages: (id: number, pages: Array<{ pageNo: number; imageUrl?: string; text?: string; audioUrl?: string }>) =>
publicApi.post(`/public/works/${id}/pages`, { pages }),
}
// ==================== AI 创作流程 ====================
export const publicCreationApi = {
// 提交创作请求(保留但降级为辅助接口)
submit: (data: {
originalImageUrl: string
voiceInputUrl?: string
textInput?: string
}): Promise<{ id: number; status: string; message: string }> =>
publicApi.post("/public/creation/submit", data),
// 查询生成进度(返回 INT 类型 status + progress
getStatus: (id: number): Promise<{
id: number
status: number
progress: number
progressMessage: string | null
remoteWorkId: string | null
title: string
coverUrl: string | null
}> => publicApi.get(`/public/creation/${id}/status`),
// 获取生成结果(包含 pageList
getResult: (id: number): Promise<UserWork> =>
publicApi.get(`/public/creation/${id}/result`),
// 创作历史
history: (params?: { page?: number; pageSize?: number }): Promise<{ list: any[]; total: number }> =>
publicApi.get("/public/creation/history", { params }),
}
// ==================== 乐读派 AI 创作集成 ====================
export const leaiApi = {
// 获取乐读派创作 Tokeniframe 模式主入口)
getToken: (): Promise<{
token: string
orgId: string
h5Url: string
phone: string
}> => publicApi.get("/leai-auth/token"),
// 刷新 TokenTOKEN_EXPIRED 时调用)
refreshToken: (): Promise<{
token: string
orgId: string
phone: string
}> => publicApi.get("/leai-auth/refresh-token"),
}
// ==================== 标签 ====================
export interface WorkTag {
id: number
name: string
category: string | null
usageCount: number
}
export const publicTagsApi = {
list: (): Promise<WorkTag[]> => publicApi.get("/public/tags"),
hot: (): Promise<WorkTag[]> => publicApi.get("/public/tags/hot"),
}
// ==================== 作品广场 ====================
export const publicGalleryApi = {
recommended: (): Promise<UserWork[]> =>
publicApi.get("/public/gallery/recommended"),
list: (params?: {
page?: number
pageSize?: number
tagId?: number
category?: string
sortBy?: string
keyword?: string
}): Promise<{ list: UserWork[]; total: number }> =>
publicApi.get("/public/gallery", { params }),
detail: (id: number): Promise<UserWork> =>
publicApi.get(`/public/gallery/${id}`),
userWorks: (userId: number, params?: { page?: number; pageSize?: number }): Promise<{ list: UserWork[]; total: number }> =>
publicApi.get(`/public/users/${userId}/works`, { params }),
}
export default publicApi