Browse Source

各服务中添加以 Admin 为前缀的后台管理 controller, 相应的 service 也以 Admin 为前缀

reghao 7 months ago
parent
commit
58d393174a
58 changed files with 2205 additions and 364 deletions
  1. 0 9
      content/content-api/src/main/java/cn/reghao/tnb/content/api/iface/AdminRecommendService.java
  2. 0 10
      content/content-api/src/main/java/cn/reghao/tnb/content/api/iface/AdminSiteService.java
  3. 10 4
      content/content-api/src/main/java/cn/reghao/tnb/content/api/iface/AdminVideoService.java
  4. 0 21
      content/content-api/src/main/java/cn/reghao/tnb/content/api/iface/UserContentService.java
  5. 106 0
      content/content-service/src/main/java/cn/reghao/tnb/content/app/vod/controller/AdminVodController.java
  6. 6 5
      content/content-service/src/main/java/cn/reghao/tnb/content/app/vod/controller/ContentController.java
  7. 15 0
      content/content-service/src/main/java/cn/reghao/tnb/content/app/vod/model/vo/SelectOption.java
  8. 15 0
      content/content-service/src/main/java/cn/reghao/tnb/content/app/vod/model/vo/VideoInfo.java
  9. 0 25
      content/content-service/src/main/java/cn/reghao/tnb/content/app/vod/rpc/AdminRecommendServiceImpl.java
  10. 0 33
      content/content-service/src/main/java/cn/reghao/tnb/content/app/vod/rpc/AdminSiteServiceImpl.java
  11. 15 48
      content/content-service/src/main/java/cn/reghao/tnb/content/app/vod/rpc/AdminVideoServiceImpl.java
  12. 0 40
      content/content-service/src/main/java/cn/reghao/tnb/content/app/vod/rpc/UserContentServiceImpl.java
  13. 221 0
      content/content-service/src/main/java/cn/reghao/tnb/content/app/vod/service/AdminVodService.java
  14. 0 32
      content/content-service/src/test/java/cn/reghao/tnb/content/app/vod/service/DiscoveryTest.java
  15. 0 13
      file/file-api/src/main/java/cn/reghao/file/api/iface/StoreConfigService.java
  16. 35 0
      file/file-service/src/main/java/cn/reghao/tnb/file/app/controller/AdminFileController.java
  17. 5 5
      file/file-service/src/main/java/cn/reghao/tnb/file/app/delay/task/PublishVideoTask.java
  18. 1 1
      file/file-service/src/main/java/cn/reghao/tnb/file/app/model/dto/StoreConfigInfo.java
  19. 1 4
      file/file-service/src/main/java/cn/reghao/tnb/file/app/rpc/JobServiceImpl.java
  20. 2 4
      file/file-service/src/main/java/cn/reghao/tnb/file/app/rpc/StoreConfigServiceImpl.java
  21. 0 15
      file/file-service/src/test/java/FileTest.java
  22. 0 19
      message/message-api/src/main/java/cn/reghao/tnb/message/api/iface/EmailAccountService.java
  23. 35 0
      message/message-service/src/main/java/cn/reghao/tnb/message/app/controller/AdminMessageController.java
  24. 0 18
      message/message-service/src/main/java/cn/reghao/tnb/message/app/controller/MessageController.java
  25. 1 1
      message/message-service/src/main/java/cn/reghao/tnb/message/app/model/dto/EmailDto.java
  26. 1 1
      message/message-service/src/main/java/cn/reghao/tnb/message/app/model/po/EmailAccount.java
  27. 6 19
      message/message-service/src/main/java/cn/reghao/tnb/message/app/service/EmailAccountService.java
  28. 2 2
      message/message-service/src/main/java/cn/reghao/tnb/message/app/service/notifier/email/EmailNotify.java
  29. 16 0
      search/search-service/pom.xml
  30. 29 0
      search/search-service/src/main/java/cn/reghao/tnb/search/app/config/SpringDocConfig.java
  31. 34 0
      search/search-service/src/main/java/cn/reghao/tnb/search/app/soa/controller/TnbGatewayController.java
  32. 123 0
      search/search-service/src/main/java/cn/reghao/tnb/search/app/soa/controller/TnbLogController.java
  33. 101 0
      search/search-service/src/main/java/cn/reghao/tnb/search/app/soa/controller/TnbServiceController.java
  34. 13 0
      search/search-service/src/main/java/cn/reghao/tnb/search/app/soa/db/mapper/BackendSystemRepository.java
  35. 26 0
      search/search-service/src/main/java/cn/reghao/tnb/search/app/soa/model/po/BackendSystem.java
  36. 23 0
      search/search-service/src/main/java/cn/reghao/tnb/search/app/soa/model/po/DubboSrv.java
  37. 21 0
      search/search-service/src/main/java/cn/reghao/tnb/search/app/soa/model/po/SpringCloudService.java
  38. 83 0
      search/search-service/src/main/java/cn/reghao/tnb/search/app/soa/model/route/FilterDefinition.java
  39. 51 0
      search/search-service/src/main/java/cn/reghao/tnb/search/app/soa/model/route/NameUtils.java
  40. 84 0
      search/search-service/src/main/java/cn/reghao/tnb/search/app/soa/model/route/PredicateDefinition.java
  41. 134 0
      search/search-service/src/main/java/cn/reghao/tnb/search/app/soa/model/route/RouteDefinition.java
  42. 18 0
      search/search-service/src/main/java/cn/reghao/tnb/search/app/soa/model/vo/EurekaInstance.java
  43. 18 0
      search/search-service/src/main/java/cn/reghao/tnb/search/app/soa/model/vo/EurekaService.java
  44. 15 0
      search/search-service/src/main/java/cn/reghao/tnb/search/app/soa/model/vo/KeyValue.java
  45. 23 0
      search/search-service/src/main/java/cn/reghao/tnb/search/app/soa/model/vo/RouteDefinitionInfo.java
  46. 15 0
      search/search-service/src/main/java/cn/reghao/tnb/search/app/soa/model/vo/SelectOption.java
  47. 34 0
      search/search-service/src/main/java/cn/reghao/tnb/search/app/soa/model/vo/ServiceInfo.java
  48. 18 0
      search/search-service/src/main/java/cn/reghao/tnb/search/app/soa/service/LoggingService.java
  49. 113 0
      search/search-service/src/main/java/cn/reghao/tnb/search/app/soa/service/RouteService.java
  50. 31 0
      search/search-service/src/main/java/cn/reghao/tnb/search/app/soa/service/RuntimeLogService.java
  51. 81 0
      search/search-service/src/main/java/cn/reghao/tnb/search/app/soa/service/TnbEurekaService.java
  52. 96 0
      search/search-service/src/main/java/cn/reghao/tnb/search/app/soa/service/TnbService.java
  53. 384 0
      search/search-service/src/main/java/cn/reghao/tnb/search/app/soa/service/TnbZkService.java
  54. 1 1
      search/search-service/src/main/java/cn/reghao/tnb/search/app/ws/handler/LogHandler.java
  55. 0 17
      user/user-api/src/main/java/cn/reghao/tnb/user/api/iface/AdminUserService.java
  56. 88 0
      user/user-service/src/main/java/cn/reghao/tnb/user/app/controller/AdminUserController.java
  57. 55 14
      user/user-service/src/main/java/cn/reghao/tnb/user/app/service/AdminUserService.java
  58. 0 3
      user/user-service/src/main/java/cn/reghao/tnb/user/app/service/UserProfileService.java

+ 0 - 9
content/content-api/src/main/java/cn/reghao/tnb/content/api/iface/AdminRecommendService.java

@@ -1,9 +0,0 @@
-package cn.reghao.tnb.content.api.iface;
-
-/**
- * @author reghao
- * @date 2025-04-01 14:34:51
- */
-public interface AdminRecommendService {
-    void emptyRecommendData();
-}

+ 0 - 10
content/content-api/src/main/java/cn/reghao/tnb/content/api/iface/AdminSiteService.java

@@ -1,10 +0,0 @@
-package cn.reghao.tnb.content.api.iface;
-
-/**
- * @author reghao
- * @date 2024-07-31 21:01:16
- */
-public interface AdminSiteService {
-    String getSiteNotice();
-    void setSiteNotice(String content);
-}

+ 10 - 4
content/content-api/src/main/java/cn/reghao/tnb/content/api/iface/AdminVideoService.java

@@ -1,6 +1,7 @@
 package cn.reghao.tnb.content.api.iface;
 
 import cn.reghao.jutil.jdk.db.PageList;
+import cn.reghao.jutil.jdk.result.Result;
 import cn.reghao.tnb.content.api.dto.*;
 
 import java.util.List;
@@ -10,9 +11,14 @@ import java.util.List;
  * @date 2024-02-15 09:38:40
  */
 public interface AdminVideoService {
-    List<VideoRegion> getVideoRegions();
-    PageList<UserVideoPost> getVideoPosts(VideoSearch videoSearch);
-    VideoUrls getVideoUrl(String videoId);
-    Long getImageAlbum(String objectId);
+    /**
+     * 获取发布内容的用户列表
+     *
+     * @param
+     * @return
+     * @date 2024-08-03 23:08:488
+     */
+    List<Long> getContentUser(int publishType);
+    Result setVideoPostPublish(String videoId);
     void addConvertedVideo(VideoConvertedDto videoConvertedDto);
 }

+ 0 - 21
content/content-api/src/main/java/cn/reghao/tnb/content/api/iface/UserContentService.java

@@ -1,21 +0,0 @@
-package cn.reghao.tnb.content.api.iface;
-
-import cn.reghao.jutil.jdk.result.Result;
-
-import java.util.List;
-
-/**
- * @author reghao
- * @date 2024-08-03 23:03:32
- */
-public interface UserContentService {
-    /**
-     * 获取发布内容的用户列表
-     *
-     * @param
-     * @return
-     * @date 2024-08-03 23:08:488
-     */
-    List<Long> getContentUser(int publishType);
-    Result setVideoPostPublish(String videoId);
-}

+ 106 - 0
content/content-service/src/main/java/cn/reghao/tnb/content/app/vod/controller/AdminVodController.java

@@ -0,0 +1,106 @@
+package cn.reghao.tnb.content.app.vod.controller;
+
+import cn.reghao.file.api.dto.JobInfo;
+import cn.reghao.jutil.jdk.db.PageList;
+import cn.reghao.jutil.web.ServletUtil;
+import cn.reghao.jutil.web.WebResult;
+import cn.reghao.tnb.account.api.dto.AccountRegistry;
+import cn.reghao.tnb.account.api.iface.AdminAccountService;
+import cn.reghao.tnb.content.api.dto.UserVideoPost;
+import cn.reghao.tnb.content.api.dto.VideoRegion;
+import cn.reghao.tnb.content.api.dto.VideoSearch;
+import cn.reghao.tnb.content.api.dto.VideoUrls;
+import cn.reghao.tnb.content.app.vod.model.vo.SelectOption;
+import cn.reghao.tnb.content.app.vod.service.AdminVodService;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import org.apache.dubbo.config.annotation.DubboReference;
+import org.springframework.http.MediaType;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.Collection;
+import java.util.List;
+import java.util.stream.Collectors;
+
+/**
+ * @author reghao
+ * @date 2025-09-26 20:03:57
+ */
+@Tag(name = "vod 管理接口")
+@RestController
+@RequestMapping("/api/content/vod/admin")
+public class AdminVodController {
+    @DubboReference(check = false, timeout = 60_000)
+    private AdminAccountService adminAccountService;
+    private final AdminVodService adminVodService;
+
+    public AdminVodController(AdminVodService adminVodService) {
+        this.adminVodService = adminVodService;
+    }
+
+    @Operation(summary = "稿件列表", description = "N")
+    @GetMapping(value = "/list", produces = MediaType.APPLICATION_JSON_VALUE)
+    public String postIndex(VideoSearch videoSearch
+                            /*@RequestParam(value = "durationGt", required = false) String durationGt,
+                            @RequestParam(value = "direction", required = false) String direction,
+                            @RequestParam(value = "orderBy", required = false) String orderBy,*/) {
+        int pageNumber = Integer.parseInt(ServletUtil.getRequestParam("pageNo", "1"));
+        videoSearch.setPageNo(pageNumber);
+        videoSearch.setOrderBy("publishAt");
+        videoSearch.setOrderDirection("DESC");
+
+        PageList<UserVideoPost> pageList = adminVodService.getUserVideoPosts(videoSearch);
+
+        String durationGt = "";
+        List<SelectOption> durationList = List.of(new SelectOption("2", "2"), new SelectOption("5", "5"), new SelectOption("10", "10"));
+
+        String direction = "";
+        List<SelectOption> directionList = List.of(new SelectOption("v", "v"), new SelectOption("h", "h"));
+
+        String orderBy = "";
+        List<SelectOption> orderByList = List.of(new SelectOption("duration", "duration"), new SelectOption("publishAt", "publishAt"));
+        return WebResult.success(pageList);
+    }
+
+    @Operation(summary = "稿件预览", description = "N")
+    @GetMapping(value = "/video_preview/{videoId}", produces = MediaType.APPLICATION_JSON_VALUE)
+    @ResponseBody
+    public String previewPage(@PathVariable(value = "videoId") String videoId) {
+        VideoUrls videoInfo = adminVodService.getVideoUrl(videoId);
+        return WebResult.success(videoInfo);
+    }
+
+    @Operation(summary = "延时任务列表", description = "N")
+    @GetMapping(value = "/video_convert", produces = MediaType.APPLICATION_JSON_VALUE)
+    public String videoConvertList() {
+        PageList<JobInfo> pageList = adminVodService.getJobs();
+        return WebResult.success(pageList);
+    }
+
+    @Operation(summary = "站点公告", description = "N")
+    @GetMapping(value = "/site_notice", produces = MediaType.APPLICATION_JSON_VALUE)
+    public String siteNoticePage() {
+        AccountRegistry accountRegistry = adminAccountService.getAccountRegistry();
+        String content = adminVodService.getSiteNotice();
+        return WebResult.success(content);
+    }
+
+    @Operation(summary = "添加站点公告", description = "N")
+    @PostMapping(value = "/site_notice", produces = MediaType.APPLICATION_JSON_VALUE)
+    @ResponseBody
+    public String addSiteNotice(String content) {
+        adminVodService.addSiteNotice(content);
+        return WebResult.success();
+    }
+
+    @Operation(summary = "视频分区", description = "N")
+    @GetMapping(value = "/video_category", produces = MediaType.APPLICATION_JSON_VALUE)
+    public String index() {
+        List<VideoRegion> list = adminVodService.getVideoRegions();
+        List<VideoRegion> regions = list.stream()
+                .map(VideoRegion::getChildren)
+                .flatMap(Collection::stream)
+                .collect(Collectors.toList());
+        return WebResult.success(regions);
+    }
+}

+ 6 - 5
content/content-service/src/main/java/cn/reghao/tnb/content/app/vod/controller/ContentController.java

@@ -2,8 +2,8 @@ package cn.reghao.tnb.content.app.vod.controller;
 
 import cn.reghao.jutil.web.WebResult;
 import cn.reghao.tnb.account.api.iface.AccountQuery;
-import cn.reghao.tnb.content.api.iface.AdminSiteService;
 import cn.reghao.tnb.content.app.vod.model.vo.UserContentData;
+import cn.reghao.tnb.content.app.vod.service.AdminVodService;
 import cn.reghao.tnb.content.app.vod.service.ContentService;
 import cn.reghao.tnb.content.app.vod.service.LogService;
 import io.swagger.v3.oas.annotations.tags.Tag;
@@ -25,18 +25,19 @@ import org.springframework.web.bind.annotation.*;
 public class ContentController {
     @DubboReference(check = false, retries = 0, timeout = 60_000)
     private AccountQuery accountQuery;
-    private final AdminSiteService siteService;
+
+    private final AdminVodService adminVodService;
     private final ContentService contentService;
 
-    public ContentController(AdminSiteService siteService, ContentService contentService) {
-        this.siteService = siteService;
+    public ContentController(AdminVodService adminVodService, ContentService contentService) {
+        this.adminVodService = adminVodService;
         this.contentService = contentService;
     }
 
     @Operation(summary = "获取站点公告", description = "N")
     @GetMapping("/site/notice")
     public String getSiteNotice() {
-        String notice = siteService.getSiteNotice();
+        String notice = adminVodService.getSiteNotice();
         return WebResult.success(notice);
     }
 

+ 15 - 0
content/content-service/src/main/java/cn/reghao/tnb/content/app/vod/model/vo/SelectOption.java

@@ -0,0 +1,15 @@
+package cn.reghao.tnb.content.app.vod.model.vo;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+/**
+ * @author reghao
+ * @date 2021-06-03 19:00:57
+ */
+@AllArgsConstructor
+@Getter
+public class SelectOption {
+    private String key;
+    private String value;
+}

+ 15 - 0
content/content-service/src/main/java/cn/reghao/tnb/content/app/vod/model/vo/VideoInfo.java

@@ -0,0 +1,15 @@
+package cn.reghao.tnb.content.app.vod.model.vo;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+/**
+ * @author reghao
+ * @date 2024-07-31 21:41:57
+ */
+@AllArgsConstructor
+@Getter
+public class VideoInfo {
+    private String videoId;
+    private String url;
+}

+ 0 - 25
content/content-service/src/main/java/cn/reghao/tnb/content/app/vod/rpc/AdminRecommendServiceImpl.java

@@ -1,25 +0,0 @@
-package cn.reghao.tnb.content.app.vod.rpc;
-
-import cn.reghao.tnb.content.api.iface.AdminRecommendService;
-import cn.reghao.tnb.content.app.vod.service.RecommendService;
-import org.apache.dubbo.config.annotation.DubboService;
-import org.springframework.stereotype.Service;
-
-/**
- * @author reghao
- * @date 2025-04-01 14:35:44
- */
-@DubboService
-@Service
-public class AdminRecommendServiceImpl implements AdminRecommendService {
-    private final RecommendService recommendService;
-
-    public AdminRecommendServiceImpl(RecommendService recommendService) {
-        this.recommendService = recommendService;
-    }
-
-    public void emptyRecommendData() {
-        long userId = -1L;
-        recommendService.resetUserRcmd(userId);
-    }
-}

+ 0 - 33
content/content-service/src/main/java/cn/reghao/tnb/content/app/vod/rpc/AdminSiteServiceImpl.java

@@ -1,33 +0,0 @@
-package cn.reghao.tnb.content.app.vod.rpc;
-
-import cn.reghao.tnb.content.api.iface.AdminSiteService;
-import cn.reghao.tnb.content.app.vod.db.mapper.SiteNoticeMapper;
-import cn.reghao.tnb.content.app.vod.model.po.SiteNotice;
-import org.apache.dubbo.config.annotation.DubboService;
-import org.springframework.stereotype.Service;
-
-/**
- * @author reghao
- * @date 2024-07-06 09:33:10
- */
-@DubboService
-@Service
-public class AdminSiteServiceImpl implements AdminSiteService {
-    private final SiteNoticeMapper siteNoticeMapper;
-
-    public AdminSiteServiceImpl(SiteNoticeMapper siteNoticeMapper) {
-        this.siteNoticeMapper = siteNoticeMapper;
-    }
-
-    @Override
-    public void setSiteNotice(String content) {
-        long createBy = 10000;
-        SiteNotice siteNotice = new SiteNotice(content, createBy);
-        siteNoticeMapper.save(siteNotice);
-    }
-
-    public String getSiteNotice() {
-        SiteNotice siteNotice = siteNoticeMapper.findLatest();
-        return siteNotice != null ? siteNotice.getContent() : "N/A";
-    }
-}

+ 15 - 48
content/content-service/src/main/java/cn/reghao/tnb/content/app/vod/rpc/AdminVideoServiceImpl.java

@@ -3,10 +3,12 @@ package cn.reghao.tnb.content.app.vod.rpc;
 import cn.reghao.file.api.iface.OssService;
 import cn.reghao.jutil.jdk.db.Page;
 import cn.reghao.jutil.jdk.db.PageList;
+import cn.reghao.jutil.jdk.result.Result;
 import cn.reghao.jutil.jdk.serializer.JsonConverter;
 import cn.reghao.oss.sdk.model.constant.ObjectScope;
 import cn.reghao.oss.sdk.model.dto.media.VideoInfo;
 import cn.reghao.oss.sdk.model.dto.media.VideoUrlDto;
+import cn.reghao.tnb.common.db.GroupCount;
 import cn.reghao.tnb.content.api.constant.PostScope;
 import cn.reghao.tnb.content.api.dto.*;
 import cn.reghao.tnb.content.api.iface.AdminVideoService;
@@ -119,54 +121,6 @@ public class AdminVideoServiceImpl implements AdminVideoService {
         rabbitTemplate.convertAndSend(routeKey, JsonConverter.objectToJson(list));
     }
 
-    @Override
-    public VideoUrls getVideoUrl(String videoId) {
-        double currentTime = 0.0;
-        VideoPost videoPost = videoPostMapper.findByVideoId(videoId);
-        if (videoPost == null) {
-            return new VideoUrls();
-        }
-
-        List<VideoUrlDto> list = videoRepository.findVideoUrls(videoId);
-        if (list.isEmpty()) {
-            return new VideoUrls();
-        }
-
-        String urlType = list.get(0).getType();
-        int scope = videoPost.getScope();
-        if (scope != PostScope.PUBLIC.getCode()) {
-            try {
-                List<VideoUrl> urls = list.stream().map(videoUrlDto -> {
-                    try {
-                        int channelId = videoUrlDto.getChannelCode();
-                        String quality = videoUrlDto.getQuality();
-                        String signedUrl = ossService.getSignedUrl(channelId, videoUrlDto.getObjectId());
-                        return new VideoUrl(quality, signedUrl);
-                    } catch (Exception e) {
-                        e.printStackTrace();
-                    }
-                    return null;
-                }).filter(Objects::nonNull).collect(Collectors.toList());
-                return new VideoUrls(currentTime, urlType, urls);
-            } catch (Exception e) {
-                e.printStackTrace();
-            }
-            return new VideoUrls();
-        } else {
-            List<VideoUrl> urls = list.stream().map(videoUrlDto -> {
-                String quality = videoUrlDto.getQuality();
-                String url = videoUrlDto.getUrl();
-                return new VideoUrl(quality, url);
-            }).collect(Collectors.toList());
-            return new VideoUrls(currentTime, urlType, urls);
-        }
-    }
-
-    @Override
-    public Long getImageAlbum(String objectId) {
-        return null;
-    }
-
     @Override
     public void addConvertedVideo(VideoConvertedDto videoConvertedDto) {
         /*String uploadId = videoConvertedDto.getUploadId();
@@ -193,4 +147,17 @@ public class AdminVideoServiceImpl implements AdminVideoService {
             e.printStackTrace();
         }*/
     }
+
+    @Override
+    public List<Long> getContentUser(int publishType) {
+        List<GroupCount> list = videoRepository.getPublishUsers(publishType);
+        return list.stream()
+                .map(groupCount -> Long.valueOf(groupCount.getId()))
+                .collect(Collectors.toList());
+    }
+
+    @Override
+    public Result setVideoPostPublish(String videoId) {
+        return Result.fail("not implement");
+    }
 }

+ 0 - 40
content/content-service/src/main/java/cn/reghao/tnb/content/app/vod/rpc/UserContentServiceImpl.java

@@ -1,40 +0,0 @@
-package cn.reghao.tnb.content.app.vod.rpc;
-
-import cn.reghao.jutil.jdk.result.Result;
-import cn.reghao.tnb.content.api.constant.VideoStatus;
-import cn.reghao.tnb.content.api.iface.UserContentService;
-import cn.reghao.tnb.content.app.vod.db.repository.VideoRepository;
-import cn.reghao.tnb.common.db.GroupCount;
-import cn.reghao.tnb.content.app.vod.model.po.VideoPost;
-import org.apache.dubbo.config.annotation.DubboService;
-import org.springframework.stereotype.Service;
-
-import java.util.List;
-import java.util.stream.Collectors;
-
-/**
- * @author reghao
- * @date 2024-08-03 23:04:28
- */
-@DubboService
-@Service
-public class UserContentServiceImpl implements UserContentService {
-    private final VideoRepository videoRepository;
-
-    public UserContentServiceImpl(VideoRepository videoRepository) {
-        this.videoRepository = videoRepository;
-    }
-
-    @Override
-    public List<Long> getContentUser(int publishType) {
-        List<GroupCount> list = videoRepository.getPublishUsers(publishType);
-        return list.stream()
-                .map(groupCount -> Long.valueOf(groupCount.getId()))
-                .collect(Collectors.toList());
-    }
-
-    @Override
-    public Result setVideoPostPublish(String videoId) {
-        return Result.fail("not implement");
-    }
-}

+ 221 - 0
content/content-service/src/main/java/cn/reghao/tnb/content/app/vod/service/AdminVodService.java

@@ -0,0 +1,221 @@
+package cn.reghao.tnb.content.app.vod.service;
+
+import cn.reghao.file.api.dto.JobInfo;
+import cn.reghao.file.api.iface.FileService;
+import cn.reghao.file.api.iface.OssService;
+import cn.reghao.jutil.jdk.db.PageList;
+import cn.reghao.jutil.jdk.serializer.JsonConverter;
+import cn.reghao.oss.sdk.model.dto.media.VideoUrlDto;
+import cn.reghao.tnb.content.api.constant.PostScope;
+import cn.reghao.tnb.content.api.dto.*;
+import cn.reghao.tnb.content.app.vod.db.mapper.SiteNoticeMapper;
+import cn.reghao.tnb.content.app.vod.db.mapper.VideoPostMapper;
+import cn.reghao.tnb.content.app.vod.db.repository.VideoRepository;
+import cn.reghao.tnb.content.app.vod.model.po.BannerVideo;
+import cn.reghao.tnb.content.app.vod.model.po.SiteNotice;
+import cn.reghao.tnb.content.app.vod.model.po.VideoCategory;
+import cn.reghao.tnb.content.app.vod.model.po.VideoPost;
+import cn.reghao.tnb.content.app.vod.model.query.VideoQuery;
+import org.apache.dubbo.config.annotation.DubboReference;
+import org.springframework.amqp.rabbit.core.RabbitTemplate;
+import org.springframework.data.domain.Page;
+import org.springframework.data.domain.PageImpl;
+import org.springframework.data.domain.PageRequest;
+import org.springframework.stereotype.Service;
+
+import java.util.*;
+import java.util.stream.Collectors;
+
+/**
+ * @author reghao
+ * @date 2024-07-06 22:16:55
+ */
+@Service
+public class AdminVodService {
+    @DubboReference(check = false)
+    private OssService ossService;
+    @DubboReference(check = false)
+    private FileService fileService;
+
+    private int pageSize = 100;
+    private RabbitTemplate rabbitTemplate;
+    private SiteNoticeMapper siteNoticeMapper;
+    private VideoPostMapper videoPostMapper;
+    private VideoPostQuery videoPostQuery;
+    private VideoRepository videoRepository;
+    private CategoryService categoryService;
+
+    public AdminVodService(RabbitTemplate rabbitTemplate, SiteNoticeMapper siteNoticeMapper, VideoPostMapper videoPostMapper,
+                           VideoPostQuery videoPostQuery, VideoRepository videoRepository, CategoryService categoryService) {
+        this.rabbitTemplate = rabbitTemplate;
+        this.siteNoticeMapper = siteNoticeMapper;
+        this.videoPostMapper = videoPostMapper;
+        this.videoPostQuery = videoPostQuery;
+        this.videoRepository = videoRepository;
+        this.categoryService = categoryService;
+    }
+
+    public void addSiteNotice(String content) {
+        setSiteNotice(content);
+    }
+
+    public void setSiteNotice(String content) {
+        long createBy = 10000;
+        SiteNotice siteNotice = new SiteNotice(content, createBy);
+        siteNoticeMapper.save(siteNotice);
+    }
+
+    public String getSiteNotice() {
+        SiteNotice siteNotice = siteNoticeMapper.findLatest();
+        return siteNotice != null ? siteNotice.getContent() : "N/A";
+    }
+
+    public PageList<UserVideoPost> getUserVideoPosts(VideoSearch videoSearch) {
+        PageList<UserVideoPost> pageList = getVideoPosts(videoSearch);
+        return pageList;
+    }
+
+    public List<VideoRegion> getVideoCategories() {
+        return Collections.emptyList();
+    }
+
+    public PageList<JobInfo> getJobs() {
+        PageList<JobInfo> pageList = fileService.getJobs(1, 10);
+        return pageList;
+    }
+
+    public List<VideoRegion> getVideoRegions() {
+        List<VideoCategory> list0 = categoryService.getAllCategory();
+        List<VideoRegion> menuTrees = list0.stream().map(videoCategory -> {
+            int pid = videoCategory.getPid();
+            int id = videoCategory.getId();
+            String name = videoCategory.getName();
+            int sort = videoCategory.getSort();
+            return new VideoRegion(pid, id, name, sort);
+        }).collect(Collectors.toList());
+
+        Map<Integer, VideoRegion> allMap = menuTrees.stream().collect(Collectors.toMap(VideoRegion::getId, k -> k));
+
+        Set<Integer> set = new HashSet<>();
+        menuTrees.forEach(menuTree -> {
+            int pid = menuTree.getPid();
+            VideoRegion menuTree1 = allMap.get(pid);
+            if (menuTree1 != null) {
+                List<VideoRegion> list = menuTree1.getChildren();
+                if (list == null) {
+                    list = new ArrayList<>();
+                    menuTree1.setChildren(list);
+                }
+
+                menuTree1.getChildren().add(menuTree);
+                menuTree1.getChildren().sort(Comparator.comparingInt(VideoRegion::getSort));
+                //allMap.remove(menuTree.getId());
+                set.add(menuTree.getId());
+            }
+        });
+
+        set.forEach(allMap::remove);
+        List<VideoRegion> results = new ArrayList<>(allMap.values());
+        results.sort(Comparator.comparingInt(VideoRegion::getSort));
+        return results;
+    }
+
+    public PageList<UserVideoPost> getVideoPosts(VideoSearch videoSearch) {
+        int pageNumber = videoSearch.getPageNumber();
+        int pageSize = videoSearch.getPageSize();
+        cn.reghao.jutil.jdk.db.Page page = new cn.reghao.jutil.jdk.db.Page(pageNumber, pageSize);
+        String content = videoSearch.getContent();
+
+        VideoQuery videoQuery = new VideoQuery.Builder()
+                .status(null)
+                .scope(null)
+                .title(content)
+                .orderBy(videoSearch.getOrderBy())
+                .orderDirection(videoSearch.getOrderDirection())
+                .build();
+        int total = videoPostMapper.countAdminVideo(videoQuery);
+        List<UserVideoPost>list = videoPostMapper.findAdminVideoByPage(page, videoQuery).stream()
+                .map(videoPostQuery::getUserVideoPost)
+                .collect(Collectors.toList());
+        return PageList.pageList(pageNumber, 20, total, list);
+    }
+
+    @Deprecated
+    public void setHotVideo() {
+        String routeKey = "tnb.data";
+        List<BannerVideo> list = new ArrayList<>();
+        rabbitTemplate.convertAndSend(routeKey, JsonConverter.objectToJson(list));
+    }
+
+    public VideoUrls getVideoUrl(String videoId) {
+        double currentTime = 0.0;
+        VideoPost videoPost = videoPostMapper.findByVideoId(videoId);
+        if (videoPost == null) {
+            return new VideoUrls();
+        }
+
+        List<VideoUrlDto> list = videoRepository.findVideoUrls(videoId);
+        if (list.isEmpty()) {
+            return new VideoUrls();
+        }
+
+        String urlType = list.get(0).getType();
+        int scope = videoPost.getScope();
+        if (scope != PostScope.PUBLIC.getCode()) {
+            try {
+                List<VideoUrl> urls = list.stream().map(videoUrlDto -> {
+                    try {
+                        int channelId = videoUrlDto.getChannelCode();
+                        String quality = videoUrlDto.getQuality();
+                        String signedUrl = ossService.getSignedUrl(channelId, videoUrlDto.getObjectId());
+                        return new VideoUrl(quality, signedUrl);
+                    } catch (Exception e) {
+                        e.printStackTrace();
+                    }
+                    return null;
+                }).filter(Objects::nonNull).collect(Collectors.toList());
+                return new VideoUrls(currentTime, urlType, urls);
+            } catch (Exception e) {
+                e.printStackTrace();
+            }
+            return new VideoUrls();
+        } else {
+            List<VideoUrl> urls = list.stream().map(videoUrlDto -> {
+                String quality = videoUrlDto.getQuality();
+                String url = videoUrlDto.getUrl();
+                return new VideoUrl(quality, url);
+            }).collect(Collectors.toList());
+            return new VideoUrls(currentTime, urlType, urls);
+        }
+    }
+
+    public Long getImageAlbum(String objectId) {
+        return null;
+    }
+
+    public void addConvertedVideo(VideoConvertedDto videoConvertedDto) {
+        /*String uploadId = videoConvertedDto.getUploadId();
+        int channelCode = videoConvertedDto.getChannelCode();
+        try {
+            VideoInfo videoInfo = ossService.getVideoInfo(channelCode, uploadId);
+            if (videoInfo == null) {
+                String errMsg = String.format("视频文件 %s 在 oss 中不存在", uploadId);
+                log.info(errMsg);
+                return;
+            }
+
+            String videoFileId = videoConvertedDto.getVideoFileId();
+            VideoPost videoPost = videoRepository.getVideoPostByFileId(videoFileId);
+            int scope = videoPost.getScope();
+            if (scope != ObjectScope.PRIVATE.getCode()) {
+                ossService.setObjectScope(channelCode, uploadId, scope);
+            }
+
+            String videoId = videoPost.getVideoId();
+            VideoFile videoFile = new VideoFile(videoId, videoFileId, channelCode, videoInfo);
+            videoRepository.updateVideoPublish(videoId, videoFile);
+        } catch (Exception e) {
+            e.printStackTrace();
+        }*/
+    }
+}

+ 0 - 32
content/content-service/src/test/java/cn/reghao/tnb/content/app/vod/service/DiscoveryTest.java

@@ -1,32 +0,0 @@
-package cn.reghao.tnb.content.app.vod.service;
-
-import cn.reghao.tnb.content.app.ContentApplication;
-import com.netflix.discovery.EurekaClient;
-import com.netflix.discovery.shared.Applications;
-import org.junit.jupiter.api.Test;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.boot.test.context.SpringBootTest;
-import org.springframework.cloud.client.discovery.DiscoveryClient;
-import org.springframework.test.context.ActiveProfiles;
-
-import java.util.List;
-
-/**
- * @author reghao
- * @date 2025-07-18 17:31:05
- */
-@ActiveProfiles("dev")
-@SpringBootTest(classes = ContentApplication.class)
-public class DiscoveryTest {
-    @Autowired
-    DiscoveryClient discoveryClient;
-    @Autowired
-    EurekaClient eurekaClient;
-    @Test
-    public void discoveryClientTest() {
-        List<String> list = discoveryClient.getServices();
-        eurekaClient.getApplicationInfoManager();
-        Applications applications = eurekaClient.getApplications();
-        System.out.println();
-    }
-}

+ 0 - 13
file/file-api/src/main/java/cn/reghao/file/api/iface/StoreConfigService.java

@@ -1,13 +0,0 @@
-package cn.reghao.file.api.iface;
-
-import cn.reghao.file.api.dto.StoreConfigInfo;
-
-import java.util.List;
-
-/**
- * @author reghao
- * @date 2024-11-01 09:44:59
- */
-public interface StoreConfigService {
-    List<StoreConfigInfo> getStoreConfigs();
-}

+ 35 - 0
file/file-service/src/main/java/cn/reghao/tnb/file/app/controller/AdminFileController.java

@@ -0,0 +1,35 @@
+package cn.reghao.tnb.file.app.controller;
+
+import cn.reghao.jutil.web.WebResult;
+import cn.reghao.tnb.file.app.model.po.StoreConfig;
+import cn.reghao.tnb.file.app.service.StoreConfigService;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import org.springframework.http.MediaType;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.util.List;
+
+/**
+ * @author reghao
+ * @date 2025-09-26 20:40:27
+ */
+@Tag(name = "file 管理接口")
+@RestController
+@RequestMapping("/api/file/admin")
+public class AdminFileController {
+    private final StoreConfigService storeConfigService;
+
+    public AdminFileController(StoreConfigService storeConfigService) {
+        this.storeConfigService = storeConfigService;
+    }
+
+    @Operation(summary = "文件存储配置页面", description = "N")
+    @GetMapping(value = "/file_store", produces = MediaType.APPLICATION_JSON_VALUE)
+    public String siteConfigPage() {
+        List<StoreConfig> list = storeConfigService.getStoreConfigs();
+        return WebResult.success(list);
+    }
+}

+ 5 - 5
file/file-service/src/main/java/cn/reghao/tnb/file/app/delay/task/PublishVideoTask.java

@@ -2,7 +2,7 @@ package cn.reghao.tnb.file.app.delay.task;
 
 import cn.reghao.jutil.jdk.result.Result;
 import cn.reghao.jutil.jdk.result.ResultStatus;
-import cn.reghao.tnb.content.api.iface.UserContentService;
+import cn.reghao.tnb.content.api.iface.AdminVideoService;
 import cn.reghao.tnb.file.app.db.mapper.JobDetailMapper;
 import cn.reghao.tnb.file.app.model.constant.JobStatus;
 
@@ -15,13 +15,13 @@ import java.time.LocalDateTime;
 public class PublishVideoTask implements Runnable {
     private final long jobId;
     private final JobDetailMapper jobDetailMapper;
-    private final UserContentService userContentService;
+    private final AdminVideoService adminVideoService;
     private final String videoId;
 
-    public PublishVideoTask(long jobId, JobDetailMapper jobDetailMapper, UserContentService userContentService, String videoId) {
+    public PublishVideoTask(long jobId, JobDetailMapper jobDetailMapper, AdminVideoService adminVideoService, String videoId) {
         this.jobId = jobId;
         this.jobDetailMapper = jobDetailMapper;
-        this.userContentService = userContentService;
+        this.adminVideoService = adminVideoService;
         this.videoId = videoId;
     }
 
@@ -29,7 +29,7 @@ public class PublishVideoTask implements Runnable {
     public void run() {
         String status = JobStatus.Success.getDesc();
         try {
-            Result result = userContentService.setVideoPostPublish(videoId);
+            Result result = adminVideoService.setVideoPostPublish(videoId);
             if (result.getCode() != ResultStatus.SUCCESS.getCode()) {
                 status = JobStatus.Fail.getDesc();
             }

+ 1 - 1
file/file-api/src/main/java/cn/reghao/file/api/dto/StoreConfigInfo.java → file/file-service/src/main/java/cn/reghao/tnb/file/app/model/dto/StoreConfigInfo.java

@@ -1,4 +1,4 @@
-package cn.reghao.file.api.dto;
+package cn.reghao.tnb.file.app.model.dto;
 
 import lombok.AllArgsConstructor;
 import lombok.Getter;

+ 1 - 4
file/file-service/src/main/java/cn/reghao/tnb/file/app/rpc/JobServiceImpl.java

@@ -6,7 +6,6 @@ import cn.reghao.oss.sdk.OssConsoleClient;
 import cn.reghao.oss.sdk.model.dto.ObjectInfo;
 import cn.reghao.tnb.content.api.iface.AdminVideoService;
 import cn.reghao.tnb.content.api.iface.MallService;
-import cn.reghao.tnb.content.api.iface.UserContentService;
 import cn.reghao.tnb.file.app.config.OssConsoleClientFactory;
 import cn.reghao.tnb.file.app.db.mapper.JobDetailMapper;
 import cn.reghao.tnb.file.app.db.mapper.OrderMapper;
@@ -31,8 +30,6 @@ import java.util.UUID;
 @DubboService
 @Service
 public class JobServiceImpl implements JobService {
-    @DubboReference(check = false, timeout = 60_000)
-    private UserContentService userContentService;
     @DubboReference(check = false, timeout = 60_000)
     private AdminVideoService adminVideoService;
     @DubboReference(check = false, timeout = 60_000)
@@ -71,7 +68,7 @@ public class JobServiceImpl implements JobService {
     @Override
     public long addPublishVideoJob(String videoId, long publishAt) {
         long jobId = idGenerator.nextId();
-        PublishVideoTask publishVideoTask = new PublishVideoTask(jobId, jobDetailMapper, userContentService, videoId);
+        PublishVideoTask publishVideoTask = new PublishVideoTask(jobId, jobDetailMapper, adminVideoService, videoId);
         long delaySecond = (publishAt - System.currentTimeMillis())/1000;
         DelayJob delayJob = new DelayJob(jobId, publishVideoTask, delaySecond);
         jobContext.addJob(delayJob);

+ 2 - 4
file/file-service/src/main/java/cn/reghao/tnb/file/app/rpc/StoreConfigServiceImpl.java

@@ -1,7 +1,6 @@
 package cn.reghao.tnb.file.app.rpc;
 
-import cn.reghao.file.api.dto.StoreConfigInfo;
-import cn.reghao.file.api.iface.StoreConfigService;
+import cn.reghao.tnb.file.app.model.dto.StoreConfigInfo;
 import cn.reghao.tnb.file.app.db.mapper.StoreConfigMapper;
 import cn.reghao.tnb.file.app.model.constant.OssType;
 import cn.reghao.tnb.file.app.model.po.StoreConfig;
@@ -17,14 +16,13 @@ import java.util.stream.Collectors;
  */
 @DubboService
 @Service
-public class StoreConfigServiceImpl implements StoreConfigService {
+public class StoreConfigServiceImpl {
     private final StoreConfigMapper storeConfigMapper;
 
     public StoreConfigServiceImpl(StoreConfigMapper storeConfigMapper) {
         this.storeConfigMapper = storeConfigMapper;
     }
 
-    @Override
     public List<StoreConfigInfo> getStoreConfigs() {
         List<StoreConfig> list = storeConfigMapper.findAll();
         return list.stream().map(this::getStoreConfigInfo).collect(Collectors.toList());

+ 0 - 15
file/file-service/src/test/java/FileTest.java

@@ -1,8 +1,6 @@
 import cn.reghao.tnb.file.app.FileApplication;
 import cn.reghao.tnb.file.app.db.mapper.StoreConfigMapper;
 import cn.reghao.tnb.file.app.model.po.StoreConfig;
-import com.netflix.discovery.EurekaClient;
-import com.netflix.discovery.shared.Applications;
 import lombok.extern.slf4j.Slf4j;
 import org.junit.jupiter.api.Test;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -50,17 +48,4 @@ public class FileTest {
         List<StoreConfig> list = List.of(storeConfig, storeConfig1, storeConfig2);
         storeConfigMapper.saveAll(list);
     }
-
-    @Autowired
-    EurekaClient eurekaClient;
-    @Test
-    public void eurekaClientTest() {
-        Applications applications = eurekaClient.getApplications();
-        applications.getRegisteredApplications().forEach(application -> {
-            String name = application.getName();
-            application.getInstances().forEach(instanceInfo -> {
-                String instanceId = instanceInfo.getInstanceId();
-            });
-        });
-    }
 }

+ 0 - 19
message/message-api/src/main/java/cn/reghao/tnb/message/api/iface/EmailAccountService.java

@@ -1,19 +0,0 @@
-package cn.reghao.tnb.message.api.iface;
-
-import cn.reghao.jutil.jdk.db.PageList;
-import cn.reghao.jutil.jdk.result.Result;
-import cn.reghao.tnb.message.api.dto.EmailDto;
-
-/**
- * @author reghao
- * @date 2024-09-25 13:56:58
- */
-public interface EmailAccountService {
-    Result addEmailAccount(EmailDto emailDto);
-    Result updatePassword(int emailId, String password);
-    Result updateDefaultSender(int emailId);
-    Result deleteEmailAccount(int emailId);
-    EmailDto getEmailAccount(int emailId);
-    EmailDto getEmailSender();
-    PageList<EmailDto> getEmailAccounts(int pageNumber);
-}

+ 35 - 0
message/message-service/src/main/java/cn/reghao/tnb/message/app/controller/AdminMessageController.java

@@ -0,0 +1,35 @@
+package cn.reghao.tnb.message.app.controller;
+
+import cn.reghao.jutil.web.WebResult;
+import cn.reghao.tnb.message.app.model.dto.EmailDto;
+import cn.reghao.tnb.message.app.service.EmailAccountService;
+import org.springframework.http.MediaType;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+/**
+ * @author reghao
+ * @date 2023-10-30 21:32:37
+ */
+@RestController
+@RequestMapping("/api/message/admin")
+public class AdminMessageController {
+    private final EmailAccountService emailAccountService;
+
+    public AdminMessageController(EmailAccountService emailAccountService) {
+        this.emailAccountService = emailAccountService;
+    }
+
+    //@Operation(summary = "第三方通知配置列表页面", description = "N")
+    @GetMapping(value = "/notify", produces = MediaType.APPLICATION_JSON_VALUE)
+    public String notifyPage() {
+        List<EmailDto> list = emailAccountService.getEmailAccounts();
+        return WebResult.success(list);
+    }
+
+    @PostMapping(value = "", produces = MediaType.APPLICATION_JSON_VALUE)
+    public String getMessage() {
+        return WebResult.success();
+    }
+}

+ 0 - 18
message/message-service/src/main/java/cn/reghao/tnb/message/app/controller/MessageController.java

@@ -1,18 +0,0 @@
-package cn.reghao.tnb.message.app.controller;
-
-import cn.reghao.jutil.web.WebResult;
-import org.springframework.http.MediaType;
-import org.springframework.web.bind.annotation.*;
-
-/**
- * @author reghao
- * @date 2023-10-30 21:32:37
- */
-@RestController
-@RequestMapping("/api/message")
-public class MessageController {
-    @GetMapping(value = "", produces = MediaType.APPLICATION_JSON_VALUE)
-    public String getMessage() {
-        return WebResult.success();
-    }
-}

+ 1 - 1
message/message-api/src/main/java/cn/reghao/tnb/message/api/dto/EmailDto.java → message/message-service/src/main/java/cn/reghao/tnb/message/app/model/dto/EmailDto.java

@@ -1,4 +1,4 @@
-package cn.reghao.tnb.message.api.dto;
+package cn.reghao.tnb.message.app.model.dto;
 
 import lombok.AllArgsConstructor;
 import lombok.Getter;

+ 1 - 1
message/message-service/src/main/java/cn/reghao/tnb/message/app/model/po/EmailAccount.java

@@ -1,7 +1,7 @@
 package cn.reghao.tnb.message.app.model.po;
 
 import cn.reghao.jutil.jdk.db.BaseObject;
-import cn.reghao.tnb.message.api.dto.EmailDto;
+import cn.reghao.tnb.message.app.model.dto.EmailDto;
 import lombok.Getter;
 import lombok.NoArgsConstructor;
 import lombok.Setter;

+ 6 - 19
message/message-service/src/main/java/cn/reghao/tnb/message/app/rpc/EmailAccountServiceImpl.java → message/message-service/src/main/java/cn/reghao/tnb/message/app/service/EmailAccountService.java

@@ -1,14 +1,11 @@
-package cn.reghao.tnb.message.app.rpc;
+package cn.reghao.tnb.message.app.service;
 
-import cn.reghao.jutil.jdk.db.Page;
 import cn.reghao.jutil.jdk.db.PageList;
 import cn.reghao.jutil.jdk.result.Result;
 import cn.reghao.jutil.jdk.string.StringRegexp;
-import cn.reghao.tnb.message.api.dto.EmailDto;
-import cn.reghao.tnb.message.api.iface.EmailAccountService;
+import cn.reghao.tnb.message.app.model.dto.EmailDto;
 import cn.reghao.tnb.message.app.db.mapper.EmailAccountMapper;
 import cn.reghao.tnb.message.app.model.po.EmailAccount;
-import org.apache.dubbo.config.annotation.DubboService;
 import org.springframework.stereotype.Service;
 
 import java.util.List;
@@ -18,16 +15,14 @@ import java.util.stream.Collectors;
  * @author reghao
  * @date 2024-09-25 13:56:58
  */
-@DubboService
 @Service
-public class EmailAccountServiceImpl implements EmailAccountService {
+public class EmailAccountService {
     private final EmailAccountMapper emailAccountMapper;
 
-    public EmailAccountServiceImpl(EmailAccountMapper emailAccountMapper) {
+    public EmailAccountService(EmailAccountMapper emailAccountMapper) {
         this.emailAccountMapper = emailAccountMapper;
     }
 
-    @Override
     public Result addEmailAccount(EmailDto emailDto) {
         String email = emailDto.getUsername();
         boolean matched = StringRegexp.matchEmail(email);
@@ -51,7 +46,6 @@ public class EmailAccountServiceImpl implements EmailAccountService {
         return Result.success();
     }
 
-    @Override
     public Result updatePassword(int emailId, String password) {
         EmailAccount emailAccount = emailAccountMapper.findById(emailId);
         if (emailAccount == null) {
@@ -63,7 +57,6 @@ public class EmailAccountServiceImpl implements EmailAccountService {
         return Result.success();
     }
 
-    @Override
     public Result updateDefaultSender(int emailId) {
         EmailAccount emailAccount = emailAccountMapper.findById(emailId);
         if (emailAccount == null) {
@@ -82,7 +75,6 @@ public class EmailAccountServiceImpl implements EmailAccountService {
         return Result.success();
     }
 
-    @Override
     public Result deleteEmailAccount(int emailId) {
         EmailAccount emailAccount = emailAccountMapper.findById(emailId);
         if (emailAccount == null) {
@@ -99,13 +91,11 @@ public class EmailAccountServiceImpl implements EmailAccountService {
         return Result.success();
     }
 
-    @Override
     public EmailDto getEmailAccount(int emailId) {
         EmailAccount emailAccount = emailAccountMapper.findById(emailId);
         return getEmailDto(emailAccount);
     }
 
-    @Override
     public EmailDto getEmailSender() {
         EmailAccount emailAccount = emailAccountMapper.findDefaultSender();
         if (emailAccount == null) {
@@ -125,11 +115,8 @@ public class EmailAccountServiceImpl implements EmailAccountService {
         return new EmailDto(id, smtp, username, password, personal, defaultSender);
     }
 
-    @Override
-    public PageList<EmailDto> getEmailAccounts(int pageNumber) {
-        int pageSize = 100;
-        Page page = new Page(pageNumber, pageSize);
+    public List<EmailDto> getEmailAccounts() {
         List<EmailDto> list = emailAccountMapper.findAll().stream().map(this::getEmailDto).collect(Collectors.toList());
-        return PageList.pageList(page, pageSize, list);
+        return list;
     }
 }

+ 2 - 2
message/message-service/src/main/java/cn/reghao/tnb/message/app/service/notifier/email/EmailNotify.java

@@ -1,7 +1,7 @@
 package cn.reghao.tnb.message.app.service.notifier.email;
 
-import cn.reghao.tnb.message.api.dto.EmailDto;
-import cn.reghao.tnb.message.api.iface.EmailAccountService;
+import cn.reghao.tnb.message.app.model.dto.EmailDto;
+import cn.reghao.tnb.message.app.service.EmailAccountService;
 import cn.reghao.tnb.message.app.service.notifier.Notify;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.stereotype.Service;

+ 16 - 0
search/search-service/pom.xml

@@ -44,6 +44,16 @@
             <artifactId>user-api</artifactId>
             <version>1.0.0-SNAPSHOT</version>
         </dependency>
+        <dependency>
+            <groupId>cn.reghao.bnt</groupId>
+            <artifactId>admin-api</artifactId>
+            <version>1.0.0-SNAPSHOT</version>
+        </dependency>
+        <dependency>
+            <groupId>cn.reghao.tnb.file</groupId>
+            <artifactId>file-api</artifactId>
+            <version>1.0.0-SNAPSHOT</version>
+        </dependency>
 
         <dependency>
             <groupId>org.springframework.boot</groupId>
@@ -159,6 +169,12 @@
             <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
             <version>2021.0.6.0</version>
         </dependency>
+
+        <dependency>
+            <groupId>org.springdoc</groupId>
+            <artifactId>springdoc-openapi-ui</artifactId>
+            <version>1.7.0</version>
+        </dependency>
     </dependencies>
 
     <profiles>

+ 29 - 0
search/search-service/src/main/java/cn/reghao/tnb/search/app/config/SpringDocConfig.java

@@ -0,0 +1,29 @@
+package cn.reghao.tnb.search.app.config;
+
+import io.swagger.v3.oas.models.ExternalDocumentation;
+import io.swagger.v3.oas.models.OpenAPI;
+import io.swagger.v3.oas.models.info.Info;
+import io.swagger.v3.oas.models.info.License;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+/**
+ * SpringDoc API 文档相关配置
+ *
+ * @author reghao
+ * @date 2025-06-09 19:01:07
+ */
+@Configuration
+public class SpringDocConfig {
+    @Bean
+    public OpenAPI springOpenAPI() {
+        return new OpenAPI()
+                .info(new Info()
+                        .title("search api")
+                        .description("search api")
+                        .version("v0.0.1")
+                        .license(new License().name("Apache 2.0").url("https://www.apache.org/licenses/LICENSE-2.0")))
+                .externalDocs(new ExternalDocumentation()
+                        .description("search api"));
+    }
+}

+ 34 - 0
search/search-service/src/main/java/cn/reghao/tnb/search/app/soa/controller/TnbGatewayController.java

@@ -0,0 +1,34 @@
+package cn.reghao.tnb.search.app.soa.controller;
+
+import cn.reghao.jutil.web.WebResult;
+import cn.reghao.tnb.search.app.soa.model.vo.RouteDefinitionInfo;
+import cn.reghao.tnb.search.app.soa.service.RouteService;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.util.List;
+
+/**
+ * @author reghao
+ * @date 2025-04-16 10:37:14
+ */
+@Tag(name = "tnb 网关接口")
+@RestController
+@RequestMapping("/api/tnb/gw")
+public class TnbGatewayController {
+    private final RouteService routeService;
+
+    public TnbGatewayController(RouteService routeService) {
+        this.routeService = routeService;
+    }
+
+    @Operation(summary = "网关路由")
+    @GetMapping("/route")
+    public String gatewayRoutePage() {
+        List<RouteDefinitionInfo> routes = routeService.getRouteInfos();
+        return WebResult.success(routes);
+    }
+}

+ 123 - 0
search/search-service/src/main/java/cn/reghao/tnb/search/app/soa/controller/TnbLogController.java

@@ -0,0 +1,123 @@
+package cn.reghao.tnb.search.app.soa.controller;
+
+import cn.reghao.jutil.web.WebResult;
+import cn.reghao.tnb.search.app.soa.model.vo.SelectOption;
+import cn.reghao.tnb.search.app.soa.service.LoggingService;
+import cn.reghao.tnb.search.app.soa.service.RuntimeLogService;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import org.springframework.data.domain.Page;
+import org.springframework.http.MediaType;
+import org.springframework.ui.Model;
+import org.springframework.web.bind.annotation.*;
+
+import java.text.ParseException;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+/**
+ * @author reghao
+ * @date 2025-04-16 10:02:27
+ */
+@Tag(name = "tnb 日志接口")
+@RestController
+@RequestMapping("/bg/tnb/sys")
+public class TnbLogController {
+    private final RuntimeLogService runtimeLogService;
+    private final LoggingService loggingService;
+
+    public TnbLogController(RuntimeLogService runtimeLogService, LoggingService loggingService) {
+        this.runtimeLogService = runtimeLogService;
+        this.loggingService = loggingService;
+    }
+
+
+    @Operation(summary = "网关日志页面")
+    @GetMapping(value = "/log", produces = MediaType.APPLICATION_JSON_VALUE)
+    public String gatewayLogPage() {
+        return WebResult.success();
+    }
+
+    @Operation(summary = "访问日志页面")
+    @GetMapping("/accesslog")
+    public String accessLogPage(Model model) {
+        try {
+            model.addAttribute("page", Page.empty());
+            return "/admin/tnb/sys/accesslog";
+        } catch (Exception e) {
+            model.addAttribute("message", e.getMessage());
+        }
+        return "/admin/errmsg";
+    }
+
+    @Operation(summary = "运行日志页面", description = "N")
+    @GetMapping("/runtimelog")
+    public String rtLogPage(@RequestParam(value = "app", required = false) String app,
+                            @RequestParam(value = "host", required = false) String host,
+                            Model model) {
+        List<SelectOption> appList;
+        List<SelectOption> hostList;
+        Map<String, List<String>> map = runtimeLogService.getAppHostMap();
+        if (!map.isEmpty()) {
+            appList = map.keySet().stream()
+                    .map(appName -> new SelectOption(appName, appName))
+                    .collect(Collectors.toList());
+            if (app == null) {
+                app = appList.get(0).getKey();
+            }
+
+            hostList = map.get(app).stream()
+                    .map(host1 -> new SelectOption(host1, host1))
+                    .collect(Collectors.toList());
+            if (host == null) {
+                host = hostList.get(0).getKey();
+            }
+        } else {
+            appList = Collections.emptyList();
+            hostList = Collections.emptyList();
+        }
+
+        runtimeLogService.getAppLogs(app, host);
+        model.addAttribute("app", app);
+        model.addAttribute("host", host);
+        model.addAttribute("appList", appList);
+        model.addAttribute("hostList", hostList);
+        return "/admin/tnb/sys/rtlog";
+    }
+
+    @Operation(summary = "前一页运行日志", description = "N")
+    @GetMapping(value = "/runtimelog/prev", produces = MediaType.APPLICATION_JSON_VALUE)
+    @ResponseBody
+    public String prevRtLog(@RequestParam(value = "app") String app,
+                          @RequestParam(value = "host") String host,
+                          @RequestParam(value = "prevId") String prevId) {
+        runtimeLogService.getPrevLogs(app, host, prevId);
+        return WebResult.success();
+    }
+
+    @Operation(summary = "后一页运行日志", description = "N")
+    @GetMapping(value = "/runtimelog/next", produces = MediaType.APPLICATION_JSON_VALUE)
+    @ResponseBody
+    public String nextRtLog(@RequestParam(value = "app") String app,
+                          @RequestParam(value = "host") String host,
+                          @RequestParam(value = "nextId") String nextId) {
+        runtimeLogService.getNextLogs(app, host, nextId);
+        return WebResult.success();
+    }
+
+    @Operation(summary = "Nginx 日志页面", description = "N")
+    @GetMapping(value = "/log/nginx")
+    public String nginxLog() {
+        return "/devops/app/stat/nginxlog";
+    }
+
+    @Operation(summary = "Nginx 日志的 echarts 数据", description = "N")
+    @GetMapping(value = "/log/nginx/chart", produces = MediaType.APPLICATION_JSON_VALUE)
+    @ResponseBody
+    public String nginxLogData() throws ParseException {
+        List list = loggingService.getChartData();
+        return WebResult.success(list);
+    }
+}

+ 101 - 0
search/search-service/src/main/java/cn/reghao/tnb/search/app/soa/controller/TnbServiceController.java

@@ -0,0 +1,101 @@
+package cn.reghao.tnb.search.app.soa.controller;
+
+import cn.reghao.jutil.web.WebResult;
+import cn.reghao.tnb.common.auth.AuthUser;
+import cn.reghao.tnb.search.app.soa.model.vo.EurekaInstance;
+import cn.reghao.tnb.search.app.soa.model.vo.EurekaService;
+import cn.reghao.tnb.search.app.soa.model.vo.ServiceInfo;
+import cn.reghao.tnb.search.app.soa.service.TnbEurekaService;
+import cn.reghao.tnb.search.app.soa.service.TnbService;
+import cn.reghao.tnb.search.app.soa.service.TnbZkService;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import org.springframework.http.MediaType;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * @author reghao
+ * @date 2024-11-12 15:29:36
+ */
+@Tag(name = "tnb 服务治理接口")
+@RestController
+@RequestMapping("/api/tnb")
+@AuthUser
+public class TnbServiceController {
+    private final TnbZkService tnbZkService;
+    private final TnbService tnbService;
+    private final TnbEurekaService tnbEurekaService;
+
+    public TnbServiceController(TnbZkService tnbZkService, TnbService tnbService, TnbEurekaService tnbEurekaService) {
+        this.tnbZkService = tnbZkService;
+        this.tnbService = tnbService;
+        this.tnbEurekaService = tnbEurekaService;
+    }
+
+    @Operation(summary = "zk 中的服务")
+    @GetMapping(value = "/zk", produces = MediaType.APPLICATION_JSON_VALUE)
+    public String zkServicePage() throws Exception {
+        String zkPath = "/";
+        List<String> list = tnbZkService.getZkService(zkPath);
+        return WebResult.success(list);
+    }
+
+    @Operation(summary = "zk 中的服务")
+    @GetMapping(value = "/zookeeper", produces = MediaType.APPLICATION_JSON_VALUE)
+    public String zkService(@RequestParam("path") String path) throws Exception {
+        List<ServiceInfo> list = new ArrayList<>();
+        if ("dubbo".equals(path)) {
+            list = tnbZkService.getDubboService();
+        } else if ("services".equals(path)) {
+            list = tnbZkService.getCloudService();
+        } else if ("zookeeper".equals(path)) {
+        }
+
+        return WebResult.success(list);
+    }
+
+    @Operation(summary = "zk 中的 dubbo 服务")
+    @GetMapping(value = "/zk/dubbo", produces = MediaType.APPLICATION_JSON_VALUE)
+    public String zkDubboService() throws Exception {
+        List<ServiceInfo> list = tnbZkService.getDubboService();
+        return WebResult.success(list);
+    }
+
+    @Operation(summary = "zk 中的 springcloud 服务")
+    @GetMapping(value = "/zk/springcloud", produces = MediaType.APPLICATION_JSON_VALUE)
+    public String zkSpringcloudService() throws Exception {
+        List<ServiceInfo> list = tnbZkService.getCloudService();
+        return WebResult.success(list);
+    }
+
+    @Operation(summary = "eureka 中的 springcloud 服务")
+    @GetMapping(value = "/eureka/springcloud", produces = MediaType.APPLICATION_JSON_VALUE)
+    public String springcloudServicePage() {
+        List<EurekaInstance> instanceList = tnbEurekaService.getRegistryServices();
+        return WebResult.success(instanceList);
+    }
+
+    @Operation(summary = "eureka 中的 springcloud 服务")
+    @GetMapping(value = "/eureka/springcloud1", produces = MediaType.APPLICATION_JSON_VALUE)
+    public String springcloudService() {
+        List<EurekaService> serviceList = tnbEurekaService.getServiceList();
+        return WebResult.success(serviceList);
+    }
+
+    @Operation(summary = "springcloud 服务")
+    @PostMapping(value = "/springcloud/service", produces = MediaType.APPLICATION_JSON_VALUE)
+    public String selectServices(@RequestParam("appName") List<String> appNames) {
+        tnbService.add(appNames);
+        return WebResult.success();
+    }
+
+    @Operation(summary = "springcloud 服务页面")
+    @PostMapping(value = "/springcloud/delete/{appName}", produces = MediaType.APPLICATION_JSON_VALUE)
+    public String deleteSpringcloudService(@PathVariable("appName") String appName) {
+        tnbZkService.deleteNode(appName);
+        return WebResult.success();
+    }
+}

+ 13 - 0
search/search-service/src/main/java/cn/reghao/tnb/search/app/soa/db/mapper/BackendSystemRepository.java

@@ -0,0 +1,13 @@
+package cn.reghao.tnb.search.app.soa.db.mapper;
+
+import cn.reghao.tnb.search.app.soa.model.po.BackendSystem;
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
+
+/**
+ * @author reghao
+ * @date 2025-09-24 00:32:06
+ */
+public interface BackendSystemRepository extends JpaRepository<BackendSystem, Integer>, JpaSpecificationExecutor<BackendSystem> {
+    BackendSystem findBySysName(String sysName);
+}

+ 26 - 0
search/search-service/src/main/java/cn/reghao/tnb/search/app/soa/model/po/BackendSystem.java

@@ -0,0 +1,26 @@
+package cn.reghao.tnb.search.app.soa.model.po;
+
+import cn.reghao.tnb.search.app.util.BaseEntity;
+import lombok.Getter;
+import lombok.Setter;
+
+import javax.persistence.CollectionTable;
+import javax.persistence.ElementCollection;
+import javax.persistence.Entity;
+import javax.persistence.Table;
+import java.util.List;
+
+/**
+ * @author reghao
+ * @date 2025-04-17 11:10:58
+ */
+@Setter
+@Getter
+@Entity
+@Table(name = "search_wenshu_doc")
+public class BackendSystem extends BaseEntity {
+    private String sysName;
+    @ElementCollection
+    @CollectionTable(name = "tnb_backend_services")
+    private List<String> sysServices;
+}

+ 23 - 0
search/search-service/src/main/java/cn/reghao/tnb/search/app/soa/model/po/DubboSrv.java

@@ -0,0 +1,23 @@
+package cn.reghao.tnb.search.app.soa.model.po;
+
+import lombok.Getter;
+import lombok.Setter;
+
+/**
+ * @author reghao
+ * @date 2024-11-12 09:58:38
+ */
+@Setter
+@Getter
+public class DubboSrv {
+    private String hostPort;
+    private String side;
+    private String application;
+    private String iface;
+    private String methods;
+    private Boolean anyhost;
+    private Integer retries;
+    private Long timeout;
+    private Integer pid;
+    private Long timestamp;
+}

+ 21 - 0
search/search-service/src/main/java/cn/reghao/tnb/search/app/soa/model/po/SpringCloudService.java

@@ -0,0 +1,21 @@
+package cn.reghao.tnb.search.app.soa.model.po;
+
+import lombok.Getter;
+import lombok.Setter;
+
+/**
+ * @author reghao
+ * @date 2024-11-12 13:12:12
+ */
+@Setter
+@Getter
+public class SpringCloudService {
+    private String id;
+    private String name;
+    private String address;
+    private Integer port;
+    private Long registrationTimeUTC;
+    private String serviceType;
+    //private String payload;
+    //private String uriSpec;
+}

+ 83 - 0
search/search-service/src/main/java/cn/reghao/tnb/search/app/soa/model/route/FilterDefinition.java

@@ -0,0 +1,83 @@
+package cn.reghao.tnb.search.app.soa.model.route;
+
+import javax.validation.constraints.NotNull;
+import java.util.LinkedHashMap;
+import java.util.Map;
+import java.util.Objects;
+
+import static org.springframework.util.StringUtils.tokenizeToStringArray;
+
+/**
+ * @author reghao
+ * @date 2024-11-22 14:00:26
+ */
+public class FilterDefinition {
+    @NotNull
+    private String name;
+
+    private Map<String, String> args = new LinkedHashMap<>();
+
+    public FilterDefinition() {
+    }
+
+    public FilterDefinition(String text) {
+        int eqIdx = text.indexOf('=');
+        if (eqIdx <= 0) {
+            setName(text);
+            return;
+        }
+        setName(text.substring(0, eqIdx));
+
+        String[] args = tokenizeToStringArray(text.substring(eqIdx + 1), ",");
+
+        for (int i = 0; i < args.length; i++) {
+            this.args.put(NameUtils.generateName(i), args[i]);
+        }
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    public Map<String, String> getArgs() {
+        return args;
+    }
+
+    public void setArgs(Map<String, String> args) {
+        this.args = args;
+    }
+
+    public void addArg(String key, String value) {
+        this.args.put(key, value);
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) {
+            return true;
+        }
+        if (o == null || getClass() != o.getClass()) {
+            return false;
+        }
+        FilterDefinition that = (FilterDefinition) o;
+        return Objects.equals(name, that.name) && Objects.equals(args, that.args);
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(name, args);
+    }
+
+    @Override
+    public String toString() {
+        final StringBuilder sb = new StringBuilder("FilterDefinition{");
+        sb.append("name='").append(name).append('\'');
+        sb.append(", args=").append(args);
+        sb.append('}');
+        return sb.toString();
+    }
+}

+ 51 - 0
search/search-service/src/main/java/cn/reghao/tnb/search/app/soa/model/route/NameUtils.java

@@ -0,0 +1,51 @@
+package cn.reghao.tnb.search.app.soa.model.route;
+
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * @author reghao
+ * @date 2024-11-22 14:01:40
+ */
+public final class NameUtils {
+
+    private NameUtils() {
+        throw new AssertionError("Must not instantiate utility class.");
+    }
+
+    /**
+     * Generated name prefix.
+     */
+    public static final String GENERATED_NAME_PREFIX = "_genkey_";
+
+    private static final Pattern NAME_PATTERN = Pattern.compile("([A-Z][a-z0-9]+)");
+
+    public static String generateName(int i) {
+        return GENERATED_NAME_PREFIX + i;
+    }
+
+    public static String normalizeToCanonicalPropertyFormat(String name) {
+        Matcher matcher = NAME_PATTERN.matcher(name);
+        StringBuffer stringBuffer = new StringBuffer();
+        while (matcher.find()) {
+            if (stringBuffer.length() != 0) {
+                matcher.appendReplacement(stringBuffer,
+                        "-" + matcher.group(1).toLowerCase());
+            }
+            else {
+                matcher.appendReplacement(stringBuffer, matcher.group(1).toLowerCase());
+            }
+        }
+        return stringBuffer.toString();
+    }
+
+    private static String removeGarbage(String s) {
+        int garbageIdx = s.indexOf("$Mockito");
+        if (garbageIdx > 0) {
+            return s.substring(0, garbageIdx);
+        }
+
+        return s;
+    }
+
+}

+ 84 - 0
search/search-service/src/main/java/cn/reghao/tnb/search/app/soa/model/route/PredicateDefinition.java

@@ -0,0 +1,84 @@
+package cn.reghao.tnb.search.app.soa.model.route;
+
+import javax.validation.ValidationException;
+import javax.validation.constraints.NotNull;
+import java.util.LinkedHashMap;
+import java.util.Map;
+import java.util.Objects;
+
+import static org.springframework.util.StringUtils.tokenizeToStringArray;
+
+/**
+ * @author reghao
+ * @date 2024-11-22 14:00:34
+ */
+public class PredicateDefinition {
+    @NotNull
+    private String name;
+
+    private Map<String, String> args = new LinkedHashMap<>();
+
+    public PredicateDefinition() {
+    }
+
+    public PredicateDefinition(String text) {
+        int eqIdx = text.indexOf('=');
+        if (eqIdx <= 0) {
+            throw new ValidationException("Unable to parse PredicateDefinition text '"
+                    + text + "'" + ", must be of the form name=value");
+        }
+        setName(text.substring(0, eqIdx));
+
+        String[] args = tokenizeToStringArray(text.substring(eqIdx + 1), ",");
+
+        for (int i = 0; i < args.length; i++) {
+            this.args.put(NameUtils.generateName(i), args[i]);
+        }
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    public Map<String, String> getArgs() {
+        return args;
+    }
+
+    public void setArgs(Map<String, String> args) {
+        this.args = args;
+    }
+
+    public void addArg(String key, String value) {
+        this.args.put(key, value);
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) {
+            return true;
+        }
+        if (o == null || getClass() != o.getClass()) {
+            return false;
+        }
+        PredicateDefinition that = (PredicateDefinition) o;
+        return Objects.equals(name, that.name) && Objects.equals(args, that.args);
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(name, args);
+    }
+
+    @Override
+    public String toString() {
+        final StringBuilder sb = new StringBuilder("PredicateDefinition{");
+        sb.append("name='").append(name).append('\'');
+        sb.append(", args=").append(args);
+        sb.append('}');
+        return sb.toString();
+    }
+}

+ 134 - 0
search/search-service/src/main/java/cn/reghao/tnb/search/app/soa/model/route/RouteDefinition.java

@@ -0,0 +1,134 @@
+package cn.reghao.tnb.search.app.soa.model.route;
+
+import javax.validation.Valid;
+import javax.validation.ValidationException;
+import javax.validation.constraints.NotEmpty;
+import javax.validation.constraints.NotNull;
+import java.net.URI;
+import java.util.*;
+
+import static org.springframework.util.StringUtils.tokenizeToStringArray;
+
+/**
+ * 取自 org.springframework.cloud.gateway.route
+ *
+ * @author reghao
+ * @date 2024-11-22 14:00:15
+ */
+public class RouteDefinition {
+
+    private String id;
+
+    @NotEmpty
+    @Valid
+    private List<PredicateDefinition> predicates = new ArrayList<>();
+
+    @Valid
+    private List<FilterDefinition> filters = new ArrayList<>();
+
+    @NotNull
+    private URI uri;
+
+    private Map<String, Object> metadata = new HashMap<>();
+
+    private int order = 0;
+
+    public RouteDefinition() {
+    }
+
+    public RouteDefinition(String text) {
+        int eqIdx = text.indexOf('=');
+        if (eqIdx <= 0) {
+            throw new ValidationException("Unable to parse RouteDefinition text '" + text
+                    + "'" + ", must be of the form name=value");
+        }
+
+        setId(text.substring(0, eqIdx));
+
+        String[] args = tokenizeToStringArray(text.substring(eqIdx + 1), ",");
+
+        setUri(URI.create(args[0]));
+
+        for (int i = 1; i < args.length; i++) {
+            this.predicates.add(new PredicateDefinition(args[i]));
+        }
+    }
+
+    public String getId() {
+        return id;
+    }
+
+    public void setId(String id) {
+        this.id = id;
+    }
+
+    public List<PredicateDefinition> getPredicates() {
+        return predicates;
+    }
+
+    public void setPredicates(List<PredicateDefinition> predicates) {
+        this.predicates = predicates;
+    }
+
+    public List<FilterDefinition> getFilters() {
+        return filters;
+    }
+
+    public void setFilters(List<FilterDefinition> filters) {
+        this.filters = filters;
+    }
+
+    public URI getUri() {
+        return uri;
+    }
+
+    public void setUri(URI uri) {
+        this.uri = uri;
+    }
+
+    public int getOrder() {
+        return order;
+    }
+
+    public void setOrder(int order) {
+        this.order = order;
+    }
+
+    public Map<String, Object> getMetadata() {
+        return metadata;
+    }
+
+    public void setMetadata(Map<String, Object> metadata) {
+        this.metadata = metadata;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) {
+            return true;
+        }
+        if (o == null || getClass() != o.getClass()) {
+            return false;
+        }
+        RouteDefinition that = (RouteDefinition) o;
+        return this.order == that.order && Objects.equals(this.id, that.id)
+                && Objects.equals(this.predicates, that.predicates)
+                && Objects.equals(this.filters, that.filters)
+                && Objects.equals(this.uri, that.uri)
+                && Objects.equals(this.metadata, that.metadata);
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(this.id, this.predicates, this.filters, this.uri,
+                this.metadata, this.order);
+    }
+
+    @Override
+    public String toString() {
+        return "RouteDefinition{" + "id='" + id + '\'' + ", predicates=" + predicates
+                + ", filters=" + filters + ", uri=" + uri + ", order=" + order
+                + ", metadata=" + metadata + '}';
+    }
+
+}

+ 18 - 0
search/search-service/src/main/java/cn/reghao/tnb/search/app/soa/model/vo/EurekaInstance.java

@@ -0,0 +1,18 @@
+package cn.reghao.tnb.search.app.soa.model.vo;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+/**
+ * @author reghao
+ * @date 2025-09-25 21:57:43
+ */
+@AllArgsConstructor
+@Getter
+public class EurekaInstance {
+    private String instanceId;
+    private String appName;
+    private String hostPort;
+    private String lastUpdateTime;
+    private String lastDirtyTime;
+}

+ 18 - 0
search/search-service/src/main/java/cn/reghao/tnb/search/app/soa/model/vo/EurekaService.java

@@ -0,0 +1,18 @@
+package cn.reghao.tnb.search.app.soa.model.vo;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+import java.util.List;
+
+/**
+ * @author reghao
+ * @date 2025-09-25 22:14:07
+ */
+@AllArgsConstructor
+@Getter
+public class EurekaService {
+    private String appName;
+    private int total;
+    private List<EurekaInstance> instanceList;
+}

+ 15 - 0
search/search-service/src/main/java/cn/reghao/tnb/search/app/soa/model/vo/KeyValue.java

@@ -0,0 +1,15 @@
+package cn.reghao.tnb.search.app.soa.model.vo;
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+
+/**
+ * @author reghao
+ * @date 2021-06-03 19:00:57
+ */
+@AllArgsConstructor
+@Data
+public class KeyValue {
+    private String key;
+    private String value;
+}

+ 23 - 0
search/search-service/src/main/java/cn/reghao/tnb/search/app/soa/model/vo/RouteDefinitionInfo.java

@@ -0,0 +1,23 @@
+package cn.reghao.tnb.search.app.soa.model.vo;
+
+import cn.reghao.tnb.search.app.soa.model.route.RouteDefinition;
+import lombok.Getter;
+import lombok.Setter;
+
+/**
+ * @author reghao
+ * @date 2024-11-22 14:23:41
+ */
+@Setter
+@Getter
+public class RouteDefinitionInfo {
+    private String id;
+    private String upstreamUrl;
+    private String routeUrl;
+
+    public RouteDefinitionInfo(RouteDefinition routeDefinition) {
+        this.id = routeDefinition.getId();
+        this.upstreamUrl = routeDefinition.getUri().toString();
+        this.routeUrl = routeDefinition.getPredicates().get(0).getArgs().get("_genkey_0");
+    }
+}

+ 15 - 0
search/search-service/src/main/java/cn/reghao/tnb/search/app/soa/model/vo/SelectOption.java

@@ -0,0 +1,15 @@
+package cn.reghao.tnb.search.app.soa.model.vo;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+/**
+ * @author reghao
+ * @date 2021-06-03 19:00:57
+ */
+@AllArgsConstructor
+@Getter
+public class SelectOption {
+    private String key;
+    private String value;
+}

+ 34 - 0
search/search-service/src/main/java/cn/reghao/tnb/search/app/soa/model/vo/ServiceInfo.java

@@ -0,0 +1,34 @@
+package cn.reghao.tnb.search.app.soa.model.vo;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+
+/**
+ * @author reghao
+ * @date 2024-11-12 16:52:44
+ */
+@AllArgsConstructor
+@NoArgsConstructor
+@Setter
+@Getter
+public class ServiceInfo {
+    private String application;
+    private int total;
+    private String hostPorts;
+    private String role;
+
+    public ServiceInfo(String application, int total, String hostPorts) {
+        this.application = application;
+        this.total = total;
+        this.hostPorts = hostPorts;
+    }
+
+    public ServiceInfo(String application, String role) {
+        this.application = application;
+        this.total = 0;
+        this.hostPorts = "";
+        this.role = role;
+    }
+}

+ 18 - 0
search/search-service/src/main/java/cn/reghao/tnb/search/app/soa/service/LoggingService.java

@@ -0,0 +1,18 @@
+package cn.reghao.tnb.search.app.soa.service;
+
+import org.springframework.stereotype.Service;
+
+import java.text.ParseException;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * @author reghao
+ * @date 2025-06-06 14:05:07
+ */
+@Service
+public class LoggingService {
+    public List getChartData() throws ParseException {
+        return Collections.emptyList();
+    }
+}

+ 113 - 0
search/search-service/src/main/java/cn/reghao/tnb/search/app/soa/service/RouteService.java

@@ -0,0 +1,113 @@
+package cn.reghao.tnb.search.app.soa.service;
+
+import cn.reghao.bnt.admin.api.dto.RouteAdd;
+import cn.reghao.bnt.admin.api.dto.RouteDelete;
+import cn.reghao.tnb.search.app.soa.model.route.RouteDefinition;
+import cn.reghao.tnb.search.app.soa.model.vo.RouteDefinitionInfo;
+import cn.reghao.jutil.jdk.http.WebRequest;
+import cn.reghao.jutil.jdk.http.WebResponse;
+import cn.reghao.jutil.jdk.serializer.JsonConverter;
+import cn.reghao.jutil.tool.http.DefaultWebRequest;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Service;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.stream.Collectors;
+
+/**
+ * @author reghao
+ * @date 2024-11-22 13:46:46
+ */
+@Slf4j
+@Service
+public class RouteService {
+    private final WebRequest webRequest;
+    private final String host = "http://192.168.0.181:16000";
+
+    public RouteService() {
+        this.webRequest = new DefaultWebRequest();
+    }
+
+    public void addRoute() {
+        RouteAdd routeAdd = new RouteAdd();
+        routeAdd.setRouteId("test-route");
+
+        String url = String.format("%s/route", host);
+        WebResponse webResponse = webRequest.postJson(url, JsonConverter.objectToJson(routeAdd));
+        String data = getWebResponse(webResponse);
+        if (data != null) {
+            System.out.println(data);
+        }
+    }
+
+    public void updateRoute() {
+        String upstreamUrl = "lb://account-service";
+        RouteAdd routeAdd = new RouteAdd();
+        routeAdd.setRouteId("test-route");
+        routeAdd.setUpstreamUrl(upstreamUrl);
+
+        String url = String.format("%s/route/update", host);
+        WebResponse webResponse = webRequest.postJson(url, JsonConverter.objectToJson(routeAdd));
+        String data = getWebResponse(webResponse);
+        if (data != null) {
+            System.out.println(data);
+        }
+    }
+
+    public void deleteRoute() {
+        RouteDelete routeDelete = new RouteDelete();
+        routeDelete.setRouteId("test-route");
+
+        String url = String.format("%s/route/delete", host);
+        WebResponse webResponse = webRequest.postJson(url, JsonConverter.objectToJson(routeDelete));
+        String data = getWebResponse(webResponse);
+        if (data != null) {
+            System.out.println(data);
+        }
+    }
+
+    public List<RouteDefinitionInfo> getRouteInfos() {
+        String url = String.format("%s/routes", host);
+        WebResponse webResponse = webRequest.get(url);
+        String data = getWebResponse(webResponse);
+        if (data != null) {
+            return JsonConverter.jsonToObjects(data, RouteDefinition.class).stream()
+                    .map(RouteDefinitionInfo::new)
+                    .collect(Collectors.toList());
+        }
+
+        return Collections.emptyList();
+    }
+
+    public RouteDefinitionInfo getRouteInfo(String routeId) {
+        String url = String.format("%s/route?id=%s", host, routeId);
+        WebResponse webResponse = webRequest.get(url);
+        String data = getWebResponse(webResponse);
+        if (data != null) {
+        }
+
+        return null;
+    }
+
+    private String getWebResponse(WebResponse webResponse) {
+        int statusCode = webResponse.getStatusCode();
+        if (statusCode != 200) {
+            log.error("请求失败");
+            return null;
+        }
+
+        String body = webResponse.getBody();
+        return body;
+
+        /*Type type = new TypeToken<WebResult<String>>(){}.getType();
+        WebResult<String> webResult = JsonConverter.jsonToObject(body, type);
+        if (webResult.getCode() != 0) {
+            String errMsg = webResult.getMsg();
+            log.error("请求失败 -> {}", errMsg);
+            return null;
+        }
+
+        return webResult.getData();*/
+    }
+}

+ 31 - 0
search/search-service/src/main/java/cn/reghao/tnb/search/app/soa/service/RuntimeLogService.java

@@ -0,0 +1,31 @@
+package cn.reghao.tnb.search.app.soa.service;
+
+import cn.reghao.jutil.jdk.result.AppLog;
+import org.springframework.stereotype.Service;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * @author reghao
+ * @date 2025-04-14 10:10:03
+ */
+@Service
+public class RuntimeLogService {
+    public void addAppLog(AppLog appLog) {
+    }
+
+    public void getAppLogs(String app, String host) {
+    }
+
+    public void getPrevLogs(String app, String host, String prevId) {
+    }
+
+    public void getNextLogs(String app, String host, String nextId) {
+    }
+
+    public Map<String, List<String>> getAppHostMap() {
+        return Collections.emptyMap();
+    }
+}

+ 81 - 0
search/search-service/src/main/java/cn/reghao/tnb/search/app/soa/service/TnbEurekaService.java

@@ -0,0 +1,81 @@
+package cn.reghao.tnb.search.app.soa.service;
+
+import cn.reghao.jutil.jdk.converter.DateTimeConverter;
+import cn.reghao.tnb.search.app.soa.model.vo.EurekaInstance;
+import cn.reghao.tnb.search.app.soa.model.vo.EurekaService;
+import com.netflix.discovery.EurekaClient;
+import com.netflix.discovery.shared.Applications;
+import org.springframework.cloud.client.discovery.DiscoveryClient;
+import org.springframework.stereotype.Service;
+
+import java.util.*;
+
+/**
+ * @author reghao
+ * @date 2025-07-18 17:31:05
+ */
+@Service
+public class TnbEurekaService {
+    private final DiscoveryClient discoveryClient;
+    private final EurekaClient eurekaClient;
+
+    public TnbEurekaService(DiscoveryClient discoveryClient, EurekaClient eurekaClient) {
+        this.discoveryClient = discoveryClient;
+        this.eurekaClient = eurekaClient;
+    }
+
+    public List<EurekaInstance> getRegistryServices() {
+        List<EurekaInstance> list = new ArrayList<>();
+        Applications applications = eurekaClient.getApplications();
+        applications.getRegisteredApplications().forEach(application -> {
+            String name = application.getName();
+            application.getInstances().forEach(instanceInfo -> {
+                String instanceId = instanceInfo.getInstanceId();
+                String appName = instanceInfo.getAppName().toLowerCase(Locale.ROOT);
+                String ipAddr = instanceInfo.getIPAddr();
+                int port = instanceInfo.getPort();
+                String hostPort = String.format("%s:%s", ipAddr, port);
+                long updateTime = instanceInfo.getLastUpdatedTimestamp();
+                String updateTimeStr = DateTimeConverter.msTimestamp(updateTime);
+                long dirtyTime = instanceInfo.getLastDirtyTimestamp();
+                String dirtyTimeStr = DateTimeConverter.msTimestamp(dirtyTime);
+                list.add(new EurekaInstance(instanceId, appName, hostPort, updateTimeStr, dirtyTimeStr));
+            });
+        });
+
+        return list;
+    }
+
+    public List<EurekaService> getServiceList() {
+        Map<String, List<EurekaInstance>> serviceMap = new HashMap<>();
+        Applications applications = eurekaClient.getApplications();
+        applications.getRegisteredApplications().forEach(application -> {
+            String name = application.getName();
+            List<EurekaInstance> serviceInstances = serviceMap.computeIfAbsent(name, v -> new ArrayList<>());
+            application.getInstances().forEach(instanceInfo -> {
+                String instanceId = instanceInfo.getInstanceId();
+                String appName = instanceInfo.getAppName().toLowerCase(Locale.ROOT);
+                String ipAddr = instanceInfo.getIPAddr();
+                int port = instanceInfo.getPort();
+                String hostPort = String.format("%s:%s", ipAddr, port);
+                long updateTime = instanceInfo.getLastUpdatedTimestamp();
+                String updateTimeStr = DateTimeConverter.msTimestamp(updateTime);
+                long dirtyTime = instanceInfo.getLastDirtyTimestamp();
+                String dirtyTimeStr = DateTimeConverter.msTimestamp(dirtyTime);
+                serviceInstances.add(new EurekaInstance(instanceId, appName, hostPort, updateTimeStr, dirtyTimeStr));
+            });
+        });
+
+        List<EurekaService> serviceList = new ArrayList<>();
+        serviceMap.forEach((name, instanceList) -> {
+            int total = instanceList.size();
+            serviceList.add(new EurekaService(name, total, instanceList));
+        });
+        return serviceList;
+    }
+
+    public void getServices() {
+        List<String> list = discoveryClient.getServices();
+        eurekaClient.getApplicationInfoManager();
+    }
+}

+ 96 - 0
search/search-service/src/main/java/cn/reghao/tnb/search/app/soa/service/TnbService.java

@@ -0,0 +1,96 @@
+package cn.reghao.tnb.search.app.soa.service;
+
+import cn.reghao.tnb.search.app.soa.model.po.BackendSystem;
+import cn.reghao.tnb.search.app.soa.model.po.DubboSrv;
+import cn.reghao.tnb.search.app.soa.model.po.SpringCloudService;
+import cn.reghao.jutil.jdk.converter.DateTimeConverter;
+import cn.reghao.jutil.jdk.thread.ThreadPoolWrapper;
+import cn.reghao.tnb.search.app.soa.db.mapper.BackendSystemRepository;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Service;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.ScheduledFuture;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * @author reghao
+ * @date 2025-04-17 11:07:52
+ */
+@Slf4j
+@Service
+public class TnbService {
+    private final ScheduledExecutorService scheduledExecutorService;
+    private final BackendSystemRepository backendSystemRepository;
+    private final TnbZkService tnbZkService;
+
+    public TnbService(BackendSystemRepository backendSystemRepository, TnbZkService tnbZkService) {
+        this.scheduledExecutorService = ThreadPoolWrapper.scheduledThreadPool("zkservice-checker", 1);
+        this.backendSystemRepository = backendSystemRepository;
+        this.tnbZkService = tnbZkService;
+    }
+
+    public void startServiceChecker() {
+        ScheduledFuture<?> future = scheduledExecutorService.scheduleAtFixedRate(new ServiceChecker(), 0, 10, TimeUnit.SECONDS);
+    }
+
+    public void add(List<String> appNames) {
+        String sysName = "vod";
+        BackendSystem backendSystem = backendSystemRepository.findBySysName(sysName);
+        if (backendSystem == null) {
+            backendSystem = new BackendSystem();
+            backendSystem.setSysName(sysName);
+        }
+
+        backendSystem.setSysServices(appNames);
+        //backendSystemRepository.save(backendSystem);
+    }
+
+    public class ServiceChecker implements Runnable {
+        @Override
+        public void run() {
+            String sysName = "vod";
+            BackendSystem backendSystem = backendSystemRepository.findBySysName(sysName);
+            if (backendSystem == null) {
+                return;
+            }
+
+            List<String> appNames = backendSystem.getSysServices();
+            if (appNames.isEmpty()) {
+                return;
+            }
+
+            try {
+                Map<String, List<SpringCloudService>> springcloudMap = tnbZkService.getSpringCloudServices();
+                Map<String, List<DubboSrv>> dubboMap = tnbZkService.getDubboServiceMap();
+                log.error("########################################{}########################################", DateTimeConverter.format(System.currentTimeMillis()));
+                List<String> springcloudServices = new ArrayList<>();
+                List<String> dubboServices = new ArrayList<>();
+                for (String appName : appNames) {
+                    List<SpringCloudService> springcloudList = springcloudMap.get(appName);
+                    if (springcloudList == null || springcloudList.isEmpty()) {
+                        springcloudServices.add(appName);
+                    }
+
+                    List<DubboSrv> dubboList = dubboMap.get(appName);
+                    if (dubboList == null || dubboList.isEmpty()) {
+                        dubboServices.add(appName);
+                    }
+                }
+
+                if (!springcloudServices.isEmpty()) {
+                    log.error("{} 没有实例注册到 SpringCloud ZK", springcloudServices);
+                }
+                if (!dubboServices.isEmpty()) {
+                    log.error("{} 没有实例注册到 Dubbo ZK", dubboServices);
+                }
+                log.error("########################################{}########################################", DateTimeConverter.format(System.currentTimeMillis()));
+            } catch (Exception e) {
+                e.printStackTrace();
+            }
+        }
+    }
+}

+ 384 - 0
search/search-service/src/main/java/cn/reghao/tnb/search/app/soa/service/TnbZkService.java

@@ -0,0 +1,384 @@
+package cn.reghao.tnb.search.app.soa.service;
+
+import cn.reghao.jutil.jdk.serializer.JsonConverter;
+import cn.reghao.tnb.search.app.soa.model.po.DubboSrv;
+import cn.reghao.tnb.search.app.soa.model.po.SpringCloudService;
+import cn.reghao.tnb.search.app.soa.model.vo.ServiceInfo;
+import com.google.gson.JsonNull;
+import com.google.gson.JsonObject;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.curator.framework.CuratorFramework;
+import org.apache.curator.framework.CuratorFrameworkFactory;
+import org.apache.curator.framework.recipes.cache.ChildData;
+import org.apache.curator.framework.recipes.cache.TreeCache;
+import org.apache.curator.framework.recipes.cache.TreeCacheEvent;
+import org.apache.curator.framework.recipes.cache.TreeCacheListener;
+import org.apache.curator.retry.ExponentialBackoffRetry;
+import org.springframework.core.env.Environment;
+import org.springframework.stereotype.Service;
+
+import java.lang.reflect.Field;
+import java.net.URI;
+import java.nio.charset.StandardCharsets;
+import java.util.*;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import java.util.stream.Collectors;
+
+/**
+ * @author reghao
+ * @date 2024-11-11 17:17:41
+ */
+@Slf4j
+@Service
+public class TnbZkService {
+    private final Pattern pattern = Pattern.compile(".*://");
+    private final String dubbo = "/dubbo";
+    private final Map<String, DubboSrv> dubboSrvMap = new HashMap<>();
+
+    private final String springcloud = "/services";
+    private final Map<String, SpringCloudService> springCloudMap = new HashMap<>();
+
+    private final String connectString;
+    private final CuratorFramework client;
+
+    public TnbZkService(Environment environment) {
+        String address = environment.getProperty("dubbo.registry.address");
+        this.connectString = address.replace("zookeeper://", "");
+        client = getZkClient();
+
+        listenNode(dubbo, "dubbo");
+        listenNode(springcloud, "springcloud");
+    }
+
+    public CuratorFramework getZkClient() {
+        CuratorFramework client = CuratorFrameworkFactory.builder()
+                .connectString(connectString)
+                .sessionTimeoutMs(5000)
+                .connectionTimeoutMs(3000)
+                .retryPolicy(new ExponentialBackoffRetry(1000, 3))
+                .build();
+        client.start();
+        return client;
+    }
+
+    public List<String> getZkService(String zkPath) throws Exception {
+        List<String> list = new ArrayList<>();
+        List<String> list1 = client.getChildren().forPath(zkPath);
+        if (list1.isEmpty()) {
+            byte[] zkData = client.getData().forPath(zkPath);
+            String zkDataStr = new String(zkData);
+            System.out.printf("%s -> %s", zkPath, zkDataStr);
+        } else {
+            return list1;
+        }
+
+        return list;
+    }
+
+    public List<ServiceInfo> getDubboService() throws Exception {
+        List<ServiceInfo> list = new ArrayList<>();
+        //List<DubboSrv> dubboSrvList = getDubboServices();
+        List<DubboSrv> dubboSrvList = new ArrayList<>(dubboSrvMap.values());
+        Map<String, List<DubboSrv>> applicationMap = dubboSrvList.stream().collect(Collectors.groupingBy(DubboSrv::getApplication));
+        applicationMap.forEach((app, appServices) -> {
+            Map<String, List<DubboSrv>> sideMap = appServices.stream().collect(Collectors.groupingBy(DubboSrv::getSide));
+            String roleStr = sideMap.keySet().toString().replace("[", "").replace("]", "");
+            ServiceInfo serviceInfo = new ServiceInfo(app, roleStr);
+
+            List<DubboSrv> providers = sideMap.get("provider");
+            if (providers != null) {
+                Map<String, List<DubboSrv>> providerHosts = providers.stream().collect(Collectors.groupingBy(DubboSrv::getHostPort));
+                Set<String> hostPorts = providerHosts.keySet();
+                String hostPortsStr = hostPorts.toString().replace("[", "").replace("]", "");
+                serviceInfo.setHostPorts(hostPortsStr);
+                serviceInfo.setTotal(hostPorts.size());
+            }
+            list.add(serviceInfo);
+        });
+
+        /*Map<String, List<DubboSrv>> map = dubboSrvList.stream().collect(Collectors.groupingBy(DubboSrv::getSide));
+        List<DubboSrv> providers = map.get("provider");
+        if (providers != null) {
+            Map<String, List<DubboSrv>> map1 = providers.stream()
+                    .collect(Collectors.groupingBy(DubboSrv::getApplication));
+            map1.forEach((serviceName, serviceList) -> {
+                Map<String, List<DubboSrv>> map2 = serviceList.stream().collect(Collectors.groupingBy(DubboSrv::getHostPort));
+                map2.forEach((hostPort, serviceList1) -> {
+                    System.out.println();
+                });
+            });
+        }*/
+
+        return list;
+    }
+
+    public Map<String, List<DubboSrv>> getDubboServiceMap() throws Exception {
+        List<DubboSrv> dubboSrvList = new ArrayList<>(dubboSrvMap.values());
+        Map<String, List<DubboSrv>> serviceMap = dubboSrvList.stream()
+                .collect(Collectors.groupingBy(DubboSrv::getApplication));
+        return serviceMap;
+    }
+
+    public Map<String, List<DubboSrv>> getDubboServiceMap1() throws Exception {
+        List<String> list = client.getChildren().forPath(dubbo);
+        List<String> serviceNames = list.stream()
+                .filter(name -> !name.equals("metadata") && !name.equals("config"))
+                .collect(Collectors.toList());
+
+        List<DubboSrv> dubboSrvList = new ArrayList<>();
+        for (String serviceName : serviceNames) {
+            String path1 = String.format("%s/%s/providers", dubbo, serviceName);
+            List<String> providers = client.getChildren().forPath(path1);
+            List<String> dubboUrl = new ArrayList<>(providers);
+
+            String path2 = String.format("%s/%s/consumers", dubbo, serviceName);
+            List<String> consumers = client.getChildren().forPath(path2);
+            dubboUrl.addAll(consumers);
+
+            List<DubboSrv> dubboSrvs = dubboUrl.stream()
+                    .map(this::getDubboSrv)
+                    .filter(Objects::nonNull)
+                    .collect(Collectors.toList());
+            dubboSrvList.addAll(dubboSrvs);
+        }
+
+        Map<String, List<DubboSrv>> serviceMap = dubboSrvList.stream().collect(Collectors.groupingBy(DubboSrv::getIface));
+        for (String serviceName : serviceNames) {
+            serviceMap.computeIfAbsent(serviceName, v -> new ArrayList<>());
+        }
+
+        return serviceMap;
+    }
+
+    private DubboSrv getDubboSrv(String zkPath) {
+        String url = URI.create(zkPath).getPath();
+        Matcher matcher = pattern.matcher(url);
+        if (matcher.find()) {
+            String protocolPrefix = matcher.group();
+            String url1 = url.replace(protocolPrefix, "");
+            String[] arr = url1.split("\\?");
+            int idx = arr[0].indexOf("/");
+            if (idx == -1) {
+                //throw new Exception("dubbo url illegal");
+                return null;
+            }
+
+            String hostPort = arr[0].substring(0, idx);
+            String clazzName = arr[0].substring(idx+1);
+            Map<String, String> map = new HashMap<>();
+            for (String kv : arr[1].split("&")) {
+                String[] kvs = kv.split("=");
+                map.put(kvs[0], kvs[1]);
+            }
+
+            Class<?> clazz = DubboSrv.class;
+            Field[] fields = clazz.getDeclaredFields();
+            try {
+                Object object = clazz.getDeclaredConstructor().newInstance();
+                for (Field field : fields) {
+                    String name = field.getName();
+                    String value = map.get(name);
+                    if (value == null) {
+                        continue;
+                    }
+
+                    Class<?> clazzType = field.getType();
+                    field.setAccessible(true);
+                    if (clazzType.equals(String.class)) {
+                        field.set(object, value);
+                    } else if (clazzType.equals(Long.class)) {
+                        field.set(object, Long.parseLong(value));
+                    } else if (clazzType.equals(Integer.class)) {
+                        field.set(object, Integer.parseInt(value));
+                    } else if (clazzType.equals(Boolean.class)){
+                        field.set(object, Boolean.valueOf(value));
+                    }
+                }
+
+                DubboSrv dubboSrv = (DubboSrv) object;
+                dubboSrv.setIface(map.get("interface"));
+                dubboSrv.setHostPort(hostPort);
+                return dubboSrv;
+            } catch (Exception e) {
+                e.printStackTrace();
+            }
+        }
+
+        return null;
+    }
+
+    public List<ServiceInfo> getCloudService() throws Exception {
+        Map<String, List<SpringCloudService>> listMap = getSpringCloudServices();
+        List<ServiceInfo> serviceInfos = new ArrayList<>();
+        listMap.forEach((app, appList) -> {
+            List<String> hostPorts = appList.stream().map(springCloudService -> {
+                String address = springCloudService.getAddress();
+                int port = springCloudService.getPort();
+                return String.format("%s:%s", address, port);
+            }).collect(Collectors.toList());
+            String hostPortsStr = hostPorts.toString().replace("[", "").replace("]", "");
+            serviceInfos.add(new ServiceInfo(app, appList.size(), hostPortsStr));
+        });
+        return serviceInfos;
+    }
+
+    public Map<String, List<SpringCloudService>> getSpringCloudServices() throws Exception {
+        //List<SpringCloudService> serviceList = new ArrayList<>();
+        List<SpringCloudService> serviceList = new ArrayList<>(springCloudMap.values());
+        List<String> list = client.getChildren().forPath(springcloud);
+        /*for (String service : list) {
+            List<String> list1 = client.getChildren().forPath(springcloud + "/" + service);
+            for (String serviceId : list1) {
+                String dataPath = springcloud + "/" + service + "/" + serviceId;
+                byte[] bytes = client.getData().forPath(dataPath);
+                SpringCloudService springCloudService = getSpringCloudService(bytes);
+                serviceList.add(springCloudService);
+            }
+        }*/
+
+        Map<String, List<SpringCloudService>> listMap = serviceList.stream()
+                .collect(Collectors.groupingBy(SpringCloudService::getName));
+        for (String serviceName : list) {
+            listMap.computeIfAbsent(serviceName, v -> new ArrayList<>());
+        }
+
+        return listMap;
+    }
+
+    private SpringCloudService getSpringCloudService(byte[] zkData) throws Exception {
+        String json = new String(zkData);
+        JsonObject jsonObject = JsonConverter.jsonToJsonElement(json).getAsJsonObject();
+        Map<String, String> map = new HashMap<>();
+        jsonObject.entrySet().forEach(entry -> {
+            String key = entry.getKey();
+            if (key.equals("payload") || key.equals("uriSpec")) {
+                return;
+            }
+
+            if (!entry.getValue().equals(JsonNull.INSTANCE)) {
+                String value = entry.getValue().getAsString();
+                map.put(key, value);
+            }
+        });
+
+        Class<?> clazz = SpringCloudService.class;
+        Field[] fields = clazz.getDeclaredFields();
+        Object object = clazz.getDeclaredConstructor().newInstance();
+        for (Field field : fields) {
+            String name = field.getName();
+            String value = map.get(name);
+            if (value == null) {
+                continue;
+            }
+
+            Class<?> clazzType = field.getType();
+            field.setAccessible(true);
+            if (clazzType.equals(String.class)) {
+                field.set(object, value);
+            } else if (clazzType.equals(Long.class)) {
+                field.set(object, Long.parseLong(value));
+            } else if (clazzType.equals(Integer.class)) {
+                field.set(object, Integer.parseInt(value));
+            } else if (clazzType.equals(Boolean.class)){
+                field.set(object, Boolean.valueOf(value));
+            }
+        }
+
+        return (SpringCloudService) object;
+    }
+
+    private void listenNode(String zkPath, String serviceType) {
+        try {
+            TreeCache treeCache  = new TreeCache(client, zkPath);
+            TreeCacheListener listener = new TreeCacheListener() {
+                @Override
+                public void childEvent(CuratorFramework client, TreeCacheEvent event) {
+                    ChildData data = event.getData();
+                    if (data == null) {
+                        log.info("数据为 null");
+                        return;
+                    } else if (data.getData().length == 0) {
+                        log.info("数据为空");
+                        return;
+                    }
+
+                    String dataPath = data.getPath();
+                    String url = URI.create(dataPath).getPath();
+                    if (serviceType.equals("dubbo")) {
+                        if (!url.contains("?")) {
+                            return;
+                        }
+                        if (dataPath.startsWith("/dubbo/config") || dataPath.startsWith("/dubbo/metadata")) {
+                            return;
+                        }
+
+                        if (dataPath.endsWith("/routers")
+                                || dataPath.startsWith("/providers")
+                                || dataPath.startsWith("/consumers")) {
+                            return;
+                        }
+                    }
+
+                    String dataContent = new String(data.getData(), StandardCharsets.UTF_8);
+                    try {
+                        switch (event.getType()) {
+                            case NODE_ADDED:
+                                log.info("[{}-TreeCache]节点增加", serviceType);
+                                if (serviceType.equals("springcloud")) {
+                                    springCloudMap.put(dataPath, getSpringCloudService(data.getData()));
+                                } else if (serviceType.equals("dubbo")) {
+                                    dubboSrvMap.put(dataPath, getDubboSrv(dataPath));
+                                } else {
+                                    log.error("serviceType {} unknown", serviceType);
+                                }
+                                break;
+                            case NODE_UPDATED:
+                                //log.info("[{}-TreeCache]节点更新, path={}, data={}", serviceType, dataPath, dataContent);
+                                if (serviceType.equals("springcloud")) {
+                                    springCloudMap.put(dataPath, getSpringCloudService(data.getData()));
+                                } else if (serviceType.equals("dubbo")) {
+                                    dubboSrvMap.put(dataPath, getDubboSrv(dataPath));
+                                } else {
+                                    log.error("serviceType {} unknown", serviceType);
+                                }
+                                break;
+                            case NODE_REMOVED:
+                                log.info("[{}-TreeCache]节点删除", serviceType);
+                                if (serviceType.equals("springcloud")) {
+                                    springCloudMap.remove(dataPath);
+                                } else if (serviceType.equals("dubbo")) {
+                                    dubboSrvMap.remove(dataPath);
+                                } else {
+                                    log.error("serviceType {} unknown", serviceType);
+                                }
+                                break;
+                            default:
+                                break;
+                        }
+                    } catch (Exception e) {
+                        e.printStackTrace();
+                    }
+                }
+            };
+
+            treeCache.getListenable().addListener(listener);
+            treeCache.start();
+        } catch (Exception e) {
+            log.error("PathCache 监听失败, path={}", zkPath);
+        }
+    }
+
+    public void deleteNode(String appName) {
+        try {
+            Map<String, List<SpringCloudService>> listMap = getSpringCloudServices();
+            List<SpringCloudService> cloudServices = listMap.get(appName);
+            cloudServices.forEach(cloudService -> {
+                String zkPath = "";
+                //client.delete().forPath(zkPath);
+            });
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+    }
+}

+ 1 - 1
search/search-service/src/main/java/cn/reghao/tnb/search/app/ws/handler/LogHandler.java

@@ -97,7 +97,7 @@ public class LogHandler implements WebSocketHandler {
             WebSocketMessage<String> message1 = new TextMessage(jsonData);
             try {
                 pullSession.sendMessage(message1);
-            } catch (IOException e) {
+            } catch (Exception e) {
                 e.printStackTrace();
             }
         }

+ 0 - 17
user/user-api/src/main/java/cn/reghao/tnb/user/api/iface/AdminUserService.java

@@ -1,17 +0,0 @@
-package cn.reghao.tnb.user.api.iface;
-
-import cn.reghao.jutil.jdk.db.PageList;
-import cn.reghao.tnb.user.api.dto.UserInfo;
-import cn.reghao.tnb.user.api.dto.UserSearch;
-import cn.reghao.tnb.user.api.dto.VipPlanInfo;
-
-import java.util.List;
-
-/**
- * @author reghao
- * @date 2024-02-15 09:15:06
- */
-public interface AdminUserService {
-    PageList<UserInfo> getUserList(UserSearch userSearch);
-    List<VipPlanInfo> getVipPlans();
-}

+ 88 - 0
user/user-service/src/main/java/cn/reghao/tnb/user/app/controller/AdminUserController.java

@@ -0,0 +1,88 @@
+package cn.reghao.tnb.user.app.controller;
+
+import cn.reghao.jutil.jdk.db.PageList;
+import cn.reghao.jutil.web.WebResult;
+import cn.reghao.tnb.account.api.dto.AdminCreateAccount;
+import cn.reghao.tnb.user.api.dto.UserInfo;
+import cn.reghao.tnb.user.api.dto.VipPlanInfo;
+import cn.reghao.tnb.user.api.dto.WalletChargeDto;
+import cn.reghao.tnb.user.app.service.AdminUserService;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import org.springframework.http.MediaType;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+/**
+ * @author reghao
+ * @date 2025-09-26 20:04:21
+ */
+@Tag(name = "user 管理接口")
+@RestController
+@RequestMapping("/api/user/admin")
+public class AdminUserController {
+    private final AdminUserService adminUserService;
+    
+    public AdminUserController(AdminUserService adminUserService) {
+        this.adminUserService = adminUserService;
+    }
+
+    @Operation(summary = "用户帐号列表页面", description = "N")
+    @GetMapping(value = "/list", produces = MediaType.APPLICATION_JSON_VALUE)
+    public String indexPage(@RequestParam(value = "nextId", required = false) Integer nextId) {
+        PageList<UserInfo> pageList = adminUserService.getUserList(1);
+        return WebResult.success(pageList);
+    }
+
+    @Operation(summary = "创建用户帐号", description = "N")
+    @PostMapping(value = "/create", produces = MediaType.APPLICATION_JSON_VALUE)
+    @ResponseBody
+    public String createAccount(@Validated AdminCreateAccount adminCreateAccount) {
+        try {
+            adminUserService.createAccount(adminCreateAccount);
+            return WebResult.success();
+        } catch (Exception e) {
+            return WebResult.failWithMsg(e.getMessage());
+        }
+    }
+
+    @Operation(summary = "充值请求列表页面", description = "N")
+    @GetMapping(value = "/charge", produces = MediaType.APPLICATION_JSON_VALUE)
+    public String chargeReq(@RequestParam("pn") int pageNumber) {
+        List<WalletChargeDto> list = adminUserService.getChargeReqs();
+        return WebResult.success(list);
+    }
+
+    @Operation(summary = "同意用户充值", description = "N")
+    @PostMapping(value = "/charge/approve/{chargeId}", produces = MediaType.APPLICATION_JSON_VALUE)
+    @ResponseBody
+    public String approveCharge(@PathVariable("chargeId") Long chargeId) {
+        adminUserService.approve(chargeId);
+        return WebResult.success();
+    }
+
+    @Operation(summary = "同意所有用户充值", description = "N")
+    @PostMapping(value = "/charge/approve_all", produces = MediaType.APPLICATION_JSON_VALUE)
+    @ResponseBody
+    public String approveAllCharge() {
+        adminUserService.approveAll();
+        return WebResult.success();
+    }
+
+    @Operation(summary = "拒绝用户充值", description = "N")
+    @PostMapping(value = "/charge/decline/{chargeId}", produces = MediaType.APPLICATION_JSON_VALUE)
+    @ResponseBody
+    public String declineCharge(@PathVariable("chargeId") Long chargeId) {
+        adminUserService.decline(chargeId);
+        return WebResult.success();
+    }
+
+    @Operation(summary = "会员计划列表页面", description = "N")
+    @GetMapping(value = "/vip_plan", produces = MediaType.APPLICATION_JSON_VALUE)
+    public String vipPage() {
+        List<VipPlanInfo> list = adminUserService.getVipPlans();
+        return WebResult.success(list);
+    }
+}

+ 55 - 14
user/user-service/src/main/java/cn/reghao/tnb/user/app/rpc/AdminUserServiceImpl.java → user/user-service/src/main/java/cn/reghao/tnb/user/app/service/AdminUserService.java

@@ -1,46 +1,61 @@
-package cn.reghao.tnb.user.app.rpc;
+package cn.reghao.tnb.user.app.service;
 
 import cn.reghao.jutil.jdk.db.PageList;
+import cn.reghao.jutil.jdk.thread.ThreadPoolWrapper;
 import cn.reghao.tnb.account.api.dto.AccountInfo;
+import cn.reghao.tnb.account.api.dto.AdminCreateAccount;
 import cn.reghao.tnb.account.api.dto.CrawledUser;
 import cn.reghao.tnb.account.api.iface.AccountQuery;
-import cn.reghao.tnb.content.api.iface.UserContentService;
+import cn.reghao.tnb.account.api.iface.AdminAccountService;
 import cn.reghao.tnb.user.api.dto.UserInfo;
 import cn.reghao.tnb.user.api.dto.UserSearch;
 import cn.reghao.tnb.user.api.dto.VipPlanInfo;
-import cn.reghao.tnb.user.api.iface.AdminUserService;
+import cn.reghao.tnb.user.api.dto.WalletChargeDto;
+import cn.reghao.tnb.user.api.iface.UserWalletService;
 import cn.reghao.tnb.user.app.db.mapper.UserProfileMapper;
 import cn.reghao.tnb.user.app.model.po.UserProfile;
 import cn.reghao.tnb.user.app.model.po.VipPlan;
-import cn.reghao.tnb.user.app.service.UserVipService;
 import org.apache.dubbo.config.annotation.DubboReference;
-import org.apache.dubbo.config.annotation.DubboService;
+import org.springframework.data.domain.Page;
+import org.springframework.data.domain.PageImpl;
+import org.springframework.data.domain.PageRequest;
 import org.springframework.stereotype.Service;
 
 import java.util.List;
+import java.util.concurrent.ExecutorService;
 import java.util.stream.Collectors;
 
 /**
  * @author reghao
- * @date 2024-02-15 09:17:08
+ * @date 2024-07-06 11:22:17
  */
-@DubboService
 @Service
-public class AdminUserServiceImpl implements AdminUserService {
+public class AdminUserService {
+    @DubboReference(check = false, timeout = 60_000)
+    private AdminAccountService adminAccountService;
     @DubboReference(check = false, retries = 0)
     private AccountQuery accountQuery;
-    @DubboReference(check = false, retries = 0, timeout = 30_000)
-    private UserContentService userContentService;
+
+    private int pageSize = 100;
+    private final ExecutorService threadPool = ThreadPoolWrapper.threadPool("approve-charge-task", 1);
+    private final UserWalletService userWalletService;
     private final UserVipService userVipService;
     private final UserProfileMapper userProfileMapper;
-    private int pageSize = 100;
 
-    public AdminUserServiceImpl(UserVipService userVipService, UserProfileMapper userProfileMapper) {
+    public AdminUserService(UserWalletService userWalletService, UserVipService userVipService,
+                            UserProfileMapper userProfileMapper) {
+        this.userWalletService = userWalletService;
         this.userVipService = userVipService;
         this.userProfileMapper = userProfileMapper;
     }
 
-    @Override
+    public Page<AccountInfo> getUserAccounts(String searchKey, PageRequest pageRequest) {
+        int pageNumber = pageRequest.getPageNumber()+1;
+        int pageSize = pageRequest.getPageSize();
+        PageList<AccountInfo> pageList = adminAccountService.getByScreenName(searchKey, pageNumber, pageSize);
+        return new PageImpl<>(pageList.getList(), pageRequest, pageList.getTotalSize());
+    }
+
     public PageList<UserInfo> getUserList(UserSearch userSearch) {
         return PageList.empty();
     }
@@ -75,7 +90,6 @@ public class AdminUserServiceImpl implements AdminUserService {
         return userInfo;
     }
 
-    @Override
     public List<VipPlanInfo> getVipPlans() {
         List<VipPlan> list = userVipService.getVipPlans();
         return list.stream().map(this::getVipPlanInfo).collect(Collectors.toList());
@@ -111,4 +125,31 @@ public class AdminUserServiceImpl implements AdminUserService {
 
         return userId;
     }
+
+    public void createAccount(AdminCreateAccount adminCreateAccount) {
+        adminAccountService.createAccount(adminCreateAccount);
+    }
+
+    public List<WalletChargeDto> getChargeReqs() {
+        return userWalletService.getChargeReqs();
+    }
+
+    public void approve(long chargeId) {
+        userWalletService.approveCharge(chargeId);
+    }
+
+    public void approveAll() {
+        threadPool.submit(new ApproveTask());
+    }
+
+    public void decline(long chargeId) {
+        userWalletService.declineCharge(chargeId);
+    }
+
+    class ApproveTask implements Runnable {
+        @Override
+        public void run() {
+            userWalletService.approveAllCharges();
+        }
+    }
 }

+ 0 - 3
user/user-service/src/main/java/cn/reghao/tnb/user/app/service/UserProfileService.java

@@ -3,7 +3,6 @@ package cn.reghao.tnb.user.app.service;
 import cn.reghao.tnb.account.api.dto.AccountInfo;
 import cn.reghao.tnb.account.api.iface.AccountQuery;
 import cn.reghao.tnb.common.auth.UserContext;
-import cn.reghao.tnb.content.api.iface.UserContentService;
 import cn.reghao.tnb.user.api.dto.UserCard;
 import cn.reghao.tnb.user.api.dto.UserInfo;
 import cn.reghao.tnb.user.app.db.mapper.UserProfileMapper;
@@ -21,8 +20,6 @@ import org.springframework.stereotype.Service;
 public class UserProfileService {
     @DubboReference(check = false, retries = 0, timeout = 30_000)
     private AccountQuery accountQuery;
-    @DubboReference(check = false, retries = 0, timeout = 30_000)
-    private UserContentService userContentService;
 
     private int pageSize = 100;
     private final UserProfileMapper userProfileMapper;