Files
cyh-tk-backend/docs/apifox-app-apis.swagger.json
zhxiao1124 55e20f9f16 feat(dramas): add play count field for drama records
1. 新增plays字段到DramaRecord接口和swagger/openapi文档
2. 在剧集创建时默认设置plays为0
3. 新增getPlayCountsByDramaIds方法聚合剧集播放量
4. 在后台和前台剧集列表中添加播放量数据
5. 更新测试用例适配新增的plays字段
2026-07-02 18:25:58 +08:00

353 lines
15 KiB
JSON
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

{
"swagger": "2.0",
"info": {
"title": "CTH TK App APIs",
"description": "Apifox import file for mini app drama and history APIs.",
"version": "1.0.0"
},
"host": "localhost:3000",
"basePath": "/",
"schemes": ["http"],
"consumes": ["application/json"],
"produces": ["application/json"],
"securityDefinitions": {
"Bearer": {
"type": "apiKey",
"name": "Authorization",
"in": "header",
"description": "Bearer <JWT>"
}
},
"tags": [
{ "name": "App Dramas", "description": "Mini app drama APIs" },
{ "name": "App History", "description": "Mini app playback history APIs" }
],
"paths": {
"/api/app/v1/dramas": {
"get": {
"tags": ["App Dramas"],
"summary": "短剧列表",
"operationId": "listAppDramas",
"parameters": [
{ "name": "page", "in": "query", "type": "integer", "default": 1, "minimum": 1 },
{ "name": "pageSize", "in": "query", "type": "integer", "default": 10, "minimum": 1, "maximum": 100 }
],
"responses": {
"200": { "description": "OK", "schema": { "$ref": "#/definitions/AppDramaPageResponse" } }
}
}
},
"/api/app/v1/dramas/recommended": {
"get": {
"tags": ["App Dramas"],
"summary": "推荐短剧列表",
"operationId": "listRecommendedAppDramas",
"parameters": [
{ "name": "page", "in": "query", "type": "integer", "default": 1, "minimum": 1 },
{ "name": "pageSize", "in": "query", "type": "integer", "default": 10, "minimum": 1, "maximum": 100 }
],
"responses": {
"200": { "description": "OK", "schema": { "$ref": "#/definitions/AppDramaPageResponse" } }
}
}
},
"/api/app/v1/dramas/presearch": {
"get": {
"tags": ["App Dramas"],
"summary": "短剧名称预查询",
"operationId": "presearchAppDramasByTitle",
"parameters": [
{ "name": "keyword", "in": "query", "type": "string", "description": "短剧名称关键字;空值返回空列表" },
{ "name": "page", "in": "query", "type": "integer", "default": 1, "minimum": 1 },
{ "name": "pageSize", "in": "query", "type": "integer", "default": 10, "minimum": 1, "maximum": 100 }
],
"responses": {
"200": { "description": "OK", "schema": { "$ref": "#/definitions/AppDramaPageResponse" } }
}
}
},
"/api/app/v1/dramas/{id}/episodes": {
"get": {
"tags": ["App Dramas"],
"summary": "短剧剧集列表",
"operationId": "listAppDramaEpisodes",
"parameters": [
{ "name": "id", "in": "path", "required": true, "type": "integer", "minimum": 1 },
{ "name": "page", "in": "query", "type": "integer", "default": 1, "minimum": 1 },
{ "name": "pageSize", "in": "query", "type": "integer", "default": 20, "minimum": 1, "maximum": 100 }
],
"responses": {
"200": { "description": "OK", "schema": { "$ref": "#/definitions/AppEpisodePageResponse" } },
"404": { "description": "Not Found", "schema": { "$ref": "#/definitions/ErrorResponse" } }
}
}
},
"/api/app/v1/dramas/{id}": {
"get": {
"tags": ["App Dramas"],
"summary": "短剧详情",
"operationId": "getAppDrama",
"parameters": [
{ "name": "id", "in": "path", "required": true, "type": "integer", "minimum": 1 }
],
"responses": {
"200": { "description": "OK", "schema": { "$ref": "#/definitions/AppDramaDetailResponse" } },
"404": { "description": "Not Found", "schema": { "$ref": "#/definitions/ErrorResponse" } }
}
}
},
"/api/app/v1/history": {
"get": {
"tags": ["App History"],
"summary": "播放历史列表",
"operationId": "listAppHistory",
"security": [{ "Bearer": [] }],
"parameters": [
{ "name": "page", "in": "query", "type": "integer", "default": 1, "minimum": 1 },
{ "name": "pageSize", "in": "query", "type": "integer", "default": 20, "minimum": 1, "maximum": 100 }
],
"responses": {
"200": { "description": "OK", "schema": { "$ref": "#/definitions/PlaybackHistoryPageResponse" } },
"401": { "description": "Unauthorized", "schema": { "$ref": "#/definitions/ErrorResponse" } }
}
},
"post": {
"tags": ["App History"],
"summary": "上报播放历史",
"operationId": "upsertAppHistory",
"security": [{ "Bearer": [] }],
"parameters": [
{ "name": "body", "in": "body", "required": true, "schema": { "$ref": "#/definitions/UpsertPlaybackHistoryRequest" } }
],
"responses": {
"201": { "description": "Created", "schema": { "$ref": "#/definitions/PlaybackHistoryRecordResponse" } },
"400": { "description": "Bad Request", "schema": { "$ref": "#/definitions/ErrorResponse" } },
"401": { "description": "Unauthorized", "schema": { "$ref": "#/definitions/ErrorResponse" } },
"404": { "description": "Not Found", "schema": { "$ref": "#/definitions/ErrorResponse" } }
}
}
}
},
"definitions": {
"ApiResponseBase": {
"type": "object",
"required": ["code", "data", "message", "timestamp", "requestId", "cost"],
"properties": {
"code": { "type": "integer", "description": "成功为 0错误为 HTTP 状态码", "example": 0 },
"message": { "type": "string", "example": "success" },
"timestamp": { "type": "integer", "format": "int64", "example": 1782986400000 },
"requestId": { "type": "string", "example": "550e8400-e29b-41d4-a716-446655440000" },
"cost": { "type": "string", "example": "12ms" }
}
},
"Pagination": {
"type": "object",
"required": ["page", "pageSize", "total"],
"properties": {
"page": { "type": "integer", "example": 1 },
"pageSize": { "type": "integer", "example": 10 },
"total": { "type": "integer", "example": 100 }
}
},
"AppDrama": {
"type": "object",
"properties": {
"id": { "type": "integer", "example": 1 },
"tiktokAlbumId": { "type": "string" },
"title": { "type": "string", "example": "Published Drama" },
"description": { "type": "string" },
"coverId": { "type": "integer" },
"coverUrl": { "type": "string", "example": "https://cdn.example.com/cover.jpg" },
"type": { "type": "string", "example": "romance" },
"tags": { "type": "array", "items": { "type": "string" } },
"region": { "type": "string" },
"language": { "type": "string" },
"year": { "type": "integer" },
"status": { "type": "string", "enum": ["draft", "scheduled", "published", "offline"], "example": "published" },
"sortOrder": { "type": "integer", "example": 0 },
"isRecommended": { "type": "boolean", "example": true },
"onlineVersion": { "type": "integer", "example": 1 },
"totalEpisodes": { "type": "integer", "example": 20 },
"publishedEpisodes": { "type": "integer", "example": 10 },
"plays": { "type": "integer", "example": 12345 },
"createdAt": { "type": "string", "format": "date-time" },
"updatedAt": { "type": "string", "format": "date-time" }
}
},
"AppDramaDetail": {
"type": "object",
"properties": {
"id": { "type": "integer", "example": 1 },
"tiktokAlbumId": { "type": "string" },
"title": { "type": "string", "example": "Published Drama" },
"description": { "type": "string" },
"coverId": { "type": "integer" },
"coverUrl": { "type": "string", "example": "https://cdn.example.com/cover.jpg" },
"portraitCoverUrl": { "type": "string" },
"landscapeCoverUrl": { "type": "string" },
"type": { "type": "string", "example": "romance" },
"tags": { "type": "array", "items": { "type": "string" } },
"region": { "type": "string" },
"language": { "type": "string" },
"year": { "type": "integer" },
"status": { "type": "string", "enum": ["draft", "scheduled", "published", "offline"], "example": "published" },
"sortOrder": { "type": "integer", "example": 0 },
"isRecommended": { "type": "boolean", "example": true },
"onlineVersion": { "type": "integer", "example": 1 },
"totalEpisodes": { "type": "integer", "example": 20 },
"publishedEpisodes": { "type": "integer", "example": 10 },
"createdAt": { "type": "string", "format": "date-time" },
"updatedAt": { "type": "string", "format": "date-time" }
}
},
"AppEpisode": {
"type": "object",
"properties": {
"id": { "type": "integer", "example": 1 },
"dramaId": { "type": "integer", "example": 1 },
"albumId": { "type": "integer", "example": 1 },
"tiktokEpisodeId": { "type": "string" },
"episodeNo": { "type": "integer", "example": 1 },
"seq": { "type": "integer", "example": 1 },
"title": { "type": "string", "example": "Episode 1" },
"description": { "type": "string" },
"byteplusVid": { "type": "string" },
"coverId": { "type": "integer" },
"coverUrl": { "type": "string", "example": "https://cdn.example.com/episode.jpg" },
"videoUrl": { "type": "string" },
"trialDurationSeconds": { "type": "integer" },
"durationSeconds": { "type": "integer", "example": 300 },
"isPaid": { "type": "boolean", "example": false },
"freeType": { "type": "string", "enum": ["free", "paid"], "example": "free" },
"unlockPrice": { "type": "integer" },
"price": { "type": "integer", "example": 0 },
"status": { "type": "string", "enum": ["draft", "scheduled", "published", "offline"], "example": "published" },
"reviewStatus": { "type": "string", "enum": ["not_submitted", "pending", "reviewing", "approved", "rejected"], "example": "approved" },
"publishStatus": { "type": "string", "enum": ["draft", "scheduled", "published", "offline"], "example": "published" },
"createdAt": { "type": "string", "format": "date-time" },
"updatedAt": { "type": "string", "format": "date-time" }
}
},
"PlaybackHistoryListItem": {
"type": "object",
"properties": {
"id": { "type": "integer", "example": 1 },
"dramaId": { "type": "integer", "example": 1 },
"episodeId": { "type": "integer", "example": 123 },
"episodeNo": { "type": "integer", "example": 1 },
"title": { "type": "string", "example": "History Episode" },
"coverUrl": { "type": "string", "example": "https://cdn.example.com/history-episode.jpg" },
"progressSeconds": { "type": "integer", "example": 86 },
"durationSeconds": { "type": "integer", "example": 300 },
"completed": { "type": "boolean", "example": false },
"lastPlayedAt": { "type": "string", "format": "date-time" },
"dramaTitle": { "type": "string", "example": "History Drama" },
"dramaCoverUrl": { "type": "string", "example": "https://cdn.example.com/history-drama.jpg" }
}
},
"PlaybackHistoryRecord": {
"type": "object",
"properties": {
"id": { "type": "integer", "example": 1 },
"userId": { "type": "integer", "example": 1 },
"dramaId": { "type": "integer", "example": 1 },
"episodeId": { "type": "integer", "example": 123 },
"progressSeconds": { "type": "integer", "example": 86 },
"durationSeconds": { "type": "integer", "example": 300 },
"completed": { "type": "boolean", "example": false },
"lastPlayedAt": { "type": "string", "format": "date-time" },
"createdAt": { "type": "string", "format": "date-time" },
"updatedAt": { "type": "string", "format": "date-time" }
}
},
"UpsertPlaybackHistoryRequest": {
"type": "object",
"required": ["episodeId", "progressSeconds"],
"properties": {
"episodeId": { "type": "integer", "minimum": 1, "example": 123 },
"progressSeconds": { "type": "integer", "minimum": 0, "example": 86 },
"completed": { "type": "boolean", "example": false },
"occurredAt": { "type": "string", "format": "date-time", "example": "2026-07-02T10:00:00.000Z" }
}
},
"AppDramaPage": {
"type": "object",
"properties": { "list": { "type": "array", "items": { "$ref": "#/definitions/AppDrama" } }, "pagination": { "$ref": "#/definitions/Pagination" } }
},
"AppEpisodePage": {
"type": "object",
"properties": { "list": { "type": "array", "items": { "$ref": "#/definitions/AppEpisode" } }, "pagination": { "$ref": "#/definitions/Pagination" } }
},
"PlaybackHistoryPage": {
"type": "object",
"properties": { "list": { "type": "array", "items": { "$ref": "#/definitions/PlaybackHistoryListItem" } }, "pagination": { "$ref": "#/definitions/Pagination" } }
},
"AppDramaPageResponse": {
"type": "object",
"properties": {
"code": { "type": "integer", "example": 0 },
"data": { "$ref": "#/definitions/AppDramaPage" },
"message": { "type": "string", "example": "success" },
"timestamp": { "type": "integer", "format": "int64" },
"requestId": { "type": "string" },
"cost": { "type": "string", "example": "12ms" }
}
},
"AppDramaDetailResponse": {
"type": "object",
"properties": {
"code": { "type": "integer", "example": 0 },
"data": { "$ref": "#/definitions/AppDramaDetail" },
"message": { "type": "string", "example": "success" },
"timestamp": { "type": "integer", "format": "int64" },
"requestId": { "type": "string" },
"cost": { "type": "string", "example": "12ms" }
}
},
"AppEpisodePageResponse": {
"type": "object",
"properties": {
"code": { "type": "integer", "example": 0 },
"data": { "$ref": "#/definitions/AppEpisodePage" },
"message": { "type": "string", "example": "success" },
"timestamp": { "type": "integer", "format": "int64" },
"requestId": { "type": "string" },
"cost": { "type": "string", "example": "12ms" }
}
},
"PlaybackHistoryPageResponse": {
"type": "object",
"properties": {
"code": { "type": "integer", "example": 0 },
"data": { "$ref": "#/definitions/PlaybackHistoryPage" },
"message": { "type": "string", "example": "success" },
"timestamp": { "type": "integer", "format": "int64" },
"requestId": { "type": "string" },
"cost": { "type": "string", "example": "12ms" }
}
},
"PlaybackHistoryRecordResponse": {
"type": "object",
"properties": {
"code": { "type": "integer", "example": 0 },
"data": { "$ref": "#/definitions/PlaybackHistoryRecord" },
"message": { "type": "string", "example": "success" },
"timestamp": { "type": "integer", "format": "int64" },
"requestId": { "type": "string" },
"cost": { "type": "string", "example": "12ms" }
}
},
"ErrorResponse": {
"type": "object",
"properties": {
"code": { "type": "integer", "example": 404 },
"data": { "type": "object" },
"message": { "type": "string", "example": "Not found" },
"timestamp": { "type": "integer", "format": "int64" },
"requestId": { "type": "string" },
"cost": { "type": "string", "example": "12ms" }
}
}
}
}