Prechádzať zdrojové kódy

playlist制作组: ok

xiang 3 týždňov pred
rodič
commit
ef2f65e093
100 zmenil súbory, kde vykonal 5964 pridanie a 0 odobranie
  1. 33 0
      apitest/api.http
  2. 33 0
      artist/.gitignore
  3. 91 0
      artist/artist.sql
  4. 89 0
      artist/pom.xml
  5. 9 0
      artist/src/main/java/com/artist/ArtistApplication.java
  6. 45 0
      artist/src/main/java/com/artist/config/ResouceServerConfig.java
  7. 33 0
      artist/src/main/java/com/artist/config/TokenConfig.java
  8. 20 0
      artist/src/main/java/com/artist/controller/ArtistAuditRecordController.java
  9. 81 0
      artist/src/main/java/com/artist/controller/ArtistController.java
  10. 20 0
      artist/src/main/java/com/artist/controller/ArtistExternalInfoController.java
  11. 20 0
      artist/src/main/java/com/artist/controller/ArtistMediaHistoryController.java
  12. 59 0
      artist/src/main/java/com/artist/controller/ArtistRealAuthController.java
  13. 32 0
      artist/src/main/java/com/artist/domain/dto/MusicianApplicationDTO.java
  14. 10 0
      artist/src/main/java/com/artist/domain/dto/updateArtistStatusDto.java
  15. 236 0
      artist/src/main/java/com/artist/domain/po/Artist.java
  16. 102 0
      artist/src/main/java/com/artist/domain/po/ArtistAuditRecord.java
  17. 53 0
      artist/src/main/java/com/artist/domain/po/ArtistExternalInfo.java
  18. 102 0
      artist/src/main/java/com/artist/domain/po/ArtistMediaHistory.java
  19. 80 0
      artist/src/main/java/com/artist/domain/po/ArtistRealAuth.java
  20. 62 0
      artist/src/main/java/com/artist/domain/po/WyUser.java
  21. 18 0
      artist/src/main/java/com/artist/mapper/ArtistAuditRecordMapper.java
  22. 18 0
      artist/src/main/java/com/artist/mapper/ArtistExternalInfoMapper.java
  23. 48 0
      artist/src/main/java/com/artist/mapper/ArtistMapper.java
  24. 18 0
      artist/src/main/java/com/artist/mapper/ArtistMediaHistoryMapper.java
  25. 18 0
      artist/src/main/java/com/artist/mapper/ArtistRealAuthMapper.java
  26. 16 0
      artist/src/main/java/com/artist/service/IArtistAuditRecordService.java
  27. 16 0
      artist/src/main/java/com/artist/service/IArtistExternalInfoService.java
  28. 16 0
      artist/src/main/java/com/artist/service/IArtistMediaHistoryService.java
  29. 16 0
      artist/src/main/java/com/artist/service/IArtistRealAuthService.java
  30. 23 0
      artist/src/main/java/com/artist/service/IArtistService.java
  31. 20 0
      artist/src/main/java/com/artist/service/impl/ArtistAuditRecordServiceImpl.java
  32. 20 0
      artist/src/main/java/com/artist/service/impl/ArtistExternalInfoServiceImpl.java
  33. 20 0
      artist/src/main/java/com/artist/service/impl/ArtistMediaHistoryServiceImpl.java
  34. 20 0
      artist/src/main/java/com/artist/service/impl/ArtistRealAuthServiceImpl.java
  35. 170 0
      artist/src/main/java/com/artist/service/impl/ArtistServiceImpl.java
  36. 23 0
      artist/src/main/resources/bootstrap.yml
  37. 5 0
      artist/src/main/resources/mapper/AlbumMapper.xml
  38. 5 0
      artist/src/main/resources/mapper/ArtistAuditRecordMapper.xml
  39. 5 0
      artist/src/main/resources/mapper/ArtistExternalInfoMapper.xml
  40. 5 0
      artist/src/main/resources/mapper/ArtistMapper.xml
  41. 5 0
      artist/src/main/resources/mapper/ArtistMediaHistoryMapper.xml
  42. 5 0
      artist/src/main/resources/mapper/ArtistRealAuthMapper.xml
  43. 24 0
      auth/auth.sql
  44. 63 0
      auth/src/main/java/com/auth/config/AuthorizationServer.java
  45. 34 0
      auth/src/main/java/com/auth/config/CustomTokenEnhancer.java
  46. 27 0
      auth/src/main/java/com/auth/config/DaoAuthenticationProviderCustom.java
  47. 54 0
      auth/src/main/java/com/auth/config/TokenConfig.java
  48. 71 0
      auth/src/main/java/com/auth/config/WebSecurityConfig.java
  49. 34 0
      auth/src/main/java/com/auth/controller/GiteeLoginController.java
  50. 42 0
      auth/src/main/java/com/auth/controller/WxLoginController.java
  51. 81 0
      auth/src/main/java/com/auth/domain/po/User.java
  52. 18 0
      auth/src/main/java/com/auth/mapper/UserMapper.java
  53. 15 0
      auth/src/main/java/com/auth/model/dto/AuthParamsDto.java
  54. 17 0
      auth/src/main/java/com/auth/model/dto/UserExt.java
  55. 21 0
      auth/src/main/java/com/auth/service/AuthService.java
  56. 20 0
      auth/src/main/java/com/auth/service/GiteeAuthService.java
  57. 16 0
      auth/src/main/java/com/auth/service/IUserService.java
  58. 18 0
      auth/src/main/java/com/auth/service/WxAuthService.java
  59. 126 0
      auth/src/main/java/com/auth/service/impl/AuthTokenService.java
  60. 140 0
      auth/src/main/java/com/auth/service/impl/GiteeAuthServiceImpl.java
  61. 89 0
      auth/src/main/java/com/auth/service/impl/PasswordAuthServiceImpl.java
  62. 97 0
      auth/src/main/java/com/auth/service/impl/UserServiceImpl.java
  63. 181 0
      auth/src/main/java/com/auth/service/impl/WxAuthServiceImpl.java
  64. 5 0
      auth/src/main/resources/mapper/UserMapper.xml
  65. 27 0
      base/src/main/java/com/base/utils/Result.java
  66. 233 0
      content/content.sql
  67. 45 0
      content/src/main/java/com/content/config/ResouceServerConfig.java
  68. 31 0
      content/src/main/java/com/content/config/SecurityUtil.java
  69. 39 0
      content/src/main/java/com/content/config/TokenConfig.java
  70. 96 0
      content/src/main/java/com/content/controller/AlbumController.java
  71. 40 0
      content/src/main/java/com/content/controller/PlaylistController.java
  72. 74 0
      content/src/main/java/com/content/controller/SongController.java
  73. 52 0
      content/src/main/java/com/content/controller/WlyricsController.java
  74. 115 0
      content/src/main/java/com/content/domain/dto/AddSongDTO.java
  75. 10 0
      content/src/main/java/com/content/domain/dto/ApplyDto.java
  76. 32 0
      content/src/main/java/com/content/domain/dto/MusicianApplicationDTO.java
  77. 8 0
      content/src/main/java/com/content/domain/dto/PageQueryDto.java
  78. 12 0
      content/src/main/java/com/content/domain/dto/PlaylistWithSongsDTO.java
  79. 123 0
      content/src/main/java/com/content/domain/po/Album.java
  80. 235 0
      content/src/main/java/com/content/domain/po/Artist.java
  81. 53 0
      content/src/main/java/com/content/domain/po/ArtistExternalInfo.java
  82. 101 0
      content/src/main/java/com/content/domain/po/ArtistMediaHistory.java
  83. 166 0
      content/src/main/java/com/content/domain/po/ArtistRealAuth.java
  84. 89 0
      content/src/main/java/com/content/domain/po/DailyRecommend.java
  85. 75 0
      content/src/main/java/com/content/domain/po/Lyric.java
  86. 150 0
      content/src/main/java/com/content/domain/po/MediaFile.java
  87. 60 0
      content/src/main/java/com/content/domain/po/Playlist.java
  88. 77 0
      content/src/main/java/com/content/domain/po/PlaylistSong.java
  89. 184 0
      content/src/main/java/com/content/domain/po/Song.java
  90. 44 0
      content/src/main/java/com/content/domain/po/Swipper.java
  91. 224 0
      content/src/main/java/com/content/domain/po/User.java
  92. 78 0
      content/src/main/java/com/content/domain/po/UserFavoriteArtist.java
  93. 78 0
      content/src/main/java/com/content/domain/po/UserFavoriteSong.java
  94. 78 0
      content/src/main/java/com/content/domain/po/UserFollow.java
  95. 78 0
      content/src/main/java/com/content/domain/po/UserPlaylistFavorite.java
  96. 63 0
      content/src/main/java/com/content/domain/po/WyUser.java
  97. 227 0
      content/src/main/java/com/content/domain/po/info.sql
  98. 18 0
      content/src/main/java/com/content/mapper/AlbumMapper.java
  99. 18 0
      content/src/main/java/com/content/mapper/ArtistExternalInfoMapper.java
  100. 18 0
      content/src/main/java/com/content/mapper/ArtistMapper.java

+ 33 - 0
apitest/api.http

@@ -0,0 +1,33 @@
+###校验jwt令牌
+POST http://localhost:8081/oauth/check_token?token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOlsid3ktbXVzaWMiXSwidXNlcl9uYW1lIjoie1wiY3JlYXRlVGltZVwiOlwiMjAyNS0xMC0zMVQxNjo1NDo0NVwiLFwiaWRcIjoyLFwibGFzdExvZ2luVGltZVwiOlwiMjAyNS0xMC0zMVQxNzoxNzo0Mi44MzYzNzQwMDBcIixcIm5hbWVcIjpcIua1i-ivleeUqOaIt1wiLFwibmlja25hbWVcIjpcIua1i-ivleeUqOaIt1wiLFwicGFzc3dvcmRcIjpcIiQyYSQxMCRTUTJZMlc0cDRQNW42MmdWYlVIQjJ1MzNKODhOa3lxdEFqSVhqZ0FxZzNSY0FpTkNQUFczbVwiLFwic3RhdHVzXCI6XCIxXCIsXCJ1c2VybmFtZVwiOlwidGVzdHVzZXJcIixcInV0eXBlXCI6XCIxMDEwMDFcIn0iLCJzY29wZSI6WyJhbGwiXSwiZXhwIjoxNzYxOTEwMTMzLCJhdXRob3JpdGllcyI6WyJwMSJdLCJqdGkiOiJlMjUzZTJjNS1jOTg0LTRiOWQtODg0Zi01OWVlMDZlNGQ3NmYiLCJjbGllbnRfaWQiOiJYY1dlYkFwcCJ9.-awmaRPURpI8CbvBtbz6C75_oebtwOErloBCWxifHL0
+
+
+
+###wt刷新令牌令牌
+POST http://localhost:8081/oauth/token
+Content-Type: application/x-www-form-urlencoded
+Authorization: Basic WGNXZWJBcHA6WGNXZWJBcHA=
+
+grant_type=refresh_token&refresh_token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOlsieHVlY2hlbmctcGx1cyJdLCJ1c2VyX25hbWUiOiJ6aGFuZ3NhbiIsInNjb3BlIjpbImFsbCJdLCJhdGkiOiI4ZDExMjBlMi0yOGQyLTRiYTEtODk0Mi00NWU2ZTNlYmFlMDQiLCJleHAiOjE3NjIxNDA5MTIsImF1dGhvcml0aWVzIjpbInAxIl0sImp0aSI6Ijk0NzU5NGIyLTdkODItNDk2OC04NGM3LTJmYzA2M2U3YjEwNCIsImNsaWVudF9pZCI6IlhjV2ViQXBwIn0.1BZNYmvRu1JPoLdWmId7ar-Y053V-q71pwLj7GCE14o
+
+
+
+grant_type=password&username={"username":"testuser","password":"123456","authType":"password"}
+
+###
+GET http://localhost:8083/content/swipper
+
+###
+GET http://localhost:8083/content/swipper/find/recommend
+
+###GET http://localhost:8083/content/swipper/test1
+GET http://localhost:8083/content/swipper/test1
+Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE3NjI4Mjk2NTcsInVzZXJfbmFtZSI6IntcImNyZWF0ZVRpbWVcIjpcIjIwMjUtMTEtMDRUMTY6Mjc6MzdcIixcImlkXCI6OCxcIm5hbWVcIjpcIuadjuWkqeelpVwiLFwibmlja25hbWVcIjpcIuadjuWkqeelpVwiLFwicGFzc3dvcmRcIjpcIiQyYSQxMCQ1eUJMOUt6TVQuc3RyL2ttNy5aeDcuVkF0VGl2S0wvSVN5VEFHOW5RRFNrMlY0SGZpLnlvR1wiLFwic3RhdHVzXCI6XCIxXCIsXCJ1cmxcIjpcImh0dHBzOi8vZm9ydWRhLmdpdGVlLmNvbS9hdmF0YXIvMTc2MjIyNjM1NDg4MDY1NDU2MC8xMTM4MDYwN194aWFuZzIyMjMzXzE3NjIyMjYzNTQucG5nXCIsXCJ1c2VybmFtZVwiOlwiZ2l0ZWVfMTEzODA2MDdcIixcInV0eXBlXCI6XCIxMDEwMDFcIixcInZpcExldmVsXCI6MCxcInZpcFN0YXR1c1wiOjB9IiwiYXV0aG9yaXRpZXMiOlsicDEiXSwianRpIjoiYjMxYmNhYmQtNGE5NS00NzJkLTlkMmMtZDA5NTAzY2JhMTM5IiwiY2xpZW50X2lkIjoiWGNXZWJBcHAiLCJzY29wZSI6WyJhbGwiXX0.dwZyeygwn1gLfe9aFznhrb_GsPUBm4u-9MlcERgr9DM
+
+###Get
+GET http://localhost:8083/artist/status
+Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOlsid3ktbXVzaWMiXSwidXNlcl9uYW1lIjoie1wiYWdlXCI6MTIzLFwiY3JlYXRlVGltZVwiOlwiMjAyNS0xMS0wM1QwOTo1NzoxOVwiLFwiaWRcIjoxLFwibmFtZVwiOlwiMTIzXCIsXCJwYXNzd29yZFwiOlwiJDJhJDEwJHRiVEVIZzVpYjk1RWp1R2VGaFgyRS53VDczeTF0T0V5ZXV2bWxVSUFrRktpbUtoaVladmJDXCIsXCJzdGF0dXNcIjpcIm5vcm1hbFwiLFwidXJsXCI6XCJodHRwczovL2ZvcnVkYS5naXRlZS5jb20vYXZhdGFyLzE3NjIyMjYzNTQ4ODA2NTQ1NjAvMTEzODA2MDdfeGlhbmcyMjIzM18xNzYyMjI2MzU0LnBuZ1wiLFwidXNlcm5hbWVcIjpcInRlc3R1c2VyXCIsXCJ1dHlwZVwiOlwibm9ybWFsXCIsXCJ2aXBMZXZlbFwiOjAsXCJ2aXBTdGF0dXNcIjowfSIsInNjb3BlIjpbImFsbCJdLCJleHAiOjE3NjQwMzg3MzQsImF1dGhvcml0aWVzIjpbInAxIl0sImp0aSI6ImQzN2Q4OGRjLTI2M2QtNGNiNS05ZDc0LTNiZTgxMDRhMmI4ZCIsImNsaWVudF9pZCI6IlhjV2ViQXBwIn0.4C3kD54BKGoiHuofWjL73_KurYH9JkLEpuSpsE9Qh6A
+
+
+###postpostpostpostpostpostpostpostpostpostpostpostpostpost
+POST http://localhost:8083/oauth/token?client_id=XcWebApp&client_secret=XcWebApp&grant_type=password&username={"username":"testuser","authType":"password","password":"123456"}

+ 33 - 0
artist/.gitignore

@@ -0,0 +1,33 @@
+HELP.md
+target/
+!.mvn/wrapper/maven-wrapper.jar
+!**/src/main/**/target/
+!**/src/test/**/target/
+
+### STS ###
+.apt_generated
+.classpath
+.factorypath
+.project
+.settings
+.springBeans
+.sts4-cache
+
+### IntelliJ IDEA ###
+.idea
+*.iws
+*.iml
+*.ipr
+
+### NetBeans ###
+/nbproject/private/
+/nbbuild/
+/dist/
+/nbdist/
+/.nb-gradle/
+build/
+!**/src/main/**/build/
+!**/src/test/**/build/
+
+### VS Code ###
+.vscode/

+ 91 - 0
artist/artist.sql

@@ -0,0 +1,91 @@
+CREATE DATABASE IF NOT EXISTS wy_artist DEFAULT CHARSET utf8mb4 COLLATE utf8mb4_unicode_ci;
+USE wy_artist;
+
+-- ------------------------------
+-- 1. 艺人基础信息表(优化:移除跨服务外键,冗余核心用户字段)
+-- ------------------------------
+CREATE TABLE `artist` (
+                          `id` INT AUTO_INCREMENT PRIMARY KEY,
+                          `user_id` INT NOT NULL COMMENT '关联auth服务的user.id(艺人必须是平台用户,仅逻辑关联,无外键)',
+                          `user_username` VARCHAR(50) NOT NULL COMMENT '冗余auth.user.username(避免频繁调用auth服务)',
+                          `user_phone` VARCHAR(20) COMMENT '冗余auth.user.phone(艺人联系电话,非实名认证)',
+                          `artist_name` VARCHAR(100) NOT NULL COMMENT '艺人名(对外展示名称)',
+                          `avatar` VARCHAR(255) COMMENT '艺人头像URL',
+                          `header_image` VARCHAR(255) COMMENT '艺人页头图(网页端顶部背景图)',
+                          `gender` TINYINT COMMENT '性别:1-男,2-女,3-团体',
+                          `birthday` DATE COMMENT '生日',
+                          `region` VARCHAR(50) COMMENT '艺人所属地区(如中国内地、韩国)',
+                          `genre` VARCHAR(100) COMMENT '流派风格(多个用逗号分隔,如流行,摇滚,电子)',
+                          `company` VARCHAR(100) COMMENT '所属公司/厂牌(如华谊兄弟、SM娱乐)',
+                          `introduction` TEXT COMMENT '艺人介绍(10-1000字,用于艺人详情页)',
+                          `invitation_code` VARCHAR(50) COMMENT '邀请码(用于平台邀请艺人入驻)',
+                          `wechat` VARCHAR(50) COMMENT '微信号(内部联系用,需加密存储)',
+                          `status` TINYINT DEFAULT 0 COMMENT '艺人账号状态:0-待审核,1-已通过,2-已拒绝,3-已冻结',
+                          `create_time` DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
+                          `update_time` DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
+                          UNIQUE KEY `uk_artist_name` (`artist_name`), -- 艺人名唯一
+                          UNIQUE KEY `uk_user_id` (`user_id`), -- 一个用户只能绑定一个艺人账号
+                          INDEX `idx_user_id` (`user_id`) -- 逻辑关联索引
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='艺人基础信息表';
+
+-- ------------------------------
+-- 2. 艺人实名认证表(无跨服务依赖,仅关联本地artist表)
+-- ------------------------------
+CREATE TABLE `artist_real_auth` (
+                                    `id` INT AUTO_INCREMENT PRIMARY KEY,
+                                    `artist_id` INT NOT NULL COMMENT '关联本服务的artist.id',
+                                    `real_name` VARCHAR(50) NOT NULL COMMENT '真实姓名(艺人身份证姓名)',
+                                    `phone` VARCHAR(20) NOT NULL COMMENT '绑定手机号(用于实名认证验证)',
+                                    `email` VARCHAR(100) NOT NULL COMMENT '邮箱(用于接收审核结果)',
+                                    `nationality` VARCHAR(50) NOT NULL COMMENT '国籍/地区(如中国、美国)',
+                                    `id_card` VARCHAR(100) NOT NULL COMMENT '证件号(建议AES加密存储,保护隐私)',
+                                    `face_auth_status` TINYINT DEFAULT 0 COMMENT '面部识别状态:0-未认证,1-已认证',
+                                    `auth_status` TINYINT DEFAULT 0 COMMENT '实名认证状态:0-待审核,1-已通过,2-已驳回',
+                                    `auth_time` DATETIME COMMENT '实名认证通过时间',
+                                    `auth_result` TEXT COMMENT '实名认证结果(通过/驳回原因)',
+                                    `create_time` DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
+                                    FOREIGN KEY (`artist_id`) REFERENCES `artist` (`id`) ON DELETE CASCADE,
+                                    UNIQUE KEY `uk_artist_auth` (`artist_id`),
+                                    UNIQUE KEY `uk_id_card` (`id_card`) -- 身份证号唯一(加密后)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='艺人实名认证信息表';
+
+-- ------------------------------
+-- 3. 艺人站外社交信息表(无跨服务依赖)
+-- ------------------------------
+CREATE TABLE `artist_external_info` (
+                                        `id` INT AUTO_INCREMENT PRIMARY KEY,
+                                        `artist_id` INT NOT NULL COMMENT '关联本服务的artist.id',
+                                        `platform_name` VARCHAR(50) NOT NULL COMMENT '站外平台名称(如微博、抖音、B站、Spotify)',
+                                        `platform_account` VARCHAR(255) NOT NULL COMMENT '平台用户ID/URL/昵称(如微博昵称:XXX)',
+                                        `fans_count` BIGINT DEFAULT 0 COMMENT '平台粉丝数(定期同步更新)',
+                                        `create_time` DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
+                                        `update_time` DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
+                                        FOREIGN KEY (`artist_id`) REFERENCES `artist` (`id`) ON DELETE CASCADE,
+                                        UNIQUE KEY `uk_artist_platform` (`artist_id`, `platform_name`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='艺人站外社交平台信息表';
+
+-- ------------------------------
+-- 4. 音乐人审核申请表(优化:移除跨服务外键,增加冗余字段)
+-- ------------------------------
+CREATE TABLE `artist_audit_record` (
+    `id` INT AUTO_INCREMENT PRIMARY KEY,
+    `user_id` INT NOT NULL COMMENT '关联auth服务的user.id(申请人,仅逻辑关联)',
+    `user_username` VARCHAR(50) NOT NULL COMMENT '冗余auth.user.username(审核人可直接查看)',
+    `artist_id` INT COMMENT '关联本服务的artist.id(已存在的艺人ID,可为空)',
+    `apply_type` TINYINT DEFAULT 1 COMMENT '申请类型:1-新注册,2-信息修改,3-重新申请',
+    `apply_reason` TEXT COMMENT '申请原因(如:更新个人信息、重新提交认证材料等)',
+    `apply_time` DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '申请时间',
+    `audit_status` TINYINT DEFAULT 0 COMMENT '审核状态:0-待审核,1-已通过,2-已驳回',
+    `audit_result` TEXT COMMENT '审核结果(详细说明)',
+    `reject_reason` TEXT COMMENT '驳回原因(详细说明)',
+    `audit_time` DATETIME COMMENT '审核时间',
+    `audit_user_id` INT COMMENT '关联auth服务的user.id(审核人,仅逻辑关联)',
+    `audit_username` VARCHAR(50) COMMENT '冗余auth.user.username(审核人姓名,便于追溯)',
+    `create_time` DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
+    `update_time` DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',-- 移除跨服务外键,仅保留逻辑索引
+    INDEX `idx_user_id` (`user_id`),
+    INDEX `idx_artist_id` (`artist_id`),
+    INDEX `idx_apply_time` (`apply_time`),
+    INDEX `idx_audit_status` (`audit_status`),
+    INDEX `idx_audit_user_id` (`audit_user_id`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='音乐人审核申请记录表';

+ 89 - 0
artist/pom.xml

@@ -0,0 +1,89 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <artifactId>parent</artifactId>
+        <groupId>com.wy-music</groupId>
+        <version>0.0.1-SNAPSHOT</version>
+        <relativePath>../parent</relativePath>
+    </parent>
+    <artifactId>artist</artifactId>
+    <dependencies>
+        <dependency>
+            <groupId>com.wy-music</groupId>
+            <artifactId>base</artifactId>
+            <version>0.0.1-SNAPSHOT</version>
+        </dependency>
+        <!-- MySQL 驱动 -->
+        <dependency>
+            <groupId>mysql</groupId>
+            <artifactId>mysql-connector-java</artifactId>
+        </dependency>
+
+        <!-- mybatis plus的依赖 -->
+        <dependency>
+            <groupId>com.baomidou</groupId>
+            <artifactId>mybatis-plus-boot-starter</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.alibaba.cloud</groupId>
+            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.alibaba.cloud</groupId>
+            <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-web</artifactId>
+        </dependency>
+        <!-- Spring Boot 集成 swagger -->
+        <dependency>
+            <groupId>com.spring4all</groupId>
+            <artifactId>swagger-spring-boot-starter</artifactId>
+        </dependency>
+        <!--认证相关-->
+        <dependency>
+            <groupId>org.springframework.cloud</groupId>
+            <artifactId>spring-cloud-starter-security</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.cloud</groupId>
+            <artifactId>spring-cloud-starter-oauth2</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>javax.xml.bind</groupId>
+            <artifactId>jaxb-api</artifactId>
+            <version>2.3.1</version>
+        </dependency>
+        <dependency>
+            <groupId>org.glassfish.jaxb</groupId>
+            <artifactId>jaxb-runtime</artifactId>
+            <version>2.3.3</version>
+        </dependency>
+        <dependency>
+            <groupId>com.alibaba</groupId>
+            <artifactId>fastjson</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-validation</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.projectlombok</groupId>
+            <artifactId>lombok</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.springframework.cloud</groupId>
+            <artifactId>spring-cloud-starter-oauth2</artifactId>
+            <exclusions>
+                <exclusion>
+                    <groupId>com.sun.xml.bind</groupId>
+                    <artifactId>jaxb-impl</artifactId>
+                </exclusion>
+            </exclusions>
+        </dependency>
+    </dependencies>
+</project>

+ 9 - 0
artist/src/main/java/com/artist/ArtistApplication.java

@@ -0,0 +1,9 @@
+package com.artist;
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+@SpringBootApplication
+public class ArtistApplication {
+    public static void main(String[] args) {
+        SpringApplication.run(ArtistApplication.class, args);
+    }
+}

+ 45 - 0
artist/src/main/java/com/artist/config/ResouceServerConfig.java

@@ -0,0 +1,45 @@
+package com.artist.config;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
+import org.springframework.security.config.annotation.web.builders.HttpSecurity;
+import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer;
+import org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfigurerAdapter;
+import org.springframework.security.oauth2.config.annotation.web.configurers.ResourceServerSecurityConfigurer;
+import org.springframework.security.oauth2.provider.token.TokenStore;
+
+/**
+ * @description 资源服务配置
+ * @author Mr.M
+ * @date 2022/10/18 16:33
+ * @version 1.0
+ */
+@Configuration
+@EnableResourceServer
+@EnableGlobalMethodSecurity(securedEnabled = true,prePostEnabled = true)
+public class ResouceServerConfig extends ResourceServerConfigurerAdapter {
+
+
+    //资源服务标识
+    public static final String RESOURCE_ID = "wy-music";
+
+    @Autowired
+    TokenStore tokenStore;
+
+    @Override
+    public void configure(ResourceServerSecurityConfigurer resources) {
+        resources.resourceId(RESOURCE_ID)//资源 id
+        .tokenStore(tokenStore)
+        .stateless(true);
+    }
+
+    @Override
+    public void configure(HttpSecurity http) throws Exception {
+        http.csrf().disable()
+        .authorizeRequests()
+//        .antMatchers("/r/**","/course/**").authenticated()//所有/r/**的请求必须认证通过
+        .anyRequest().permitAll()
+        ;
+    }
+
+}

+ 33 - 0
artist/src/main/java/com/artist/config/TokenConfig.java

@@ -0,0 +1,33 @@
+package com.artist.config;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.security.oauth2.provider.token.TokenStore;
+import org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter;
+import org.springframework.security.oauth2.provider.token.store.JwtTokenStore;
+
+/**
+ * @author Administrator
+ * @version 1.0
+ **/
+@Configuration
+public class TokenConfig {
+
+    String SIGNING_KEY = "wy_music_token";
+    @Autowired
+    private JwtAccessTokenConverter accessTokenConverter;
+
+    @Bean
+    public TokenStore tokenStore() {
+        return new JwtTokenStore(accessTokenConverter());
+    }
+
+    @Bean
+    public JwtAccessTokenConverter accessTokenConverter() {
+        JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
+        converter.setSigningKey(SIGNING_KEY);
+        return converter;
+    }
+
+
+}

+ 20 - 0
artist/src/main/java/com/artist/controller/ArtistAuditRecordController.java

@@ -0,0 +1,20 @@
+package com.artist.controller;
+
+
+import org.springframework.web.bind.annotation.RequestMapping;
+
+import org.springframework.web.bind.annotation.RestController;
+
+/**
+ * <p>
+ * 音乐人审核申请记录表 前端控制器
+ * </p>
+ *
+ * @author xiang
+ * @since 2025-12-09
+ */
+@RestController
+@RequestMapping("/artist-audit-record")
+public class ArtistAuditRecordController {
+
+}

+ 81 - 0
artist/src/main/java/com/artist/controller/ArtistController.java

@@ -0,0 +1,81 @@
+package com.artist.controller;
+
+
+import com.alibaba.fastjson.JSON;
+import com.artist.domain.dto.MusicianApplicationDTO;
+import com.artist.domain.po.Artist;
+import com.artist.domain.po.ArtistAuditRecord;
+import com.artist.domain.po.WyUser;
+import com.artist.service.IArtistAuditRecordService;
+import com.artist.service.IArtistService;
+import com.base.exception.WyMusicException;
+import com.base.utils.Result;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.security.core.context.SecurityContextHolder;
+import org.springframework.web.bind.annotation.*;
+
+import org.springframework.stereotype.Controller;
+
+import java.util.List;
+
+/**
+ * <p>
+ * 艺人基础信息表 前端控制器
+ * </p>
+ *
+ * @author xiang
+ * @since 2025-11-24
+ */
+@RestController
+@RequestMapping("/artist")
+public class ArtistController {
+    @Autowired
+    private IArtistService iArtistApplyService;
+    @Autowired
+    private IArtistAuditRecordService iArtistAuditRecordService;
+    @Autowired
+    private IArtistService artistService;
+    @PostMapping("/apply")
+    @PreAuthorize("hasRole('ROLE_USER')")
+    public Result apply(@RequestBody MusicianApplicationDTO musicianApplicationDTO) {
+        try {
+            iArtistApplyService.applyMusician(musicianApplicationDTO);
+            return Result.success("申请已提交");
+        } catch (WyMusicException e) {
+            return Result.fail(e.getMessage());
+        }
+    }
+    @GetMapping("/status")
+    @PreAuthorize("hasRole('ROLE_USER')")
+    public Result applyStatus(@RequestParam(required = false) Integer id) {
+        if (id == null) {
+            Object principalObj = SecurityContextHolder.getContext().getAuthentication().getPrincipal();
+            if (principalObj instanceof String) {
+                String principal = principalObj.toString();
+                WyUser user = JSON.parseObject(principal, WyUser.class);
+                id = user.getId();
+            }
+        }
+        Artist i = iArtistApplyService.applyStatus(id);
+        return Result.success(i);
+    }
+
+    @GetMapping("/allApply")
+    @PreAuthorize("hasRole('ROLE_ADMIN')")
+    public Result allApply() {
+        List<ArtistAuditRecord> list = iArtistAuditRecordService.lambdaQuery().list();
+        return Result.success(list);
+    }
+    @GetMapping("/updateArtistStatus")
+    @PreAuthorize("hasRole('ROLE_ADMIN')")
+    public Result updateArtistStatus(@RequestParam Integer id, @RequestParam Integer status, @RequestParam(required = false, defaultValue = "") String reason) {
+        iArtistApplyService.updateArtistApply(id, status,reason);
+        return Result.success("更新成功");
+    }
+    @GetMapping("/application-info")
+    public Result getApplicationInfo(@RequestParam Integer userId) {
+        MusicianApplicationDTO musicianApplicationInfo = artistService.getMusicianApplicationInfo(userId);
+        return Result.success(musicianApplicationInfo);
+    }
+}

+ 20 - 0
artist/src/main/java/com/artist/controller/ArtistExternalInfoController.java

@@ -0,0 +1,20 @@
+package com.artist.controller;
+
+
+import org.springframework.web.bind.annotation.RequestMapping;
+
+import org.springframework.stereotype.Controller;
+
+/**
+ * <p>
+ * 艺人站外社交平台信息表 前端控制器
+ * </p>
+ *
+ * @author xiang
+ * @since 2025-11-24
+ */
+@Controller
+@RequestMapping("/artist-external-info")
+public class ArtistExternalInfoController {
+
+}

+ 20 - 0
artist/src/main/java/com/artist/controller/ArtistMediaHistoryController.java

@@ -0,0 +1,20 @@
+package com.artist.controller;
+
+
+import org.springframework.web.bind.annotation.RequestMapping;
+
+import org.springframework.stereotype.Controller;
+
+/**
+ * <p>
+ * 艺人媒体文件历史记录表 前端控制器
+ * </p>
+ *
+ * @author xiang
+ * @since 2025-11-24
+ */
+@Controller
+@RequestMapping("/artist-media-history")
+public class ArtistMediaHistoryController {
+
+}

+ 59 - 0
artist/src/main/java/com/artist/controller/ArtistRealAuthController.java

@@ -0,0 +1,59 @@
+package com.artist.controller;
+
+
+import com.artist.domain.po.ArtistExternalInfo;
+import com.artist.domain.po.ArtistRealAuth;
+import com.artist.service.IArtistExternalInfoService;
+import com.artist.service.IArtistRealAuthService;
+import com.base.utils.Result;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.util.HashMap;
+
+/**
+ * <p>
+ * 艺人实名认证信息表 前端控制器
+ * </p>
+ *
+ * @author xiang
+ * @since 2025-11-24
+ */
+@RestController
+@RequestMapping("/artist")
+public class ArtistRealAuthController {
+    @Autowired
+    private IArtistRealAuthService artistRealAuthService;
+    @Autowired
+    private IArtistExternalInfoService artistExternalInfoService;
+
+    @GetMapping("/ArtistAuth")
+    @PreAuthorize("hasRole('ROLE_ADMIN')")
+    public Result<HashMap<String, Object>> ArtistAuth(@RequestParam Integer id){
+        ArtistRealAuth artistRealAuth = artistRealAuthService.lambdaQuery().eq(ArtistRealAuth::getArtistId, id).one();
+        ArtistExternalInfo one = artistExternalInfoService.lambdaQuery().eq(ArtistExternalInfo::getArtistId, id).one();
+        HashMap<String, Object> objectObjectHashMap = new HashMap<>();
+        objectObjectHashMap.put("artistRealAuth",artistRealAuth);
+        objectObjectHashMap.put("artistExternalInfo",one);
+        return Result.success(objectObjectHashMap);
+    }
+    @GetMapping("/ArtistAuthStatusUpdate")
+    @PreAuthorize("hasRole('ROLE_ADMIN')")
+    public Result ArtistAuthStatus(@RequestParam Integer id,@RequestParam Integer status){
+        artistRealAuthService.lambdaUpdate().eq(ArtistRealAuth::getId,id).set(ArtistRealAuth::getAuthStatus,status).update();
+        return Result.success("审核完毕");
+    }
+    @GetMapping("/ArtistAuthStatus")
+    @PreAuthorize("hasRole('ROLE_ADMIN')")
+    public Result ArtistAuthStatus(@RequestParam Integer id){
+        ArtistRealAuth artistRealAuth = artistRealAuthService.lambdaQuery().eq(ArtistRealAuth::getArtistId, id).select(ArtistRealAuth::getAuthStatus).one();
+        Integer authStatus = artistRealAuth.getAuthStatus();
+        return Result.success(authStatus);
+    }
+}

+ 32 - 0
artist/src/main/java/com/artist/domain/dto/MusicianApplicationDTO.java

@@ -0,0 +1,32 @@
+package com.artist.domain.dto;
+
+import lombok.Data;
+
+import java.time.LocalDate;
+@Data
+public class MusicianApplicationDTO {
+    private Boolean agreeFaceRecognition;
+    private Boolean agreeTerms;
+    private String artistName;
+    private String avatar;
+    private String headerImage;
+    private LocalDate birthday;
+    private String code;
+    private String company;
+    private String email;
+    private String platformAccount;
+    private String platformName;
+    private Long fanCount;
+    private String gender;
+    private String genre;
+    private String idCard;
+    private String introduction;
+    private String invitationCode;
+    private String nationality;
+    private String phone;
+    private String qrCode;
+    private String realName;
+    private String region;
+    private String termsContent;
+    private String wechat;
+}

+ 10 - 0
artist/src/main/java/com/artist/domain/dto/updateArtistStatusDto.java

@@ -0,0 +1,10 @@
+package com.artist.domain.dto;
+
+import lombok.Data;
+
+@Data
+public class updateArtistStatusDto {
+    private Integer id;
+    private Integer status;
+    private String reason;
+}

+ 236 - 0
artist/src/main/java/com/artist/domain/po/Artist.java

@@ -0,0 +1,236 @@
+package com.artist.domain.po;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+
+import java.io.Serializable;
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+
+/**
+ * <p>
+ * 艺人基础信息表
+ * </p>
+ *
+ * @author xiang
+ * @since 2025-11-18
+ */
+@TableName("artist")
+public class Artist implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    @TableId(value = "id", type = IdType.AUTO)
+    private Integer id;
+
+    /**
+     * 关联平台用户ID(对应user表id)
+     */
+    private Integer userId;
+
+    /**
+     * 艺人名
+     */
+    private String artistName;
+
+    /**
+     * 艺人头像URL
+     */
+    private String avatar;
+
+    /**
+     * 艺人页头图(网页端)URL
+     */
+    private String headerImage;
+
+    /**
+     * 性别:1-男,2-女,3-团体
+     */
+    private Integer gender;
+
+    /**
+     * 生日
+     */
+    private LocalDate birthday;
+
+    /**
+     * 艺人所属地区
+     */
+    private String region;
+
+    /**
+     * 流派风格(多个用逗号分隔,如流行,摇滚)
+     */
+    private String genre;
+
+    /**
+     * 所属公司/厂牌
+     */
+    private String company;
+
+    /**
+     * 艺人介绍(10-1000字)
+     */
+    private String introduction;
+
+    /**
+     * 邀请码
+     */
+    private String invitationCode;
+
+    /**
+     * 微信号
+     */
+    private String wechat;
+
+    /**
+     * 艺人账号状态:0-待审核,1-已通过,2-已拒绝,3-已冻结
+     */
+    private Integer status;
+
+    /**
+     * 创建时间
+     */
+    private LocalDateTime createTime;
+
+    /**
+     * 更新时间
+     */
+    private LocalDateTime updateTime;
+
+    public Integer getId() {
+        return id;
+    }
+
+    public void setId(Integer id) {
+        this.id = id;
+    }
+    public Integer getUserId() {
+        return userId;
+    }
+
+    public void setUserId(Integer userId) {
+        this.userId = userId;
+    }
+    public String getArtistName() {
+        return artistName;
+    }
+
+    public void setArtistName(String artistName) {
+        this.artistName = artistName;
+    }
+    public String getAvatar() {
+        return avatar;
+    }
+
+    public void setAvatar(String avatar) {
+        this.avatar = avatar;
+    }
+    public String getHeaderImage() {
+        return headerImage;
+    }
+
+    public void setHeaderImage(String headerImage) {
+        this.headerImage = headerImage;
+    }
+    public Integer getGender() {
+        return gender;
+    }
+
+    public void setGender(Integer gender) {
+        this.gender = gender;
+    }
+    public LocalDate getBirthday() {
+        return birthday;
+    }
+
+    public void setBirthday(LocalDate birthday) {
+        this.birthday = birthday;
+    }
+    public String getRegion() {
+        return region;
+    }
+
+    public void setRegion(String region) {
+        this.region = region;
+    }
+    public String getGenre() {
+        return genre;
+    }
+
+    public void setGenre(String genre) {
+        this.genre = genre;
+    }
+    public String getCompany() {
+        return company;
+    }
+
+    public void setCompany(String company) {
+        this.company = company;
+    }
+    public String getIntroduction() {
+        return introduction;
+    }
+
+    public void setIntroduction(String introduction) {
+        this.introduction = introduction;
+    }
+    public String getInvitationCode() {
+        return invitationCode;
+    }
+
+    public void setInvitationCode(String invitationCode) {
+        this.invitationCode = invitationCode;
+    }
+    public String getWechat() {
+        return wechat;
+    }
+
+    public void setWechat(String wechat) {
+        this.wechat = wechat;
+    }
+    public Integer getStatus() {
+        return status;
+    }
+
+    public void setStatus(Integer status) {
+        this.status = status;
+    }
+    public LocalDateTime getCreateTime() {
+        return createTime;
+    }
+
+    public void setCreateTime(LocalDateTime createTime) {
+        this.createTime = createTime;
+    }
+    public LocalDateTime getUpdateTime() {
+        return updateTime;
+    }
+
+    public void setUpdateTime(LocalDateTime updateTime) {
+        this.updateTime = updateTime;
+    }
+
+    @Override
+    public String toString() {
+        return "Artist{" +
+            "id=" + id +
+            ", userId=" + userId +
+            ", artistName=" + artistName +
+            ", avatar=" + avatar +
+            ", headerImage=" + headerImage +
+            ", gender=" + gender +
+            ", birthday=" + birthday +
+            ", region=" + region +
+            ", genre=" + genre +
+            ", company=" + company +
+            ", introduction=" + introduction +
+            ", invitationCode=" + invitationCode +
+            ", wechat=" + wechat +
+            ", status=" + status +
+            ", createTime=" + createTime +
+            ", updateTime=" + updateTime +
+        "}";
+    }
+}

+ 102 - 0
artist/src/main/java/com/artist/domain/po/ArtistAuditRecord.java

@@ -0,0 +1,102 @@
+package com.artist.domain.po;
+
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import java.time.LocalDateTime;
+import java.io.Serializable;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.experimental.Accessors;
+
+/**
+ * <p>
+ * 音乐人审核申请记录表
+ * </p>
+ *
+ * @author xiang
+ * @since 2025-12-09
+ */
+@Data
+@EqualsAndHashCode(callSuper = false)
+@Accessors(chain = true)
+@TableName("artist_audit_record")
+public class ArtistAuditRecord implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    @TableId(value = "id", type = IdType.AUTO)
+    private Integer id;
+
+    /**
+     * 关联auth服务的user.id(申请人,仅逻辑关联)
+     */
+    private Integer userId;
+
+    /**
+     * 冗余auth.user.username(审核人可直接查看)
+     */
+    private String userUsername;
+
+    /**
+     * 关联本服务的artist.id(已存在的艺人ID,可为空)
+     */
+    private Integer artistId;
+
+    /**
+     * 申请类型:1-新注册,2-信息修改,3-重新申请
+     */
+    private Integer applyType;
+
+    /**
+     * 申请原因(如:更新个人信息、重新提交认证材料等)
+     */
+    private String applyReason;
+
+    /**
+     * 申请时间
+     */
+    private LocalDateTime applyTime;
+
+    /**
+     * 审核状态:0-待审核,1-已通过,2-已驳回
+     */
+    private Integer auditStatus;
+
+    /**
+     * 审核结果(详细说明)
+     */
+    private String auditResult;
+
+    /**
+     * 驳回原因(详细说明)
+     */
+    private String rejectReason;
+
+    /**
+     * 审核时间
+     */
+    private LocalDateTime auditTime;
+
+    /**
+     * 关联auth服务的user.id(审核人,仅逻辑关联)
+     */
+    private Integer auditUserId;
+
+    /**
+     * 冗余auth.user.username(审核人姓名,便于追溯)
+     */
+    private String auditUsername;
+
+    /**
+     * 创建时间
+     */
+    private LocalDateTime createTime;
+
+    /**
+     * 更新时间
+     */
+    private LocalDateTime updateTime;
+
+
+}

+ 53 - 0
artist/src/main/java/com/artist/domain/po/ArtistExternalInfo.java

@@ -0,0 +1,53 @@
+package com.artist.domain.po;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.Data;
+
+import java.io.Serializable;
+import java.time.LocalDateTime;
+
+/**
+ * <p>
+ * 艺人站外社交平台信息表
+ * </p>
+ *
+ * @author xiang
+ * @since 2025-11-18
+ */
+@Data
+@TableName("artist_external_info")
+public class ArtistExternalInfo implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    @TableId(value = "id", type = IdType.AUTO)
+    private Integer id;
+
+    /**
+     * 关联艺人ID(对应artist表id)
+     */
+    private Integer artistId;
+
+    /**
+     * 站外平台名称(如微博、抖音、B站)
+     */
+    private String platformName;
+
+    /**
+     * 平台用户ID/URL/昵称
+     */
+    private String platformAccount;
+
+    /**
+     * 平台粉丝数
+     */
+    private Long fansCount;
+
+    private LocalDateTime createTime;
+
+    private LocalDateTime updateTime;
+
+
+}

+ 102 - 0
artist/src/main/java/com/artist/domain/po/ArtistMediaHistory.java

@@ -0,0 +1,102 @@
+package com.artist.domain.po;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+
+import java.io.Serializable;
+import java.time.LocalDateTime;
+
+/**
+ * <p>
+ * 艺人媒体文件历史记录表
+ * </p>
+ *
+ * @author xiang
+ * @since 2025-11-18
+ */
+@TableName("artist_media_history")
+public class ArtistMediaHistory implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    @TableId(value = "id", type = IdType.AUTO)
+    private Long id;
+
+    /**
+     * 关联艺人ID(对应artist表id)
+     */
+    private Integer artistId;
+
+    /**
+     * 媒体类型: avatar/header_image 等
+     */
+    private String mediaType;
+
+    /**
+     * 关联media_file表id
+     */
+    private Long mediaFileId;
+
+    /**
+     * 是否为当前使用版本:0-否,1-是
+     */
+    private Integer isCurrent;
+
+    private LocalDateTime createTime;
+
+    public Long getId() {
+        return id;
+    }
+
+    public void setId(Long id) {
+        this.id = id;
+    }
+    public Integer getArtistId() {
+        return artistId;
+    }
+
+    public void setArtistId(Integer artistId) {
+        this.artistId = artistId;
+    }
+    public String getMediaType() {
+        return mediaType;
+    }
+
+    public void setMediaType(String mediaType) {
+        this.mediaType = mediaType;
+    }
+    public Long getMediaFileId() {
+        return mediaFileId;
+    }
+
+    public void setMediaFileId(Long mediaFileId) {
+        this.mediaFileId = mediaFileId;
+    }
+    public Integer getIsCurrent() {
+        return isCurrent;
+    }
+
+    public void setIsCurrent(Integer isCurrent) {
+        this.isCurrent = isCurrent;
+    }
+    public LocalDateTime getCreateTime() {
+        return createTime;
+    }
+
+    public void setCreateTime(LocalDateTime createTime) {
+        this.createTime = createTime;
+    }
+
+    @Override
+    public String toString() {
+        return "ArtistMediaHistory{" +
+            "id=" + id +
+            ", artistId=" + artistId +
+            ", mediaType=" + mediaType +
+            ", mediaFileId=" + mediaFileId +
+            ", isCurrent=" + isCurrent +
+            ", createTime=" + createTime +
+        "}";
+    }
+}

+ 80 - 0
artist/src/main/java/com/artist/domain/po/ArtistRealAuth.java

@@ -0,0 +1,80 @@
+package com.artist.domain.po;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.Data;
+
+import java.io.Serializable;
+import java.time.LocalDateTime;
+
+/**
+ * <p>
+ * 艺人实名认证信息表
+ * </p>
+ *
+ * @author xiang
+ * @since 2025-11-18
+ */
+@TableName("artist_real_auth")
+@Data
+public class ArtistRealAuth implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    @TableId(value = "id", type = IdType.AUTO)
+    private Integer id;
+
+    /**
+     * 关联艺人ID(对应artist表id)
+     */
+    private Integer artistId;
+
+    /**
+     * 真实姓名
+     */
+    private String realName;
+
+    /**
+     * 绑定手机号
+     */
+    private String phone;
+
+    /**
+     * 邮箱
+     */
+    private String email;
+
+    /**
+     * 国籍/地区
+     */
+    private String nationality;
+
+    /**
+     * 证件号(建议加密存储)
+     */
+    private String idCard;
+
+    /**
+     * 面部识别状态:0-未认证,1-已认证
+     */
+    private Integer faceAuthStatus;
+
+    /**
+     * 实名认证状态:0-待审核,1-已通过,2-已驳回
+     */
+    private Integer authStatus;
+
+    /**
+     * 实名认证通过时间
+     */
+    private LocalDateTime authTime;
+
+    /**
+     * 证件号(建议加密存储)
+     */
+
+    private String authResult;
+
+    private LocalDateTime createTime;
+}

+ 62 - 0
artist/src/main/java/com/artist/domain/po/WyUser.java

@@ -0,0 +1,62 @@
+package com.artist.domain.po;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import lombok.Data;
+
+import java.io.Serializable;
+import java.time.LocalDateTime;
+@Data
+public class WyUser implements Serializable {
+        private static final long serialVersionUID = 1L;
+        /**
+         * 用户ID
+         */
+        @TableId(value = "id", type = IdType.AUTO)
+        private Integer id;
+
+        /**
+         * 账号
+         */
+        private String username;
+
+        /**
+         * 用户昵称
+         */
+        private String name;
+
+        /**
+         * 用户年龄
+         */
+        private Integer age;
+
+        /**
+         * 登录密码
+         */
+        private String password;
+
+        /**
+         * 用户头像URL
+         */
+        private String url;
+
+        /**
+         * VIP等级
+         */
+        private Integer vipLevel;
+
+        /**
+         * VIP状态
+         */
+        private Integer vipStatus;
+
+        /**
+         * 创建时间
+         */
+        private LocalDateTime createTime;
+
+        /**
+         * 最后登录时间
+         */
+        private LocalDateTime lastLoginTime;
+    }

+ 18 - 0
artist/src/main/java/com/artist/mapper/ArtistAuditRecordMapper.java

@@ -0,0 +1,18 @@
+package com.artist.mapper;
+
+import com.artist.domain.po.ArtistAuditRecord;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import org.apache.ibatis.annotations.Mapper;
+
+/**
+ * <p>
+ * 音乐人审核申请记录表 Mapper 接口
+ * </p>
+ *
+ * @author xiang
+ * @since 2025-12-09
+ */
+@Mapper
+public interface ArtistAuditRecordMapper extends BaseMapper<ArtistAuditRecord> {
+
+}

+ 18 - 0
artist/src/main/java/com/artist/mapper/ArtistExternalInfoMapper.java

@@ -0,0 +1,18 @@
+package com.artist.mapper;
+
+import com.artist.domain.po.ArtistExternalInfo;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import org.apache.ibatis.annotations.Mapper;
+
+/**
+ * <p>
+ * 艺人站外社交平台信息表 Mapper 接口
+ * </p>
+ *
+ * @author xiang
+ * @since 2025-11-24
+ */
+@Mapper
+public interface ArtistExternalInfoMapper extends BaseMapper<ArtistExternalInfo> {
+
+}

+ 48 - 0
artist/src/main/java/com/artist/mapper/ArtistMapper.java

@@ -0,0 +1,48 @@
+package com.artist.mapper;
+
+import com.artist.domain.dto.MusicianApplicationDTO;
+import com.artist.domain.po.Artist;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Param;
+import org.apache.ibatis.annotations.Select;
+
+/**
+ * <p>
+ * 艺人基础信息表 Mapper 接口
+ * </p>
+ *
+ * @author xiang
+ * @since 2025-11-24
+ */
+@Mapper
+public interface ArtistMapper extends BaseMapper<Artist> {
+    @Select({
+            "SELECT ",
+            "a.artist_name AS artistName, ",
+            "a.avatar AS avatar, ",
+            "a.header_image AS headerImage, ",
+            "a.birthday AS birthday, ",
+            "a.region AS region, ",
+            "a.genre AS genre, ",
+            "a.company AS company, ",
+            "a.introduction AS introduction, ",
+            "a.invitation_code AS invitationCode, ",
+            "a.wechat AS wechat, ",
+            "ara.real_name AS realName, ",
+            "ara.phone AS phone, ",
+            "ara.email AS email, ",
+            "ara.nationality AS nationality, ",
+            "ara.id_card AS idCard, ",
+            "ara.face_auth_status AS faceAuthStatus, ",
+            "aei.platform_name AS platformName, ",
+            "aei.platform_account AS platformAccount, ",
+            "aei.fans_count AS fanCount ",
+            "FROM artist a ",
+            "LEFT JOIN artist_real_auth ara ON a.id = ara.artist_id ",
+            "LEFT JOIN artist_external_info aei ON a.id = aei.artist_id ",
+            "WHERE a.user_id = #{userId}"
+    })
+    MusicianApplicationDTO getArtistApplicationInfoByUserId(@Param("userId") Integer userId);
+
+}

+ 18 - 0
artist/src/main/java/com/artist/mapper/ArtistMediaHistoryMapper.java

@@ -0,0 +1,18 @@
+package com.artist.mapper;
+
+import com.artist.domain.po.ArtistMediaHistory;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import org.apache.ibatis.annotations.Mapper;
+
+/**
+ * <p>
+ * 艺人媒体文件历史记录表 Mapper 接口
+ * </p>
+ *
+ * @author xiang
+ * @since 2025-11-24
+ */
+@Mapper
+public interface ArtistMediaHistoryMapper extends BaseMapper<ArtistMediaHistory> {
+
+}

+ 18 - 0
artist/src/main/java/com/artist/mapper/ArtistRealAuthMapper.java

@@ -0,0 +1,18 @@
+package com.artist.mapper;
+
+import com.artist.domain.po.ArtistRealAuth;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import org.apache.ibatis.annotations.Mapper;
+
+/**
+ * <p>
+ * 艺人实名认证信息表 Mapper 接口
+ * </p>
+ *
+ * @author xiang
+ * @since 2025-11-24
+ */
+@Mapper
+public interface ArtistRealAuthMapper extends BaseMapper<ArtistRealAuth> {
+
+}

+ 16 - 0
artist/src/main/java/com/artist/service/IArtistAuditRecordService.java

@@ -0,0 +1,16 @@
+package com.artist.service;
+
+import com.artist.domain.po.ArtistAuditRecord;
+import com.baomidou.mybatisplus.extension.service.IService;
+
+/**
+ * <p>
+ * 音乐人审核申请记录表 服务类
+ * </p>
+ *
+ * @author xiang
+ * @since 2025-12-09
+ */
+public interface IArtistAuditRecordService extends IService<ArtistAuditRecord> {
+
+}

+ 16 - 0
artist/src/main/java/com/artist/service/IArtistExternalInfoService.java

@@ -0,0 +1,16 @@
+package com.artist.service;
+
+import com.artist.domain.po.ArtistExternalInfo;
+import com.baomidou.mybatisplus.extension.service.IService;
+
+/**
+ * <p>
+ * 艺人站外社交平台信息表 服务类
+ * </p>
+ *
+ * @author xiang
+ * @since 2025-11-24
+ */
+public interface IArtistExternalInfoService extends IService<ArtistExternalInfo> {
+
+}

+ 16 - 0
artist/src/main/java/com/artist/service/IArtistMediaHistoryService.java

@@ -0,0 +1,16 @@
+package com.artist.service;
+
+import com.artist.domain.po.ArtistMediaHistory;
+import com.baomidou.mybatisplus.extension.service.IService;
+
+/**
+ * <p>
+ * 艺人媒体文件历史记录表 服务类
+ * </p>
+ *
+ * @author xiang
+ * @since 2025-11-24
+ */
+public interface IArtistMediaHistoryService extends IService<ArtistMediaHistory> {
+
+}

+ 16 - 0
artist/src/main/java/com/artist/service/IArtistRealAuthService.java

@@ -0,0 +1,16 @@
+package com.artist.service;
+
+import com.artist.domain.po.ArtistRealAuth;
+import com.baomidou.mybatisplus.extension.service.IService;
+
+/**
+ * <p>
+ * 艺人实名认证信息表 服务类
+ * </p>
+ *
+ * @author xiang
+ * @since 2025-11-24
+ */
+public interface IArtistRealAuthService extends IService<ArtistRealAuth> {
+
+}

+ 23 - 0
artist/src/main/java/com/artist/service/IArtistService.java

@@ -0,0 +1,23 @@
+package com.artist.service;
+
+import com.artist.domain.dto.MusicianApplicationDTO;
+import com.artist.domain.po.Artist;
+import com.baomidou.mybatisplus.extension.service.IService;
+
+/**
+ * <p>
+ * 艺人基础信息表 服务类
+ * </p>
+ *
+ * @author xiang
+ * @since 2025-11-24
+ */
+public interface IArtistService extends IService<Artist> {
+    void applyMusician(MusicianApplicationDTO musicianApplicationDTO);
+
+    Artist applyStatus(Integer userid);
+
+    void updateArtistApply(Integer id, Integer status, String reason);
+
+    MusicianApplicationDTO getMusicianApplicationInfo(Integer userId);
+}

+ 20 - 0
artist/src/main/java/com/artist/service/impl/ArtistAuditRecordServiceImpl.java

@@ -0,0 +1,20 @@
+package com.artist.service.impl;
+
+import com.artist.domain.po.ArtistAuditRecord;
+import com.artist.mapper.ArtistAuditRecordMapper;
+import com.artist.service.IArtistAuditRecordService;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import org.springframework.stereotype.Service;
+
+/**
+ * <p>
+ * 音乐人审核申请记录表 服务实现类
+ * </p>
+ *
+ * @author xiang
+ * @since 2025-12-09
+ */
+@Service
+public class ArtistAuditRecordServiceImpl extends ServiceImpl<ArtistAuditRecordMapper, ArtistAuditRecord> implements IArtistAuditRecordService {
+
+}

+ 20 - 0
artist/src/main/java/com/artist/service/impl/ArtistExternalInfoServiceImpl.java

@@ -0,0 +1,20 @@
+package com.artist.service.impl;
+
+import com.artist.domain.po.ArtistExternalInfo;
+import com.artist.mapper.ArtistExternalInfoMapper;
+import com.artist.service.IArtistExternalInfoService;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import org.springframework.stereotype.Service;
+
+/**
+ * <p>
+ * 艺人站外社交平台信息表 服务实现类
+ * </p>
+ *
+ * @author xiang
+ * @since 2025-11-24
+ */
+@Service
+public class ArtistExternalInfoServiceImpl extends ServiceImpl<ArtistExternalInfoMapper, ArtistExternalInfo> implements IArtistExternalInfoService {
+
+}

+ 20 - 0
artist/src/main/java/com/artist/service/impl/ArtistMediaHistoryServiceImpl.java

@@ -0,0 +1,20 @@
+package com.artist.service.impl;
+
+import com.artist.domain.po.ArtistMediaHistory;
+import com.artist.mapper.ArtistMediaHistoryMapper;
+import com.artist.service.IArtistMediaHistoryService;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import org.springframework.stereotype.Service;
+
+/**
+ * <p>
+ * 艺人媒体文件历史记录表 服务实现类
+ * </p>
+ *
+ * @author xiang
+ * @since 2025-11-24
+ */
+@Service
+public class ArtistMediaHistoryServiceImpl extends ServiceImpl<ArtistMediaHistoryMapper, ArtistMediaHistory> implements IArtistMediaHistoryService {
+
+}

+ 20 - 0
artist/src/main/java/com/artist/service/impl/ArtistRealAuthServiceImpl.java

@@ -0,0 +1,20 @@
+package com.artist.service.impl;
+
+import com.artist.domain.po.ArtistRealAuth;
+import com.artist.mapper.ArtistRealAuthMapper;
+import com.artist.service.IArtistRealAuthService;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import org.springframework.stereotype.Service;
+
+/**
+ * <p>
+ * 艺人实名认证信息表 服务实现类
+ * </p>
+ *
+ * @author xiang
+ * @since 2025-11-24
+ */
+@Service
+public class ArtistRealAuthServiceImpl extends ServiceImpl<ArtistRealAuthMapper, ArtistRealAuth> implements IArtistRealAuthService {
+
+}

+ 170 - 0
artist/src/main/java/com/artist/service/impl/ArtistServiceImpl.java

@@ -0,0 +1,170 @@
+package com.artist.service.impl;
+
+import com.alibaba.fastjson.JSON;
+import com.artist.domain.dto.MusicianApplicationDTO;
+import com.artist.domain.po.*;
+import com.artist.mapper.ArtistMapper;
+import com.artist.service.IArtistAuditRecordService;
+import com.artist.service.IArtistExternalInfoService;
+import com.artist.service.IArtistRealAuthService;
+import com.artist.service.IArtistService;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.base.exception.WyMusicException;
+import com.base.utils.Result;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.BeanUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.core.context.SecurityContextHolder;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.time.LocalDateTime;
+import java.util.Date;
+
+/**
+ * <p>
+ * 艺人基础信息表 服务实现类
+ * </p>
+ *
+ * @author xiang
+ * @since 2025-11-24
+ */
+@Slf4j
+@Service
+public class ArtistServiceImpl extends ServiceImpl<ArtistMapper, Artist> implements IArtistService {
+    @Autowired
+    private IArtistRealAuthService iArtistRealAuthService;
+
+    @Autowired
+    private IArtistExternalInfoService iArtistExternalInfoService;
+
+    @Autowired
+    private ArtistMapper artistMapper;
+
+    @Autowired
+    private IArtistAuditRecordService iArtistAuditRecordService;
+    @Autowired
+    private IArtistService iArtistApplyService;
+    @Override
+    @Transactional
+    public void applyMusician(MusicianApplicationDTO musicianApplicationDTO) {
+        Object principalObj = SecurityContextHolder.getContext().getAuthentication().getPrincipal();
+        Integer userId = null;
+        WyUser wyUser = null;
+
+        if (principalObj instanceof String) {
+            String principal = principalObj.toString();
+            wyUser = JSON.parseObject(principal, WyUser.class);
+            userId = wyUser.getId();
+        }
+
+        // 检查用户是否已有艺人信息
+        Artist existingArtist = this.lambdaQuery().eq(Artist::getUserId, userId).one();
+
+        if (existingArtist != null) {
+            // 更新现有艺人信息
+            updateExistingArtist(existingArtist, musicianApplicationDTO, userId);
+        } else {
+            // 创建新艺人
+            createNewArtist(musicianApplicationDTO, userId, wyUser);
+        }
+    }
+
+    private void updateExistingArtist(Artist existingArtist, MusicianApplicationDTO dto, Integer userId) {
+        // 更新基础信息
+        LocalDateTime now = LocalDateTime.now();
+        BeanUtils.copyProperties(dto, existingArtist);
+        existingArtist.setUpdateTime(now);
+        existingArtist.setStatus(0);
+        this.updateById(existingArtist);
+
+        // 更新实名认证信息
+        ArtistRealAuth realAuth = iArtistRealAuthService.lambdaQuery()
+                .eq(ArtistRealAuth::getArtistId, existingArtist.getId())
+                .one();
+
+        if (realAuth != null) {
+            BeanUtils.copyProperties(dto, realAuth);
+            iArtistRealAuthService.updateById(realAuth);
+        }
+
+        // 更新外部平台信息
+        ArtistExternalInfo externalInfo = iArtistExternalInfoService.lambdaQuery()
+                .eq(ArtistExternalInfo::getArtistId, existingArtist.getId())
+                .one();
+
+        if (externalInfo != null) {
+            BeanUtils.copyProperties(dto, externalInfo);
+            externalInfo.setUpdateTime(now);
+            iArtistExternalInfoService.updateById(externalInfo);
+        }
+
+        // 更新审核记录
+        ArtistAuditRecord auditRecord = iArtistAuditRecordService.lambdaQuery()
+                .eq(ArtistAuditRecord::getArtistId, existingArtist.getId())
+                .one();
+
+        if (auditRecord != null) {
+            auditRecord.setApplyType(2); // 信息修改
+            auditRecord.setApplyTime(now);
+
+            auditRecord.setAuditStatus(0); // 重新进入待审核状态
+            iArtistAuditRecordService.updateById(auditRecord);
+        }
+    }
+
+    private void createNewArtist(MusicianApplicationDTO dto, Integer userId, WyUser wyUser) {
+        // 创建新艺人
+        Artist artist = new Artist();
+        BeanUtils.copyProperties(dto, artist);
+        artist.setUserId(userId);
+        artist.setStatus(0); // 待审核状态
+        this.save(artist);
+
+        // 创建实名认证信息
+        ArtistRealAuth realAuth = new ArtistRealAuth();
+        BeanUtils.copyProperties(dto, realAuth);
+        realAuth.setArtistId(artist.getId());
+        iArtistRealAuthService.save(realAuth);
+
+        // 创建外部平台信息
+        ArtistExternalInfo externalInfo = new ArtistExternalInfo();
+        BeanUtils.copyProperties(dto, externalInfo);
+        externalInfo.setArtistId(artist.getId());
+        iArtistExternalInfoService.save(externalInfo);
+
+        // 创建审核记录
+        ArtistAuditRecord auditRecord = new ArtistAuditRecord();
+        auditRecord.setUserId(userId);
+        auditRecord.setUserUsername(wyUser.getUsername());
+        auditRecord.setArtistId(artist.getId());
+        auditRecord.setApplyType(1); // 新注册
+        auditRecord.setAuditStatus(0); // 待审核
+        iArtistAuditRecordService.save(auditRecord);
+    }
+
+    @Override
+    public Artist applyStatus(Integer userid) {
+        Artist one = this.lambdaQuery().eq(Artist::getUserId, userid).one();
+        System.out.println("one = " + one);
+        return one;
+    }
+    @Transactional
+    @Override
+    public void updateArtistApply(Integer id, Integer status, String reason) {
+        try {
+            iArtistApplyService.lambdaUpdate().eq(Artist::getId, id).set(Artist::getStatus, status).update();
+            iArtistAuditRecordService.lambdaUpdate().
+                    eq(ArtistAuditRecord::getArtistId, id)
+                    .set(ArtistAuditRecord::getAuditStatus, status)
+                    .set(ArtistAuditRecord::getRejectReason, reason).update();
+        } catch (Exception e) {
+            log.error("更新失败:{}",e);
+            throw new WyMusicException("更新失败");
+        }
+
+    }
+    public MusicianApplicationDTO getMusicianApplicationInfo(Integer userId) {
+        return artistMapper.getArtistApplicationInfoByUserId(userId);
+    }
+}

+ 23 - 0
artist/src/main/resources/bootstrap.yml

@@ -0,0 +1,23 @@
+spring:
+  application:
+    name: artist
+  cloud:
+    nacos:
+      server-addr: 117.72.120.45:8848
+      discovery:
+        namespace: wy-music-dev
+        group: wy-music
+      config:
+        namespace: wy-music-dev
+        group: wy-music
+        file-extension: yaml
+        refresh-enabled: true
+        shared-configs:
+          - data-id: wy-music-artist-${spring.profiles.active}.yaml
+            group: wy-music
+            refresh: true
+          - data-id: wy-music-common-${spring.profiles.active}.yaml
+            group: wy-music
+            refresh: true
+  profiles:
+    active: dev

+ 5 - 0
artist/src/main/resources/mapper/AlbumMapper.xml

@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.artist.mapper.AlbumMapper">
+
+</mapper>

+ 5 - 0
artist/src/main/resources/mapper/ArtistAuditRecordMapper.xml

@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.artist.mapper.ArtistAuditRecordMapper">
+
+</mapper>

+ 5 - 0
artist/src/main/resources/mapper/ArtistExternalInfoMapper.xml

@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.artist.mapper.ArtistExternalInfoMapper">
+
+</mapper>

+ 5 - 0
artist/src/main/resources/mapper/ArtistMapper.xml

@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.artist.mapper.ArtistMapper">
+
+</mapper>

+ 5 - 0
artist/src/main/resources/mapper/ArtistMediaHistoryMapper.xml

@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.artist.mapper.ArtistMediaHistoryMapper">
+
+</mapper>

+ 5 - 0
artist/src/main/resources/mapper/ArtistRealAuthMapper.xml

@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.artist.mapper.ArtistRealAuthMapper">
+
+</mapper>

+ 24 - 0
auth/auth.sql

@@ -0,0 +1,24 @@
+CREATE DATABASE IF NOT EXISTS wy_auth DEFAULT CHARSET utf8mb4 COLLATE utf8mb4_unicode_ci;
+USE wy_auth;
+
+-- 修正后的用户表(匹配PO类字段)
+CREATE TABLE `user` (
+                        `id` BIGINT AUTO_INCREMENT PRIMARY KEY COMMENT '用户ID',
+                        `username` VARCHAR(50) NOT NULL COMMENT '账号(唯一,用于登录)',
+                        `name` VARCHAR(50) COMMENT '用户昵称(冗余,兼容PO)',
+                        `age` INT COMMENT '用户年龄',
+                        `password` VARCHAR(100) NOT NULL COMMENT '登录密码(建议BCrypt加密)',
+                        `url` VARCHAR(500) COMMENT '用户头像URL',
+                        `vip_level` INT DEFAULT 0 COMMENT 'VIP等级',
+                        `vip_status` INT DEFAULT 0 COMMENT 'VIP状态(0-非VIP,1-VIP)',
+                        `create_time` DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
+                        `last_login_time` DATETIME COMMENT '最后登录时间',
+                        `nickname` VARCHAR(50) COMMENT '用户昵称(用于展示)',
+                        `wx_unionid` VARCHAR(100) COMMENT '微信unionid',
+                        `utype` VARCHAR(20) DEFAULT 'normal' COMMENT '用户类型(normal-普通用户,admin-管理员,artist-艺人)',
+                        `status` VARCHAR(20) DEFAULT 'normal' COMMENT '用户状态(normal-正常,forbid-禁用,freeze-冻结)',
+                        `phone` VARCHAR(20) COMMENT '手机号(唯一)',
+                        UNIQUE KEY `uk_username` (`username`),
+                        UNIQUE KEY `uk_phone` (`phone`),
+                        UNIQUE KEY `uk_wx_unionid` (`wx_unionid`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户基础信息表';ad

+ 63 - 0
auth/src/main/java/com/auth/config/AuthorizationServer.java

@@ -0,0 +1,63 @@
+package com.auth.config;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.http.HttpMethod;
+import org.springframework.security.authentication.AuthenticationManager;
+import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
+import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer;
+import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter;
+import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer;
+import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerEndpointsConfigurer;
+import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerSecurityConfigurer;
+import org.springframework.security.oauth2.provider.token.AuthorizationServerTokenServices;
+import org.springframework.security.oauth2.provider.token.DefaultTokenServices;
+
+import javax.annotation.Resource;
+/**
+ * @author Mr.M
+ * @version 1.0
+ * @description 授权服务器配置
+ * @date 2022/9/26 22:25
+ */
+@Configuration
+@EnableAuthorizationServer
+public class AuthorizationServer extends AuthorizationServerConfigurerAdapter {
+    @Resource(name = "authorizationServerTokenServicesCustom")
+    private AuthorizationServerTokenServices authorizationServerTokenServices;
+    @Autowired
+    private AuthenticationManager authenticationManager;
+    //客户端详情服务
+    @Override
+    public void configure(ClientDetailsServiceConfigurer clients)
+            throws Exception {
+        clients.inMemory()// 使用in-memory存储
+                .withClient("wyMusic")// client_id
+//                .secret("wyMusic")//客户端密钥
+                .secret(new BCryptPasswordEncoder().encode("wyMusic"))//客户端密钥
+                .resourceIds("wy-music")//资源列表
+                .authorizedGrantTypes("authorization_code", "password", "client_credentials", "implicit", "refresh_token")// 该client允许的授权类型authorization_code,password,refresh_token,implicit,client_credentials
+                .scopes("all")// 允许的授权范围
+                .autoApprove(false)//false跳转到授权页面
+                //客户端接收授权码的重定向地址
+                .redirectUris("http://localhost:5173/find/recommend")
+        ;
+    }
+    //令牌端点的访问配置
+    @Override
+    public void configure(AuthorizationServerEndpointsConfigurer endpoints) {
+        endpoints
+                .authenticationManager(authenticationManager)//认证管理器
+                .tokenServices(authorizationServerTokenServices)//令牌管理服务
+                .allowedTokenEndpointRequestMethods(HttpMethod.POST);
+    }
+    //令牌端点的安全配置
+    @Override
+    public void configure(AuthorizationServerSecurityConfigurer security) {
+        security
+                .tokenKeyAccess("permitAll()")                    //oauth/token_key是公开
+                .checkTokenAccess("permitAll()")                  //oauth/check_token公开
+                .allowFormAuthenticationForClients()                //表单认证(申请令牌)
+        ;
+    }
+}

+ 34 - 0
auth/src/main/java/com/auth/config/CustomTokenEnhancer.java

@@ -0,0 +1,34 @@
+package com.auth.config;
+import com.alibaba.fastjson.JSON;
+import org.springframework.security.oauth2.common.DefaultOAuth2AccessToken;
+import org.springframework.security.oauth2.common.OAuth2AccessToken;
+import org.springframework.security.oauth2.provider.OAuth2Authentication;
+import org.springframework.security.oauth2.provider.token.TokenEnhancer;
+import org.springframework.stereotype.Component;
+
+import java.util.HashMap;
+import java.util.Map;
+@Component
+public class CustomTokenEnhancer implements TokenEnhancer {
+    @Override
+    public OAuth2AccessToken enhance(OAuth2AccessToken accessToken, OAuth2Authentication authentication) {
+        // 获取用户信息
+        Object principal = authentication.getPrincipal();
+        if (principal instanceof org.springframework.security.core.userdetails.User) {
+            org.springframework.security.core.userdetails.User userDetail = 
+                (org.springframework.security.core.userdetails.User) principal;
+            try {
+                // 用户信息在 UserDetails.username 中以 JSON 形式存储
+                String userJsonStr = userDetail.getUsername();
+                Map<String, Object> userInfo = JSON.parseObject(userJsonStr, Map.class);
+                // 添加用户信息到额外信息中
+                Map<String, Object> additionalInfo = new HashMap<>();
+                additionalInfo.put("userinfo", userInfo);
+                ((DefaultOAuth2AccessToken) accessToken).setAdditionalInformation(additionalInfo);
+            } catch (Exception e) {
+                // 解析失败则不添加用户信息
+            }
+        }
+        return accessToken;
+    }
+}

+ 27 - 0
auth/src/main/java/com/auth/config/DaoAuthenticationProviderCustom.java

@@ -0,0 +1,27 @@
+package com.auth.config;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.authentication.BadCredentialsException;
+import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
+import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
+import org.springframework.security.core.AuthenticationException;
+import org.springframework.security.core.userdetails.UserDetails;
+import org.springframework.security.core.userdetails.UserDetailsService;
+import org.springframework.stereotype.Component;
+/**
+ * @description 自定义DaoAuthenticationProvider
+ * @author Mr.M
+ * @date 2022/9/29 10:31
+ * @version 1.0
+ */
+@Slf4j
+@Component
+public class DaoAuthenticationProviderCustom extends DaoAuthenticationProvider {
+    @Autowired
+    public void setUserDetailsService(UserDetailsService userDetailsService) {
+        super.setUserDetailsService(userDetailsService);
+    }
+    //屏蔽密码对比
+    protected void additionalAuthenticationChecks(UserDetails userDetails, UsernamePasswordAuthenticationToken authentication) throws AuthenticationException {
+    }
+}

+ 54 - 0
auth/src/main/java/com/auth/config/TokenConfig.java

@@ -0,0 +1,54 @@
+// TokenConfig.java
+package com.auth.config;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.security.oauth2.provider.token.AuthorizationServerTokenServices;
+import org.springframework.security.oauth2.provider.token.DefaultTokenServices;
+import org.springframework.security.oauth2.provider.token.TokenEnhancerChain;
+import org.springframework.security.oauth2.provider.token.TokenStore;
+import org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter;
+import org.springframework.security.oauth2.provider.token.store.JwtTokenStore;
+
+import java.util.Arrays;
+
+@Configuration
+public class TokenConfig {
+    private String SIGNING_KEY = "wy_music_token";
+
+    @Autowired
+    private JwtAccessTokenConverter accessTokenConverter;
+
+    @Autowired
+    private CustomTokenEnhancer customTokenEnhancer; // 注入自定义TokenEnhancer
+
+    @Bean
+    public TokenStore tokenStore() {
+        return new JwtTokenStore(accessTokenConverter());
+    }
+
+    @Bean
+    public JwtAccessTokenConverter accessTokenConverter() {
+        JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
+        converter.setSigningKey(SIGNING_KEY);
+        return converter;
+    }
+
+    // 令牌管理服务
+    @Bean(name="authorizationServerTokenServicesCustom")
+    public AuthorizationServerTokenServices tokenService() {
+        DefaultTokenServices service=new DefaultTokenServices();
+        service.setSupportRefreshToken(true); // 支持刷新令牌
+        service.setTokenStore(tokenStore()); // 令牌存储策略
+
+        TokenEnhancerChain tokenEnhancerChain = new TokenEnhancerChain();
+        // 将自定义TokenEnhancer加入到链中,注意顺序很重要
+        tokenEnhancerChain.setTokenEnhancers(Arrays.asList(customTokenEnhancer, accessTokenConverter));
+        service.setTokenEnhancer(tokenEnhancerChain);
+
+        service.setAccessTokenValiditySeconds(7200); // 令牌默认有效期2小时
+        service.setRefreshTokenValiditySeconds(259200); // 刷新令牌默认有效期3天
+        return service;
+    }
+}

+ 71 - 0
auth/src/main/java/com/auth/config/WebSecurityConfig.java

@@ -0,0 +1,71 @@
+package com.auth.config;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Bean;
+import org.springframework.security.authentication.AuthenticationManager;
+import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
+import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
+import org.springframework.security.config.annotation.web.builders.HttpSecurity;
+import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
+import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
+import org.springframework.security.core.userdetails.User;
+import org.springframework.security.core.userdetails.UserDetailsService;
+import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
+import org.springframework.security.crypto.password.NoOpPasswordEncoder;
+import org.springframework.security.crypto.password.PasswordEncoder;
+import org.springframework.security.provisioning.InMemoryUserDetailsManager;
+import org.springframework.web.client.RestTemplate;
+
+/**
+ * @author Mr.M
+ * @version 1.0
+ * @description 安全管理配置
+ * @date 2022/9/26 20:53
+ */
+@EnableWebSecurity
+@EnableGlobalMethodSecurity(securedEnabled = true,prePostEnabled = true)
+public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
+    @Bean
+    public PasswordEncoder passwordEncoder() {
+//        //密码为明文方式
+//        return NoOpPasswordEncoder.getInstance();
+        return new BCryptPasswordEncoder();
+    }
+    @Autowired
+    DaoAuthenticationProviderCustom daoAuthenticationProviderCustom;
+    //配置安全拦截机制
+    @Override
+    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
+        auth.authenticationProvider(daoAuthenticationProviderCustom);
+    }
+    @Override
+    protected void configure(HttpSecurity http) throws Exception {
+        http .csrf().disable()
+                .authorizeRequests()
+//                .antMatchers("/r/**").authenticated()//访问/r开始的请求需要认证通过
+                .antMatchers("/github", "/login/**", "/error").permitAll()
+                .anyRequest().permitAll()//其它请求全部放行
+                .and()
+                .formLogin().successForwardUrl("/login-success")
+        ;//登录成功跳转到/login-success
+    }
+    @Bean
+    public AuthenticationManager authenticationManagerBean() throws Exception {
+        return super.authenticationManagerBean();
+    }
+    public static void main(String[] args) {
+        String password = "admin";
+        PasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
+        for(int i=0;i<10;i++) {
+            //每个计算出的Hash值都不一样
+            String hashPass = passwordEncoder.encode(password);
+            System.out.println(hashPass);
+            //虽然每次计算的密码Hash值不一样但是校验是通过的
+            boolean f = passwordEncoder.matches(password, hashPass);
+            System.out.println(f);
+        }
+    }
+    @Bean
+    public RestTemplate restTemplate() {
+        return new RestTemplate();
+    }
+}

+ 34 - 0
auth/src/main/java/com/auth/controller/GiteeLoginController.java

@@ -0,0 +1,34 @@
+package com.auth.controller;
+
+import com.auth.service.GiteeAuthService;
+import com.base.exception.WyMusicException;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RestController;
+import java.util.Map;
+
+@RestController
+public class GiteeLoginController {
+
+    @Autowired
+    GiteeAuthService giteeAuthService;
+
+    @PostMapping(value = "/auth/gitee")
+    public Map<String, Object> giteeLogin(@RequestBody Map<String, String> params) {
+        String code = params.get("code");
+        if (code == null || code.trim().isEmpty()) {
+            WyMusicException.cast("Gitee授权码为空");
+        }
+        try {
+            Map<String, Object> tokenInfo = giteeAuthService.giteeAuth(code);
+            if (tokenInfo == null || tokenInfo.isEmpty()) {
+                WyMusicException.cast("Gitee用户认证失败");
+            }
+            return tokenInfo;
+        } catch (Exception e) {
+            WyMusicException.cast("Gitee登录异常: " + e.getMessage());
+            return null; // 这行不会执行,因为上面会抛出异常
+        }
+    }
+}

+ 42 - 0
auth/src/main/java/com/auth/controller/WxLoginController.java

@@ -0,0 +1,42 @@
+package com.auth.controller;
+
+import com.auth.service.WxAuthService;
+import com.base.exception.WyMusicException;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+import java.util.Map;
+
+/**
+ * @author Mr.M
+ * @version 1.0
+ * @description 微信登录控制器
+ * @date 2023/2/24 15:13
+ */
+@RestController
+public class WxLoginController {
+
+    @Autowired
+    WxAuthService wxAuthService;
+
+    @RequestMapping("/auth/wxLogin")
+    public Map<String, Object> wxLogin(String code, String state) {
+
+        if (code == null || code.trim().isEmpty()) {
+            WyMusicException.cast("微信授权码为空");
+        }
+
+        try {
+            //远程调用微信请令牌,拿到令牌查询用户信息,将用户信息写入本项目数据库
+            Map<String, Object> tokenInfo = wxAuthService.wxAuth(code);
+            if (tokenInfo == null || tokenInfo.isEmpty()) {
+                WyMusicException.cast("微信用户认证失败");
+            }
+
+            return tokenInfo;
+        } catch (Exception e) {
+            WyMusicException.cast("微信登录异常: " + e.getMessage());
+            return null; // 这行不会执行,因为上面会抛出异常
+        }
+    }
+}

+ 81 - 0
auth/src/main/java/com/auth/domain/po/User.java

@@ -0,0 +1,81 @@
+package com.auth.domain.po;
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import java.time.LocalDateTime;
+import java.io.Serializable;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.experimental.Accessors;
+@Data
+@EqualsAndHashCode(callSuper = false)
+@Accessors(chain = true)
+@TableName("user")
+public class User implements Serializable {
+    private static final long serialVersionUID = 1L;
+    /**
+     * 用户ID
+     */
+    @TableId(value = "id", type = IdType.AUTO)
+    private Long id;
+    /**
+     * 账号
+     */
+    private String username;
+    /**
+     * 用户昵称
+     */
+    private String name;
+    /**
+     * 用户年龄
+     */
+    private Integer age;
+    /**
+     * 登录密码
+     */
+    private String password;
+    /**
+     * 用户头像URL
+     */
+    private String url;
+    /**
+     * VIP等级
+     */
+    private Integer vipLevel;
+    /**
+     * VIP状态
+     */
+    private Integer vipStatus;
+    /**
+     * 创建时间
+     */
+    private LocalDateTime createTime;
+    /**
+     * 最后登录时间
+     */
+    private LocalDateTime lastLoginTime;
+    /**
+     * 用户昵称(用于展示)
+     */
+    private String nickname;
+
+    /**
+     * 微信unionid,用于微信平台用户唯一标识
+     */
+    private String wxUnionid;
+
+    /**
+     * 用户类型,如:普通用户、管理员、VIP等
+     */
+    private Integer role;
+
+    /**
+     * 用户状态,如:正常、禁用、冻结等
+     */
+    private String status;
+
+    /**
+     * 手机号
+     */
+    private String phone;
+}

+ 18 - 0
auth/src/main/java/com/auth/mapper/UserMapper.java

@@ -0,0 +1,18 @@
+package com.auth.mapper;
+
+import com.auth.domain.po.User;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import org.apache.ibatis.annotations.Mapper;
+
+/**
+ * <p>
+ * 用户表 Mapper 接口
+ * </p>
+ *
+ * @author xiang
+ * @since 2025-10-31
+ */
+@Mapper
+public interface UserMapper extends BaseMapper<User> {
+
+}

+ 15 - 0
auth/src/main/java/com/auth/model/dto/AuthParamsDto.java

@@ -0,0 +1,15 @@
+package com.auth.model.dto;
+import lombok.Data;
+import java.util.HashMap;
+import java.util.Map;
+@Data
+public class AuthParamsDto {
+    private String username; //用户名
+    private String password; //域  用于扩展
+    private String cellphone;//手机号
+    private String checkcode;//验证码
+    private String checkcodekey;//验证码key
+    private String authType; // 认证的类型   password:用户名密码模式类型    sms:短信模式类型
+    private Map<String, Object> payload = new HashMap<>();
+    //附加数据,作为扩展,不同认证类型可拥有不同的附加数据。如认证类型为短信时包含smsKey : sms:3d21042d054548b08477142bbca95cfa; 所有情况下都包含clientId
+}

+ 17 - 0
auth/src/main/java/com/auth/model/dto/UserExt.java

@@ -0,0 +1,17 @@
+package com.auth.model.dto;
+import com.auth.domain.po.User;
+import lombok.Data;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * @description 用户扩展信息
+ * @author Mr.M
+ * @date 2022/9/30 13:56
+ * @version 1.0
+ */
+@Data
+public class UserExt extends User {
+    private String[] authorities;
+}

+ 21 - 0
auth/src/main/java/com/auth/service/AuthService.java

@@ -0,0 +1,21 @@
+package com.auth.service;
+import com.auth.model.dto.AuthParamsDto;
+import com.auth.model.dto.UserExt;
+/**
+ * @author Mr.M
+ * @version 1.0
+ * @description 统一的认证接口
+ * @date 2023/2/24 11:55
+ */
+public interface AuthService {
+
+ /**
+  * @description 认证方法
+  * @param authParamsDto 认证参数
+  * @return com.xuecheng.ucenter.model.po.XcUser 用户信息
+  * @author Mr.M
+  * @date 2022/9/29 12:11
+  */
+ UserExt execute(AuthParamsDto authParamsDto);
+
+}

+ 20 - 0
auth/src/main/java/com/auth/service/GiteeAuthService.java

@@ -0,0 +1,20 @@
+// auth/src/main/java/com/auth/service/GiteeAuthService.java
+package com.auth.service;
+
+import java.util.Map;
+
+/**
+ * @author 
+ * @version 1.0
+ * @description Gitee认证服务
+ */
+public interface GiteeAuthService {
+    /**
+     * Gitee认证,申请令牌,携带令牌查询用户信息、保存用户信息到数据库
+     * @param code 授权码
+     * @return OAuth2 token信息
+     */
+    public Map<String, Object> giteeAuth(String code);
+}
+
+

+ 16 - 0
auth/src/main/java/com/auth/service/IUserService.java

@@ -0,0 +1,16 @@
+package com.auth.service;
+
+import com.auth.domain.po.User;
+import com.baomidou.mybatisplus.extension.service.IService;
+
+/**
+ * <p>
+ * 用户表 服务类
+ * </p>
+ *
+ * @author xiang
+ * @since 2025-10-31
+ */
+public interface IUserService extends IService<User> {
+
+}

+ 18 - 0
auth/src/main/java/com/auth/service/WxAuthService.java

@@ -0,0 +1,18 @@
+package com.auth.service;
+
+import java.util.Map;
+
+/**
+ * @author Mr.M
+ * @version 1.0
+ * @description 微信扫码接入
+ * @date 2023/2/24 15:42
+ */
+public interface WxAuthService {
+ /**
+  * 微信扫码认证,申请令牌,携带令牌查询用户信息、保存用户信息到数据库
+  * @param code 授权码
+  * @return OAuth2 token信息
+  */
+ public Map<String, Object> wxAuth(String code);
+}

+ 126 - 0
auth/src/main/java/com/auth/service/impl/AuthTokenService.java

@@ -0,0 +1,126 @@
+package com.auth.service.impl;
+import com.alibaba.fastjson.JSON;
+import com.auth.domain.po.User;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Qualifier;
+import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
+import org.springframework.security.core.Authentication;
+import org.springframework.security.core.authority.SimpleGrantedAuthority;
+import org.springframework.security.oauth2.common.OAuth2AccessToken;
+import org.springframework.security.oauth2.provider.OAuth2Authentication;
+import org.springframework.security.oauth2.provider.OAuth2Request;
+import org.springframework.security.oauth2.provider.token.AuthorizationServerTokenServices;
+import org.springframework.stereotype.Service;
+import java.util.*;
+@Service
+public class AuthTokenService {
+
+    @Autowired
+    @Qualifier("authorizationServerTokenServicesCustom")
+    private AuthorizationServerTokenServices authorizationServerTokenServices;
+
+    public Map<String, Object> generateToken(User user) {
+        try {
+            // 根据用户角色设置权限
+            List<SimpleGrantedAuthority> authorities = getUserAuthorities(user);
+            // 将用户信息和权限都放入token
+            Map<String, Object> userInfo = new HashMap<>();
+            userInfo.put("id", user.getId());
+            userInfo.put("username", user.getUsername());
+            userInfo.put("name", user.getName());
+            userInfo.put("nickname", user.getNickname());
+            userInfo.put("role", user.getRole());
+            userInfo.put("status", user.getStatus());
+            userInfo.put("url", user.getUrl());
+            userInfo.put("vipLevel", user.getVipLevel());
+            userInfo.put("vipStatus", user.getVipStatus());
+            userInfo.put("phone", user.getPhone().substring(0, 3) + "****" + user.getPhone().substring(7));
+            userInfo.put("authorities", authorities.stream()
+                    .map(SimpleGrantedAuthority::getAuthority)
+                    .toArray(String[]::new));
+
+            String userJson = JSON.toJSONString(userInfo);
+
+            Authentication authentication = new UsernamePasswordAuthenticationToken(
+                    userJson,
+                    user.getPassword(),
+                    authorities
+            );
+
+            // 创建OAuth2请求
+            OAuth2Request oAuth2Request = new OAuth2Request(
+                    null,
+                    "wyMusic",
+                    null,
+                    true,
+                    Collections.singleton("all"),
+                    null,
+                    null,
+                    null,
+                    null
+            );
+
+            // 创建OAuth2认证
+            OAuth2Authentication oAuth2Authentication = new OAuth2Authentication(oAuth2Request, authentication);
+
+            // 创建访问令牌
+            OAuth2AccessToken oAuth2AccessToken = authorizationServerTokenServices.createAccessToken(oAuth2Authentication);
+
+            // 添加用户信息到token的额外信息中
+            Map<String, Object> additionalInfo = new HashMap<>();
+            additionalInfo.put("userId", user.getId());
+            additionalInfo.put("username", user.getUsername());
+            additionalInfo.put("name", user.getName());
+            additionalInfo.put("nickname", user.getNickname());
+            additionalInfo.put("role", user.getRole());
+            additionalInfo.put("status", user.getStatus());
+            additionalInfo.put("url", user.getUrl());
+            additionalInfo.put("vipLevel", user.getVipLevel());
+            additionalInfo.put("vipStatus", user.getVipStatus());
+            //手机号中间四位换****
+            additionalInfo.put("phone", user.getPhone().substring(0, 3) + "****" + user.getPhone().substring(7));
+            // 转换为Map格式返回
+            Map<String,Object> tokenInfo = new HashMap<>();
+            tokenInfo.put("access_token", oAuth2AccessToken.getValue());
+            tokenInfo.put("token_type",oAuth2AccessToken.getTokenType());
+            tokenInfo.put("expires_in", oAuth2AccessToken.getExpiresIn());
+            tokenInfo.put("scope",oAuth2AccessToken.getScope());
+            tokenInfo.put("user_info", userInfo); // 添加用户信息
+
+            if (oAuth2AccessToken.getAdditionalInformation().containsKey("jti")) {
+                tokenInfo.put("jti", oAuth2AccessToken.getAdditionalInformation().get("jti"));
+            }
+
+            if (oAuth2AccessToken.getRefreshToken() != null) {
+                tokenInfo.put("refresh_token", oAuth2AccessToken.getRefreshToken().getValue());
+            }
+
+            return tokenInfo;
+        } catch (Exception e) {
+            throw new RuntimeException("生成OAuth2令牌失败", e);
+        }
+    }
+
+    /**
+     * 根据用户角色获取权限列表
+     */
+    private List<SimpleGrantedAuthority> getUserAuthorities(User user) {
+        List<SimpleGrantedAuthority> authorities = new ArrayList<>();
+        if (user.getRole() != null) {
+            if (user.getRole() == 1) {
+                // 管理员权限
+                authorities.add(new SimpleGrantedAuthority("ROLE_ADMIN"));
+                authorities.add(new SimpleGrantedAuthority("ROLE_USER"));
+            } else {
+                // 普通用户权限
+                authorities.add(new SimpleGrantedAuthority("ROLE_USER"));
+            }
+        } else {
+            // 默认权限
+            authorities.add(new SimpleGrantedAuthority("ROLE_USER"));
+        }
+        // 添加基础权限
+        authorities.add(new SimpleGrantedAuthority("p1"));
+        return authorities;
+    }
+}

+ 140 - 0
auth/src/main/java/com/auth/service/impl/GiteeAuthServiceImpl.java

@@ -0,0 +1,140 @@
+package com.auth.service.impl;
+import com.alibaba.fastjson.JSON;
+import com.auth.domain.po.User;
+import com.auth.mapper.UserMapper;
+import com.auth.service.GiteeAuthService;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.http.*;
+import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
+import org.springframework.security.crypto.password.PasswordEncoder;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+import org.springframework.util.LinkedMultiValueMap;
+import org.springframework.util.MultiValueMap;
+import org.springframework.web.client.HttpClientErrorException;
+import org.springframework.web.client.RestTemplate;
+
+import java.time.LocalDateTime;
+import java.util.Map;
+
+@Service("gitee_authservice")
+public class GiteeAuthServiceImpl implements GiteeAuthService {
+
+    @Autowired
+    UserMapper userMapper;
+
+    @Autowired
+    RestTemplate restTemplate;
+
+    @Value("${gitee.client.id}")
+    String clientId;
+
+    @Value("${gitee.client.secret}")
+    String clientSecret;
+
+    @Value("${gitee.redirect.url}")
+    String redirectUri;
+
+
+    @Autowired
+    AuthTokenService authTokenService;
+    @Override
+    public Map<String, Object> giteeAuth(String code) {
+        // 申请令牌
+        Map<String, String> accessTokenMap = getAccessToken(code);
+        String accessToken = accessTokenMap.get("access_token");
+
+        // 携带令牌查询用户信息
+        Map<String, Object> userInfo = getUserInfo(accessToken);
+
+        // 保存用户信息到数据库
+        User user = addGiteeUser(userInfo);
+        System.out.println("user = " + user);
+        // 生成OAuth2 token
+        Map<String, Object> tokenInfo = authTokenService.generateToken(user);
+
+        return tokenInfo;
+    }
+
+    /**
+     * 携带授权码申请令牌
+     */
+    /**
+     * 携带授权码申请令牌
+     */
+    private Map<String, String> getAccessToken(String code) {
+        // 使用 POST 请求体方式传递参数,而不是 URL 参数
+        String url = "https://gitee.com/oauth/token";
+
+        HttpHeaders headers = new HttpHeaders();
+        headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
+
+        MultiValueMap<String, String> requestBody = new LinkedMultiValueMap<>();
+        requestBody.add("grant_type", "authorization_code");
+        requestBody.add("code", code);
+        requestBody.add("client_id", clientId);
+        requestBody.add("redirect_uri", redirectUri);
+        requestBody.add("client_secret", clientSecret);
+
+        HttpEntity<MultiValueMap<String, String>> requestEntity = new HttpEntity<>(requestBody, headers);
+
+        try {
+            ResponseEntity<String> exchange = restTemplate.exchange(
+                    url,
+                    HttpMethod.POST,
+                    requestEntity,
+                    String.class
+            );
+            String result = exchange.getBody();
+            return JSON.parseObject(result, Map.class);
+        } catch (HttpClientErrorException.Unauthorized e) {
+            throw new RuntimeException("Gitee认证失败:客户端凭证无效或授权码已过期", e);
+        }
+    }
+
+
+    /**
+     * 携带令牌查询用户信息
+     */
+    private Map<String, Object> getUserInfo(String accessToken) {
+        String url = "https://gitee.com/api/v5/user?access_token=" + accessToken;
+        ResponseEntity<String> exchange = restTemplate.exchange(url, HttpMethod.GET, null, String.class);
+        String result = exchange.getBody();
+        return JSON.parseObject(result, Map.class);
+    }
+
+    /**
+     * 添加Gitee用户到数据库
+     */
+    /**
+     * 添加Gitee用户到数据库
+     */
+
+    @Transactional
+    public User addGiteeUser(Map<String, Object> userInfo) {
+        String giteeId = String.valueOf(userInfo.get("id"));
+        User user = userMapper.selectOne(new LambdaQueryWrapper<User>().eq(User::getUsername, "gitee_" + giteeId));
+
+        if (user != null) {
+            return user;
+        }
+
+        // 创建新用户
+        user = new User();
+        user.setUsername("gitee_" + giteeId);
+        PasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
+        String hashPass = passwordEncoder.encode(giteeId);
+        user.setPassword(hashPass);
+        user.setName(String.valueOf(userInfo.get("name")));
+        user.setNickname(String.valueOf(userInfo.get("name")));
+        user.setUrl(String.valueOf(userInfo.get("avatar_url")));
+        user.setRole(0);
+        user.setStatus("1");
+        user.setCreateTime(LocalDateTime.now());
+        userMapper.insert(user);
+        return user;
+    }
+
+}

+ 89 - 0
auth/src/main/java/com/auth/service/impl/PasswordAuthServiceImpl.java

@@ -0,0 +1,89 @@
+package com.auth.service.impl;
+
+import com.auth.domain.po.User;
+import com.auth.mapper.UserMapper;
+import com.auth.model.dto.AuthParamsDto;
+import com.auth.model.dto.UserExt;
+import com.auth.service.AuthService;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import org.springframework.beans.BeanUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.core.authority.SimpleGrantedAuthority;
+import org.springframework.security.crypto.password.PasswordEncoder;
+import org.springframework.stereotype.Service;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * @author Mr.M
+ * @version 1.0
+ * @description 账号名密码方式
+ * @date 2023/2/24 11:56
+ */
+@Service("password_authservice")
+public class PasswordAuthServiceImpl implements AuthService {
+
+ @Autowired
+ UserMapper userMapper;
+
+ @Autowired
+ PasswordEncoder passwordEncoder;
+
+ @Override
+ public UserExt execute(AuthParamsDto authParamsDto) {
+  // 账号
+  String username = authParamsDto.getUsername();
+
+  // 根据username账号查询数据库
+  User user = userMapper.selectOne(new LambdaQueryWrapper<User>().eq(User::getUsername, username));
+
+  // 查询到用户不存在,要返回null即可,spring security框架抛出异常用户不存在
+  if (user == null) {
+   throw new RuntimeException("账号不存在");
+  }
+
+  // 验证密码是否正确
+  String passwordDb = user.getPassword();
+  String passwordForm = authParamsDto.getPassword();
+  boolean matches = passwordEncoder.matches(passwordForm, passwordDb);
+
+  if (!matches) {
+   throw new RuntimeException("账号或密码错误");
+  }
+
+  UserExt userExt = new UserExt();
+  BeanUtils.copyProperties(user, userExt);
+
+  // 设置用户权限
+  List<SimpleGrantedAuthority> authorities = getAuthorities(user);
+  userExt.setAuthorities(authorities.stream()
+          .map(SimpleGrantedAuthority::getAuthority)
+          .toArray(String[]::new));
+
+  return userExt;
+ }
+
+ /**
+  * 根据用户角色获取权限列表
+  */
+ private List<SimpleGrantedAuthority> getAuthorities(User user) {
+  List<SimpleGrantedAuthority> authorities = new ArrayList<>();
+
+  if (user.getRole() != null) {
+   if (user.getRole() == 1) {
+    // 管理员权限
+    authorities.add(new SimpleGrantedAuthority("ROLE_ADMIN"));
+    authorities.add(new SimpleGrantedAuthority("ROLE_USER"));
+   } else {
+    // 普通用户权限
+    authorities.add(new SimpleGrantedAuthority("ROLE_USER"));
+   }
+  } else {
+   // 默认权限
+   authorities.add(new SimpleGrantedAuthority("ROLE_USER"));
+  }
+
+  return authorities;
+ }
+}

+ 97 - 0
auth/src/main/java/com/auth/service/impl/UserServiceImpl.java

@@ -0,0 +1,97 @@
+package com.auth.service.impl;
+
+import com.alibaba.fastjson.JSON;
+import com.auth.domain.po.User;
+import com.auth.mapper.UserMapper;
+import com.auth.model.dto.AuthParamsDto;
+import com.auth.model.dto.UserExt;
+import com.auth.service.AuthService;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.ApplicationContext;
+import org.springframework.security.core.authority.SimpleGrantedAuthority;
+import org.springframework.security.core.userdetails.UserDetails;
+import org.springframework.security.core.userdetails.UserDetailsService;
+import org.springframework.security.core.userdetails.UsernameNotFoundException;
+import org.springframework.stereotype.Service;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * @author Mr.M
+ * @version 1.0
+ * @description 自定义UserDetailsService用来对接Spring Security
+ * @date 2022/9/28 18:09
+ */
+@Slf4j
+@Service
+public class UserServiceImpl implements UserDetailsService {
+
+    @Autowired
+    UserMapper userMapper;
+
+    @Autowired
+    ApplicationContext applicationContext;
+
+    /**
+     * @param s AuthParamsDto类型的json数据
+     * @return org.springframework.security.core.userdetails.UserDetails
+     * @description 查询用户信息组成用户身份信息
+     * @author Mr.M
+     * @date 2022/9/28 18:30
+     */
+    @Override
+    public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException {
+        AuthParamsDto authParamsDto = null;
+        try {
+            // 将认证参数转为AuthParamsDto类型
+            authParamsDto = JSON.parseObject(s, AuthParamsDto.class);
+        } catch (Exception e) {
+            log.info("认证请求不符合项目要求:{}", s);
+            throw new RuntimeException("认证请求数据格式不对");
+        }
+
+        // 认证方式
+        String authType = authParamsDto.getAuthType();
+        AuthService authService = applicationContext.getBean(authType + "_authservice", AuthService.class);
+
+        // 调用认证服务执行认证
+        UserExt userExt = authService.execute(authParamsDto);
+
+        // 获取用户权限
+        List<SimpleGrantedAuthority> authorities = new ArrayList<>();
+
+        // 添加角色权限
+        if (userExt.getRole() != null) {
+            if (userExt.getRole() == 1) {
+                authorities.add(new SimpleGrantedAuthority("ROLE_ADMIN"));
+                authorities.add(new SimpleGrantedAuthority("ROLE_USER"));
+            } else {
+                authorities.add(new SimpleGrantedAuthority("ROLE_USER"));
+            }
+        } else {
+            authorities.add(new SimpleGrantedAuthority("ROLE_USER"));
+        }
+
+        // 添加其他权限
+        if (userExt.getAuthorities() != null) {
+            for (String authority : userExt.getAuthorities()) {
+                authorities.add(new SimpleGrantedAuthority(authority));
+            }
+        } else {
+            // 默认权限
+            authorities.add(new SimpleGrantedAuthority("ROLE_USER"));
+        }
+        String userString = JSON.toJSONString(userExt);
+        String password = userExt.getPassword();
+
+        // 创建UserDetails对象
+        return org.springframework.security.core.userdetails.User
+                .withUsername(userString)
+                .password(password)
+                .authorities(authorities)
+                .build();
+    }
+}

+ 181 - 0
auth/src/main/java/com/auth/service/impl/WxAuthServiceImpl.java

@@ -0,0 +1,181 @@
+package com.auth.service.impl;
+import com.alibaba.fastjson.JSON;
+import com.auth.domain.po.User;
+import com.auth.mapper.UserMapper;
+import com.auth.model.dto.AuthParamsDto;
+import com.auth.model.dto.UserExt;
+import com.auth.service.AuthService;
+import com.auth.service.WxAuthService;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import org.springframework.beans.BeanUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.http.HttpMethod;
+import org.springframework.http.ResponseEntity;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+import org.springframework.web.client.RestTemplate;
+import java.nio.charset.StandardCharsets;
+import java.time.LocalDateTime;
+import java.util.Map;
+import java.util.UUID;
+/**
+ * @author Mr.M
+ * @version 1.0
+ * @description 微信扫码认证
+ * @date 2023/2/24 11:57
+ */
+@Service("wx_authservice")
+public class WxAuthServiceImpl implements AuthService, WxAuthService {
+    @Autowired
+    UserMapper WyUserMapper;
+
+
+    @Autowired
+    WxAuthServiceImpl currentPorxy;
+
+    @Autowired
+    RestTemplate restTemplate;
+
+    @Autowired
+    AuthTokenService authTokenService;
+
+    @Value("${weixin.appid}")
+    String appid;
+    @Value("${weixin.secret}")
+    String secret;
+
+    @Override
+    public UserExt execute(AuthParamsDto authParamsDto) {
+        //得到账号
+        String username = authParamsDto.getUsername();
+        //查询数据库
+        User user = WyUserMapper.selectOne(new LambdaQueryWrapper<User>().eq(User::getUsername, username));
+        if(user == null){
+            throw new RuntimeException("用户不存在");
+        }
+
+        UserExt WyUserExt = new UserExt();
+        BeanUtils.copyProperties(user, WyUserExt);
+
+
+        return WyUserExt;
+    }
+
+    @Override
+    public Map<String, Object> wxAuth(String code) {
+        //申请令牌
+        Map<String, String> access_token_map = getAccess_token(code);
+        //访问令牌
+        String access_token = access_token_map.get("access_token");
+        String openid = access_token_map.get("openid");
+
+        //携带令牌查询用户信息
+        Map<String, String> userinfo = getUserinfo(access_token, openid);
+
+        // 保存用户信息到数据库
+        User User = currentPorxy.addWxUser(userinfo);
+
+        // 生成OAuth2 token
+        Map<String, Object> tokenInfo = authTokenService.generateToken(User);
+        return tokenInfo;
+    }
+
+    @Transactional
+    public User addWxUser(Map<String,String> userInfo_map){
+        String unionid = userInfo_map.get("unionid");
+        String nickname = userInfo_map.get("nickname");
+        //根据unionid查询用户信息
+        User user = WyUserMapper.selectOne(new LambdaQueryWrapper<User>().eq(User::getWxUnionid, unionid));
+        if(user !=null){
+            return user;
+        }
+        //向数据库新增记录
+        user = new User();
+        String userId= UUID.randomUUID().toString();
+        user.setId(Long.valueOf(userId));//主键
+        user.setUsername(unionid);
+        user.setPassword(unionid);
+        user.setWxUnionid(unionid);
+        user.setNickname(nickname);
+        user.setName(nickname);
+        user.setRole(0);
+        user.setStatus("1");
+        user.setCreateTime(LocalDateTime.now());
+        //插入
+        int insert = WyUserMapper.insert(user);
+        return user;
+
+    }
+
+    /**
+     * 携带授权码申请令牌
+     * https://api.weixin.qq.com/sns/oauth2/access_token?appid=APPID&secret=SECRET&code=CODE&grant_type=authorization_code
+     *
+     * {
+     * "access_token":"ACCESS_TOKEN",
+     * "expires_in":7200,
+     * "refresh_token":"REFRESH_TOKEN",
+     * "openid":"OPENID",
+     * "scope":"SCOPE",
+     * "unionid": "o6_bmasdasdsad6_2sgVt7hMZOPfL"
+     * }
+     * @param code 授权
+     * @return
+     */
+    private Map<String,String> getAccess_token(String code){
+
+        String url_template = "https://api.weixin.qq.com/sns/oauth2/access_token?appid=%s&secret=%s&code=%s&grant_type=authorization_code";
+        //最终的请求路径
+        String url = String.format(url_template, appid, secret, code);
+
+        //远程调用此url
+        ResponseEntity<String> exchange = restTemplate.exchange(url, HttpMethod.POST, null, String.class);
+        //获取响应的结果
+        String result = exchange.getBody();
+        //将result转成map
+        Map<String,String> map = JSON.parseObject(result, Map.class);
+        return map;
+
+
+    }
+
+    /**
+     * 携带令牌查询用户信息
+     *
+     * https://api.weixin.qq.com/sns/userinfo?access_token=ACCESS_TOKEN&openid=OPENID
+     *
+     * {
+     * "openid":"OPENID",
+     * "nickname":"NICKNAME",
+     * "sex":1,
+     * "province":"PROVINCE",
+     * "city":"CITY",
+     * "country":"COUNTRY",
+     * "headimgurl": "https://thirdwx.qlogo.cn/mmopen/g3MonUZtNHkdmzicIlibx6iaFqAc56vxLSUfpb6n5WKSYVY0ChQKkiaJSgQ1dZuTOgvLLrhJbERQQ4eMsv84eavHiaiceqxibJxCfHe/0",
+     * "privilege":[
+     * "PRIVILEGE1",
+     * "PRIVILEGE2"
+     * ],
+     * "unionid": " o6_bmasdasdsad6_2sgVt7hMZOPfL"
+     *
+     * }
+     * @param access_token
+     * @param openid
+     * @return
+     */
+    private Map<String,String> getUserinfo(String access_token,String openid){
+
+        String url_template = "https://api.weixin.qq.com/sns/userinfo?access_token=%s&openid=%s";
+        String url = String.format(url_template, access_token, openid);
+
+        ResponseEntity<String> exchange = restTemplate.exchange(url, HttpMethod.GET, null, String.class);
+
+        //获取响应的结果
+        String result = new String(exchange.getBody().getBytes(StandardCharsets.ISO_8859_1),StandardCharsets.UTF_8);
+        //将result转成map
+        Map<String,String> map = JSON.parseObject(result, Map.class);
+        return map;
+
+    }
+}

+ 5 - 0
auth/src/main/resources/mapper/UserMapper.xml

@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.auth.mapper.UserMapper">
+
+</mapper>

+ 27 - 0
base/src/main/java/com/base/utils/Result.java

@@ -0,0 +1,27 @@
+package com.base.utils;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import java.io.Serializable;
+
+// base/src/main/java/com/base/model/Result.java
+@Data
+@AllArgsConstructor
+@NoArgsConstructor
+public class Result<T> implements Serializable {
+    private static final long serialVersionUID = 1L;
+    
+    private Integer code;     // 状态码
+    private String message;   // 响应消息
+    private T data;           // 响应数据
+    
+    // 成功响应
+    public static <T> Result<T> success(T data) {
+        return new Result<>(200, "success", data);
+    }
+    
+    // 失败响应
+    public static <T> Result<T> fail(String message) {
+        return new Result<>(500, message, null);
+    }
+}

+ 233 - 0
content/content.sql

@@ -0,0 +1,233 @@
+-- ------------------------------
+-- 1. 专辑表(已包含已添加的管理字段)
+-- ------------------------------
+CREATE TABLE `album` (
+    `id` INT AUTO_INCREMENT PRIMARY KEY,
+    `album_name` VARCHAR(100) NOT NULL COMMENT '专辑名称',
+    `artist_id` INT NOT NULL COMMENT '关联artist服务的artist.id',
+    `artist_name` VARCHAR(16) COMMENT '关联artist服务的artist.name',
+    `cover_url` VARCHAR(255) COMMENT '专辑封面URL',
+    `release_time` DATE COMMENT '发行时间',
+    `description` TEXT COMMENT '专辑描述(介绍专辑主题、曲目等)',
+    `album_type` TINYINT DEFAULT 1 COMMENT '专辑类型:1-数字专辑,2-实体专辑,3-EP',
+    `price` DECIMAL(10,2) COMMENT '专辑价格(实体专辑或付费数字专辑使用)',
+    `create_time` DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
+    `update_time` DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
+-- 已添加的管理字段
+    `status` TINYINT DEFAULT 0 COMMENT '专辑状态:0--审核中,1-审核失败,2-发布中,3-已上架,4-已下架',
+    `audit_reason` VARCHAR(500) COMMENT '审核失败原因',
+    `audit_time` DATETIME COMMENT '审核时间',
+    `publish_time` DATETIME COMMENT '发布时间',
+    `shelf_time` DATETIME COMMENT '上架时间',
+    `off_shelf_time` DATETIME COMMENT '下架时间',
+    `delete_flag` TINYINT DEFAULT 0 COMMENT '删除标志:0-未删除,1-已删除',
+    `delete_time` DATETIME COMMENT '删除时间',
+    INDEX `idx_album_name` (`album_name`),
+    INDEX `idx_artist_id` (`artist_id`),
+    INDEX `idx_status` (`status`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='专辑表';
+
+-- ------------------------------
+-- 2. 歌曲表(已包含已添加的管理字段)
+-- ------------------------------
+CREATE TABLE `song` (
+                        `id` INT AUTO_INCREMENT PRIMARY KEY,
+                        `song_name` VARCHAR(100) NOT NULL COMMENT '歌曲名称',
+                        `artist_id` INT NOT NULL COMMENT '关联artist服务的artist.id',
+                        `album_id` INT COMMENT '关联本服务的album.id(可为空,单曲不关联专辑)',
+                        `duration` INT COMMENT '时长(秒,如300秒=5分钟)',
+                        `file_url` VARCHAR(255) NOT NULL COMMENT '歌曲音频文件URL',
+                        `cover_url` VARCHAR(255) COMMENT '歌曲封面URL(优先使用专辑封面,无专辑时用此封面)',
+                        `release_time` DATE COMMENT '发行时间',
+                        `lyrics` TEXT COMMENT '歌词(冗余存储,核心歌词)',
+                        `play_count` BIGINT DEFAULT 0 COMMENT '播放量',
+                        `is_paid` TINYINT DEFAULT 0 COMMENT '是否付费:0-免费,1-付费',
+                        `price` DECIMAL(10,2) DEFAULT 0.00 COMMENT '单曲价格',
+                        `create_time` DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
+                        `update_time` DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
+
+-- 已添加的管理字段
+                        `status` TINYINT DEFAULT 0 COMMENT '歌曲状态:0-草稿,1-审核中,2-审核失败,3-发布中,4-已上架,5-已下架',
+                        `audit_reason` VARCHAR(500) COMMENT '审核失败原因',
+                        `audit_time` DATETIME COMMENT '审核时间',
+                        `publish_time` DATETIME COMMENT '发布时间',
+                        `shelf_time` DATETIME COMMENT '上架时间',
+                        `off_shelf_time` DATETIME COMMENT '下架时间',
+                        `delete_flag` TINYINT DEFAULT 0 COMMENT '删除标志:0-未删除,1-已删除',
+                        `delete_time` DATETIME COMMENT '删除时间',
+                        `song_type` VARCHAR(50) COMMENT '歌曲类型',
+                        `version` VARCHAR(50) COMMENT '版本',
+                        `work_type` VARCHAR(50) COMMENT '作品类型',
+                        `genre` VARCHAR(255) COMMENT '音乐风格',
+                        `language` VARCHAR(20) COMMENT '语言',
+                        `lyricist` VARCHAR(100) COMMENT '作词人',
+                        `composer` VARCHAR(100) COMMENT '作曲人',
+                        `arranger` VARCHAR(100) COMMENT '编曲人',
+                        `singer_name` VARCHAR(100) COMMENT '演唱者姓名',
+                        FOREIGN KEY (`album_id`) REFERENCES `album` (`id`) ON DELETE SET NULL,
+                        INDEX `idx_song_name` (`song_name`),
+                        INDEX `idx_play_count` (`play_count`),
+                        INDEX `idx_artist_id` (`artist_id`),
+                        INDEX `idx_status` (`status`),
+                        INDEX `idx_delete_flag` (`delete_flag`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='歌曲表';
+-- ------------------------------
+-- 3. 歌单表(关联auth服务的user.id,逻辑关联)
+-- ------------------------------
+CREATE TABLE `playlist` (
+                            `id` INT AUTO_INCREMENT PRIMARY KEY,
+                            `user_id` INT NOT NULL COMMENT '关联auth服务的user.id',
+                            `playlist_name` VARCHAR(100) NOT NULL COMMENT '歌单名称',
+                            `cover_url` VARCHAR(255) COMMENT '歌单封面URL',
+                            `description` TEXT COMMENT '歌单描述',
+                            `tag` VARCHAR(255) COMMENT '歌单标签(多个用逗号分隔)',
+                            `status` Boolean  DEFAULT true COMMENT '0-公开,1-私密',
+                            `song_count` INT DEFAULT 0 COMMENT '歌单歌曲数量',
+                            `play_count` BIGINT DEFAULT 0 COMMENT '歌单播放量',
+                            `create_time` DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
+                            `update_time` DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
+                            INDEX `idx_playlist_name` (`playlist_name`),
+                            INDEX `idx_user_id` (`user_id`) -- 逻辑关联索引
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='歌单表';
+
+-- ------------------------------
+-- 4. 歌单-歌曲关联表(关联本服务的playlist和song表)
+-- ------------------------------
+CREATE TABLE `playlist_song` (
+                                 `id` INT AUTO_INCREMENT PRIMARY KEY,
+                                 `playlist_id` INT NOT NULL COMMENT '关联本服务的playlist.id',
+                                 `song_id` INT NOT NULL COMMENT '关联本服务的song.id',
+                                 `order_num` INT NOT NULL COMMENT '歌曲在歌单中的排序序号',
+                                 `add_time` DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '歌曲添加时间',
+                                 FOREIGN KEY (`playlist_id`) REFERENCES `playlist` (`id`) ON DELETE CASCADE,
+                                 FOREIGN KEY (`song_id`) REFERENCES `song` (`id`) ON DELETE CASCADE,
+                                 UNIQUE KEY `uk_playlist_song` (`playlist_id`, `song_id`),
+                                 INDEX `idx_order_num` (`order_num`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='歌单-歌曲关联表';
+
+-- ------------------------------
+-- 10. 歌词表(关联本服务的song.id、auth服务的user.id)
+-- ------------------------------
+CREATE TABLE `lyric` (
+                         `id` INT AUTO_INCREMENT PRIMARY KEY,
+                          `lyric_name` VARCHAR(32) NOT NULL COMMENT '歌词名',
+                         `song_id` INT NOT NULL COMMENT '关联本服务的song.id',
+                         `lyrics` TEXT NOT NULL COMMENT 'LRC格式歌词文本',
+                         `language` VARCHAR(20) DEFAULT 'zh' COMMENT '歌词语言(zh-中文,en-英文等)',
+                         `version` VARCHAR(50) COMMENT '歌词版本(如艺人原版、用户翻译版)',
+                         `upload_user_id` INT NOT NULL COMMENT '上传用户ID,关联auth服务的user.id',
+                         `status` TINYINT DEFAULT 0 COMMENT '状态:0-待审核,1-已通过,2-已驳回',
+                         `lyric_reason` VARCHAR(500) COMMENT '审核失败原因',
+                         `create_time` DATETIME DEFAULT CURRENT_TIMESTAMP,
+                         FOREIGN KEY (`song_id`) REFERENCES `song` (`id`) ON DELETE CASCADE,
+                         INDEX `idx_song_id` (`song_id`),
+                         INDEX `idx_upload_user_id` (`upload_user_id`) -- 逻辑关联索引
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='歌词表(多版本支持)';
+
+
+-- ------------------------------
+-- 5. 每日推荐表(关联auth服务的user.id、本服务的song.id)
+-- ------------------------------
+CREATE TABLE `daily_recommend` (
+                                   `id` INT AUTO_INCREMENT PRIMARY KEY,
+                                   `user_id` INT NOT NULL COMMENT '关联auth服务的user.id',
+                                   `song_id` INT NOT NULL COMMENT '关联本服务的song.id',
+                                   `recommend_date` DATE NOT NULL COMMENT '推荐日期',
+                                   `reason` VARCHAR(255) COMMENT '推荐理由',
+                                   `create_time` DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
+                                   UNIQUE KEY `uk_user_song_date` (`user_id`, `song_id`, `recommend_date`),
+                                   INDEX `idx_recommend_date` (`recommend_date`),
+                                   INDEX `idx_user_id` (`user_id`), -- 逻辑关联索引
+                                   INDEX `idx_song_id` (`song_id`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='每日推荐表';
+
+-- ------------------------------
+-- 6. 我喜欢的音乐表(关联auth服务的user.id、本服务的song.id)
+-- ------------------------------
+CREATE TABLE `user_favorite_song` (
+                                      `id` INT AUTO_INCREMENT PRIMARY KEY,
+                                      `user_id` INT NOT NULL COMMENT '关联auth服务的user.id',
+                                      `song_id` INT NOT NULL COMMENT '关联本服务的song.id',
+                                      `create_time` DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '收藏时间',
+                                      UNIQUE KEY `uk_user_song` (`user_id`, `song_id`),
+                                      INDEX `idx_user_id` (`user_id`), -- 逻辑关联索引
+                                      INDEX `idx_song_id` (`song_id`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='我喜欢的音乐表';
+
+-- ------------------------------
+-- 7. 我喜欢的歌手表(关联auth服务的user.id、artist服务的artist.id)
+-- ------------------------------
+CREATE TABLE `user_favorite_artist` (
+                                        `id` INT AUTO_INCREMENT PRIMARY KEY,
+                                        `user_id` INT NOT NULL COMMENT '关联auth服务的user.id',
+                                        `artist_id` INT NOT NULL COMMENT '关联artist服务的artist.id',
+                                        `create_time` DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '关注时间',
+                                        UNIQUE KEY `uk_user_artist` (`user_id`, `artist_id`),
+                                        INDEX `idx_user_id` (`user_id`), -- 逻辑关联索引
+                                        INDEX `idx_artist_id` (`artist_id`) -- 逻辑关联索引
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='我喜欢的歌手表';
+
+-- ------------------------------
+-- 8. 我关注的用户表(关联auth服务的user.id)
+-- ------------------------------
+CREATE TABLE `user_follow` (
+                               `id` INT AUTO_INCREMENT PRIMARY KEY,
+                               `follower_id` INT NOT NULL COMMENT '关注者ID,关联auth服务的user.id',
+                               `followed_id` INT NOT NULL COMMENT '被关注者ID,关联auth服务的user.id',
+                               `create_time` DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '关注时间',
+                               UNIQUE KEY `uk_follower_followed` (`follower_id`, `followed_id`),
+                               INDEX `idx_follower_id` (`follower_id`), -- 逻辑关联索引
+                               INDEX `idx_followed_id` (`followed_id`) -- 逻辑关联索引
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='我关注的用户表';
+
+-- ------------------------------
+-- 9. 收藏歌单表(关联auth服务的user.id、本服务的playlist.id)
+-- ------------------------------
+CREATE TABLE `user_playlist_favorite` (
+                                          `id` INT AUTO_INCREMENT PRIMARY KEY,
+                                          `user_id` INT NOT NULL COMMENT '关联auth服务的user.id',
+                                          `playlist_id` INT NOT NULL COMMENT '关联本服务的playlist.id',
+                                          `create_time` DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '收藏时间',
+                                          FOREIGN KEY (`playlist_id`) REFERENCES `playlist` (`id`) ON DELETE CASCADE,
+                                          UNIQUE KEY `uk_user_playlist` (`user_id`, `playlist_id`),
+                                          INDEX `idx_user_id` (`user_id`) -- 逻辑关联索引
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='我收藏的歌单表';
+
+
+-- ------------------------------
+-- 11. 歌曲推广表(关联artist服务的artist.id、本服务的song.id)
+-- ------------------------------
+CREATE TABLE `song_promotion` (
+                                  `id` INT AUTO_INCREMENT PRIMARY KEY,
+                                  `song_id` INT NOT NULL COMMENT '关联本服务的song.id',
+                                  `artist_id` INT NOT NULL COMMENT '关联artist服务的artist.id',
+                                  `promotion_type` TINYINT NOT NULL COMMENT '推广类型:1-首页推荐,2-热门榜单,3-新歌推荐,4-个性化推荐',
+                                  `start_time` DATETIME NOT NULL COMMENT '推广开始时间',
+                                  `end_time` DATETIME NOT NULL COMMENT '推广结束时间',
+                                  `sort` INT DEFAULT 0 COMMENT '推荐排序权重(数值越小越靠前)',
+                                  `status` TINYINT DEFAULT 1 COMMENT '状态:0-未生效,1-生效中,2-已过期',
+                                  `create_time` DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
+                                  `update_time` DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
+                                  UNIQUE KEY `uk_song_type` (`song_id`, `promotion_type`),
+                                  INDEX `idx_promotion_type` (`promotion_type`),
+                                  INDEX `idx_status` (`status`),
+                                  INDEX `idx_time_range` (`start_time`, `end_time`),
+                                  INDEX `idx_artist_id` (`artist_id`) -- 逻辑关联索引
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='歌曲推广表';
+
+-- ------------------------------
+-- 12. 推广效果统计表(关联本服务的song_promotion表)
+-- ------------------------------
+CREATE TABLE `promotion_stat` (
+                                  `id` INT AUTO_INCREMENT PRIMARY KEY,
+                                  `promotion_id` INT NOT NULL COMMENT '关联本服务的song_promotion.id',
+                                  `stat_date` DATE NOT NULL COMMENT '统计日期',
+                                  `click_count` INT DEFAULT 0 COMMENT '点击量',
+                                  `play_count` INT DEFAULT 0 COMMENT '播放量',
+                                  `collect_count` INT DEFAULT 0 COMMENT '收藏量',
+                                  `share_count` INT DEFAULT 0 COMMENT '分享量',
+                                  `create_time` DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
+                                  FOREIGN KEY (`promotion_id`) REFERENCES `song_promotion` (`id`) ON DELETE CASCADE,
+                                  UNIQUE KEY `uk_promotion_date` (`promotion_id`, `stat_date`),
+                                  INDEX `idx_stat_date` (`stat_date`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='推广效果统计表';

+ 45 - 0
content/src/main/java/com/content/config/ResouceServerConfig.java

@@ -0,0 +1,45 @@
+package com.content.config;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
+import org.springframework.security.config.annotation.web.builders.HttpSecurity;
+import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer;
+import org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfigurerAdapter;
+import org.springframework.security.oauth2.config.annotation.web.configurers.ResourceServerSecurityConfigurer;
+import org.springframework.security.oauth2.provider.token.TokenStore;
+
+/**
+ * @description 资源服务配置
+ * @author Mr.M
+ * @date 2022/10/18 16:33
+ * @version 1.0
+ */
+@Configuration
+@EnableResourceServer
+@EnableGlobalMethodSecurity(securedEnabled = true,prePostEnabled = true)
+public class ResouceServerConfig extends ResourceServerConfigurerAdapter {
+
+
+    //资源服务标识
+    public static final String RESOURCE_ID = "wy-music";
+
+    @Autowired
+    TokenStore tokenStore;
+
+    @Override
+    public void configure(ResourceServerSecurityConfigurer resources) {
+        resources.resourceId(RESOURCE_ID)//资源 id
+        .tokenStore(tokenStore)
+        .stateless(true);
+    }
+
+    @Override
+    public void configure(HttpSecurity http) throws Exception {
+        http.csrf().disable()
+        .authorizeRequests()
+//        .antMatchers("/r/**","/course/**").authenticated()//所有/r/**的请求必须认证通过
+        .anyRequest().permitAll()
+        ;
+    }
+
+}

+ 31 - 0
content/src/main/java/com/content/config/SecurityUtil.java

@@ -0,0 +1,31 @@
+package com.content.config;
+import com.alibaba.fastjson.JSON;
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.content.domain.po.WyUser;
+import org.springframework.security.core.context.SecurityContextHolder;
+import java.io.Serializable;
+import java.time.LocalDateTime;
+/**
+ * @author Mr.M
+ * @version 1.0
+ * @description 获取当前用户身份工具类
+ * @date 2022/10/18 18:02
+ */
+public class SecurityUtil {
+    public static WyUser getUser() {
+        try {
+            Object principalObj = SecurityContextHolder.getContext().getAuthentication().getPrincipal();
+            if (principalObj instanceof String) {
+                //取出用户身份信息
+                String principal = principalObj.toString();
+                //将json转成对象
+                WyUser user = JSON.parseObject(principal, WyUser.class);
+                return user;
+            }
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+        return null;
+    }
+}

+ 39 - 0
content/src/main/java/com/content/config/TokenConfig.java

@@ -0,0 +1,39 @@
+package com.content.config;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.security.oauth2.provider.token.AuthorizationServerTokenServices;
+import org.springframework.security.oauth2.provider.token.DefaultTokenServices;
+import org.springframework.security.oauth2.provider.token.TokenEnhancerChain;
+import org.springframework.security.oauth2.provider.token.TokenStore;
+import org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter;
+import org.springframework.security.oauth2.provider.token.store.JwtTokenStore;
+
+import java.util.Arrays;
+
+/**
+ * @author Administrator
+ * @version 1.0
+ **/
+@Configuration
+public class TokenConfig {
+
+    String SIGNING_KEY = "wy_music_token";
+    @Autowired
+    private JwtAccessTokenConverter accessTokenConverter;
+
+    @Bean
+    public TokenStore tokenStore() {
+        return new JwtTokenStore(accessTokenConverter());
+    }
+
+    @Bean
+    public JwtAccessTokenConverter accessTokenConverter() {
+        JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
+        converter.setSigningKey(SIGNING_KEY);
+        return converter;
+    }
+
+
+}

+ 96 - 0
content/src/main/java/com/content/controller/AlbumController.java

@@ -0,0 +1,96 @@
+package com.content.controller;
+import com.base.utils.Result;
+import com.content.domain.dto.ApplyDto;
+import com.content.domain.dto.PageQueryDto;
+import com.content.domain.po.Album;
+import com.content.domain.po.Song;
+import com.content.service.IAlbumManageService;
+import com.content.service.IAlbumService;
+import com.content.service.ISongService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.*;
+
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.util.List;
+@RestController
+@RequestMapping("/album")
+public class AlbumController {
+    @Autowired
+    private IAlbumService albumService;
+    @Autowired
+    private ISongService iSongService;
+    // 新增依赖
+    @Autowired
+    private IAlbumManageService albumManageService;
+    @PostMapping("/add")
+    @PreAuthorize("hasRole('ROLE_USER')")
+    public Result add(@RequestBody Album album) {
+        System.out.println("album = " + album);
+        boolean save = albumService.save(album);
+        if (!save) {
+            return Result.fail("添加失败");
+        }
+        return Result.success("添加成功");
+    }
+
+    @PostMapping("/update")
+    @PreAuthorize("hasRole('ROLE_USER')")
+    public Result update(@RequestBody Album album) {
+        System.out.println("album = " + album);
+        boolean save = albumService.updateById(album);
+        if (!save) {
+            return Result.fail("修改失败");
+        }
+        return Result.success("修改成功");
+    }
+
+    @PostMapping("/list")
+    @PreAuthorize("hasRole('ROLE_USER')")
+    public Result list(@RequestBody PageQueryDto wsongsPageDto) {
+        List<Album> list = albumService.lambdaQuery().eq(Album::getArtistId, wsongsPageDto.getId()).eq(Album::getStatus, wsongsPageDto.getStatus()).eq(Album::getDeleteFlag, 0).list();
+        return Result.success(list);
+    }
+
+    @GetMapping("/list")
+    @PreAuthorize("hasRole('ROLE_USER')")
+    public Result list(@RequestParam Integer id) {
+        List<Album> list = albumService.lambdaQuery().eq(Album::getArtistId, id).eq(Album::getDeleteFlag, 0).list();
+        return Result.success(list);
+    }
+
+    @GetMapping("/listDetail")
+    @PreAuthorize("hasRole('ROLE_USER')")
+    public Result listDetail(@RequestParam Integer id) {
+        List<Song> list = iSongService.lambdaQuery().eq(Song::getAlbumId, id).eq(Song::getDeleteFlag, 0).list();
+        return Result.success(list);
+    }
+
+    @GetMapping("/delete")
+    @PreAuthorize("hasRole('ROLE_USER')")
+    public Result delete(@RequestParam Integer id,Boolean IsDeleteAll) {
+        albumManageService.deleteAlbumByid(id,IsDeleteAll);
+        return Result.success("删除成功");
+    }
+    @GetMapping("/listAll")
+    @PreAuthorize("hasRole('ROLE_ADMIN')")
+    public Result listAll(@RequestParam Integer status) {
+        if(status==6){
+            List<Album> list = albumService.lambdaQuery().ne(Album::getStatus, 0).eq(Album::getDeleteFlag, 0).list();
+            return Result.success(list);
+        }
+        List<Album> list = albumService.lambdaQuery().eq(Album::getStatus, status).eq(Album::getDeleteFlag, 0).list();
+        return Result.success(list);
+    }
+    @PostMapping("/audit")
+    @PreAuthorize("hasRole('ROLE_ADMIN')")
+    public Result audit(@RequestBody ApplyDto applyDto) {
+        albumService.lambdaUpdate()
+                .eq(Album::getId, applyDto.getId())
+                .set(Album::getStatus, applyDto.getStatus())
+                .set(Album::getUpdateTime, LocalDateTime.now())
+                .set(Album::getAuditReason, applyDto.getValue()).update();
+        return Result.success("审核成功");
+    }
+}

+ 40 - 0
content/src/main/java/com/content/controller/PlaylistController.java

@@ -0,0 +1,40 @@
+package com.content.controller;
+
+import com.base.utils.Result;
+import com.content.config.SecurityUtil;
+import com.content.domain.po.Playlist;
+import com.content.domain.po.WyUser;
+import com.content.service.IPlaylistService;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+@Slf4j
+@RestController
+@RequestMapping("/playlist")
+public class PlaylistController {
+    @Autowired
+    private IPlaylistService playlistService;
+    @GetMapping("/list")
+    @PreAuthorize("hasRole('ROLE_USER')")
+    public Result list() {
+        WyUser user = SecurityUtil.getUser();
+        List<Playlist> list = playlistService.lambdaQuery().eq(Playlist::getUserId, user.getId()).list();
+        return Result.success(list);
+    }
+    @PostMapping("/add")
+    @PreAuthorize("hasRole('ROLE_USER')")
+    public Result add(@RequestBody Playlist playlist) {
+        playlist.setUserId(SecurityUtil.getUser().getId());
+        playlistService.save(playlist);
+        return Result.success("添加成功");
+    }
+    @GetMapping("/payListDetail")
+    @PreAuthorize("hasRole('ROLE_USER')")
+    public Result payListDetail(@RequestParam Integer id) {
+        log.info("id: " + id);
+        return Result.success(playlistService.payListDetail(id));
+    }
+}

+ 74 - 0
content/src/main/java/com/content/controller/SongController.java

@@ -0,0 +1,74 @@
+package com.content.controller;
+import com.base.utils.Result;
+import com.content.domain.dto.AddSongDTO;
+import com.content.domain.dto.ApplyDto;
+import com.content.domain.dto.PageQueryDto;
+import com.content.domain.po.Album;
+import com.content.domain.po.Song;
+import com.content.service.ISongService;
+import com.content.service.SongBusinessService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.transaction.annotation.Transactional;
+import org.springframework.web.bind.annotation.*;
+import java.util.List;
+@RestController
+@RequestMapping("/song")
+public class SongController {
+    @Autowired
+    private SongBusinessService songBusinessService;
+    @Autowired
+    private ISongService iSongService;
+    @PostMapping("/add")
+    @PreAuthorize("hasRole('ROLE_USER')")
+    public Result add(@RequestBody AddSongDTO addSongDTO) {
+        songBusinessService.addSongWithLyric(addSongDTO);
+        return Result.success("添加成功");
+    }
+    @PostMapping("/update")
+    @PreAuthorize("hasRole('ROLE_USER')")
+    public Result update(@RequestBody AddSongDTO addSongDTO) {
+        songBusinessService.updateSongWithLyric(addSongDTO);
+        return Result.success("添加成功");
+    }
+    @PostMapping("/list")
+    @PreAuthorize("hasRole('ROLE_USER')")
+    public Result list(@RequestBody PageQueryDto pageQueryDto) {
+        List<Song> list = iSongService.lambdaQuery()
+                .eq(Song::getArtistId, pageQueryDto.getId())
+                .eq(Song::getStatus, pageQueryDto.getStatus())
+                .eq(Song::getDeleteFlag, 0)
+                .isNull(Song::getAlbumId).list();
+        return Result.success(list);
+    }
+    @GetMapping("/delete")
+    @PreAuthorize("hasRole('ROLE_USER')")
+    public Result add(@RequestParam Integer id) {
+        iSongService.lambdaUpdate().eq(Song::getId, id).set(Song::getDeleteFlag, 1).update();
+        return Result.success("删除成功");
+    }
+    @GetMapping("/list")
+    @PreAuthorize("hasRole('ROLE_ADMIN')")
+    public Result list(@RequestParam Integer status) {
+        if(status == 6){
+            //status不为0
+            List<Song> list = iSongService.lambdaQuery().ne(Song::getStatus, 0).eq(Song::getDeleteFlag, 0).isNull(Song::getAlbumId).list();
+            return Result.success(list);
+        }
+        List<Song> list = iSongService.lambdaQuery().eq(Song::getStatus, status).eq(Song::getDeleteFlag, 0).isNull(Song::getAlbumId).list();
+        return Result.success(list);
+    }
+//    歌曲审核
+    @PostMapping("/audit")
+    @PreAuthorize("hasRole('ROLE_ADMIN')")
+    public Result audit(@RequestBody ApplyDto applyDto) {
+        iSongService.updateApplyAndLyrics(applyDto);
+        return Result.success("ok");
+    }
+    @PutMapping("/updateSongStatus")
+    @PreAuthorize("hasRole('ROLE_USER')")
+    public Result updateSongStatus(@RequestBody PageQueryDto pageQueryDto) {
+        iSongService.lambdaUpdate().eq(Song::getId, pageQueryDto.getId()).set(Song::getStatus, pageQueryDto.getStatus()).update();
+        return Result.success("修改完成");
+    }
+}

+ 52 - 0
content/src/main/java/com/content/controller/WlyricsController.java

@@ -0,0 +1,52 @@
+package com.content.controller;
+import com.base.utils.Result;
+import com.content.domain.dto.ApplyDto;
+import com.content.domain.dto.PageQueryDto;
+import com.content.domain.po.Lyric;
+import com.content.service.ILyricService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.*;
+import java.util.List;
+@RestController
+@RequestMapping("/content")
+public class WlyricsController {
+    @Autowired
+    private ILyricService iLyricService;
+    @PostMapping("/getlyric")
+    @PreAuthorize("hasRole('ROLE_USER')")
+    public Result< List<Lyric>> findById(@RequestBody PageQueryDto pageQueryDto){
+        List<Lyric> list = iLyricService.lambdaQuery().eq(Lyric::getUploadUserId, pageQueryDto.getId()).eq(Lyric::getStatus, pageQueryDto.getStatus()).list();
+        return Result.success(list);
+    }
+    @GetMapping("/getlyric")
+    @PreAuthorize("hasRole('ROLE_ADMIN')")
+    public Result< List<Lyric>> list(@RequestParam Integer status){
+        if(status == 6){
+            List<Lyric> list = iLyricService.lambdaQuery().ne(Lyric::getStatus, 0).list();
+            return Result.success(list);
+        }
+        List<Lyric> list = iLyricService.lambdaQuery().eq(Lyric::getStatus, status).list();
+        return Result.success(list);
+    }
+    @PostMapping("/audit")
+    @PreAuthorize("hasRole('ROLE_USER')")
+    public Result audit(@RequestBody ApplyDto applyDto) {
+        System.out.println("applyDto = " + applyDto);
+        iLyricService.lambdaUpdate().eq(Lyric::getId, applyDto.getId()).set(Lyric::getStatus, applyDto.getStatus()).set(Lyric::getLyricReason, applyDto.getValue()).update();
+        return Result.success("ok");
+    }
+
+
+
+
+
+
+
+
+
+
+
+
+
+}

+ 115 - 0
content/src/main/java/com/content/domain/dto/AddSongDTO.java

@@ -0,0 +1,115 @@
+package com.content.domain.dto;
+
+import java.math.BigDecimal;
+import java.time.LocalDate;
+import java.util.List;
+import lombok.Data;
+
+/**
+ * 添加歌曲的请求参数 DTO
+ */
+@Data
+public class AddSongDTO {
+
+    /**
+     * 歌曲主键
+     */
+
+    private Integer id;
+
+    /**
+     * 歌曲名称
+     */
+
+    private String songName;
+
+    /**
+     * 关联艺术家 ID
+     */
+    private Integer artistId;
+
+    /**
+     * 关联专辑 ID(可为空)
+     */
+    private Integer albumId;
+
+    /**
+     * 时长(秒)
+     */
+    private Integer duration;
+
+    /**
+     * 音频文件 URL
+     */
+    private String fileUrl;
+
+    /**
+     * 封面 URL
+     */
+    private String coverUrl;
+
+    /**
+     * 发行时间
+     */
+    private LocalDate releaseTime;
+
+    /**
+     * 歌词内容(带时间码)
+     */
+    private String lyrics;
+
+    /**
+     * 是否付费:0-免费,1-付费
+     */
+    private Integer isPaid;
+
+    /**
+     * 单曲价格
+     */
+    private BigDecimal price;
+
+    /**
+     * 歌曲类型:original, remix 等
+     */
+    private String songType;
+
+    /**
+     * 版本:studio, live 等
+     */
+    private String version;
+
+    /**
+     * 作品类型:album, single 等
+     */
+    private String workType;
+
+    /**
+     * 风格列表
+     */
+    private List<String> genre;
+
+    /**
+     * 语言
+     */
+    private String language;
+
+    /**
+     * 作词人
+     */
+    private String lyricist;
+
+    /**
+     * 作曲人
+     */
+    private String composer;
+
+    /**
+     * 编曲人
+     */
+    private String arranger;
+
+    /**
+     * 演唱者姓名
+     */
+    private String singerName;
+}

+ 10 - 0
content/src/main/java/com/content/domain/dto/ApplyDto.java

@@ -0,0 +1,10 @@
+package com.content.domain.dto;
+
+import lombok.Data;
+
+@Data
+public class ApplyDto {
+    private Integer id;
+    private Integer status;
+    private String value;
+}

+ 32 - 0
content/src/main/java/com/content/domain/dto/MusicianApplicationDTO.java

@@ -0,0 +1,32 @@
+package com.content.domain.dto;
+
+import lombok.Data;
+
+import java.time.LocalDate;
+@Data
+public class MusicianApplicationDTO {
+    private Boolean agreeFaceRecognition;
+    private Boolean agreeTerms;
+    private String artistName;
+    private String avatar;
+    private String headerImage;  // 改为 headerImage 而不是 banner
+    private LocalDate birthday;
+    private String code;
+    private String company;
+    private String email;
+    private String platformAccount;  // 改为 platformAccount 而不是 externalId
+    private String platformName;     // 改为 platformName 而不是 externalPlatform
+    private Long fanCount;
+    private String gender;
+    private String genre;
+    private String idCard;
+    private String introduction;
+    private String invitationCode;   // 改为 invitationCode 而不是 inviteCode
+    private String nationality;
+    private String phone;
+    private String qrCode;
+    private String realName;
+    private String region;
+    private String termsContent;
+    private String wechat;
+}

+ 8 - 0
content/src/main/java/com/content/domain/dto/PageQueryDto.java

@@ -0,0 +1,8 @@
+package com.content.domain.dto;
+
+import lombok.Data;
+@Data
+public class PageQueryDto {
+    private Integer id;
+    private Integer status;
+}

+ 12 - 0
content/src/main/java/com/content/domain/dto/PlaylistWithSongsDTO.java

@@ -0,0 +1,12 @@
+package com.content.domain.dto;
+import com.content.domain.po.Playlist;
+import com.content.domain.po.Song;
+import lombok.Data;
+
+import java.util.List;
+
+@Data
+public class PlaylistWithSongsDTO {
+    private Playlist playlist; // 歌单对象
+    private List<Song> songs;  // 歌曲列表
+}

+ 123 - 0
content/src/main/java/com/content/domain/po/Album.java

@@ -0,0 +1,123 @@
+package com.content.domain.po;
+
+import java.math.BigDecimal;
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.baomidou.mybatisplus.annotation.IdType;
+import java.time.LocalDate;
+import com.baomidou.mybatisplus.annotation.TableId;
+import java.time.LocalDateTime;
+import java.io.Serializable;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.experimental.Accessors;
+
+/**
+ * <p>
+ * 专辑表
+ * </p>
+ *
+ * @author xiang
+ * @since 2025-12-05
+ */
+@Data
+@EqualsAndHashCode(callSuper = false)
+@Accessors(chain = true)
+@TableName("album")
+public class Album implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    @TableId(value = "id", type = IdType.AUTO)
+    private Integer id;
+
+    /**
+     * 专辑名称
+     */
+    private String albumName;
+
+    /**
+     * 关联artist服务的artist.id
+     */
+    private Integer artistId;
+
+    /**
+     * artistName
+     */
+    private String artistName;
+
+    /**
+     * 专辑封面URL
+     */
+    private String coverUrl;
+
+    /**
+     * 发行时间
+     */
+    private LocalDate releaseTime;
+
+    /**
+     * 专辑描述(介绍专辑主题、曲目等)
+     */
+    private String description;
+
+    /**
+     * 专辑类型:1-数字专辑,2-实体专辑,3-EP
+     */
+    private Integer albumType;
+
+    /**
+     * 专辑价格(实体专辑或付费数字专辑使用)
+     */
+    private BigDecimal price;
+
+    /**
+     * 创建时间
+     */
+    private LocalDateTime createTime;
+
+    /**
+     * 更新时间
+     */
+    private LocalDateTime updateTime;
+
+    /**
+     * 专辑状态:0-审核中,1-审核失败,2-发布中,3-已上架,4-已下架
+     */
+    private Integer status;
+
+    /**
+     * 审核失败原因
+     */
+    private String auditReason;
+
+    /**
+     * 审核时间
+     */
+    private LocalDateTime auditTime;
+
+    /**
+     * 发布时间
+     */
+    private LocalDateTime publishTime;
+
+    /**
+     * 上架时间
+     */
+    private LocalDateTime shelfTime;
+
+    /**
+     * 下架时间
+     */
+    private LocalDateTime offShelfTime;
+
+    /**
+     * 删除标志:0-未删除,1-已删除
+     */
+    private Integer deleteFlag;
+
+    /**
+     * 删除时间
+     */
+    private LocalDateTime deleteTime;
+
+}

+ 235 - 0
content/src/main/java/com/content/domain/po/Artist.java

@@ -0,0 +1,235 @@
+package com.content.domain.po;
+
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.baomidou.mybatisplus.annotation.IdType;
+import java.time.LocalDate;
+import com.baomidou.mybatisplus.annotation.TableId;
+import java.time.LocalDateTime;
+import java.io.Serializable;
+
+/**
+ * <p>
+ * 艺人基础信息表
+ * </p>
+ *
+ * @author xiang
+ * @since 2025-11-18
+ */
+@TableName("artist")
+public class Artist implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    @TableId(value = "id", type = IdType.AUTO)
+    private Integer id;
+
+    /**
+     * 关联平台用户ID(对应user表id)
+     */
+    private Integer userId;
+
+    /**
+     * 艺人名
+     */
+    private String artistName;
+
+    /**
+     * 艺人头像URL
+     */
+    private String avatar;
+
+    /**
+     * 艺人页头图(网页端)URL
+     */
+    private String headerImage;
+
+    /**
+     * 性别:1-男,2-女,3-团体
+     */
+    private Integer gender;
+
+    /**
+     * 生日
+     */
+    private LocalDate birthday;
+
+    /**
+     * 艺人所属地区
+     */
+    private String region;
+
+    /**
+     * 流派风格(多个用逗号分隔,如流行,摇滚)
+     */
+    private String genre;
+
+    /**
+     * 所属公司/厂牌
+     */
+    private String company;
+
+    /**
+     * 艺人介绍(10-1000字)
+     */
+    private String introduction;
+
+    /**
+     * 邀请码
+     */
+    private String invitationCode;
+
+    /**
+     * 微信号
+     */
+    private String wechat;
+
+    /**
+     * 艺人账号状态:0-待审核,1-已通过,2-已拒绝,3-已冻结
+     */
+    private Integer status;
+
+    /**
+     * 创建时间
+     */
+    private LocalDateTime createTime;
+
+    /**
+     * 更新时间
+     */
+    private LocalDateTime updateTime;
+
+    public Integer getId() {
+        return id;
+    }
+
+    public void setId(Integer id) {
+        this.id = id;
+    }
+    public Integer getUserId() {
+        return userId;
+    }
+
+    public void setUserId(Integer userId) {
+        this.userId = userId;
+    }
+    public String getArtistName() {
+        return artistName;
+    }
+
+    public void setArtistName(String artistName) {
+        this.artistName = artistName;
+    }
+    public String getAvatar() {
+        return avatar;
+    }
+
+    public void setAvatar(String avatar) {
+        this.avatar = avatar;
+    }
+    public String getHeaderImage() {
+        return headerImage;
+    }
+
+    public void setHeaderImage(String headerImage) {
+        this.headerImage = headerImage;
+    }
+    public Integer getGender() {
+        return gender;
+    }
+
+    public void setGender(Integer gender) {
+        this.gender = gender;
+    }
+    public LocalDate getBirthday() {
+        return birthday;
+    }
+
+    public void setBirthday(LocalDate birthday) {
+        this.birthday = birthday;
+    }
+    public String getRegion() {
+        return region;
+    }
+
+    public void setRegion(String region) {
+        this.region = region;
+    }
+    public String getGenre() {
+        return genre;
+    }
+
+    public void setGenre(String genre) {
+        this.genre = genre;
+    }
+    public String getCompany() {
+        return company;
+    }
+
+    public void setCompany(String company) {
+        this.company = company;
+    }
+    public String getIntroduction() {
+        return introduction;
+    }
+
+    public void setIntroduction(String introduction) {
+        this.introduction = introduction;
+    }
+    public String getInvitationCode() {
+        return invitationCode;
+    }
+
+    public void setInvitationCode(String invitationCode) {
+        this.invitationCode = invitationCode;
+    }
+    public String getWechat() {
+        return wechat;
+    }
+
+    public void setWechat(String wechat) {
+        this.wechat = wechat;
+    }
+    public Integer getStatus() {
+        return status;
+    }
+
+    public void setStatus(Integer status) {
+        this.status = status;
+    }
+    public LocalDateTime getCreateTime() {
+        return createTime;
+    }
+
+    public void setCreateTime(LocalDateTime createTime) {
+        this.createTime = createTime;
+    }
+    public LocalDateTime getUpdateTime() {
+        return updateTime;
+    }
+
+    public void setUpdateTime(LocalDateTime updateTime) {
+        this.updateTime = updateTime;
+    }
+
+    @Override
+    public String toString() {
+        return "Artist{" +
+            "id=" + id +
+            ", userId=" + userId +
+            ", artistName=" + artistName +
+            ", avatar=" + avatar +
+            ", headerImage=" + headerImage +
+            ", gender=" + gender +
+            ", birthday=" + birthday +
+            ", region=" + region +
+            ", genre=" + genre +
+            ", company=" + company +
+            ", introduction=" + introduction +
+            ", invitationCode=" + invitationCode +
+            ", wechat=" + wechat +
+            ", status=" + status +
+            ", createTime=" + createTime +
+            ", updateTime=" + updateTime +
+        "}";
+    }
+}

+ 53 - 0
content/src/main/java/com/content/domain/po/ArtistExternalInfo.java

@@ -0,0 +1,53 @@
+package com.content.domain.po;
+
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import lombok.Data;
+
+import java.time.LocalDateTime;
+import java.io.Serializable;
+
+/**
+ * <p>
+ * 艺人站外社交平台信息表
+ * </p>
+ *
+ * @author xiang
+ * @since 2025-11-18
+ */
+@Data
+@TableName("artist_external_info")
+public class ArtistExternalInfo implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    @TableId(value = "id", type = IdType.AUTO)
+    private Integer id;
+
+    /**
+     * 关联艺人ID(对应artist表id)
+     */
+    private Integer artistId;
+
+    /**
+     * 站外平台名称(如微博、抖音、B站)
+     */
+    private String platformName;
+
+    /**
+     * 平台用户ID/URL/昵称
+     */
+    private String platformAccount;
+
+    /**
+     * 平台粉丝数
+     */
+    private Long fansCount;
+
+    private LocalDateTime createTime;
+
+    private LocalDateTime updateTime;
+
+
+}

+ 101 - 0
content/src/main/java/com/content/domain/po/ArtistMediaHistory.java

@@ -0,0 +1,101 @@
+package com.content.domain.po;
+
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import java.time.LocalDateTime;
+import java.io.Serializable;
+
+/**
+ * <p>
+ * 艺人媒体文件历史记录表
+ * </p>
+ *
+ * @author xiang
+ * @since 2025-11-18
+ */
+@TableName("artist_media_history")
+public class ArtistMediaHistory implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    @TableId(value = "id", type = IdType.AUTO)
+    private Long id;
+
+    /**
+     * 关联艺人ID(对应artist表id)
+     */
+    private Integer artistId;
+
+    /**
+     * 媒体类型: avatar/header_image 等
+     */
+    private String mediaType;
+
+    /**
+     * 关联media_file表id
+     */
+    private Long mediaFileId;
+
+    /**
+     * 是否为当前使用版本:0-否,1-是
+     */
+    private Integer isCurrent;
+
+    private LocalDateTime createTime;
+
+    public Long getId() {
+        return id;
+    }
+
+    public void setId(Long id) {
+        this.id = id;
+    }
+    public Integer getArtistId() {
+        return artistId;
+    }
+
+    public void setArtistId(Integer artistId) {
+        this.artistId = artistId;
+    }
+    public String getMediaType() {
+        return mediaType;
+    }
+
+    public void setMediaType(String mediaType) {
+        this.mediaType = mediaType;
+    }
+    public Long getMediaFileId() {
+        return mediaFileId;
+    }
+
+    public void setMediaFileId(Long mediaFileId) {
+        this.mediaFileId = mediaFileId;
+    }
+    public Integer getIsCurrent() {
+        return isCurrent;
+    }
+
+    public void setIsCurrent(Integer isCurrent) {
+        this.isCurrent = isCurrent;
+    }
+    public LocalDateTime getCreateTime() {
+        return createTime;
+    }
+
+    public void setCreateTime(LocalDateTime createTime) {
+        this.createTime = createTime;
+    }
+
+    @Override
+    public String toString() {
+        return "ArtistMediaHistory{" +
+            "id=" + id +
+            ", artistId=" + artistId +
+            ", mediaType=" + mediaType +
+            ", mediaFileId=" + mediaFileId +
+            ", isCurrent=" + isCurrent +
+            ", createTime=" + createTime +
+        "}";
+    }
+}

+ 166 - 0
content/src/main/java/com/content/domain/po/ArtistRealAuth.java

@@ -0,0 +1,166 @@
+package com.content.domain.po;
+
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import java.time.LocalDateTime;
+import java.io.Serializable;
+
+/**
+ * <p>
+ * 艺人实名认证信息表
+ * </p>
+ *
+ * @author xiang
+ * @since 2025-11-18
+ */
+@TableName("artist_real_auth")
+public class ArtistRealAuth implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    @TableId(value = "id", type = IdType.AUTO)
+    private Integer id;
+
+    /**
+     * 关联艺人ID(对应artist表id)
+     */
+    private Integer artistId;
+
+    /**
+     * 真实姓名
+     */
+    private String realName;
+
+    /**
+     * 绑定手机号
+     */
+    private String phone;
+
+    /**
+     * 邮箱
+     */
+    private String email;
+
+    /**
+     * 国籍/地区
+     */
+    private String nationality;
+
+    /**
+     * 证件号(建议加密存储)
+     */
+    private String idCard;
+
+    /**
+     * 面部识别状态:0-未认证,1-已认证
+     */
+    private Integer faceAuthStatus;
+
+    /**
+     * 实名认证状态:0-待审核,1-已通过,2-已驳回
+     */
+    private Integer authStatus;
+
+    /**
+     * 实名认证通过时间
+     */
+    private LocalDateTime authTime;
+
+    private LocalDateTime createTime;
+
+    public Integer getId() {
+        return id;
+    }
+
+    public void setId(Integer id) {
+        this.id = id;
+    }
+    public Integer getArtistId() {
+        return artistId;
+    }
+
+    public void setArtistId(Integer artistId) {
+        this.artistId = artistId;
+    }
+    public String getRealName() {
+        return realName;
+    }
+
+    public void setRealName(String realName) {
+        this.realName = realName;
+    }
+    public String getPhone() {
+        return phone;
+    }
+
+    public void setPhone(String phone) {
+        this.phone = phone;
+    }
+    public String getEmail() {
+        return email;
+    }
+
+    public void setEmail(String email) {
+        this.email = email;
+    }
+    public String getNationality() {
+        return nationality;
+    }
+
+    public void setNationality(String nationality) {
+        this.nationality = nationality;
+    }
+    public String getIdCard() {
+        return idCard;
+    }
+
+    public void setIdCard(String idCard) {
+        this.idCard = idCard;
+    }
+    public Integer getFaceAuthStatus() {
+        return faceAuthStatus;
+    }
+
+    public void setFaceAuthStatus(Integer faceAuthStatus) {
+        this.faceAuthStatus = faceAuthStatus;
+    }
+    public Integer getAuthStatus() {
+        return authStatus;
+    }
+
+    public void setAuthStatus(Integer authStatus) {
+        this.authStatus = authStatus;
+    }
+    public LocalDateTime getAuthTime() {
+        return authTime;
+    }
+
+    public void setAuthTime(LocalDateTime authTime) {
+        this.authTime = authTime;
+    }
+    public LocalDateTime getCreateTime() {
+        return createTime;
+    }
+
+    public void setCreateTime(LocalDateTime createTime) {
+        this.createTime = createTime;
+    }
+
+    @Override
+    public String toString() {
+        return "ArtistRealAuth{" +
+            "id=" + id +
+            ", artistId=" + artistId +
+            ", realName=" + realName +
+            ", phone=" + phone +
+            ", email=" + email +
+            ", nationality=" + nationality +
+            ", idCard=" + idCard +
+            ", faceAuthStatus=" + faceAuthStatus +
+            ", authStatus=" + authStatus +
+            ", authTime=" + authTime +
+            ", createTime=" + createTime +
+        "}";
+    }
+}

+ 89 - 0
content/src/main/java/com/content/domain/po/DailyRecommend.java

@@ -0,0 +1,89 @@
+package com.content.domain.po;
+
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.baomidou.mybatisplus.annotation.IdType;
+import java.time.LocalDate;
+import com.baomidou.mybatisplus.annotation.TableId;
+import java.time.LocalDateTime;
+import java.io.Serializable;
+
+/**
+ * <p>
+ * 每日推荐表
+ * </p>
+ *
+ * @author xiang
+ * @since 2025-11-18
+ */
+@TableName("daily_recommend")
+public class DailyRecommend implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    @TableId(value = "id", type = IdType.AUTO)
+    private Integer id;
+
+    /**
+     * 关联用户ID(对应user表id)
+     */
+    private Integer userId;
+
+    /**
+     * 关联歌曲ID(对应song表id)
+     */
+    private Integer songId;
+
+    /**
+     * 推荐日期
+     */
+    private LocalDate recommendDate;
+
+    private LocalDateTime createTime;
+
+    public Integer getId() {
+        return id;
+    }
+
+    public void setId(Integer id) {
+        this.id = id;
+    }
+    public Integer getUserId() {
+        return userId;
+    }
+
+    public void setUserId(Integer userId) {
+        this.userId = userId;
+    }
+    public Integer getSongId() {
+        return songId;
+    }
+
+    public void setSongId(Integer songId) {
+        this.songId = songId;
+    }
+    public LocalDate getRecommendDate() {
+        return recommendDate;
+    }
+
+    public void setRecommendDate(LocalDate recommendDate) {
+        this.recommendDate = recommendDate;
+    }
+    public LocalDateTime getCreateTime() {
+        return createTime;
+    }
+
+    public void setCreateTime(LocalDateTime createTime) {
+        this.createTime = createTime;
+    }
+
+    @Override
+    public String toString() {
+        return "DailyRecommend{" +
+            "id=" + id +
+            ", userId=" + userId +
+            ", songId=" + songId +
+            ", recommendDate=" + recommendDate +
+            ", createTime=" + createTime +
+        "}";
+    }
+}

+ 75 - 0
content/src/main/java/com/content/domain/po/Lyric.java

@@ -0,0 +1,75 @@
+package com.content.domain.po;
+
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import java.time.LocalDateTime;
+import java.io.Serializable;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.experimental.Accessors;
+
+/**
+ * <p>
+ * 歌词表(多版本支持)
+ * </p>
+ *
+ * @author xiang
+ * @since 2025-12-04
+ */
+@Data
+@EqualsAndHashCode(callSuper = false)
+@Accessors(chain = true)
+@TableName("lyric")
+public class Lyric implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    @TableId(value = "id", type = IdType.AUTO)
+    private Integer id;
+
+    /**
+     * 关联本服务的song.id
+     */
+    private Integer songId;
+
+    /**
+     * 歌词名
+     */
+    private String lyricName;
+
+    /**
+     * LRC格式歌词文本
+     */
+    private String lyrics;
+
+    /**
+     * 歌词语言(zh-中文,en-英文等)
+     */
+    private String language;
+
+    /**
+     * 歌词版本(0 如艺人原版、1 用户翻译版)
+     */
+    private String version;
+
+    /**
+     * 上传用户ID,关联auth服务的user.id
+     */
+    private Integer uploadUserId;
+
+    /**
+     * 状态:0-待审核,1-已通过,2-已驳回
+     */
+    private Integer status;
+
+    /**
+     * 歌词版本(0 如艺人原版、1 用户翻译版)
+     */
+    private String lyricReason;
+
+    /**
+     * 创建时间
+     */
+    private LocalDateTime createTime;
+}

+ 150 - 0
content/src/main/java/com/content/domain/po/MediaFile.java

@@ -0,0 +1,150 @@
+package com.content.domain.po;
+
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import java.time.LocalDateTime;
+import java.io.Serializable;
+
+/**
+ * <p>
+ * 媒体文件信息表
+ * </p>
+ *
+ * @author xiang
+ * @since 2025-11-18
+ */
+@TableName("media_file")
+public class MediaFile implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    @TableId(value = "id", type = IdType.AUTO)
+    private Long id;
+
+    /**
+     * 原始文件名
+     */
+    private String originalName;
+
+    /**
+     * 存储文件名
+     */
+    private String fileName;
+
+    /**
+     * 文件类型:image, video, audio
+     */
+    private String fileType;
+
+    /**
+     * 文件大小(字节)
+     */
+    private Long fileSize;
+
+    /**
+     * 存储桶名称
+     */
+    private String bucketName;
+
+    /**
+     * 文件URL
+     */
+    private String fileUrl;
+
+    /**
+     * 文件状态:0-正常,1-已删除
+     */
+    private Integer status;
+
+    private LocalDateTime createTime;
+
+    private LocalDateTime updateTime;
+
+    public Long getId() {
+        return id;
+    }
+
+    public void setId(Long id) {
+        this.id = id;
+    }
+    public String getOriginalName() {
+        return originalName;
+    }
+
+    public void setOriginalName(String originalName) {
+        this.originalName = originalName;
+    }
+    public String getFileName() {
+        return fileName;
+    }
+
+    public void setFileName(String fileName) {
+        this.fileName = fileName;
+    }
+    public String getFileType() {
+        return fileType;
+    }
+
+    public void setFileType(String fileType) {
+        this.fileType = fileType;
+    }
+    public Long getFileSize() {
+        return fileSize;
+    }
+
+    public void setFileSize(Long fileSize) {
+        this.fileSize = fileSize;
+    }
+    public String getBucketName() {
+        return bucketName;
+    }
+
+    public void setBucketName(String bucketName) {
+        this.bucketName = bucketName;
+    }
+    public String getFileUrl() {
+        return fileUrl;
+    }
+
+    public void setFileUrl(String fileUrl) {
+        this.fileUrl = fileUrl;
+    }
+    public Integer getStatus() {
+        return status;
+    }
+
+    public void setStatus(Integer status) {
+        this.status = status;
+    }
+    public LocalDateTime getCreateTime() {
+        return createTime;
+    }
+
+    public void setCreateTime(LocalDateTime createTime) {
+        this.createTime = createTime;
+    }
+    public LocalDateTime getUpdateTime() {
+        return updateTime;
+    }
+
+    public void setUpdateTime(LocalDateTime updateTime) {
+        this.updateTime = updateTime;
+    }
+
+    @Override
+    public String toString() {
+        return "MediaFile{" +
+            "id=" + id +
+            ", originalName=" + originalName +
+            ", fileName=" + fileName +
+            ", fileType=" + fileType +
+            ", fileSize=" + fileSize +
+            ", bucketName=" + bucketName +
+            ", fileUrl=" + fileUrl +
+            ", status=" + status +
+            ", createTime=" + createTime +
+            ", updateTime=" + updateTime +
+        "}";
+    }
+}

+ 60 - 0
content/src/main/java/com/content/domain/po/Playlist.java

@@ -0,0 +1,60 @@
+package com.content.domain.po;
+
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import lombok.Data;
+
+import java.time.LocalDateTime;
+import java.io.Serializable;
+
+/**
+ * <p>
+ * 歌单表
+ * </p>
+ *
+ * @author xiang
+ * @since 2025-11-18
+ */
+@Data
+@TableName("playlist")
+public class Playlist implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    @TableId(value = "id", type = IdType.AUTO)
+    private Integer id;
+
+    /**
+     * 关联用户ID(对应user表id)
+     */
+    private Integer userId;
+
+    private String playlistName;
+
+    private String coverUrl;
+
+    private String description;
+
+    private String tag;
+
+    /**
+     * 歌单歌曲数量
+     */
+    private Integer songCount;
+
+
+    /**
+     * 歌单播放量
+     */
+    private Integer playCount;
+
+    private LocalDateTime createTime;
+
+    private LocalDateTime updateTime;
+
+    /**
+     * 0-公开,1-私密
+     */
+    private Boolean status;
+}

+ 77 - 0
content/src/main/java/com/content/domain/po/PlaylistSong.java

@@ -0,0 +1,77 @@
+package com.content.domain.po;
+
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import java.io.Serializable;
+
+/**
+ * <p>
+ * 歌单-歌曲关联表
+ * </p>
+ *
+ * @author xiang
+ * @since 2025-11-18
+ */
+@TableName("playlist_song")
+public class PlaylistSong implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    @TableId(value = "id", type = IdType.AUTO)
+    private Integer id;
+
+    /**
+     * 关联歌单ID(对应playlist表id)
+     */
+    private Integer playlistId;
+
+    /**
+     * 关联歌曲ID(对应song表id)
+     */
+    private Integer songId;
+
+    /**
+     * 歌曲在歌单中的排序序号
+     */
+    private Integer orderNum;
+
+    public Integer getId() {
+        return id;
+    }
+
+    public void setId(Integer id) {
+        this.id = id;
+    }
+    public Integer getPlaylistId() {
+        return playlistId;
+    }
+
+    public void setPlaylistId(Integer playlistId) {
+        this.playlistId = playlistId;
+    }
+    public Integer getSongId() {
+        return songId;
+    }
+
+    public void setSongId(Integer songId) {
+        this.songId = songId;
+    }
+    public Integer getOrderNum() {
+        return orderNum;
+    }
+
+    public void setOrderNum(Integer orderNum) {
+        this.orderNum = orderNum;
+    }
+
+    @Override
+    public String toString() {
+        return "PlaylistSong{" +
+            "id=" + id +
+            ", playlistId=" + playlistId +
+            ", songId=" + songId +
+            ", orderNum=" + orderNum +
+        "}";
+    }
+}

+ 184 - 0
content/src/main/java/com/content/domain/po/Song.java

@@ -0,0 +1,184 @@
+package com.content.domain.po;
+
+import java.math.BigDecimal;
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.baomidou.mybatisplus.annotation.IdType;
+import java.time.LocalDate;
+import com.baomidou.mybatisplus.annotation.TableId;
+import java.time.LocalDateTime;
+import java.io.Serializable;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.experimental.Accessors;
+
+/**
+ * <p>
+ * 歌曲表
+ * </p>
+ *
+ * @author xiang
+ * @since 2025-12-11
+ */
+@Data
+@EqualsAndHashCode(callSuper = false)
+@Accessors(chain = true)
+@TableName("song")
+public class Song implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    @TableId(value = "id", type = IdType.AUTO)
+    private Integer id;
+
+    /**
+     * 歌曲名称
+     */
+    private String songName;
+
+    /**
+     * 关联artist服务的artist.id
+     */
+    private Integer artistId;
+
+    /**
+     * 关联本服务的album.id(可为空,单曲不关联专辑)
+     */
+    private Integer albumId;
+
+    /**
+     * 时长(秒,如300秒=5分钟)
+     */
+    private Integer duration;
+
+    /**
+     * 歌曲音频文件URL
+     */
+    private String fileUrl;
+
+    /**
+     * 歌曲封面URL(优先使用专辑封面,无专辑时用此封面)
+     */
+    private String coverUrl;
+
+    /**
+     * 发行时间
+     */
+    private LocalDate releaseTime;
+
+    /**
+     * 歌词(冗余存储,核心歌词)
+     */
+    private String lyrics;
+
+    /**
+     * 播放量
+     */
+    private Long playCount;
+
+    /**
+     * 是否付费:0-免费,1-付费
+     */
+    private Integer isPaid;
+
+    /**
+     * 单曲价格
+     */
+    private BigDecimal price;
+
+    /**
+     * 创建时间
+     */
+    private LocalDateTime createTime;
+
+    /**
+     * 更新时间
+     */
+    private LocalDateTime updateTime;
+
+    /**
+     * 歌曲状态:0-草稿,1-审核中,2-审核失败,3-发布中,4-已上架,5-已下架
+     */
+    private Integer status;
+
+    /**
+     * 审核失败原因
+     */
+    private String auditReason;
+
+    /**
+     * 审核时间
+     */
+    private LocalDateTime auditTime;
+
+    /**
+     * 发布时间
+     */
+    private LocalDateTime publishTime;
+
+    /**
+     * 上架时间
+     */
+    private LocalDateTime shelfTime;
+
+    /**
+     * 下架时间
+     */
+    private LocalDateTime offShelfTime;
+
+    /**
+     * 删除标志:0-未删除,1-已删除
+     */
+    private Integer deleteFlag;
+
+    /**
+     * 删除时间
+     */
+    private LocalDateTime deleteTime;
+
+    /**
+     * 歌曲类型:original-原创, remix-混音, cover-翻唱
+     */
+    private String songType;
+
+    /**
+     * 版本:studio-录音室版, live-现场版
+     */
+    private String version;
+
+    /**
+     * 作品类型:album-专辑曲, single-单曲, ep-迷你专辑
+     */
+    private String workType;
+
+    /**
+     * 音乐风格(多个用逗号分隔)
+     */
+    private String genre;
+
+    /**
+     * 语言
+     */
+    private String language;
+
+    /**
+     * 作词人
+     */
+    private String lyricist;
+
+    /**
+     * 作曲人
+     */
+    private String composer;
+
+    /**
+     * 编曲人
+     */
+    private String arranger;
+
+    /**
+     * 演唱者姓名
+     */
+    private String singerName;
+
+
+}

+ 44 - 0
content/src/main/java/com/content/domain/po/Swipper.java

@@ -0,0 +1,44 @@
+package com.content.domain.po;
+
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import java.io.Serializable;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.experimental.Accessors;
+
+/**
+ * <p>
+ * 轮播图表
+ * </p>
+ *
+ * @author xiang
+ * @since 2025-11-27
+ */
+@Data
+@EqualsAndHashCode(callSuper = false)
+@Accessors(chain = true)
+@TableName("swipper")
+public class Swipper implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 主键ID
+     */
+    @TableId(value = "id", type = IdType.AUTO)
+    private Integer id;
+
+    /**
+     * 图片URL地址
+     */
+    private String url;
+
+    /**
+     * 轮播类型:1-主页轮播,2-商城轮播
+     */
+    private Integer type;
+
+
+}

+ 224 - 0
content/src/main/java/com/content/domain/po/User.java

@@ -0,0 +1,224 @@
+package com.content.domain.po;
+
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import java.time.LocalDateTime;
+import java.io.Serializable;
+
+/**
+ * <p>
+ * 用户表
+ * </p>
+ *
+ * @author xiang
+ * @since 2025-11-18
+ */
+@TableName("user")
+public class User implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 用户ID
+     */
+    @TableId(value = "id", type = IdType.AUTO)
+    private Integer id;
+
+    /**
+     * 账号
+     */
+    private String username;
+
+    /**
+     * 用户昵称
+     */
+    private String name;
+
+    /**
+     * 用户年龄
+     */
+    private Integer age;
+
+    /**
+     * 登录密码(建议存储BCrypt加密后的值)
+     */
+    private String password;
+
+    /**
+     * 用户头像URL
+     */
+    private String url;
+
+    /**
+     * VIP等级
+     */
+    private Integer vipLevel;
+
+    /**
+     * VIP状态(0:非VIP,1:VIP)
+     */
+    private Integer vipStatus;
+
+    /**
+     * 创建时间
+     */
+    private LocalDateTime createTime;
+
+    /**
+     * 最后登录时间
+     */
+    private LocalDateTime lastLoginTime;
+
+    /**
+     * 用户昵称(用于展示)
+     */
+    private String nickname;
+
+    /**
+     * 微信unionid,用于微信平台用户唯一标识
+     */
+    private String wxUnionid;
+
+    /**
+     * 用户类型(normal:普通用户,admin:管理员,vip:VIP)
+     */
+    private String utype;
+
+    /**
+     * 用户状态(normal:正常,disabled:禁用,frozen:冻结)
+     */
+    private String status;
+
+    /**
+     * 手机联系方式
+     */
+    private String phone;
+
+    public Integer getId() {
+        return id;
+    }
+
+    public void setId(Integer id) {
+        this.id = id;
+    }
+    public String getUsername() {
+        return username;
+    }
+
+    public void setUsername(String username) {
+        this.username = username;
+    }
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+    public Integer getAge() {
+        return age;
+    }
+
+    public void setAge(Integer age) {
+        this.age = age;
+    }
+    public String getPassword() {
+        return password;
+    }
+
+    public void setPassword(String password) {
+        this.password = password;
+    }
+    public String getUrl() {
+        return url;
+    }
+
+    public void setUrl(String url) {
+        this.url = url;
+    }
+    public Integer getVipLevel() {
+        return vipLevel;
+    }
+
+    public void setVipLevel(Integer vipLevel) {
+        this.vipLevel = vipLevel;
+    }
+    public Integer getVipStatus() {
+        return vipStatus;
+    }
+
+    public void setVipStatus(Integer vipStatus) {
+        this.vipStatus = vipStatus;
+    }
+    public LocalDateTime getCreateTime() {
+        return createTime;
+    }
+
+    public void setCreateTime(LocalDateTime createTime) {
+        this.createTime = createTime;
+    }
+    public LocalDateTime getLastLoginTime() {
+        return lastLoginTime;
+    }
+
+    public void setLastLoginTime(LocalDateTime lastLoginTime) {
+        this.lastLoginTime = lastLoginTime;
+    }
+    public String getNickname() {
+        return nickname;
+    }
+
+    public void setNickname(String nickname) {
+        this.nickname = nickname;
+    }
+    public String getWxUnionid() {
+        return wxUnionid;
+    }
+
+    public void setWxUnionid(String wxUnionid) {
+        this.wxUnionid = wxUnionid;
+    }
+    public String getUtype() {
+        return utype;
+    }
+
+    public void setUtype(String utype) {
+        this.utype = utype;
+    }
+    public String getStatus() {
+        return status;
+    }
+
+    public void setStatus(String status) {
+        this.status = status;
+    }
+    public String getPhone() {
+        return phone;
+    }
+
+    public void setPhone(String phone) {
+        this.phone = phone;
+    }
+
+    @Override
+    public String toString() {
+        return "User{" +
+            "id=" + id +
+            ", username=" + username +
+            ", name=" + name +
+            ", age=" + age +
+            ", password=" + password +
+            ", url=" + url +
+            ", vipLevel=" + vipLevel +
+            ", vipStatus=" + vipStatus +
+            ", createTime=" + createTime +
+            ", lastLoginTime=" + lastLoginTime +
+            ", nickname=" + nickname +
+            ", wxUnionid=" + wxUnionid +
+            ", utype=" + utype +
+            ", status=" + status +
+            ", phone=" + phone +
+        "}";
+    }
+}

+ 78 - 0
content/src/main/java/com/content/domain/po/UserFavoriteArtist.java

@@ -0,0 +1,78 @@
+package com.content.domain.po;
+
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import java.time.LocalDateTime;
+import java.io.Serializable;
+
+/**
+ * <p>
+ * 我喜欢的歌手表
+ * </p>
+ *
+ * @author xiang
+ * @since 2025-11-18
+ */
+@TableName("user_favorite_artist")
+public class UserFavoriteArtist implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    @TableId(value = "id", type = IdType.AUTO)
+    private Integer id;
+
+    /**
+     * 关联用户ID(对应user表id)
+     */
+    private Integer userId;
+
+    /**
+     * 关联艺人ID(对应artist表id)
+     */
+    private Integer artistId;
+
+    /**
+     * 关注时间
+     */
+    private LocalDateTime createTime;
+
+    public Integer getId() {
+        return id;
+    }
+
+    public void setId(Integer id) {
+        this.id = id;
+    }
+    public Integer getUserId() {
+        return userId;
+    }
+
+    public void setUserId(Integer userId) {
+        this.userId = userId;
+    }
+    public Integer getArtistId() {
+        return artistId;
+    }
+
+    public void setArtistId(Integer artistId) {
+        this.artistId = artistId;
+    }
+    public LocalDateTime getCreateTime() {
+        return createTime;
+    }
+
+    public void setCreateTime(LocalDateTime createTime) {
+        this.createTime = createTime;
+    }
+
+    @Override
+    public String toString() {
+        return "UserFavoriteArtist{" +
+            "id=" + id +
+            ", userId=" + userId +
+            ", artistId=" + artistId +
+            ", createTime=" + createTime +
+        "}";
+    }
+}

+ 78 - 0
content/src/main/java/com/content/domain/po/UserFavoriteSong.java

@@ -0,0 +1,78 @@
+package com.content.domain.po;
+
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import java.time.LocalDateTime;
+import java.io.Serializable;
+
+/**
+ * <p>
+ * 我喜欢的音乐表
+ * </p>
+ *
+ * @author xiang
+ * @since 2025-11-18
+ */
+@TableName("user_favorite_song")
+public class UserFavoriteSong implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    @TableId(value = "id", type = IdType.AUTO)
+    private Integer id;
+
+    /**
+     * 关联用户ID(对应user表id)
+     */
+    private Integer userId;
+
+    /**
+     * 关联歌曲ID(对应song表id)
+     */
+    private Integer songId;
+
+    /**
+     * 收藏时间
+     */
+    private LocalDateTime createTime;
+
+    public Integer getId() {
+        return id;
+    }
+
+    public void setId(Integer id) {
+        this.id = id;
+    }
+    public Integer getUserId() {
+        return userId;
+    }
+
+    public void setUserId(Integer userId) {
+        this.userId = userId;
+    }
+    public Integer getSongId() {
+        return songId;
+    }
+
+    public void setSongId(Integer songId) {
+        this.songId = songId;
+    }
+    public LocalDateTime getCreateTime() {
+        return createTime;
+    }
+
+    public void setCreateTime(LocalDateTime createTime) {
+        this.createTime = createTime;
+    }
+
+    @Override
+    public String toString() {
+        return "UserFavoriteSong{" +
+            "id=" + id +
+            ", userId=" + userId +
+            ", songId=" + songId +
+            ", createTime=" + createTime +
+        "}";
+    }
+}

+ 78 - 0
content/src/main/java/com/content/domain/po/UserFollow.java

@@ -0,0 +1,78 @@
+package com.content.domain.po;
+
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import java.time.LocalDateTime;
+import java.io.Serializable;
+
+/**
+ * <p>
+ * 我关注的用户表
+ * </p>
+ *
+ * @author xiang
+ * @since 2025-11-18
+ */
+@TableName("user_follow")
+public class UserFollow implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    @TableId(value = "id", type = IdType.AUTO)
+    private Integer id;
+
+    /**
+     * 关注者ID(对应user表id)
+     */
+    private Integer followerId;
+
+    /**
+     * 被关注者ID(对应user表id)
+     */
+    private Integer followedId;
+
+    /**
+     * 关注时间
+     */
+    private LocalDateTime createTime;
+
+    public Integer getId() {
+        return id;
+    }
+
+    public void setId(Integer id) {
+        this.id = id;
+    }
+    public Integer getFollowerId() {
+        return followerId;
+    }
+
+    public void setFollowerId(Integer followerId) {
+        this.followerId = followerId;
+    }
+    public Integer getFollowedId() {
+        return followedId;
+    }
+
+    public void setFollowedId(Integer followedId) {
+        this.followedId = followedId;
+    }
+    public LocalDateTime getCreateTime() {
+        return createTime;
+    }
+
+    public void setCreateTime(LocalDateTime createTime) {
+        this.createTime = createTime;
+    }
+
+    @Override
+    public String toString() {
+        return "UserFollow{" +
+            "id=" + id +
+            ", followerId=" + followerId +
+            ", followedId=" + followedId +
+            ", createTime=" + createTime +
+        "}";
+    }
+}

+ 78 - 0
content/src/main/java/com/content/domain/po/UserPlaylistFavorite.java

@@ -0,0 +1,78 @@
+package com.content.domain.po;
+
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import java.time.LocalDateTime;
+import java.io.Serializable;
+
+/**
+ * <p>
+ * 我喜欢的歌单表
+ * </p>
+ *
+ * @author xiang
+ * @since 2025-11-18
+ */
+@TableName("user_playlist_favorite")
+public class UserPlaylistFavorite implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    @TableId(value = "id", type = IdType.AUTO)
+    private Integer id;
+
+    /**
+     * 关联用户ID(对应user表id)
+     */
+    private Integer userId;
+
+    /**
+     * 关联歌单ID(对应playlist表id)
+     */
+    private Integer playlistId;
+
+    /**
+     * 收藏时间
+     */
+    private LocalDateTime createTime;
+
+    public Integer getId() {
+        return id;
+    }
+
+    public void setId(Integer id) {
+        this.id = id;
+    }
+    public Integer getUserId() {
+        return userId;
+    }
+
+    public void setUserId(Integer userId) {
+        this.userId = userId;
+    }
+    public Integer getPlaylistId() {
+        return playlistId;
+    }
+
+    public void setPlaylistId(Integer playlistId) {
+        this.playlistId = playlistId;
+    }
+    public LocalDateTime getCreateTime() {
+        return createTime;
+    }
+
+    public void setCreateTime(LocalDateTime createTime) {
+        this.createTime = createTime;
+    }
+
+    @Override
+    public String toString() {
+        return "UserPlaylistFavorite{" +
+            "id=" + id +
+            ", userId=" + userId +
+            ", playlistId=" + playlistId +
+            ", createTime=" + createTime +
+        "}";
+    }
+}

+ 63 - 0
content/src/main/java/com/content/domain/po/WyUser.java

@@ -0,0 +1,63 @@
+package com.content.domain.po;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import lombok.Data;
+
+import java.io.Serializable;
+import java.time.LocalDateTime;
+@Data
+public class WyUser implements Serializable {
+        private static final long serialVersionUID = 1L;
+
+        /**
+         * 用户ID
+         */
+        @TableId(value = "id", type = IdType.AUTO)
+        private Integer id;
+
+        /**
+         * 账号
+         */
+        private String username;
+
+        /**
+         * 用户昵称
+         */
+        private String name;
+
+        /**
+         * 用户年龄
+         */
+        private Integer age;
+
+        /**
+         * 登录密码
+         */
+        private String password;
+
+        /**
+         * 用户头像URL
+         */
+        private String url;
+
+        /**
+         * VIP等级
+         */
+        private Integer vipLevel;
+
+        /**
+         * VIP状态
+         */
+        private Integer vipStatus;
+
+        /**
+         * 创建时间
+         */
+        private LocalDateTime createTime;
+
+        /**
+         * 最后登录时间
+         */
+        private LocalDateTime lastLoginTime;
+    }

+ 227 - 0
content/src/main/java/com/content/domain/po/info.sql

@@ -0,0 +1,227 @@
+-- 1. 艺人基础信息表(扩充后,关联user表)
+CREATE TABLE `artist`
+(
+    `id`              INT AUTO_INCREMENT PRIMARY KEY, -- 主键统一改为id
+    `user_id`         INT          NOT NULL COMMENT '关联平台用户ID(对应user表id)',
+    `artist_name`     VARCHAR(100) NOT NULL COMMENT '艺人名',
+    `avatar`          VARCHAR(255) COMMENT '艺人头像URL',
+    `header_image`    VARCHAR(255) COMMENT '艺人页头图(网页端)URL',
+    `gender`          TINYINT COMMENT '性别:1-男,2-女,3-团体',
+    `birthday`        DATE COMMENT '生日',
+    `region`          VARCHAR(50) COMMENT '艺人所属地区',
+    `genre`           VARCHAR(100) COMMENT '流派风格(多个用逗号分隔,如流行,摇滚)',
+    `company`         VARCHAR(100) COMMENT '所属公司/厂牌',
+    `introduction`    TEXT COMMENT '艺人介绍(10-1000字)',
+    `invitation_code` VARCHAR(50) COMMENT '邀请码',
+    `wechat`          VARCHAR(50) COMMENT '微信号',
+    `status`          TINYINT  DEFAULT 0 COMMENT '艺人账号状态:0-待审核,1-已通过,2-已拒绝,3-已冻结',
+    `create_time`     DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
+    `update_time`     DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
+    FOREIGN KEY (`user_id`) REFERENCES `user` (`id`) ON DELETE CASCADE,
+    UNIQUE KEY `uk_artist_name` (`artist_name`)
+) ENGINE = InnoDB
+  DEFAULT CHARSET = utf8mb4 COMMENT ='艺人基础信息表';
+
+-- 2. 艺人实名认证表(关联艺人表)
+CREATE TABLE `artist_real_auth`
+(
+    `id`               INT AUTO_INCREMENT PRIMARY KEY, -- 主键统一改为id
+    `artist_id`        INT          NOT NULL COMMENT '关联艺人ID(对应artist表id)',
+    `real_name`        VARCHAR(50)  NOT NULL COMMENT '真实姓名',
+    `phone`            VARCHAR(20)  NOT NULL COMMENT '绑定手机号',
+    `email`            VARCHAR(100) NOT NULL COMMENT '邮箱',
+    `nationality`      VARCHAR(50)  NOT NULL COMMENT '国籍/地区',
+    `id_card`          VARCHAR(100) NOT NULL COMMENT '证件号(建议加密存储)',
+    `face_auth_status` TINYINT  DEFAULT 0 COMMENT '面部识别状态:0-未认证,1-已认证',
+    `auth_status`      TINYINT  DEFAULT 0 COMMENT '实名认证状态:0-待审核,1-已通过,2-已驳回',
+    `auth_time`        DATETIME COMMENT '实名认证通过时间',
+    `create_time`      DATETIME DEFAULT CURRENT_TIMESTAMP,
+    FOREIGN KEY (`artist_id`) REFERENCES `artist` (`id`) ON DELETE CASCADE, -- 关联改为艺人表id
+    UNIQUE KEY `uk_artist_auth` (`artist_id`)
+) ENGINE = InnoDB
+  DEFAULT CHARSET = utf8mb4 COMMENT ='艺人实名认证信息表';
+
+-- 3. 艺人站外社交信息表(关联艺人表)
+CREATE TABLE `artist_external_info`
+(
+    `id`               INT AUTO_INCREMENT PRIMARY KEY, -- 主键统一改为id
+    `artist_id`        INT          NOT NULL COMMENT '关联艺人ID(对应artist表id)',
+    `platform_name`    VARCHAR(50)  NOT NULL COMMENT '站外平台名称(如微博、抖音、B站)',
+    `platform_account` VARCHAR(255) NOT NULL COMMENT '平台用户ID/URL/昵称',
+    `fans_count`       BIGINT   DEFAULT 0 COMMENT '平台粉丝数',
+    `create_time`      DATETIME DEFAULT CURRENT_TIMESTAMP,
+    `update_time`      DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
+    FOREIGN KEY (`artist_id`) REFERENCES `artist` (`id`) ON DELETE CASCADE, -- 关联改为艺人表id
+    UNIQUE KEY `uk_artist_platform` (`artist_id`, `platform_name`)
+) ENGINE = InnoDB
+  DEFAULT CHARSET = utf8mb4 COMMENT ='艺人站外社交平台信息表';
+
+-- 4. 专辑表(关联艺人表,字段类型与艺人表匹配)
+CREATE TABLE `album`
+(
+    `id`           INT AUTO_INCREMENT PRIMARY KEY, -- 主键统一改为id
+    `album_name`   VARCHAR(100) NOT NULL,
+    `artist_id`    INT          NOT NULL COMMENT '关联艺人ID(对应artist表id)',
+    `cover_url`    VARCHAR(255),
+    `release_time` DATE,
+    `description`  TEXT,
+    FOREIGN KEY (`artist_id`) REFERENCES `artist` (`id`) ON DELETE CASCADE -- 关联改为艺人表id
+) ENGINE = InnoDB
+  DEFAULT CHARSET = utf8mb4 COMMENT ='专辑表';
+
+-- 5. 歌曲表(关联艺人表、专辑表)
+CREATE TABLE `song`
+(
+    `id`           INT AUTO_INCREMENT PRIMARY KEY, -- 主键统一改为id
+    `song_name`    VARCHAR(100) NOT NULL,
+    `artist_id`    INT          NOT NULL COMMENT '关联艺人ID(对应artist表id)',
+    `album_id`     INT COMMENT '关联专辑ID(对应album表id,可为空)',
+    `duration`     INT COMMENT '时长(秒)',
+    `file_url`     VARCHAR(255) NOT NULL,
+    `cover_url`    VARCHAR(255),
+    `release_time` DATE,
+    `create_time`  DATETIME DEFAULT CURRENT_TIMESTAMP,
+    FOREIGN KEY (`artist_id`) REFERENCES `artist` (`id`) ON DELETE CASCADE, -- 关联改为艺人表id
+    FOREIGN KEY (`album_id`) REFERENCES `album` (`id`) ON DELETE SET NULL -- 关联改为专辑表id
+) ENGINE = InnoDB
+  DEFAULT CHARSET = utf8mb4 COMMENT ='歌曲表';
+
+-- 6. 歌单表(关联用户表)
+CREATE TABLE `playlist`
+(
+    `id`            INT AUTO_INCREMENT PRIMARY KEY, -- 主键统一改为id
+    `user_id`       INT          NOT NULL COMMENT '关联用户ID(对应user表id)',
+    `playlist_name` VARCHAR(100) NOT NULL,
+    `cover_url`     VARCHAR(255),
+    `description`   TEXT,
+    `tag`           VARCHAR(255),
+    `create_time`   DATETIME DEFAULT CURRENT_TIMESTAMP,
+    `update_time`   DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
+    `status`        TINYINT  DEFAULT 0 COMMENT '0-公开,1-私密',
+    FOREIGN KEY (`user_id`) REFERENCES `user` (`id`) ON DELETE CASCADE
+) ENGINE = InnoDB
+  DEFAULT CHARSET = utf8mb4 COMMENT ='歌单表';
+
+-- 7. 歌单-歌曲关联表(关联歌单表、歌曲表)
+CREATE TABLE `playlist_song`
+(
+    `id`           INT AUTO_INCREMENT PRIMARY KEY, -- 主键统一改为id
+    `playlist_id`  INT NOT NULL COMMENT '关联歌单ID(对应playlist表id)',
+    `song_id`      INT NOT NULL COMMENT '关联歌曲ID(对应song表id)',
+    `order_num`    INT NOT NULL COMMENT '歌曲在歌单中的排序序号',
+    FOREIGN KEY (`playlist_id`) REFERENCES `playlist` (`id`) ON DELETE CASCADE, -- 关联改为歌单表id
+    FOREIGN KEY (`song_id`) REFERENCES `song` (`id`) ON DELETE CASCADE, -- 关联改为歌曲表id
+    UNIQUE KEY `uk_playlist_song` (`playlist_id`, `song_id`)
+) ENGINE = InnoDB
+  DEFAULT CHARSET = utf8mb4 COMMENT ='歌单-歌曲关联表';
+
+-- 8. 每日推荐表(关联用户表、歌曲表)
+CREATE TABLE `daily_recommend`
+(
+    `id`             INT AUTO_INCREMENT PRIMARY KEY, -- 主键统一改为id
+    `user_id`        INT  NOT NULL COMMENT '关联用户ID(对应user表id)',
+    `song_id`        INT  NOT NULL COMMENT '关联歌曲ID(对应song表id)',
+    `recommend_date` DATE NOT NULL COMMENT '推荐日期',
+    `create_time`    DATETIME DEFAULT CURRENT_TIMESTAMP,
+    FOREIGN KEY (`user_id`) REFERENCES `user` (`id`) ON DELETE CASCADE,
+    FOREIGN KEY (`song_id`) REFERENCES `song` (`id`) ON DELETE CASCADE, -- 关联改为歌曲表id
+    UNIQUE KEY `uk_user_song_date` (`user_id`, `song_id`, `recommend_date`)
+) ENGINE = InnoDB
+  DEFAULT CHARSET = utf8mb4 COMMENT ='每日推荐表';
+
+-- 9. 我喜欢的音乐表(关联用户表、歌曲表)
+CREATE TABLE `user_favorite_song`
+(
+    `id`          INT AUTO_INCREMENT PRIMARY KEY, -- 主键统一改为id
+    `user_id`     INT NOT NULL COMMENT '关联用户ID(对应user表id)',
+    `song_id`     INT NOT NULL COMMENT '关联歌曲ID(对应song表id)',
+    `create_time` DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '收藏时间',
+    FOREIGN KEY (`user_id`) REFERENCES `user` (`id`) ON DELETE CASCADE,
+    FOREIGN KEY (`song_id`) REFERENCES `song` (`id`) ON DELETE CASCADE, -- 关联改为歌曲表id
+    UNIQUE KEY `uk_user_song` (`user_id`, `song_id`)
+) ENGINE = InnoDB
+  DEFAULT CHARSET = utf8mb4 COMMENT ='我喜欢的音乐表';
+
+-- 10. 我喜欢的歌手表(关联用户表、艺人表)
+CREATE TABLE `user_favorite_artist`
+(
+    `id`          INT AUTO_INCREMENT PRIMARY KEY, -- 主键统一改为id
+    `user_id`     INT NOT NULL COMMENT '关联用户ID(对应user表id)',
+    `artist_id`   INT NOT NULL COMMENT '关联艺人ID(对应artist表id)',
+    `create_time` DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '关注时间',
+    FOREIGN KEY (`user_id`) REFERENCES `user` (`id`) ON DELETE CASCADE,
+    FOREIGN KEY (`artist_id`) REFERENCES `artist` (`id`) ON DELETE CASCADE, -- 关联改为艺人表id
+    UNIQUE KEY `uk_user_artist` (`user_id`, `artist_id`)
+) ENGINE = InnoDB
+  DEFAULT CHARSET = utf8mb4 COMMENT ='我喜欢的歌手表';
+
+-- 11. 我关注的用户表(关联用户表)
+CREATE TABLE `user_follow`
+(
+    `id`          INT AUTO_INCREMENT PRIMARY KEY, -- 主键统一改为id
+    `follower_id` INT NOT NULL COMMENT '关注者ID(对应user表id)',
+    `followed_id` INT NOT NULL COMMENT '被关注者ID(对应user表id)',
+    `create_time` DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '关注时间',
+    FOREIGN KEY (`follower_id`) REFERENCES `user` (`id`) ON DELETE CASCADE,
+    FOREIGN KEY (`followed_id`) REFERENCES `user` (`id`) ON DELETE CASCADE,
+    UNIQUE KEY `uk_follower_followed` (`follower_id`, `followed_id`)
+) ENGINE = InnoDB
+  DEFAULT CHARSET = utf8mb4 COMMENT ='我关注的用户表';
+
+-- 12. 我喜欢的歌单表(关联用户表、歌单表)
+CREATE TABLE `user_playlist_favorite`
+(
+    `id`          INT AUTO_INCREMENT PRIMARY KEY, -- 主键统一改为id
+    `user_id`     INT NOT NULL COMMENT '关联用户ID(对应user表id)',
+    `playlist_id` INT NOT NULL COMMENT '关联歌单ID(对应playlist表id)',
+    `create_time` DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '收藏时间',
+    FOREIGN KEY (`user_id`) REFERENCES `user` (`id`) ON DELETE CASCADE,
+    FOREIGN KEY (`playlist_id`) REFERENCES `playlist` (`id`) ON DELETE CASCADE, -- 关联改为歌单表id
+    UNIQUE KEY `uk_user_playlist` (`user_id`, `playlist_id`)
+) ENGINE = InnoDB
+  DEFAULT CHARSET = utf8mb4 COMMENT ='我喜欢的歌单表';
+
+-- 13. 媒体文件信息表
+CREATE TABLE `media_file`
+(
+    `id`            BIGINT AUTO_INCREMENT PRIMARY KEY, -- 主键统一改为id
+    `original_name` VARCHAR(255) NOT NULL COMMENT '原始文件名',
+    `file_name`     VARCHAR(255) NOT NULL COMMENT '存储文件名',
+    `file_type`     VARCHAR(20)  NOT NULL COMMENT '文件类型:image, video, audio',
+    `file_size`     BIGINT COMMENT '文件大小(字节)',
+    `bucket_name`   VARCHAR(100) NOT NULL COMMENT '存储桶名称',
+    `file_url`      VARCHAR(500) NOT NULL COMMENT '文件URL',
+    `status`        TINYINT  DEFAULT 0 COMMENT '文件状态:0-正常,1-已删除',
+    `create_time`   DATETIME DEFAULT CURRENT_TIMESTAMP,
+    `update_time`   DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
+    INDEX `idx_file_type` (`file_type`),
+    INDEX `idx_bucket_name` (`bucket_name`),
+    INDEX `idx_create_time` (`create_time`)
+) ENGINE = InnoDB
+  DEFAULT CHARSET = utf8mb4 COMMENT ='媒体文件信息表';
+
+-- 14. 艺人媒体文件历史记录表
+CREATE TABLE `artist_media_history`
+(
+    `id`            BIGINT AUTO_INCREMENT PRIMARY KEY, -- 主键统一改为id
+    `artist_id`     INT         NOT NULL COMMENT '关联艺人ID(对应artist表id)',
+    `media_type`    VARCHAR(20) NOT NULL COMMENT '媒体类型: avatar/header_image 等',
+    `media_file_id` BIGINT      NOT NULL COMMENT '关联media_file表id',
+    `is_current`    TINYINT  DEFAULT 0 COMMENT '是否为当前使用版本:0-否,1-是',
+    `create_time`   DATETIME DEFAULT CURRENT_TIMESTAMP,
+    FOREIGN KEY (`artist_id`) REFERENCES `artist` (`id`) ON DELETE CASCADE, -- 关联改为艺人表id
+    FOREIGN KEY (`media_file_id`) REFERENCES `media_file` (`id`) ON DELETE RESTRICT -- 关联改为媒体文件表id
+) ENGINE = InnoDB
+  DEFAULT CHARSET = utf8mb4 COMMENT ='艺人媒体文件历史记录表';
+
+CREATE DATABASE IF NOT EXISTS wy_content DEFAULT CHARSET utf8mb4 COLLATE utf8mb4_unicode_ci;
+USE wy_content;
+
+-- 轮播图表(仅新增type字段,保留原字段)
+CREATE TABLE `swipper` (
+                           `id` INT AUTO_INCREMENT COMMENT '主键ID' PRIMARY KEY,
+                           `url` VARCHAR(500) NOT NULL COMMENT '图片URL地址',
+                           `type` TINYINT NOT NULL DEFAULT 1 COMMENT '轮播类型:1-主页轮播,2-商城轮播',
+    -- 索引优化(针对类型查询)
+                           INDEX idx_type (`type`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='轮播图表';

+ 18 - 0
content/src/main/java/com/content/mapper/AlbumMapper.java

@@ -0,0 +1,18 @@
+package com.content.mapper;
+
+import com.content.domain.po.Album;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import org.apache.ibatis.annotations.Mapper;
+
+/**
+ * <p>
+ *  Mapper 接口
+ * </p>
+ *
+ * @author xiang
+ * @since 2025-11-06
+ */
+@Mapper
+public interface AlbumMapper extends BaseMapper<Album> {
+
+}

+ 18 - 0
content/src/main/java/com/content/mapper/ArtistExternalInfoMapper.java

@@ -0,0 +1,18 @@
+package com.content.mapper;
+
+import com.content.domain.po.ArtistExternalInfo;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import org.apache.ibatis.annotations.Mapper;
+
+/**
+ * <p>
+ * 艺人站外社交平台信息表 Mapper 接口
+ * </p>
+ *
+ * @author xiang
+ * @since 2025-11-19
+ */
+@Mapper
+public interface ArtistExternalInfoMapper extends BaseMapper<ArtistExternalInfo> {
+
+}

+ 18 - 0
content/src/main/java/com/content/mapper/ArtistMapper.java

@@ -0,0 +1,18 @@
+package com.content.mapper;
+
+import com.content.domain.po.Artist;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import org.apache.ibatis.annotations.Mapper;
+
+/**
+ * <p>
+ *  Mapper 接口
+ * </p>
+ *
+ * @author xiang
+ * @since 2025-11-06
+ */
+@Mapper
+public interface ArtistMapper extends BaseMapper<Artist> {
+
+}

Niektoré súbory nie sú zobrazené, pretože je v týchto rozdielových dátach zmenené mnoho súborov