diff --git a/fruitshorts-admin-api/src/main/java/com/fruitshorts/FruitShortsApplication.java b/fruitshorts-admin-api/src/main/java/com/fruitshorts/FruitShortsApplication.java index d5758d3..d3461e9 100644 --- a/fruitshorts-admin-api/src/main/java/com/fruitshorts/FruitShortsApplication.java +++ b/fruitshorts-admin-api/src/main/java/com/fruitshorts/FruitShortsApplication.java @@ -3,7 +3,48 @@ package com.fruitshorts; import org.mybatis.spring.annotation.MapperScan; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; +import io.swagger.v3.oas.annotations.OpenAPIDefinition; +import io.swagger.v3.oas.annotations.info.Info; +import io.swagger.v3.oas.annotations.tags.Tag; +@OpenAPIDefinition( + info = @Info( + title = "FruitShorts 运营后台接口(/admin/**)", + version = "1.0.0", + description = "接口契约以 FruitServer/docs/api-phase1.md 为准" + ), + tags = { + @Tag(name = "后台-管理员账号", description = "后台管理员账号管理"), + @Tag(name = "后台-App 用户", description = "App 用户查询与处置"), + @Tag(name = "后台-登录与个人", description = "管理端登录、菜单、个人资料与改密"), + @Tag(name = "后台-轮播图管理", description = "轮播图维护与排序"), + @Tag(name = "后台-评论审核", description = "评论检索与审核"), + @Tag(name = "后台-系统配置", description = "系统参数配置"), + @Tag(name = "后台-创作者管理", description = "创作者入驻审核与账号开通"), + @Tag(name = "创作者中心", description = "创作者工作台(作品、通知、看板)"), + @Tag(name = "创作者中心-内容与收费", description = "创作者内容编辑、提交审核与分集收费"), + @Tag(name = "后台-数据看板", description = "运营大盘与转码看板"), + @Tag(name = "后台-字典", description = "分类与状态字典"), + @Tag(name = "后台-离线下载管理", description = "下载授权查询、吊销与清理"), + @Tag(name = "后台-短剧分类", description = "短剧分类维护"), + @Tag(name = "后台-短剧管理", description = "短剧 CRUD 与审核发布流转"), + @Tag(name = "后台-权益管理", description = "权益补发与回收"), + @Tag(name = "后台-剧集管理", description = "剧集 CRUD 与排序"), + @Tag(name = "后台-媒资管理", description = "分片上传与媒资详情"), + @Tag(name = "后台-菜单管理", description = "菜单树维护"), + @Tag(name = "后台-操作日志", description = "操作日志检索"), + @Tag(name = "后台-订单管理", description = "订单检索、补发与退款"), + @Tag(name = "后台-权限点", description = "权限点查询"), + @Tag(name = "后台-分集收费", description = "分集价格配置"), + @Tag(name = "后台-对账", description = "对账任务与手动对账"), + @Tag(name = "后台-举报工单", description = "举报工单处理"), + @Tag(name = "后台-角色分类", description = "角色分类维护"), + @Tag(name = "后台-角色管理", description = "角色与角色权限"), + @Tag(name = "后台-敏感词库", description = "敏感词维护"), + @Tag(name = "后台-内容提交审核", description = "创作者内容提交审核"), + @Tag(name = "后台-金币钱包", description = "金币流水与人工补币"), + } +) @SpringBootApplication @MapperScan("com.fruitshorts.**.dal.mapper") public class FruitShortsApplication { diff --git a/fruitshorts-admin-api/src/main/java/com/fruitshorts/admin/controller/AdminUserController.java b/fruitshorts-admin-api/src/main/java/com/fruitshorts/admin/controller/AdminUserController.java index 571848c..1b338a0 100644 --- a/fruitshorts-admin-api/src/main/java/com/fruitshorts/admin/controller/AdminUserController.java +++ b/fruitshorts-admin-api/src/main/java/com/fruitshorts/admin/controller/AdminUserController.java @@ -8,6 +8,8 @@ import com.fruitshorts.framework.log.OperationLog; import com.fruitshorts.system.vo.AdminUserPageReqVO; import com.fruitshorts.system.vo.AdminUserRespVO; import com.fruitshorts.system.vo.AdminUserSaveReqVO; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.validation.Valid; import lombok.RequiredArgsConstructor; import org.springframework.security.access.prepost.PreAuthorize; @@ -23,6 +25,7 @@ import org.springframework.web.bind.annotation.RestController; import java.util.Map; +@Tag(name = "后台-管理员账号") @RestController @RequestMapping("/admin/admin-users") @RequiredArgsConstructor @@ -30,18 +33,21 @@ public class AdminUserController { private final AdminUserService adminUserService; + @Operation(summary = "管理员分页查询") @GetMapping("/page") @PreAuthorize("@ss.hasPermission('system:admin-user')") public Result> page(AdminUserPageReqVO req) { return Result.ok(adminUserService.page(req)); } + @Operation(summary = "管理员详情") @GetMapping("/{id}") @PreAuthorize("@ss.hasPermission('system:admin-user')") public Result get(@PathVariable Long id) { return Result.ok(adminUserService.get(id)); } + @Operation(summary = "新建管理员") @PostMapping @PreAuthorize("@ss.hasPermission('system:admin-user')") @OperationLog(module = "后台管理", action = "新增管理员") @@ -49,6 +55,7 @@ public class AdminUserController { return Result.ok(adminUserService.create(req)); } + @Operation(summary = "编辑管理员") @PutMapping("/{id}") @PreAuthorize("@ss.hasPermission('system:admin-user')") @OperationLog(module = "后台管理", action = "编辑管理员") @@ -57,6 +64,7 @@ public class AdminUserController { return Result.ok(); } + @Operation(summary = "删除管理员") @DeleteMapping("/{id}") @PreAuthorize("@ss.hasPermission('system:admin-user')") @OperationLog(module = "后台管理", action = "删除管理员") @@ -65,6 +73,7 @@ public class AdminUserController { return Result.ok(); } + @Operation(summary = "启用 / 停用管理员") @PutMapping("/{id}/status") @PreAuthorize("@ss.hasPermission('system:admin-user')") @OperationLog(module = "后台管理", action = "修改管理员状态") @@ -73,6 +82,7 @@ public class AdminUserController { return Result.ok(); } + @Operation(summary = "重置管理员密码") @PutMapping("/{id}/password") @PreAuthorize("@ss.hasPermission('system:admin-user')") @OperationLog(module = "后台管理", action = "重置管理员密码") diff --git a/fruitshorts-admin-api/src/main/java/com/fruitshorts/admin/controller/AppUserAdminController.java b/fruitshorts-admin-api/src/main/java/com/fruitshorts/admin/controller/AppUserAdminController.java index fcd38df..d216d69 100644 --- a/fruitshorts-admin-api/src/main/java/com/fruitshorts/admin/controller/AppUserAdminController.java +++ b/fruitshorts-admin-api/src/main/java/com/fruitshorts/admin/controller/AppUserAdminController.java @@ -16,6 +16,8 @@ import com.fruitshorts.user.dal.entity.AppUserBanRecord; import com.fruitshorts.user.service.AppUserAdminService; import com.fruitshorts.user.vo.AppUserQueryReqVO; import com.fruitshorts.user.vo.AppUserAdminRespVO; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; import lombok.RequiredArgsConstructor; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.web.bind.annotation.GetMapping; @@ -30,6 +32,7 @@ import java.util.Map; import java.util.stream.Collectors; /** 后台用户管理。 */ +@Tag(name = "后台-App 用户") @RestController @RequestMapping("/admin/app-users") @RequiredArgsConstructor @@ -40,18 +43,21 @@ public class AppUserAdminController { private final DramaService dramaService; private final EpisodeService episodeService; + @Operation(summary = "App 用户分页查询") @GetMapping("/page") @PreAuthorize("@ss.hasPermission('app-user:list')") public Result> page(AppUserQueryReqVO req) { return Result.ok(appUserAdminService.page(req)); } + @Operation(summary = "App 用户详情") @GetMapping("/{id}") @PreAuthorize("@ss.hasPermission('app-user:list')") public Result detail(@PathVariable Long id) { return Result.ok(appUserAdminService.detail(id)); } + @Operation(summary = "封禁 / 处置记录") @GetMapping("/{id}/ban-records") @PreAuthorize("@ss.hasPermission('app-user:list')") public Result> banRecords(@PathVariable Long id) { @@ -59,6 +65,7 @@ public class AppUserAdminController { } /** 观看流水明细:客服核对"用户说看了但没记录"这类问题时用,带上剧名与集号。 */ + @Operation(summary = "观看流水明细(客服核对用)") @GetMapping("/{id}/watch-history") @PreAuthorize("@ss.hasPermission('app-user:list')") public Result> watchHistory(@PathVariable Long id, @@ -106,6 +113,7 @@ public class AppUserAdminController { } /** 状态处置:normal/limited/banned。封禁会立即吊销该用户全部会话。 */ + @Operation(summary = "处置用户状态(封禁会立即吊销全部会话)") @PutMapping("/{id}/status") @PreAuthorize("@ss.hasPermission('app-user:update')") @OperationLog(module = "用户管理", action = "修改用户状态") diff --git a/fruitshorts-admin-api/src/main/java/com/fruitshorts/admin/controller/AuthController.java b/fruitshorts-admin-api/src/main/java/com/fruitshorts/admin/controller/AuthController.java index 1cd72f0..b3b0e02 100644 --- a/fruitshorts-admin-api/src/main/java/com/fruitshorts/admin/controller/AuthController.java +++ b/fruitshorts-admin-api/src/main/java/com/fruitshorts/admin/controller/AuthController.java @@ -10,6 +10,8 @@ import com.fruitshorts.system.vo.LoginRespVO; import com.fruitshorts.system.vo.MenuVO; import com.fruitshorts.system.vo.PasswordChangeReqVO; import com.fruitshorts.system.vo.ProfileRespVO; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.servlet.http.HttpServletRequest; import jakarta.validation.Valid; import lombok.RequiredArgsConstructor; @@ -21,6 +23,7 @@ import org.springframework.web.bind.annotation.RestController; import java.util.List; +@Tag(name = "后台-登录与个人") @RestController @RequestMapping("/admin/auth") @RequiredArgsConstructor @@ -28,6 +31,7 @@ public class AuthController { private final AuthService authService; + @Operation(summary = "管理端登录") @PostMapping("/login") @OperationLog(module = "认证", action = "登录") public Result login(@Valid @RequestBody LoginReqVO req, HttpServletRequest request) { @@ -35,23 +39,27 @@ public class AuthController { } /** 当前用户的菜单路由树,结构与前端 element-plus-admin 的动态路由一致。 */ + @Operation(summary = "当前用户菜单路由树") @GetMapping("/menus") public Result> menus() { return Result.ok(authService.listMenus(SecurityUtils.getUserId())); } + @Operation(summary = "当前用户资料") @GetMapping("/profile") public Result profile() { return Result.ok(authService.profile(SecurityUtils.getUserId())); } /** JWT 无状态,登出由前端清除 token 即可。 */ + @Operation(summary = "登出") @PostMapping("/logout") @OperationLog(module = "认证", action = "退出登录") public Result logout() { return Result.ok(); } + @Operation(summary = "修改自己的登录密码") @PostMapping("/password") @OperationLog(module = "认证", action = "修改密码") public Result changePassword(@Valid @RequestBody PasswordChangeReqVO req) { diff --git a/fruitshorts-admin-api/src/main/java/com/fruitshorts/admin/controller/BannerController.java b/fruitshorts-admin-api/src/main/java/com/fruitshorts/admin/controller/BannerController.java index aaee7f6..2c00f99 100644 --- a/fruitshorts-admin-api/src/main/java/com/fruitshorts/admin/controller/BannerController.java +++ b/fruitshorts-admin-api/src/main/java/com/fruitshorts/admin/controller/BannerController.java @@ -7,6 +7,8 @@ import com.fruitshorts.content.vo.BannerRespVO; import com.fruitshorts.content.vo.BannerSaveReqVO; import com.fruitshorts.framework.security.SecurityUtils; import com.fruitshorts.framework.log.OperationLog; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.validation.Valid; import lombok.RequiredArgsConstructor; import org.springframework.security.access.prepost.PreAuthorize; @@ -23,6 +25,7 @@ import org.springframework.web.bind.annotation.RestController; import java.util.List; import java.util.Map; +@Tag(name = "后台-轮播图管理") @RestController @RequestMapping("/admin/banners") @RequiredArgsConstructor @@ -30,6 +33,7 @@ public class BannerController { private final BannerService bannerService; + @Operation(summary = "轮播图分页查询") @GetMapping("/page") @PreAuthorize("@ss.hasPermission('banner:list')") public Result> page(@RequestParam(required = false) String position, @@ -39,12 +43,14 @@ public class BannerController { return Result.ok(bannerService.page(position, status, pageIndex, pageSize)); } + @Operation(summary = "轮播图详情") @GetMapping("/{id}") @PreAuthorize("@ss.hasPermission('banner:list')") public Result get(@PathVariable Long id) { return Result.ok(bannerService.get(id)); } + @Operation(summary = "新建轮播图") @PostMapping @PreAuthorize("@ss.hasPermission('banner:create')") @OperationLog(module = "内容管理", action = "新增轮播图") @@ -52,6 +58,7 @@ public class BannerController { return Result.ok(bannerService.create(req, SecurityUtils.getUserId())); } + @Operation(summary = "编辑轮播图") @PutMapping("/{id}") @PreAuthorize("@ss.hasPermission('banner:update')") @OperationLog(module = "内容管理", action = "编辑轮播图") @@ -60,6 +67,7 @@ public class BannerController { return Result.ok(); } + @Operation(summary = "删除轮播图") @DeleteMapping("/{id}") @PreAuthorize("@ss.hasPermission('banner:delete')") @OperationLog(module = "内容管理", action = "删除轮播图") @@ -68,6 +76,7 @@ public class BannerController { return Result.ok(); } + @Operation(summary = "上架 / 下架轮播图") @PutMapping("/{id}/status") @PreAuthorize("@ss.hasPermission('banner:update')") @OperationLog(module = "内容管理", action = "修改轮播图状态") @@ -76,6 +85,7 @@ public class BannerController { return Result.ok(); } + @Operation(summary = "调整轮播排序") @PutMapping("/sort") @PreAuthorize("@ss.hasPermission('banner:update')") public Result sort(@RequestBody Map> body) { diff --git a/fruitshorts-admin-api/src/main/java/com/fruitshorts/admin/controller/CommentAdminController.java b/fruitshorts-admin-api/src/main/java/com/fruitshorts/admin/controller/CommentAdminController.java index 4ae7780..99d46b8 100644 --- a/fruitshorts-admin-api/src/main/java/com/fruitshorts/admin/controller/CommentAdminController.java +++ b/fruitshorts-admin-api/src/main/java/com/fruitshorts/admin/controller/CommentAdminController.java @@ -9,6 +9,8 @@ import com.fruitshorts.interaction.service.CommentService; import com.fruitshorts.interaction.vo.CommentAuditReqVO; import com.fruitshorts.interaction.vo.CommentQueryReqVO; import com.fruitshorts.interaction.vo.CommentRespVO; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.validation.Valid; import lombok.RequiredArgsConstructor; import org.springframework.security.access.prepost.PreAuthorize; @@ -23,6 +25,7 @@ import org.springframework.web.bind.annotation.RestController; import java.util.List; /** 后台评论审核。 */ +@Tag(name = "后台-评论审核") @RestController @RequestMapping("/admin/comments") @RequiredArgsConstructor @@ -31,6 +34,7 @@ public class CommentAdminController { private final CommentService commentService; /** 检索评论:默认按状态过滤,`status=pending` 即审核队列。 */ + @Operation(summary = "评论检索(默认按状态过滤,待审队列)") @GetMapping("/page") @PreAuthorize("@ss.hasPermission('comment:list')") public Result> page(CommentQueryReqVO req) { @@ -38,12 +42,14 @@ public class CommentAdminController { } /** 审核留证:机审与人审的完整链路。 */ + @Operation(summary = "评论审核留证(机审 + 人审链路)") @GetMapping("/{id}/audit-records") @PreAuthorize("@ss.hasPermission('comment:list')") public Result> auditRecords(@PathVariable Long id) { return Result.ok(commentService.auditRecords(id)); } + @Operation(summary = "审核评论(通过 / 驳回)") @PutMapping("/{id}/audit") @PreAuthorize("@ss.hasPermission('comment:audit')") @OperationLog(module = "内容治理", action = "审核评论") @@ -52,6 +58,7 @@ public class CommentAdminController { return Result.ok(); } + @Operation(summary = "删除评论") @DeleteMapping("/{id}") @PreAuthorize("@ss.hasPermission('comment:audit')") @OperationLog(module = "内容治理", action = "删除评论") diff --git a/fruitshorts-admin-api/src/main/java/com/fruitshorts/admin/controller/ConfigController.java b/fruitshorts-admin-api/src/main/java/com/fruitshorts/admin/controller/ConfigController.java index 4393d1a..bc414c3 100644 --- a/fruitshorts-admin-api/src/main/java/com/fruitshorts/admin/controller/ConfigController.java +++ b/fruitshorts-admin-api/src/main/java/com/fruitshorts/admin/controller/ConfigController.java @@ -4,6 +4,8 @@ import com.fruitshorts.common.pojo.Result; import com.fruitshorts.system.service.ConfigService; import com.fruitshorts.framework.log.OperationLog; import com.fruitshorts.system.vo.ConfigItemVO; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; import lombok.RequiredArgsConstructor; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.web.bind.annotation.GetMapping; @@ -15,6 +17,7 @@ import org.springframework.web.bind.annotation.RestController; import java.util.List; import java.util.Map; +@Tag(name = "后台-系统配置") @RestController @RequestMapping("/admin/configs") @RequiredArgsConstructor @@ -22,12 +25,14 @@ public class ConfigController { private final ConfigService configService; + @Operation(summary = "系统配置列表") @GetMapping @PreAuthorize("@ss.hasAnyPermission('system:role','system:menu')") public Result> list() { return Result.ok(configService.list()); } + @Operation(summary = "保存系统配置") @PutMapping @PreAuthorize("@ss.hasPermission('system:role')") @OperationLog(module = "后台管理", action = "修改系统设置") diff --git a/fruitshorts-admin-api/src/main/java/com/fruitshorts/admin/controller/CreatorAdminController.java b/fruitshorts-admin-api/src/main/java/com/fruitshorts/admin/controller/CreatorAdminController.java index 6b9d976..93a6909 100644 --- a/fruitshorts-admin-api/src/main/java/com/fruitshorts/admin/controller/CreatorAdminController.java +++ b/fruitshorts-admin-api/src/main/java/com/fruitshorts/admin/controller/CreatorAdminController.java @@ -13,6 +13,8 @@ import com.fruitshorts.creator.vo.CreatorAuditReqVO; import com.fruitshorts.creator.vo.CreatorQueryReqVO; import com.fruitshorts.framework.log.OperationLog; import com.fruitshorts.framework.security.SecurityUtils; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.validation.Valid; import lombok.RequiredArgsConstructor; import org.springframework.security.access.prepost.PreAuthorize; @@ -27,6 +29,7 @@ import org.springframework.web.bind.annotation.RestController; import java.util.List; /** 后台创作者:检索、详情、资质、入驻审核。 */ +@Tag(name = "后台-创作者管理") @RestController @RequestMapping("/admin/creators") @RequiredArgsConstructor @@ -35,12 +38,14 @@ public class CreatorAdminController { private final CreatorService creatorService; private final CreatorAccountService creatorAccountService; + @Operation(summary = "创作者分页查询") @GetMapping("/page") @PreAuthorize("@ss.hasPermission('creator:list')") public Result> page(CreatorQueryReqVO req) { return Result.ok(creatorService.page(req)); } + @Operation(summary = "创作者详情") @GetMapping("/{id}") @PreAuthorize("@ss.hasPermission('creator:list')") public Result detail(@PathVariable Long id) { @@ -48,12 +53,14 @@ public class CreatorAdminController { } /** 资质文件:审核前要看证件原件。 */ + @Operation(summary = "创作者资质文件") @GetMapping("/{id}/documents") @PreAuthorize("@ss.hasPermission('creator:list')") public Result> documents(@PathVariable Long id) { return Result.ok(creatorService.documents(id)); } + @Operation(summary = "创作者入驻审核") @PutMapping("/{id}/audit") @PreAuthorize("@ss.hasPermission('creator:audit')") @OperationLog(module = "创作者管理", action = "入驻审核") @@ -62,6 +69,7 @@ public class CreatorAdminController { } /** 手工录入创作者主体(C 端申请入驻还没实现,先用它打通链路)。 */ + @Operation(summary = "手工录入创作者主体") @PostMapping @PreAuthorize("@ss.hasPermission('creator:audit')") @OperationLog(module = "创作者管理", action = "新增创作者") @@ -70,6 +78,7 @@ public class CreatorAdminController { } /** 开通创作者账号:仅审核通过可开;已开通则幂等返回,不重复建号。 */ + @Operation(summary = "开通创作者账号(仅审核通过可开通,幂等)") @PostMapping("/{id}/account") @PreAuthorize("@ss.hasPermission('creator:account')") @OperationLog(module = "创作者管理", action = "开通创作者账号") @@ -79,6 +88,7 @@ public class CreatorAdminController { } /** 重置创作者账号密码:一次性明文返回,旧密码立即失效。 */ + @Operation(summary = "重置创作者账号密码(一次性明文返回)") @PostMapping("/{id}/account/reset-password") @PreAuthorize("@ss.hasPermission('creator:account')") @OperationLog(module = "创作者管理", action = "重置创作者密码") diff --git a/fruitshorts-admin-api/src/main/java/com/fruitshorts/admin/controller/CreatorCenterController.java b/fruitshorts-admin-api/src/main/java/com/fruitshorts/admin/controller/CreatorCenterController.java index 4c118e9..0bb6ce0 100644 --- a/fruitshorts-admin-api/src/main/java/com/fruitshorts/admin/controller/CreatorCenterController.java +++ b/fruitshorts-admin-api/src/main/java/com/fruitshorts/admin/controller/CreatorCenterController.java @@ -9,6 +9,8 @@ import com.fruitshorts.creator.vo.CreatorCenterNoticeVO; import com.fruitshorts.creator.vo.CreatorCenterProfileVO; import com.fruitshorts.creator.vo.CreatorCenterTargetVO; import com.fruitshorts.admin.service.CreatorDashboardService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; import lombok.RequiredArgsConstructor; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.web.bind.annotation.GetMapping; @@ -26,6 +28,7 @@ import java.util.Map; * 归属由 {@link CreatorCenterService#requireCurrentCreator()} 从登录态解析, * 查询强制带 `where creator_id = 当前创作者`;访问他人作品统一 403。 */ +@Tag(name = "创作者中心") @RestController @RequestMapping("/admin/creator-center") @RequiredArgsConstructor @@ -35,6 +38,7 @@ public class CreatorCenterController { private final CreatorDashboardService creatorDashboardService; /** 当前创作者的主体信息与入驻状态。 */ + @Operation(summary = "我的创作者资料与入驻状态") @GetMapping("/profile") @PreAuthorize("@ss.hasPermission('creator-center:view')") public Result profile() { @@ -42,6 +46,7 @@ public class CreatorCenterController { } /** 我的作品列表(含最近一次提交的审核进度)。 */ + @Operation(summary = "我的作品列表(含最近一次审核进度)") @GetMapping("/dramas/page") @PreAuthorize("@ss.hasPermission('creator-center:view')") public Result> pageMyDramas(CreatorCenterDramaQueryReqVO req) { @@ -49,6 +54,7 @@ public class CreatorCenterController { } /** 我的作品详情:id 是别人的作品时返回 403,不区分"不存在"。 */ + @Operation(summary = "我的作品详情") @GetMapping("/dramas/{id}") @PreAuthorize("@ss.hasPermission('creator-center:view')") public Result myDrama(@PathVariable Long id) { @@ -56,6 +62,7 @@ public class CreatorCenterController { } /** 我的通知:入驻审核结果 + 我提交内容的审核结果。 */ + @Operation(summary = "我的通知(入驻与内容审核结果)") @GetMapping("/notices") @PreAuthorize("@ss.hasPermission('creator-center:view')") public Result> notices() { @@ -63,6 +70,7 @@ public class CreatorCenterController { } /** 我的数据看板:播放 / 完播 / 收藏 / 评论 / 解锁收入概览(只读,只含自己的作品)。 */ + @Operation(summary = "我的数据看板(播放 / 完播 / 收藏 / 评论 / 解锁收入)") @GetMapping("/dashboard") @PreAuthorize("@ss.hasPermission('creator-center:stat:view')") public Result> dashboard() { @@ -73,6 +81,7 @@ public class CreatorCenterController { * 代看目标下拉的数据源:只有带 `creator-center:impersonate` 的账号(第一阶段 = 超管)能调。 * 前端拿它渲染顶部的「当前创作者」下拉;没权限的账号不显示下拉,也不会请求这个接口。 */ + @Operation(summary = "代看可选创作者列表") @GetMapping("/impersonation/targets") @PreAuthorize("@ss.hasPermission('creator-center:impersonate')") public Result> impersonationTargets() { diff --git a/fruitshorts-admin-api/src/main/java/com/fruitshorts/admin/controller/CreatorContentController.java b/fruitshorts-admin-api/src/main/java/com/fruitshorts/admin/controller/CreatorContentController.java index 4bb646a..cfa4e2f 100644 --- a/fruitshorts-admin-api/src/main/java/com/fruitshorts/admin/controller/CreatorContentController.java +++ b/fruitshorts-admin-api/src/main/java/com/fruitshorts/admin/controller/CreatorContentController.java @@ -12,6 +12,8 @@ import com.fruitshorts.creator.vo.CreatorDramaEditReqVO; import com.fruitshorts.creator.vo.CreatorEpisodeReqVO; import com.fruitshorts.creator.vo.CreatorSubmitReqVO; import com.fruitshorts.framework.log.OperationLog; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.validation.Valid; import lombok.RequiredArgsConstructor; import org.springframework.security.access.prepost.PreAuthorize; @@ -32,6 +34,7 @@ import java.util.List; * 与 {@link CreatorCenterController} 一样**不接收 creatorId**:归属由登录态解析, * 服务层强制 `where creator_id = 当前创作者`,改别人的剧或分集一律 403。 */ +@Tag(name = "创作者中心-内容与收费") @RestController @RequestMapping("/admin/creator-center") @RequiredArgsConstructor @@ -40,6 +43,7 @@ public class CreatorContentController { private final CreatorContentService creatorContentService; /** 新建草稿。 */ + @Operation(summary = "新建作品草稿") @PostMapping("/dramas") @PreAuthorize("@ss.hasPermission('creator-center:drama:edit')") @OperationLog(module = "创作者中心", action = "新建作品") @@ -48,6 +52,7 @@ public class CreatorContentController { } /** 编辑作品信息(仅草稿 / 已下线可改)。 */ + @Operation(summary = "编辑作品信息(仅草稿 / 已下线可改)") @PutMapping("/dramas/{id}") @PreAuthorize("@ss.hasPermission('creator-center:drama:edit')") @OperationLog(module = "创作者中心", action = "编辑作品") @@ -57,6 +62,7 @@ public class CreatorContentController { } /** 分集列表。 */ + @Operation(summary = "分集列表") @GetMapping("/dramas/{id}/episodes") @PreAuthorize("@ss.hasPermission('creator-center:view')") public Result> listEpisodes(@PathVariable Long id) { @@ -64,6 +70,7 @@ public class CreatorContentController { } /** 新增分集(集号不传自动排到最后)。 */ + @Operation(summary = "新增分集") @PostMapping("/dramas/{id}/episodes") @PreAuthorize("@ss.hasPermission('creator-center:drama:edit')") @OperationLog(module = "创作者中心", action = "新增分集") @@ -72,6 +79,7 @@ public class CreatorContentController { } /** 编辑分集(时长 / 封面 / 片源 / 排序)。 */ + @Operation(summary = "编辑分集(时长 / 封面 / 片源)") @PutMapping("/dramas/{id}/episodes/{episodeId}") @PreAuthorize("@ss.hasPermission('creator-center:drama:edit')") @OperationLog(module = "创作者中心", action = "编辑分集") @@ -82,6 +90,7 @@ public class CreatorContentController { } /** 删除分集。 */ + @Operation(summary = "删除分集") @DeleteMapping("/dramas/{id}/episodes/{episodeId}") @PreAuthorize("@ss.hasPermission('creator-center:drama:edit')") @OperationLog(module = "创作者中心", action = "删除分集") @@ -91,6 +100,7 @@ public class CreatorContentController { } /** 批量排序:body 里按新顺序给出分集 id。 */ + @Operation(summary = "分集批量排序") @PutMapping("/dramas/{id}/episodes/sort") @PreAuthorize("@ss.hasPermission('creator-center:drama:edit')") @OperationLog(module = "创作者中心", action = "调整分集顺序") @@ -100,6 +110,7 @@ public class CreatorContentController { } /** 提交审核:CREATE / UPDATE / PUBLISH / OFFLINE。 */ + @Operation(summary = "提交审核(CREATE / UPDATE / PUBLISH / OFFLINE)") @PostMapping("/dramas/{id}/submit") @PreAuthorize("@ss.hasPermission('creator-center:drama:edit')") @OperationLog(module = "创作者中心", action = "提交审核") @@ -108,6 +119,7 @@ public class CreatorContentController { } /** 撤回自己的提交(撤回后作品退回草稿,可继续编辑)。 */ + @Operation(summary = "撤回自己的提交") @PostMapping("/submissions/{id}/withdraw") @PreAuthorize("@ss.hasPermission('creator-center:drama:edit')") @OperationLog(module = "创作者中心", action = "撤回提交") @@ -116,6 +128,7 @@ public class CreatorContentController { } /** 我的提交历史(审核进度)。 */ + @Operation(summary = "我的提交历史") @GetMapping("/dramas/{id}/submissions") @PreAuthorize("@ss.hasPermission('creator-center:view')") public Result> listSubmissions(@PathVariable Long id) { @@ -123,6 +136,7 @@ public class CreatorContentController { } /** 把上传好的视频产物挂到自己的分集上(产物必须是本人上传的)。 */ + @Operation(summary = "把上传产物挂到自己的分集上") @PostMapping("/dramas/{id}/episodes/{episodeId}/attach") @PreAuthorize("@ss.hasPermission('creator-center:upload')") @OperationLog(module = "创作者中心", action = "挂载分集视频") @@ -133,6 +147,7 @@ public class CreatorContentController { } /** 分集收费与试看秒数:读现状。 */ + @Operation(summary = "分集收费与试看秒数(读)") @GetMapping("/dramas/{id}/prices") @PreAuthorize("@ss.hasPermission('creator-center:view')") public Result priceDetail(@PathVariable Long id) { @@ -140,6 +155,7 @@ public class CreatorContentController { } /** 分集收费与试看秒数:保存(复用后台同一套 PriceService,改完立即影响付费判定)。 */ + @Operation(summary = "分集收费与试看秒数(保存)") @PutMapping("/dramas/{id}/prices") @PreAuthorize("@ss.hasPermission('creator-center:price:update')") @OperationLog(module = "创作者中心", action = "配置分集价格") diff --git a/fruitshorts-admin-api/src/main/java/com/fruitshorts/admin/controller/DashboardAdminController.java b/fruitshorts-admin-api/src/main/java/com/fruitshorts/admin/controller/DashboardAdminController.java index 4f929a6..cb9a01b 100644 --- a/fruitshorts-admin-api/src/main/java/com/fruitshorts/admin/controller/DashboardAdminController.java +++ b/fruitshorts-admin-api/src/main/java/com/fruitshorts/admin/controller/DashboardAdminController.java @@ -2,6 +2,8 @@ package com.fruitshorts.admin.controller; import com.fruitshorts.admin.service.DashboardService; import com.fruitshorts.common.pojo.Result; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; import lombok.RequiredArgsConstructor; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.web.bind.annotation.GetMapping; @@ -16,6 +18,7 @@ import java.util.Map; * 指标口径写在 DashboardService 的类注释与 docs/api-phase1.md 里; * 取不到数据源的指标返回 null 并在 notes 里说明,不用 0 冒充。 */ +@Tag(name = "后台-数据看板") @RestController @RequestMapping("/admin/dashboard") @RequiredArgsConstructor @@ -24,6 +27,7 @@ public class DashboardAdminController { private final DashboardService dashboardService; /** 总览:用户 / 内容 / 播放 / 收入 / 成本。 */ + @Operation(summary = "运营大盘总览(用户 / 内容 / 播放 / 收入 / 成本)") @GetMapping("/overview") @PreAuthorize("@ss.hasPermission('dashboard:view')") public Result> overview() { @@ -31,6 +35,7 @@ public class DashboardAdminController { } /** 转码看板:队列积压与失败任务明细。 */ + @Operation(summary = "转码看板(队列积压与失败任务)") @GetMapping("/transcode") @PreAuthorize("@ss.hasPermission('dashboard:view')") public Result> transcode() { diff --git a/fruitshorts-admin-api/src/main/java/com/fruitshorts/admin/controller/DictController.java b/fruitshorts-admin-api/src/main/java/com/fruitshorts/admin/controller/DictController.java index 903bafd..c6209af 100644 --- a/fruitshorts-admin-api/src/main/java/com/fruitshorts/admin/controller/DictController.java +++ b/fruitshorts-admin-api/src/main/java/com/fruitshorts/admin/controller/DictController.java @@ -4,6 +4,8 @@ import com.fruitshorts.common.pojo.Result; import com.fruitshorts.content.enums.ContentStatus; import com.fruitshorts.content.service.DramaCategoryService; import com.fruitshorts.content.vo.DramaCategoryRespVO; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; import lombok.RequiredArgsConstructor; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.web.bind.annotation.GetMapping; @@ -17,6 +19,7 @@ import java.util.Map; /** * 字典接口:题材、内容状态等下拉数据。 */ +@Tag(name = "后台-字典") @RestController @RequestMapping("/admin/dicts") @RequiredArgsConstructor @@ -24,12 +27,14 @@ public class DictController { private final DramaCategoryService dramaCategoryService; + @Operation(summary = "短剧分类字典") @GetMapping("/drama-category") @PreAuthorize("@ss.hasPermission('drama:list')") public Result> dramaCategories() { return Result.ok(dramaCategoryService.list()); } + @Operation(summary = "内容状态字典") @GetMapping("/content-status") @PreAuthorize("@ss.hasPermission('drama:list')") public Result>> contentStatus() { diff --git a/fruitshorts-admin-api/src/main/java/com/fruitshorts/admin/controller/DownloadAdminController.java b/fruitshorts-admin-api/src/main/java/com/fruitshorts/admin/controller/DownloadAdminController.java index 682ca41..abe021e 100644 --- a/fruitshorts-admin-api/src/main/java/com/fruitshorts/admin/controller/DownloadAdminController.java +++ b/fruitshorts-admin-api/src/main/java/com/fruitshorts/admin/controller/DownloadAdminController.java @@ -6,6 +6,8 @@ import com.fruitshorts.framework.log.OperationLog; import com.fruitshorts.playback.service.DownloadService; import com.fruitshorts.playback.vo.DownloadLicenseRespVO; import com.fruitshorts.playback.vo.DownloadQueryReqVO; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; import lombok.RequiredArgsConstructor; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.web.bind.annotation.GetMapping; @@ -18,6 +20,7 @@ import org.springframework.web.bind.annotation.RestController; import java.util.Map; /** 后台下载授权管理。 */ +@Tag(name = "后台-离线下载管理") @RestController @RequestMapping("/admin/downloads") @RequiredArgsConstructor @@ -25,12 +28,14 @@ public class DownloadAdminController { private final DownloadService downloadService; + @Operation(summary = "下载授权分页查询") @GetMapping("/page") @PreAuthorize("@ss.hasPermission('download:list')") public Result> page(DownloadQueryReqVO req) { return Result.ok(downloadService.page(req)); } + @Operation(summary = "下载统计") @GetMapping("/stats") @PreAuthorize("@ss.hasPermission('download:list')") public Result> stats() { @@ -38,6 +43,7 @@ public class DownloadAdminController { } /** 吊销单条授权:用户侧下次联网即失效。 */ + @Operation(summary = "吊销单条下载授权") @PutMapping("/{id}/revoke") @PreAuthorize("@ss.hasPermission('download:revoke')") @OperationLog(module = "下载管理", action = "吊销下载授权") @@ -47,6 +53,7 @@ public class DownloadAdminController { } /** 手动触发过期清理,正常情况下由定时任务每天执行。 */ + @Operation(summary = "手动触发过期授权清理") @PostMapping("/cleanup") @PreAuthorize("@ss.hasPermission('download:revoke')") @OperationLog(module = "下载管理", action = "清理过期下载授权") diff --git a/fruitshorts-admin-api/src/main/java/com/fruitshorts/admin/controller/DramaCategoryController.java b/fruitshorts-admin-api/src/main/java/com/fruitshorts/admin/controller/DramaCategoryController.java index b77964e..4401c71 100644 --- a/fruitshorts-admin-api/src/main/java/com/fruitshorts/admin/controller/DramaCategoryController.java +++ b/fruitshorts-admin-api/src/main/java/com/fruitshorts/admin/controller/DramaCategoryController.java @@ -6,6 +6,8 @@ import com.fruitshorts.content.vo.DramaCategoryRespVO; import com.fruitshorts.content.vo.DramaCategorySaveReqVO; import com.fruitshorts.framework.security.SecurityUtils; import com.fruitshorts.framework.log.OperationLog; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.validation.Valid; import lombok.RequiredArgsConstructor; import org.springframework.security.access.prepost.PreAuthorize; @@ -23,6 +25,7 @@ import java.util.List; /** * 短剧类型管理。类型属于短剧域,权限沿用 drama:*,不再单开权限点。 */ +@Tag(name = "后台-短剧分类") @RestController @RequestMapping("/admin/drama-categories") @RequiredArgsConstructor @@ -30,12 +33,14 @@ public class DramaCategoryController { private final DramaCategoryService dramaCategoryService; + @Operation(summary = "分类列表") @GetMapping @PreAuthorize("@ss.hasPermission('drama:list')") public Result> list() { return Result.ok(dramaCategoryService.list()); } + @Operation(summary = "新建分类") @PostMapping @PreAuthorize("@ss.hasPermission('drama:create')") @OperationLog(module = "内容管理", action = "新增短剧类型") @@ -43,6 +48,7 @@ public class DramaCategoryController { return Result.ok(dramaCategoryService.create(req)); } + @Operation(summary = "编辑分类") @PutMapping("/{id}") @PreAuthorize("@ss.hasPermission('drama:update')") @OperationLog(module = "内容管理", action = "编辑短剧类型") @@ -51,6 +57,7 @@ public class DramaCategoryController { return Result.ok(); } + @Operation(summary = "删除分类") @DeleteMapping("/{id}") @PreAuthorize("@ss.hasPermission('drama:delete')") @OperationLog(module = "内容管理", action = "删除短剧类型") diff --git a/fruitshorts-admin-api/src/main/java/com/fruitshorts/admin/controller/DramaController.java b/fruitshorts-admin-api/src/main/java/com/fruitshorts/admin/controller/DramaController.java index d469383..103e7c5 100644 --- a/fruitshorts-admin-api/src/main/java/com/fruitshorts/admin/controller/DramaController.java +++ b/fruitshorts-admin-api/src/main/java/com/fruitshorts/admin/controller/DramaController.java @@ -10,6 +10,8 @@ import com.fruitshorts.content.vo.DramaSaveReqVO; import com.fruitshorts.content.vo.DramaStatusReqVO; import com.fruitshorts.framework.security.SecurityUtils; import com.fruitshorts.framework.log.OperationLog; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.validation.Valid; import lombok.RequiredArgsConstructor; import org.springframework.security.access.prepost.PreAuthorize; @@ -24,6 +26,7 @@ import org.springframework.web.bind.annotation.RestController; import java.util.List; +@Tag(name = "后台-短剧管理") @RestController @RequestMapping("/admin/dramas") @RequiredArgsConstructor @@ -31,18 +34,21 @@ public class DramaController { private final DramaService dramaService; + @Operation(summary = "短剧分页查询") @GetMapping("/page") @PreAuthorize("@ss.hasPermission('drama:list')") public Result> page(DramaPageReqVO req) { return Result.ok(dramaService.page(req)); } + @Operation(summary = "短剧详情") @GetMapping("/{id}") @PreAuthorize("@ss.hasPermission('drama:list')") public Result get(@PathVariable Long id) { return Result.ok(dramaService.get(id)); } + @Operation(summary = "新建短剧") @PostMapping @PreAuthorize("@ss.hasPermission('drama:create')") @OperationLog(module = "内容管理", action = "新建短剧") @@ -50,6 +56,7 @@ public class DramaController { return Result.ok(dramaService.create(req, SecurityUtils.getUserId())); } + @Operation(summary = "编辑短剧") @PutMapping("/{id}") @PreAuthorize("@ss.hasPermission('drama:update')") @OperationLog(module = "内容管理", action = "编辑短剧") @@ -58,6 +65,7 @@ public class DramaController { return Result.ok(); } + @Operation(summary = "删除短剧") @DeleteMapping("/{id}") @PreAuthorize("@ss.hasPermission('drama:delete')") @OperationLog(module = "内容管理", action = "删除短剧") @@ -67,6 +75,7 @@ public class DramaController { } /** 提交审核:内容运营即可操作。 */ + @Operation(summary = "提交审核") @PostMapping("/{id}/submit") @PreAuthorize("@ss.hasAnyPermission('drama:review','drama:update')") @OperationLog(module = "内容管理", action = "提交审核") @@ -75,6 +84,7 @@ public class DramaController { return Result.ok(); } + @Operation(summary = "审核通过") @PostMapping("/{id}/approve") @PreAuthorize("@ss.hasPermission('drama:review')") @OperationLog(module = "内容管理", action = "审核通过") @@ -83,6 +93,7 @@ public class DramaController { return Result.ok(); } + @Operation(summary = "审核驳回") @PostMapping("/{id}/reject") @PreAuthorize("@ss.hasPermission('drama:review')") @OperationLog(module = "内容管理", action = "驳回短剧") @@ -91,6 +102,7 @@ public class DramaController { return Result.ok(); } + @Operation(summary = "上线") @PostMapping("/{id}/publish") @PreAuthorize("@ss.hasPermission('drama:review')") @OperationLog(module = "内容管理", action = "短剧上线") @@ -99,6 +111,7 @@ public class DramaController { return Result.ok(); } + @Operation(summary = "下线") @PostMapping("/{id}/offline") @PreAuthorize("@ss.hasPermission('drama:review')") @OperationLog(module = "内容管理", action = "短剧下线") @@ -107,6 +120,7 @@ public class DramaController { return Result.ok(); } + @Operation(summary = "审核记录") @GetMapping("/{id}/review-records") @PreAuthorize("@ss.hasPermission('drama:list')") public Result> reviewRecords(@PathVariable Long id) { diff --git a/fruitshorts-admin-api/src/main/java/com/fruitshorts/admin/controller/EntitlementAdminController.java b/fruitshorts-admin-api/src/main/java/com/fruitshorts/admin/controller/EntitlementAdminController.java index 5130079..12f200a 100644 --- a/fruitshorts-admin-api/src/main/java/com/fruitshorts/admin/controller/EntitlementAdminController.java +++ b/fruitshorts-admin-api/src/main/java/com/fruitshorts/admin/controller/EntitlementAdminController.java @@ -6,6 +6,8 @@ import com.fruitshorts.commerce.vo.EntitlementGrantReqVO; import com.fruitshorts.common.pojo.PageResult; import com.fruitshorts.common.pojo.Result; import com.fruitshorts.framework.log.OperationLog; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.validation.Valid; import lombok.RequiredArgsConstructor; import org.springframework.security.access.prepost.PreAuthorize; @@ -19,6 +21,7 @@ import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; /** 后台权益:检索、人工补发、回收。 */ +@Tag(name = "后台-权益管理") @RestController @RequestMapping("/admin/entitlements") @RequiredArgsConstructor @@ -26,6 +29,7 @@ public class EntitlementAdminController { private final EntitlementService entitlementService; + @Operation(summary = "权益分页查询") @GetMapping("/page") @PreAuthorize("@ss.hasPermission('entitlement:list')") public Result> page(@RequestParam(required = false) Long userId, @@ -37,6 +41,7 @@ public class EntitlementAdminController { } /** 客服补偿:直接给用户某集/整剧的播放权益。 */ + @Operation(summary = "补发权益(客服补偿)") @PostMapping @PreAuthorize("@ss.hasPermission('entitlement:update')") @OperationLog(module = "订单管理", action = "人工补发权益") @@ -48,6 +53,7 @@ public class EntitlementAdminController { } /** 回收权益:退款、违规处置后用。 */ + @Operation(summary = "回收权益(退款 / 违规处置)") @PutMapping("/{id}/revoke") @PreAuthorize("@ss.hasPermission('entitlement:update')") @OperationLog(module = "订单管理", action = "回收权益") diff --git a/fruitshorts-admin-api/src/main/java/com/fruitshorts/admin/controller/EpisodeController.java b/fruitshorts-admin-api/src/main/java/com/fruitshorts/admin/controller/EpisodeController.java index 21d3ff6..0d2094e 100644 --- a/fruitshorts-admin-api/src/main/java/com/fruitshorts/admin/controller/EpisodeController.java +++ b/fruitshorts-admin-api/src/main/java/com/fruitshorts/admin/controller/EpisodeController.java @@ -6,6 +6,8 @@ import com.fruitshorts.content.vo.EpisodeRespVO; import com.fruitshorts.content.vo.EpisodeSaveReqVO; import com.fruitshorts.content.vo.EpisodeSortReqVO; import com.fruitshorts.framework.log.OperationLog; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.validation.Valid; import lombok.RequiredArgsConstructor; import org.springframework.security.access.prepost.PreAuthorize; @@ -21,6 +23,7 @@ import org.springframework.web.bind.annotation.RestController; import java.util.List; +@Tag(name = "后台-剧集管理") @RestController @RequestMapping("/admin/episodes") @RequiredArgsConstructor @@ -28,6 +31,7 @@ public class EpisodeController { private final EpisodeService episodeService; + @Operation(summary = "剧集列表") @GetMapping @PreAuthorize("@ss.hasPermission('episode:list')") public Result> list(@RequestParam Long dramaId, @@ -35,6 +39,7 @@ public class EpisodeController { return Result.ok(episodeService.listByDrama(dramaId, status)); } + @Operation(summary = "新建剧集") @PostMapping @PreAuthorize("@ss.hasPermission('episode:upload')") @OperationLog(module = "内容管理", action = "新增剧集") @@ -42,6 +47,7 @@ public class EpisodeController { return Result.ok(episodeService.create(req)); } + @Operation(summary = "编辑剧集") @PutMapping("/{id}") @PreAuthorize("@ss.hasPermission('episode:upload')") @OperationLog(module = "内容管理", action = "编辑剧集") @@ -50,6 +56,7 @@ public class EpisodeController { return Result.ok(); } + @Operation(summary = "删除剧集") @DeleteMapping("/{id}") @PreAuthorize("@ss.hasPermission('episode:upload')") @OperationLog(module = "内容管理", action = "删除剧集") @@ -58,6 +65,7 @@ public class EpisodeController { return Result.ok(); } + @Operation(summary = "剧集排序") @PutMapping("/sort") @PreAuthorize("@ss.hasPermission('episode:sort')") @OperationLog(module = "内容管理", action = "调整剧集顺序") diff --git a/fruitshorts-admin-api/src/main/java/com/fruitshorts/admin/controller/MediaController.java b/fruitshorts-admin-api/src/main/java/com/fruitshorts/admin/controller/MediaController.java index 99b36a2..9d146d3 100644 --- a/fruitshorts-admin-api/src/main/java/com/fruitshorts/admin/controller/MediaController.java +++ b/fruitshorts-admin-api/src/main/java/com/fruitshorts/admin/controller/MediaController.java @@ -9,6 +9,8 @@ import com.fruitshorts.media.vo.UploadCompleteReqVO; import com.fruitshorts.media.vo.UploadInitReqVO; import com.fruitshorts.media.vo.UploadInitRespVO; import com.fruitshorts.media.vo.UploadProgressRespVO; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.validation.Valid; import lombok.RequiredArgsConstructor; import org.springframework.security.access.prepost.PreAuthorize; @@ -24,6 +26,7 @@ import org.springframework.web.multipart.MultipartFile; /** * 媒资上传(本地存储版):init 建会话 → chunk 传分片 → complete 合并出地址。 */ +@Tag(name = "后台-媒资管理") @RestController @RequestMapping("/admin/media") @RequiredArgsConstructor @@ -31,6 +34,7 @@ public class MediaController { private final MediaService mediaService; + @Operation(summary = "初始化分片上传") @PostMapping("/upload/init") @PreAuthorize("@ss.hasAnyPermission('cover:upload','episode:upload')") public Result init(@Valid @RequestBody UploadInitReqVO req) { @@ -39,6 +43,7 @@ public class MediaController { return Result.ok(mediaService.init(req, SecurityUtils.getUserId())); } + @Operation(summary = "上传分片") @PostMapping("/upload/chunk") @PreAuthorize("@ss.hasAnyPermission('cover:upload','episode:upload')") public Result uploadChunk(@RequestParam String uploadId, @@ -49,6 +54,7 @@ public class MediaController { return Result.ok(index); } + @Operation(summary = "完成上传") @PostMapping("/upload/complete") @PreAuthorize("@ss.hasAnyPermission('cover:upload','episode:upload')") public Result complete(@Valid @RequestBody UploadCompleteReqVO req) { @@ -57,12 +63,14 @@ public class MediaController { } /** 断点续传:查上传会话进度(只能查自己发起的会话)。 */ + @Operation(summary = "查询上传进度(断点续传)") @GetMapping("/upload/{uploadId}") @PreAuthorize("@ss.hasAnyPermission('cover:upload','episode:upload')") public Result progress(@PathVariable String uploadId) { return Result.ok(mediaService.progress(uploadId, SecurityUtils.getUserId())); } + @Operation(summary = "媒资详情") @GetMapping("/{id}") @PreAuthorize("@ss.hasAnyPermission('cover:upload','episode:upload')") public Result get(@PathVariable Long id) { diff --git a/fruitshorts-admin-api/src/main/java/com/fruitshorts/admin/controller/MenuController.java b/fruitshorts-admin-api/src/main/java/com/fruitshorts/admin/controller/MenuController.java index 1c4ea03..a578db7 100644 --- a/fruitshorts-admin-api/src/main/java/com/fruitshorts/admin/controller/MenuController.java +++ b/fruitshorts-admin-api/src/main/java/com/fruitshorts/admin/controller/MenuController.java @@ -5,6 +5,8 @@ import com.fruitshorts.system.service.MenuService; import com.fruitshorts.framework.log.OperationLog; import com.fruitshorts.system.vo.MenuSaveReqVO; import com.fruitshorts.system.vo.MenuVO; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.validation.Valid; import lombok.RequiredArgsConstructor; import org.springframework.security.access.prepost.PreAuthorize; @@ -19,6 +21,7 @@ import org.springframework.web.bind.annotation.RestController; import java.util.List; +@Tag(name = "后台-菜单管理") @RestController @RequestMapping("/admin/menus") @RequiredArgsConstructor @@ -26,12 +29,14 @@ public class MenuController { private final MenuService menuService; + @Operation(summary = "菜单树") @GetMapping("/tree") @PreAuthorize("@ss.hasPermission('system:menu')") public Result> tree() { return Result.ok(menuService.listAll()); } + @Operation(summary = "新建菜单") @PostMapping @PreAuthorize("@ss.hasPermission('system:menu')") @OperationLog(module = "后台管理", action = "新增菜单") @@ -39,6 +44,7 @@ public class MenuController { return Result.ok(menuService.create(req)); } + @Operation(summary = "编辑菜单") @PutMapping("/{id}") @PreAuthorize("@ss.hasPermission('system:menu')") @OperationLog(module = "后台管理", action = "编辑菜单") @@ -47,6 +53,7 @@ public class MenuController { return Result.ok(); } + @Operation(summary = "删除菜单") @DeleteMapping("/{id}") @PreAuthorize("@ss.hasPermission('system:menu')") @OperationLog(module = "后台管理", action = "删除菜单") diff --git a/fruitshorts-admin-api/src/main/java/com/fruitshorts/admin/controller/OperationLogController.java b/fruitshorts-admin-api/src/main/java/com/fruitshorts/admin/controller/OperationLogController.java index f2094b2..bd484f8 100644 --- a/fruitshorts-admin-api/src/main/java/com/fruitshorts/admin/controller/OperationLogController.java +++ b/fruitshorts-admin-api/src/main/java/com/fruitshorts/admin/controller/OperationLogController.java @@ -5,6 +5,8 @@ import com.fruitshorts.common.pojo.Result; import com.fruitshorts.system.service.OperationLogService; import com.fruitshorts.system.vo.OperationLogPageReqVO; import com.fruitshorts.system.vo.OperationLogRespVO; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; import lombok.RequiredArgsConstructor; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.web.bind.annotation.GetMapping; @@ -12,6 +14,7 @@ import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; +@Tag(name = "后台-操作日志") @RestController @RequestMapping("/admin/operation-logs") @RequiredArgsConstructor @@ -19,12 +22,14 @@ public class OperationLogController { private final OperationLogService operationLogService; + @Operation(summary = "操作日志分页查询") @GetMapping("/page") @PreAuthorize("@ss.hasPermission('log:list')") public Result> page(OperationLogPageReqVO req) { return Result.ok(operationLogService.page(req)); } + @Operation(summary = "操作日志详情") @GetMapping("/{id}") @PreAuthorize("@ss.hasPermission('log:list')") public Result get(@PathVariable Long id) { diff --git a/fruitshorts-admin-api/src/main/java/com/fruitshorts/admin/controller/OrderAdminController.java b/fruitshorts-admin-api/src/main/java/com/fruitshorts/admin/controller/OrderAdminController.java index 703a698..cb95f23 100644 --- a/fruitshorts-admin-api/src/main/java/com/fruitshorts/admin/controller/OrderAdminController.java +++ b/fruitshorts-admin-api/src/main/java/com/fruitshorts/admin/controller/OrderAdminController.java @@ -8,6 +8,8 @@ import com.fruitshorts.common.pojo.PageResult; import com.fruitshorts.common.pojo.Result; import com.fruitshorts.framework.log.OperationLog; import com.fruitshorts.framework.security.SecurityUtils; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; import lombok.RequiredArgsConstructor; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.web.bind.annotation.GetMapping; @@ -22,6 +24,7 @@ import java.util.List; import java.util.Map; /** 后台订单:检索、补发、退款回收。 */ +@Tag(name = "后台-订单管理") @RestController @RequestMapping("/admin/orders") @RequiredArgsConstructor @@ -29,12 +32,14 @@ public class OrderAdminController { private final OrderService orderService; + @Operation(summary = "订单分页查询") @GetMapping("/page") @PreAuthorize("@ss.hasPermission('order:list')") public Result> page(OrderQueryReqVO req) { return Result.ok(orderService.page(req)); } + @Operation(summary = "订单详情") @GetMapping("/{orderNo}") @PreAuthorize("@ss.hasPermission('order:list')") public Result detail(@PathVariable String orderNo) { @@ -42,6 +47,7 @@ public class OrderAdminController { } /** 订单状态流转流水:支付争议时的证据链。 */ + @Operation(summary = "订单状态流转流水") @GetMapping("/{orderNo}/events") @PreAuthorize("@ss.hasPermission('order:list')") public Result> events(@PathVariable String orderNo) { @@ -49,6 +55,7 @@ public class OrderAdminController { } /** 补发:已支付未交付的订单重新交付;已交付时幂等返回。 */ + @Operation(summary = "补发订单(已支付未交付重新交付,幂等)") @PostMapping("/{orderNo}/compensate") @PreAuthorize("@ss.hasPermission('order:update')") @OperationLog(module = "订单管理", action = "补发订单") @@ -57,6 +64,7 @@ public class OrderAdminController { } /** 退款/撤销:回收权益并扣回金币。 */ + @Operation(summary = "退款 / 撤销(回收权益并扣回金币)") @PostMapping("/{orderNo}/refund") @PreAuthorize("@ss.hasPermission('order:update')") @OperationLog(module = "订单管理", action = "订单退款") diff --git a/fruitshorts-admin-api/src/main/java/com/fruitshorts/admin/controller/PermissionController.java b/fruitshorts-admin-api/src/main/java/com/fruitshorts/admin/controller/PermissionController.java index ab15a18..f3608b0 100644 --- a/fruitshorts-admin-api/src/main/java/com/fruitshorts/admin/controller/PermissionController.java +++ b/fruitshorts-admin-api/src/main/java/com/fruitshorts/admin/controller/PermissionController.java @@ -3,6 +3,8 @@ package com.fruitshorts.admin.controller; import com.fruitshorts.common.pojo.Result; import com.fruitshorts.system.service.PermissionService; import com.fruitshorts.system.vo.PermissionGroupVO; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; import lombok.RequiredArgsConstructor; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.web.bind.annotation.GetMapping; @@ -11,6 +13,7 @@ import org.springframework.web.bind.annotation.RestController; import java.util.List; +@Tag(name = "后台-权限点") @RestController @RequestMapping("/admin/permissions") @RequiredArgsConstructor @@ -19,6 +22,7 @@ public class PermissionController { private final PermissionService permissionService; /** 按分组返回权限点,直接喂给前端的角色权限配置页。 */ + @Operation(summary = "权限点列表(按分组返回)") @GetMapping @PreAuthorize("@ss.hasPermission('system:role')") public Result> groups() { diff --git a/fruitshorts-admin-api/src/main/java/com/fruitshorts/admin/controller/PriceAdminController.java b/fruitshorts-admin-api/src/main/java/com/fruitshorts/admin/controller/PriceAdminController.java index cae7213..df7baa1 100644 --- a/fruitshorts-admin-api/src/main/java/com/fruitshorts/admin/controller/PriceAdminController.java +++ b/fruitshorts-admin-api/src/main/java/com/fruitshorts/admin/controller/PriceAdminController.java @@ -5,6 +5,8 @@ import com.fruitshorts.content.service.PriceService; import com.fruitshorts.content.vo.PriceRespVO; import com.fruitshorts.content.vo.PriceSaveReqVO; import com.fruitshorts.framework.log.OperationLog; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; import lombok.RequiredArgsConstructor; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.web.bind.annotation.PutMapping; @@ -15,6 +17,7 @@ import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; /** 后台分集价格与免费集配置。 */ +@Tag(name = "后台-分集收费") @RestController @RequestMapping("/admin/prices") @RequiredArgsConstructor @@ -23,12 +26,14 @@ public class PriceAdminController { private final PriceService priceService; /** 当前价格配置:整剧默认 + 分集明细。 */ + @Operation(summary = "分集价格配置(整剧默认 + 分集明细)") @GetMapping @PreAuthorize("@ss.hasPermission('price:update')") public Result detail(@RequestParam Long dramaId) { return Result.ok(priceService.detail(dramaId)); } + @Operation(summary = "保存分集价格配置") @PutMapping @PreAuthorize("@ss.hasPermission('price:update')") @OperationLog(module = "定价管理", action = "配置分集价格") diff --git a/fruitshorts-admin-api/src/main/java/com/fruitshorts/admin/controller/ReconcileAdminController.java b/fruitshorts-admin-api/src/main/java/com/fruitshorts/admin/controller/ReconcileAdminController.java index 19b0404..7916e80 100644 --- a/fruitshorts-admin-api/src/main/java/com/fruitshorts/admin/controller/ReconcileAdminController.java +++ b/fruitshorts-admin-api/src/main/java/com/fruitshorts/admin/controller/ReconcileAdminController.java @@ -5,6 +5,8 @@ import com.fruitshorts.commerce.service.ReconcileService; import com.fruitshorts.common.pojo.PageResult; import com.fruitshorts.common.pojo.Result; import com.fruitshorts.framework.log.OperationLog; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; import lombok.RequiredArgsConstructor; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.web.bind.annotation.GetMapping; @@ -16,6 +18,7 @@ import org.springframework.web.bind.annotation.RestController; import java.time.LocalDate; /** 后台对账:手动触发与历史查看。 */ +@Tag(name = "后台-对账") @RestController @RequestMapping("/admin/reconcile") @RequiredArgsConstructor @@ -23,6 +26,7 @@ public class ReconcileAdminController { private final ReconcileService reconcileService; + @Operation(summary = "对账任务列表") @GetMapping("/page") @PreAuthorize("@ss.hasPermission('order:list')") public Result> page(@RequestParam(defaultValue = "1") Integer pageIndex, @@ -31,6 +35,7 @@ public class ReconcileAdminController { } /** 手动对账:默认前一天,可指定日期与渠道。 */ + @Operation(summary = "手动触发对账") @PostMapping("/run") @PreAuthorize("@ss.hasPermission('reconcile:run')") @OperationLog(module = "订单管理", action = "手动对账") diff --git a/fruitshorts-admin-api/src/main/java/com/fruitshorts/admin/controller/ReportAdminController.java b/fruitshorts-admin-api/src/main/java/com/fruitshorts/admin/controller/ReportAdminController.java index 9c2d3ae..80b0b7e 100644 --- a/fruitshorts-admin-api/src/main/java/com/fruitshorts/admin/controller/ReportAdminController.java +++ b/fruitshorts-admin-api/src/main/java/com/fruitshorts/admin/controller/ReportAdminController.java @@ -8,6 +8,8 @@ import com.fruitshorts.interaction.dal.entity.ContentReport; import com.fruitshorts.interaction.service.ReportService; import com.fruitshorts.interaction.vo.ReportHandleReqVO; import com.fruitshorts.interaction.vo.ReportQueryReqVO; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; import lombok.RequiredArgsConstructor; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.web.bind.annotation.GetMapping; @@ -18,6 +20,7 @@ import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; /** 后台举报工单。 */ +@Tag(name = "后台-举报工单") @RestController @RequestMapping("/admin/reports") @RequiredArgsConstructor @@ -25,6 +28,7 @@ public class ReportAdminController { private final ReportService reportService; + @Operation(summary = "举报工单分页查询") @GetMapping("/page") @PreAuthorize("@ss.hasPermission('report:list')") public Result> page(ReportQueryReqVO req) { @@ -32,6 +36,7 @@ public class ReportAdminController { } /** 处理工单:结论成立会联动驳回被举报评论,可选择同时封禁被举报用户。 */ + @Operation(summary = "处理举报工单(可联动驳回评论与封禁用户)") @PutMapping("/{id}/handle") @PreAuthorize("@ss.hasPermission('report:handle')") @OperationLog(module = "内容治理", action = "处理举报") diff --git a/fruitshorts-admin-api/src/main/java/com/fruitshorts/admin/controller/RoleCategoryController.java b/fruitshorts-admin-api/src/main/java/com/fruitshorts/admin/controller/RoleCategoryController.java index cfd6b68..4391d8d 100644 --- a/fruitshorts-admin-api/src/main/java/com/fruitshorts/admin/controller/RoleCategoryController.java +++ b/fruitshorts-admin-api/src/main/java/com/fruitshorts/admin/controller/RoleCategoryController.java @@ -5,6 +5,8 @@ import com.fruitshorts.system.service.RoleCategoryService; import com.fruitshorts.framework.log.OperationLog; import com.fruitshorts.system.vo.RoleCategoryRespVO; import com.fruitshorts.system.vo.RoleCategorySaveReqVO; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.validation.Valid; import lombok.RequiredArgsConstructor; import org.springframework.security.access.prepost.PreAuthorize; @@ -19,6 +21,7 @@ import org.springframework.web.bind.annotation.RestController; import java.util.List; +@Tag(name = "后台-角色分类") @RestController @RequestMapping("/admin/role-categories") @RequiredArgsConstructor @@ -26,12 +29,14 @@ public class RoleCategoryController { private final RoleCategoryService roleCategoryService; + @Operation(summary = "角色分类列表") @GetMapping @PreAuthorize("@ss.hasPermission('system:role-category')") public Result> list() { return Result.ok(roleCategoryService.list()); } + @Operation(summary = "新建角色分类") @PostMapping @PreAuthorize("@ss.hasPermission('system:role-category')") @OperationLog(module = "后台管理", action = "新增角色分类") @@ -39,6 +44,7 @@ public class RoleCategoryController { return Result.ok(roleCategoryService.create(req)); } + @Operation(summary = "编辑角色分类") @PutMapping("/{id}") @PreAuthorize("@ss.hasPermission('system:role-category')") @OperationLog(module = "后台管理", action = "编辑角色分类") @@ -47,6 +53,7 @@ public class RoleCategoryController { return Result.ok(); } + @Operation(summary = "删除角色分类") @DeleteMapping("/{id}") @PreAuthorize("@ss.hasPermission('system:role-category')") @OperationLog(module = "后台管理", action = "删除角色分类") diff --git a/fruitshorts-admin-api/src/main/java/com/fruitshorts/admin/controller/RoleController.java b/fruitshorts-admin-api/src/main/java/com/fruitshorts/admin/controller/RoleController.java index 118cf5d..3179cf8 100644 --- a/fruitshorts-admin-api/src/main/java/com/fruitshorts/admin/controller/RoleController.java +++ b/fruitshorts-admin-api/src/main/java/com/fruitshorts/admin/controller/RoleController.java @@ -7,6 +7,8 @@ import com.fruitshorts.framework.log.OperationLog; import com.fruitshorts.system.vo.RolePermissionSaveReqVO; import com.fruitshorts.system.vo.RoleRespVO; import com.fruitshorts.system.vo.RoleSaveReqVO; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.validation.Valid; import lombok.RequiredArgsConstructor; import org.springframework.security.access.prepost.PreAuthorize; @@ -22,6 +24,7 @@ import org.springframework.web.bind.annotation.RestController; import java.util.List; +@Tag(name = "后台-角色管理") @RestController @RequestMapping("/admin/roles") @RequiredArgsConstructor @@ -29,6 +32,7 @@ public class RoleController { private final RoleService roleService; + @Operation(summary = "角色分页查询") @GetMapping("/page") @PreAuthorize("@ss.hasPermission('system:role')") public Result> page(@RequestParam(required = false) String keyword, @@ -37,17 +41,20 @@ public class RoleController { return Result.ok(roleService.page(keyword, pageIndex, pageSize)); } + @Operation(summary = "角色下拉列表") @GetMapping("/list") public Result> list() { return Result.ok(roleService.listAll()); } + @Operation(summary = "角色详情") @GetMapping("/{id}") @PreAuthorize("@ss.hasPermission('system:role')") public Result get(@PathVariable Long id) { return Result.ok(roleService.get(id)); } + @Operation(summary = "新建角色") @PostMapping @PreAuthorize("@ss.hasPermission('system:role')") @OperationLog(module = "后台管理", action = "新增角色") @@ -55,6 +62,7 @@ public class RoleController { return Result.ok(roleService.create(req)); } + @Operation(summary = "编辑角色") @PutMapping("/{id}") @PreAuthorize("@ss.hasPermission('system:role')") @OperationLog(module = "后台管理", action = "编辑角色") @@ -63,6 +71,7 @@ public class RoleController { return Result.ok(); } + @Operation(summary = "删除角色") @DeleteMapping("/{id}") @PreAuthorize("@ss.hasPermission('system:role')") @OperationLog(module = "后台管理", action = "删除角色") @@ -71,12 +80,14 @@ public class RoleController { return Result.ok(); } + @Operation(summary = "角色已授权限") @GetMapping("/{id}/permissions") @PreAuthorize("@ss.hasPermission('system:role')") public Result> permissions(@PathVariable Long id) { return Result.ok(roleService.listCodesByRoleId(id)); } + @Operation(summary = "保存角色权限") @PutMapping("/{id}/permissions") @PreAuthorize("@ss.hasPermission('system:role')") @OperationLog(module = "后台管理", action = "修改角色权限") diff --git a/fruitshorts-admin-api/src/main/java/com/fruitshorts/admin/controller/SensitiveWordAdminController.java b/fruitshorts-admin-api/src/main/java/com/fruitshorts/admin/controller/SensitiveWordAdminController.java index 009857e..89d89be 100644 --- a/fruitshorts-admin-api/src/main/java/com/fruitshorts/admin/controller/SensitiveWordAdminController.java +++ b/fruitshorts-admin-api/src/main/java/com/fruitshorts/admin/controller/SensitiveWordAdminController.java @@ -6,6 +6,8 @@ import com.fruitshorts.framework.log.OperationLog; import com.fruitshorts.interaction.dal.entity.SensitiveWord; import com.fruitshorts.interaction.service.SensitiveWordService; import com.fruitshorts.interaction.vo.SensitiveWordReqVO; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.validation.Valid; import lombok.RequiredArgsConstructor; import org.springframework.security.access.prepost.PreAuthorize; @@ -20,6 +22,7 @@ import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; /** 后台敏感词库。改动即时生效(服务端词库缓存会失效重建)。 */ +@Tag(name = "后台-敏感词库") @RestController @RequestMapping("/admin/sensitive-words") @RequiredArgsConstructor @@ -27,6 +30,7 @@ public class SensitiveWordAdminController { private final SensitiveWordService sensitiveWordService; + @Operation(summary = "敏感词分页查询") @GetMapping("/page") @PreAuthorize("@ss.hasPermission('sensitive-word:list')") public Result> page(@RequestParam(required = false) String keyword, @@ -37,6 +41,7 @@ public class SensitiveWordAdminController { return Result.ok(sensitiveWordService.page(keyword, category, level, pageIndex, pageSize)); } + @Operation(summary = "新增敏感词") @PostMapping @PreAuthorize("@ss.hasPermission('sensitive-word:update')") @OperationLog(module = "内容治理", action = "新增敏感词") @@ -44,6 +49,7 @@ public class SensitiveWordAdminController { return Result.ok(sensitiveWordService.create(req)); } + @Operation(summary = "编辑敏感词") @PutMapping("/{id}") @PreAuthorize("@ss.hasPermission('sensitive-word:update')") @OperationLog(module = "内容治理", action = "修改敏感词") @@ -52,6 +58,7 @@ public class SensitiveWordAdminController { return Result.ok(); } + @Operation(summary = "删除敏感词") @DeleteMapping("/{id}") @PreAuthorize("@ss.hasPermission('sensitive-word:update')") @OperationLog(module = "内容治理", action = "删除敏感词") diff --git a/fruitshorts-admin-api/src/main/java/com/fruitshorts/admin/controller/SubmissionAdminController.java b/fruitshorts-admin-api/src/main/java/com/fruitshorts/admin/controller/SubmissionAdminController.java index 10a9922..152f9a5 100644 --- a/fruitshorts-admin-api/src/main/java/com/fruitshorts/admin/controller/SubmissionAdminController.java +++ b/fruitshorts-admin-api/src/main/java/com/fruitshorts/admin/controller/SubmissionAdminController.java @@ -8,6 +8,8 @@ import com.fruitshorts.creator.vo.SubmissionAuditReqVO; import com.fruitshorts.creator.vo.SubmissionQueryReqVO; import com.fruitshorts.framework.log.OperationLog; import com.fruitshorts.framework.security.SecurityUtils; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; import lombok.RequiredArgsConstructor; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.web.bind.annotation.GetMapping; @@ -18,6 +20,7 @@ import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; /** 后台内容提交审核:检索、详情、审核(通过 / 驳回 / 撤回)。 */ +@Tag(name = "后台-内容提交审核") @RestController @RequestMapping("/admin/submissions") @RequiredArgsConstructor @@ -25,18 +28,21 @@ public class SubmissionAdminController { private final ContentSubmissionService submissionService; + @Operation(summary = "内容提交分页查询") @GetMapping("/page") @PreAuthorize("@ss.hasPermission('submission:list')") public Result> page(SubmissionQueryReqVO req) { return Result.ok(submissionService.page(req)); } + @Operation(summary = "内容提交详情") @GetMapping("/{id}") @PreAuthorize("@ss.hasPermission('submission:list')") public Result detail(@PathVariable Long id) { return Result.ok(submissionService.getExisting(id)); } + @Operation(summary = "内容提交审核") @PutMapping("/{id}/audit") @PreAuthorize("@ss.hasPermission('submission:audit')") @OperationLog(module = "内容审核", action = "提交审核") diff --git a/fruitshorts-admin-api/src/main/java/com/fruitshorts/admin/controller/WalletAdminController.java b/fruitshorts-admin-api/src/main/java/com/fruitshorts/admin/controller/WalletAdminController.java index 0e3d6ce..1f8123b 100644 --- a/fruitshorts-admin-api/src/main/java/com/fruitshorts/admin/controller/WalletAdminController.java +++ b/fruitshorts-admin-api/src/main/java/com/fruitshorts/admin/controller/WalletAdminController.java @@ -9,6 +9,8 @@ import com.fruitshorts.common.pojo.Result; import com.fruitshorts.framework.log.OperationLog; import com.fruitshorts.framework.security.SecurityUtils; import com.fruitshorts.user.dal.mapper.AppUserMapper; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.validation.Valid; import lombok.RequiredArgsConstructor; import org.springframework.security.access.prepost.PreAuthorize; @@ -23,6 +25,7 @@ import org.springframework.web.bind.annotation.RestController; import java.util.List; /** 后台钱包:人工补币/扣回,全部进流水且必须带幂等键。 */ +@Tag(name = "后台-金币钱包") @RestController @RequestMapping("/admin/wallets") @RequiredArgsConstructor @@ -31,6 +34,7 @@ public class WalletAdminController { private final WalletService walletService; private final AppUserMapper appUserMapper; + @Operation(summary = "金币流水") @GetMapping("/{userId}/ledger") @PreAuthorize("@ss.hasPermission('order:list')") public Result> ledger(@PathVariable Long userId, @@ -38,6 +42,7 @@ public class WalletAdminController { return Result.ok(walletService.recentLedger(userId, limit)); } + @Operation(summary = "人工补币") @PostMapping("/coins") @PreAuthorize("@ss.hasPermission('wallet:update')") @OperationLog(module = "订单管理", action = "人工补币") diff --git a/fruitshorts-app-api/src/main/java/com/fruitshorts/app/AppApiApplication.java b/fruitshorts-app-api/src/main/java/com/fruitshorts/app/AppApiApplication.java index 94ee1ad..8b63aa8 100644 --- a/fruitshorts-app-api/src/main/java/com/fruitshorts/app/AppApiApplication.java +++ b/fruitshorts-app-api/src/main/java/com/fruitshorts/app/AppApiApplication.java @@ -3,12 +3,34 @@ package com.fruitshorts.app; import org.mybatis.spring.annotation.MapperScan; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; +import io.swagger.v3.oas.annotations.OpenAPIDefinition; +import io.swagger.v3.oas.annotations.info.Info; +import io.swagger.v3.oas.annotations.tags.Tag; /** * 客户端接口服务,只暴露 /app/** 与静态媒资 /files/**。 * 与 fruitshorts-admin-api 共用同一套领域模块和数据库,但入口、鉴权和限流策略独立。 */ /* 显式指定扫描根包:本类在 com.fruitshorts.app 下,默认扫不到 content/system/framework 模块的 Bean */ +@OpenAPIDefinition( + info = @Info( + title = "FruitShorts 客户端接口(/app/**)", + version = "1.0.0", + description = "接口契约以 FruitServer/docs/api-phase1.md 为准" + ), + tags = { + @Tag(name = "客户端-账号", description = "验证码、注册、登录、令牌刷新与登出"), + @Tag(name = "客户端-内容浏览", description = "首页 / 发现 / 分类聚合接口"), + @Tag(name = "客户端-评论", description = "评论发布、列表与删除"), + @Tag(name = "客户端-金币与订单", description = "钱包、金币解锁与订单票据"), + @Tag(name = "客户端-离线下载", description = "下载授权、下载偏好与断点续传"), + @Tag(name = "客户端-短剧与播放", description = "短剧详情与播放票据"), + @Tag(name = "客户端-收藏", description = "收藏切换与列表"), + @Tag(name = "客户端-点赞与举报", description = "点赞与举报提报"), + @Tag(name = "客户端-个人中心", description = "资料、设备、数据导出与注销"), + @Tag(name = "客户端-观看进度", description = "观看进度上报与续看位置"), + } +) @SpringBootApplication(scanBasePackages = "com.fruitshorts") @MapperScan("com.fruitshorts.**.dal.mapper") public class AppApiApplication { diff --git a/fruitshorts-app-api/src/main/java/com/fruitshorts/app/controller/AppAuthController.java b/fruitshorts-app-api/src/main/java/com/fruitshorts/app/controller/AppAuthController.java index d904f9e..ab71970 100644 --- a/fruitshorts-app-api/src/main/java/com/fruitshorts/app/controller/AppAuthController.java +++ b/fruitshorts-app-api/src/main/java/com/fruitshorts/app/controller/AppAuthController.java @@ -11,6 +11,8 @@ import com.fruitshorts.user.vo.OtpSendReqVO; import com.fruitshorts.user.vo.RefreshReqVO; import com.fruitshorts.user.vo.RegisterReqVO; import com.fruitshorts.user.vo.TokenRespVO; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.servlet.http.HttpServletRequest; import jakarta.validation.Valid; import lombok.RequiredArgsConstructor; @@ -20,6 +22,7 @@ import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; /** 客户端账号:验证码、注册、登录、刷新、登出。 */ +@Tag(name = "客户端-账号") @RestController @RequestMapping("/app/auth") @RequiredArgsConstructor @@ -29,30 +32,35 @@ public class AppAuthController { private final AppAuthService authService; /** 发送验证码。频控在服务端,客户端不需要自己限流。 */ + @Operation(summary = "发送验证码(频控在服务端)") @PostMapping("/otp") public Result sendOtp(@Valid @RequestBody OtpSendReqVO req, HttpServletRequest request) { otpService.send(req, WebUtils.getClientIp(request)); return Result.ok(); } + @Operation(summary = "注册账号(邮箱免验证码 / 手机号需验证码)") @PostMapping("/register") public Result register(@Valid @RequestBody RegisterReqVO req, HttpServletRequest request) { return Result.ok(authService.register(req, WebUtils.getClientIp(request))); } + @Operation(summary = "登录(验证码或密码)") @PostMapping("/login") public Result login(@Valid @RequestBody LoginReqVO req, HttpServletRequest request) { return Result.ok(authService.login(req, WebUtils.getClientIp(request))); } + @Operation(summary = "刷新令牌(旧 refresh token 立即失效)") @PostMapping("/refresh") public Result refresh(@Valid @RequestBody RefreshReqVO req) { return Result.ok(authService.refresh(req.getRefreshToken())); } /** 登出:默认只吊销当前设备的会话,allDevices=true 时吊销全部。 */ + @Operation(summary = "登出(默认当前设备,allDevices 吊销全部)") @PostMapping("/logout") public Result logout(@RequestBody(required = false) LogoutReqVO req) { authService.logout(SecurityUtils.getUserIdOrNull(), req == null ? new LogoutReqVO() : req); diff --git a/fruitshorts-app-api/src/main/java/com/fruitshorts/app/controller/AppCatalogController.java b/fruitshorts-app-api/src/main/java/com/fruitshorts/app/controller/AppCatalogController.java index 937581e..823739c 100644 --- a/fruitshorts-app-api/src/main/java/com/fruitshorts/app/controller/AppCatalogController.java +++ b/fruitshorts-app-api/src/main/java/com/fruitshorts/app/controller/AppCatalogController.java @@ -4,6 +4,8 @@ import com.fruitshorts.app.service.AppCatalogService; import com.fruitshorts.app.vo.AppCategoryVO; import com.fruitshorts.app.vo.AppFeedVO; import com.fruitshorts.common.pojo.Result; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; import lombok.RequiredArgsConstructor; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; @@ -14,6 +16,7 @@ import java.util.List; /** * 客户端目录接口:首页与发现页各一次请求拿全量聚合数据。 */ +@Tag(name = "客户端-内容浏览") @RestController @RequestMapping("/app") @RequiredArgsConstructor @@ -21,16 +24,19 @@ public class AppCatalogController { private final AppCatalogService appCatalogService; + @Operation(summary = "首页聚合:轮播 + 分区,一次请求渲染整页") @GetMapping("/home/feed") public Result homeFeed() { return Result.ok(appCatalogService.homeFeed()); } + @Operation(summary = "发现页聚合:分区列表") @GetMapping("/discover/feed") public Result discoverFeed() { return Result.ok(appCatalogService.discoverFeed()); } + @Operation(summary = "分类列表") @GetMapping("/categories") public Result> categories() { return Result.ok(appCatalogService.categories()); diff --git a/fruitshorts-app-api/src/main/java/com/fruitshorts/app/controller/AppCommentController.java b/fruitshorts-app-api/src/main/java/com/fruitshorts/app/controller/AppCommentController.java index 4fc40b1..a5ba86f 100644 --- a/fruitshorts-app-api/src/main/java/com/fruitshorts/app/controller/AppCommentController.java +++ b/fruitshorts-app-api/src/main/java/com/fruitshorts/app/controller/AppCommentController.java @@ -8,6 +8,8 @@ import com.fruitshorts.interaction.service.CommentService; import com.fruitshorts.interaction.vo.CommentPublishReqVO; import com.fruitshorts.interaction.vo.CommentQueryReqVO; import com.fruitshorts.interaction.vo.CommentRespVO; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.servlet.http.HttpServletRequest; import jakarta.validation.Valid; import lombok.RequiredArgsConstructor; @@ -27,6 +29,7 @@ import org.springframework.web.bind.annotation.RestController; * 不传 `rootId` 时返回顶层评论,传了则返回该楼层的回复。 * 列表允许匿名浏览;发布与删除需要登录。 */ +@Tag(name = "客户端-评论") @RestController @RequestMapping("/app/comments") @RequiredArgsConstructor @@ -34,6 +37,7 @@ public class AppCommentController { private final CommentService commentService; + @Operation(summary = "发布评论") @PostMapping public Result publish(@Valid @RequestBody CommentPublishReqVO req, HttpServletRequest request) { @@ -41,6 +45,7 @@ public class AppCommentController { WebUtils.getClientIp(request), request.getHeader("X-Device-Id"))); } + @Operation(summary = "评论列表(游标翻页,可匿名浏览)") @GetMapping public Result> page(@RequestParam Long dramaId, @RequestParam(required = false) Long episodeId, @@ -56,6 +61,7 @@ public class AppCommentController { return Result.ok(commentService.page(SecurityUtils.getUserIdOrNull(), query)); } + @Operation(summary = "删除自己的评论") @DeleteMapping("/{id}") public Result delete(@PathVariable Long id) { commentService.delete(SecurityUtils.getAppUserId(), id); diff --git a/fruitshorts-app-api/src/main/java/com/fruitshorts/app/controller/AppCommerceController.java b/fruitshorts-app-api/src/main/java/com/fruitshorts/app/controller/AppCommerceController.java index 0d1df14..6d931f5 100644 --- a/fruitshorts-app-api/src/main/java/com/fruitshorts/app/controller/AppCommerceController.java +++ b/fruitshorts-app-api/src/main/java/com/fruitshorts/app/controller/AppCommerceController.java @@ -6,6 +6,8 @@ import com.fruitshorts.commerce.service.UnlockService; import com.fruitshorts.commerce.service.WalletService; import com.fruitshorts.common.pojo.Result; import com.fruitshorts.framework.security.SecurityUtils; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; import lombok.RequiredArgsConstructor; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; @@ -24,6 +26,7 @@ import java.util.Map; * 金币解锁是第一阶段真实的收费方式;真实商店购买走 {@code /app/orders/verify}, * 本轮只预留接口(商店未接入时返回明确业务提示,不会产生假订单)。 */ +@Tag(name = "客户端-金币与订单") @RestController @RequestMapping("/app") @RequiredArgsConstructor @@ -34,6 +37,7 @@ public class AppCommerceController { private final OrderService orderService; /** 我的钱包:余额 + 最近流水,客户端一处渲染。 */ + @Operation(summary = "我的钱包(余额 + 最近流水)") @GetMapping("/wallet") public Result> wallet() { Long userId = SecurityUtils.getAppUserId(); @@ -44,17 +48,20 @@ public class AppCommerceController { } /** 金币解锁分集:幂等,重复点击不会重复扣币。 */ + @Operation(summary = "金币解锁分集(幂等,重复点击不重复扣币)") @PostMapping("/episodes/{episodeId}/unlock") public Result> unlock(@PathVariable Long episodeId) { return Result.ok(unlockService.unlock(SecurityUtils.getAppUserId(), episodeId)); } + @Operation(summary = "我的订单列表") @GetMapping("/orders") public Result> orders() { return Result.ok(orderService.listByUser(SecurityUtils.getAppUserId())); } /** 提交商店票据。第一阶段商店未接入,会返回明确的"尚未配置"。 */ + @Operation(summary = "提交商店票据(第一阶段商店未接入,返回明确提示)") @PostMapping("/orders/verify") public Result verify(@RequestBody Map body) { return Result.ok(orderService.verifyAndDeliver(SecurityUtils.getAppUserId(), diff --git a/fruitshorts-app-api/src/main/java/com/fruitshorts/app/controller/AppDownloadController.java b/fruitshorts-app-api/src/main/java/com/fruitshorts/app/controller/AppDownloadController.java index 300932f..e801302 100644 --- a/fruitshorts-app-api/src/main/java/com/fruitshorts/app/controller/AppDownloadController.java +++ b/fruitshorts-app-api/src/main/java/com/fruitshorts/app/controller/AppDownloadController.java @@ -8,6 +8,8 @@ import com.fruitshorts.playback.vo.DownloadLicenseRespVO; import com.fruitshorts.playback.vo.DownloadPolicyRespVO; import com.fruitshorts.playback.vo.DownloadProgressReqVO; import com.fruitshorts.playback.vo.DownloadSettingReqVO; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.servlet.http.HttpServletRequest; import jakarta.validation.Valid; import lombok.RequiredArgsConstructor; @@ -29,6 +31,7 @@ import java.util.List; *

服务端只发授权与地址,分片由客户端向 CDN 拉取;进度上报用于断点续传与跨端展示。 * 设备标识优先取请求体,其次取请求头 X-Device-Id。 */ +@Tag(name = "客户端-离线下载") @RestController @RequestMapping("/app/downloads") @RequiredArgsConstructor @@ -37,6 +40,7 @@ public class AppDownloadController { private final DownloadService downloadService; /** 申请下载授权(同一剧集重复申请幂等,只刷新有效期)。 */ + @Operation(summary = "申请下载授权(同一剧集幂等,只刷新有效期)") @PostMapping public Result grant(@Valid @RequestBody DownloadGrantReqVO req, HttpServletRequest request) { @@ -44,17 +48,20 @@ public class AppDownloadController { request.getHeader("X-Device-Id"))); } + @Operation(summary = "我的下载授权列表") @GetMapping public Result> list(@RequestParam(required = false) String deviceId) { return Result.ok(downloadService.list(SecurityUtils.getAppUserId(), deviceId)); } + @Operation(summary = "下载规则(设备上限 / 仅 Wi-Fi / 清晰度上限)") @GetMapping("/policy") public Result policy(@RequestParam(required = false) String deviceId) { return Result.ok(downloadService.policy(SecurityUtils.getAppUserId(), deviceId)); } /** 仅 Wi-Fi 下载、清晰度上限等偏好。 */ + @Operation(summary = "更新下载偏好设置") @PutMapping("/settings") public Result updateSettings(@RequestBody DownloadSettingReqVO req) { downloadService.updateSettings(SecurityUtils.getAppUserId(), req); @@ -62,6 +69,7 @@ public class AppDownloadController { } /** 断点续传前重新取一次地址:授权不变,只有地址是短时效的。 */ + @Operation(summary = "重新获取下载地址(断点续传前刷新短时效地址)") @GetMapping("/{episodeId}/url") public Result refreshUrl(@PathVariable Long episodeId, HttpServletRequest request) { @@ -69,6 +77,7 @@ public class AppDownloadController { request.getHeader("X-Device-Id"))); } + @Operation(summary = "上报下载进度") @PostMapping("/{episodeId}/progress") public Result reportProgress(@PathVariable Long episodeId, @RequestBody DownloadProgressReqVO req, @@ -77,6 +86,7 @@ public class AppDownloadController { request.getHeader("X-Device-Id"))); } + @Operation(summary = "吊销某集的下载授权") @DeleteMapping("/{episodeId}") public Result revoke(@PathVariable Long episodeId, @RequestParam(required = false) String deviceId, @@ -87,6 +97,7 @@ public class AppDownloadController { } /** 清空当前设备的全部下载授权。 */ + @Operation(summary = "清空当前设备的全部下载授权") @DeleteMapping public Result clear(@RequestParam(required = false) String deviceId, HttpServletRequest request) { diff --git a/fruitshorts-app-api/src/main/java/com/fruitshorts/app/controller/AppDramaController.java b/fruitshorts-app-api/src/main/java/com/fruitshorts/app/controller/AppDramaController.java index d5573ad..1dcc60c 100644 --- a/fruitshorts-app-api/src/main/java/com/fruitshorts/app/controller/AppDramaController.java +++ b/fruitshorts-app-api/src/main/java/com/fruitshorts/app/controller/AppDramaController.java @@ -7,6 +7,8 @@ import com.fruitshorts.framework.security.SecurityUtils; import com.fruitshorts.framework.web.WebUtils; import com.fruitshorts.playback.service.PlaybackService; import com.fruitshorts.playback.vo.PlayRespVO; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.servlet.http.HttpServletRequest; import lombok.RequiredArgsConstructor; import org.springframework.web.bind.annotation.GetMapping; @@ -14,6 +16,7 @@ import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; +@Tag(name = "客户端-短剧与播放") @RestController @RequestMapping("/app") @RequiredArgsConstructor @@ -23,6 +26,7 @@ public class AppDramaController { private final PlaybackService playbackService; /** 详情:包含剧集列表,客户端进详情页一次请求即可渲染 */ + @Operation(summary = "短剧详情(含剧集列表,进详情页一次请求即可渲染)") @GetMapping("/dramas/{id}") public Result detail(@PathVariable Long id) { return Result.ok(appCatalogService.dramaDetail(id)); @@ -32,6 +36,7 @@ public class AppDramaController { * 播放票据:服务端判定权益后签发短时效播放地址。 * 未登录也能播免费集;付费集未解锁时只返回需要多少金币。 */ + @Operation(summary = "播放票据:判定权益后签发短时效播放地址") @GetMapping("/episodes/{id}/play") public Result play(@PathVariable Long id, HttpServletRequest request) { return Result.ok(playbackService.play( diff --git a/fruitshorts-app-api/src/main/java/com/fruitshorts/app/controller/AppFavoriteController.java b/fruitshorts-app-api/src/main/java/com/fruitshorts/app/controller/AppFavoriteController.java index 6dc12c4..8fe7f64 100644 --- a/fruitshorts-app-api/src/main/java/com/fruitshorts/app/controller/AppFavoriteController.java +++ b/fruitshorts-app-api/src/main/java/com/fruitshorts/app/controller/AppFavoriteController.java @@ -6,6 +6,8 @@ import com.fruitshorts.common.pojo.Result; import com.fruitshorts.framework.security.SecurityUtils; import com.fruitshorts.playback.service.FavoriteService; import com.fruitshorts.playback.vo.FavoriteToggleReqVO; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.validation.Valid; import lombok.RequiredArgsConstructor; import org.springframework.web.bind.annotation.DeleteMapping; @@ -19,6 +21,7 @@ import org.springframework.web.bind.annotation.RestController; import java.util.List; /** 收藏。 */ +@Tag(name = "客户端-收藏") @RestController @RequestMapping("/app/favorites") @RequiredArgsConstructor @@ -28,18 +31,21 @@ public class AppFavoriteController { private final AppCatalogService appCatalogService; /** 切换收藏,返回切换后的状态:true 为已收藏。 */ + @Operation(summary = "切换收藏(返回切换后的状态)") @PostMapping("/toggle") public Result toggle(@Valid @RequestBody FavoriteToggleReqVO req) { return Result.ok(favoriteService.toggle(SecurityUtils.getAppUserId(), req.getDramaId())); } /** 收藏列表,卡片结构与首页一致。 */ + @Operation(summary = "我的收藏列表") @GetMapping public Result> list() { return Result.ok(appCatalogService.toCards( favoriteService.listDramas(SecurityUtils.getAppUserId()))); } + @Operation(summary = "取消收藏") @DeleteMapping("/{dramaId}") public Result remove(@PathVariable Long dramaId) { favoriteService.remove(SecurityUtils.getAppUserId(), dramaId); diff --git a/fruitshorts-app-api/src/main/java/com/fruitshorts/app/controller/AppInteractionController.java b/fruitshorts-app-api/src/main/java/com/fruitshorts/app/controller/AppInteractionController.java index 3593afe..62afea5 100644 --- a/fruitshorts-app-api/src/main/java/com/fruitshorts/app/controller/AppInteractionController.java +++ b/fruitshorts-app-api/src/main/java/com/fruitshorts/app/controller/AppInteractionController.java @@ -7,6 +7,8 @@ import com.fruitshorts.interaction.service.ReportService; import com.fruitshorts.interaction.vo.LikeToggleReqVO; import com.fruitshorts.interaction.vo.LikeToggleRespVO; import com.fruitshorts.interaction.vo.ReportCreateReqVO; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.validation.Valid; import lombok.RequiredArgsConstructor; import org.springframework.web.bind.annotation.PostMapping; @@ -15,6 +17,7 @@ import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; /** 点赞与举报。 */ +@Tag(name = "客户端-点赞与举报") @RestController @RequestMapping("/app") @RequiredArgsConstructor @@ -24,12 +27,14 @@ public class AppInteractionController { private final ReportService reportService; /** 点赞/取消点赞,返回切换后的状态与最新计数。 */ + @Operation(summary = "点赞 / 取消点赞") @PostMapping("/likes/toggle") public Result toggleLike(@Valid @RequestBody LikeToggleReqVO req) { return Result.ok(likeService.toggle(SecurityUtils.getAppUserId(), req)); } /** 提交举报:同一用户对同一目标只保留一条待处理工单。 */ + @Operation(summary = "提交举报(同一目标只保留一条待处理工单)") @PostMapping("/reports") public Result report(@Valid @RequestBody ReportCreateReqVO req) { return Result.ok(reportService.create(SecurityUtils.getAppUserId(), req)); diff --git a/fruitshorts-app-api/src/main/java/com/fruitshorts/app/controller/AppMeController.java b/fruitshorts-app-api/src/main/java/com/fruitshorts/app/controller/AppMeController.java index b459202..046cd70 100644 --- a/fruitshorts-app-api/src/main/java/com/fruitshorts/app/controller/AppMeController.java +++ b/fruitshorts-app-api/src/main/java/com/fruitshorts/app/controller/AppMeController.java @@ -7,6 +7,8 @@ import com.fruitshorts.user.service.AppUserService; import com.fruitshorts.user.vo.AppUserRespVO; import com.fruitshorts.user.vo.DeactivateReqVO; import com.fruitshorts.user.vo.ProfileUpdateReqVO; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.validation.Valid; import lombok.RequiredArgsConstructor; import org.springframework.web.bind.annotation.GetMapping; @@ -21,6 +23,7 @@ import java.util.List; import java.util.Map; /** 客户端个人中心:资料、设备、注销、数据导出。 */ +@Tag(name = "客户端-个人中心") @RestController @RequestMapping("/app/me") @RequiredArgsConstructor @@ -28,33 +31,39 @@ public class AppMeController { private final AppUserService userService; + @Operation(summary = "我的资料") @GetMapping public Result me() { return Result.ok(userService.me(SecurityUtils.getAppUserId())); } + @Operation(summary = "修改资料(昵称 / 头像 / 语言等)") @PutMapping public Result update(@Valid @RequestBody ProfileUpdateReqVO req) { return Result.ok(userService.updateProfile(SecurityUtils.getAppUserId(), req)); } + @Operation(summary = "我的登录设备列表") @GetMapping("/devices") public Result> devices() { return Result.ok(userService.devices(SecurityUtils.getAppUserId())); } /** 商店与隐私法规要求的数据导出,返回账号侧数据;内容侧数据由客户端自行下载。 */ + @Operation(summary = "数据导出(合规要求)") @GetMapping("/export") public Result> export() { return Result.ok(userService.exportAccount(SecurityUtils.getAppUserId())); } /** 申请注销:立即登出全部设备,进入冷静期,期间可撤销。 */ + @Operation(summary = "申请注销(进入冷静期并登出全部设备)") @PostMapping("/deactivate") public Result deactivate(@RequestBody(required = false) DeactivateReqVO req) { return Result.ok(userService.requestDeactivation(SecurityUtils.getAppUserId(), req)); } + @Operation(summary = "撤销注销申请") @PostMapping("/deactivate/cancel") public Result cancelDeactivate() { userService.cancelDeactivation(SecurityUtils.getAppUserId()); diff --git a/fruitshorts-app-api/src/main/java/com/fruitshorts/app/controller/AppWatchController.java b/fruitshorts-app-api/src/main/java/com/fruitshorts/app/controller/AppWatchController.java index 524645a..4772478 100644 --- a/fruitshorts-app-api/src/main/java/com/fruitshorts/app/controller/AppWatchController.java +++ b/fruitshorts-app-api/src/main/java/com/fruitshorts/app/controller/AppWatchController.java @@ -5,6 +5,8 @@ import com.fruitshorts.framework.security.SecurityUtils; import com.fruitshorts.playback.service.WatchProgressService; import com.fruitshorts.playback.vo.ProgressRespVO; import com.fruitshorts.playback.vo.ProgressSaveReqVO; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.validation.Valid; import lombok.RequiredArgsConstructor; import org.springframework.web.bind.annotation.DeleteMapping; @@ -19,6 +21,7 @@ import org.springframework.web.bind.annotation.RestController; import java.util.List; /** 观看进度与观看记录。 */ +@Tag(name = "客户端-观看进度") @RestController @RequestMapping("/app/watch") @RequiredArgsConstructor @@ -27,28 +30,33 @@ public class AppWatchController { private final WatchProgressService progressService; /** 上报进度:客户端每 10 秒一次,切集时立即上报一次。 */ + @Operation(summary = "上报观看进度(客户端每 10 秒一次)") @PostMapping("/progress") public Result save(@Valid @RequestBody ProgressSaveReqVO req) { return Result.ok(progressService.save(SecurityUtils.getAppUserId(), req)); } /** 某部剧的续看位置,进详情页时用它决定"续看第 N 集"。 */ + @Operation(summary = "某部剧的续看位置") @GetMapping("/progress") public Result ofDrama(@RequestParam Long dramaId) { return Result.ok(progressService.ofDrama(SecurityUtils.getAppUserId(), dramaId)); } + @Operation(summary = "最近观看列表") @GetMapping("/recent") public Result> recent(@RequestParam(defaultValue = "20") int limit) { return Result.ok(progressService.recent(SecurityUtils.getAppUserId(), limit)); } + @Operation(summary = "删除某部剧的观看记录") @DeleteMapping("/progress/{dramaId}") public Result remove(@PathVariable Long dramaId) { progressService.remove(SecurityUtils.getAppUserId(), dramaId); return Result.ok(); } + @Operation(summary = "清空观看记录") @DeleteMapping("/progress") public Result clear() { progressService.clear(SecurityUtils.getAppUserId()); diff --git a/fruitshorts-app-api/src/main/resources/application.yml b/fruitshorts-app-api/src/main/resources/application.yml index ddc31af..ea654ab 100644 --- a/fruitshorts-app-api/src/main/resources/application.yml +++ b/fruitshorts-app-api/src/main/resources/application.yml @@ -55,6 +55,11 @@ fruitshorts: cors: allowed-origins: "*" +# 接口文档:/doc.html 打开 Swagger UI,/v3/api-docs 是机器可读契约(前端联调按它写) +springdoc: + swagger-ui: + path: /doc.html + logging: level: com.fruitshorts: info