后台管理功能补充

This commit is contained in:
2025-12-25 00:13:42 +08:00
parent 90d9de0e71
commit f4bc9f6dab
9 changed files with 259 additions and 3 deletions
@@ -2,9 +2,11 @@ package com.emotion.controller;
import com.emotion.common.PageResult;
import com.emotion.common.Result;
import com.emotion.dto.request.AiConfigCallStatsRequest;
import com.emotion.dto.request.AdminCreateRequest;
import com.emotion.dto.request.AdminPageRequest;
import com.emotion.dto.request.AdminUpdateRequest;
import com.emotion.dto.response.AiConfigCallStatsResponse;
import com.emotion.dto.response.AdminResponse;
import com.emotion.dto.response.DashboardStatsResponse;
import com.emotion.service.AdminService;
@@ -166,4 +168,14 @@ public class AdminController {
List<DashboardStatsResponse.RecentLogin> recentLogins = dashboardService.getRecentLogins(limit);
return Result.success("获取成功", recentLogins);
}
/**
* 获取 AI 配置调用次数统计
*/
@Operation(summary = "获取AI配置调用次数统计", description = "按 t_ai_config 的 workflow_id 关联 t_coze_api_call 统计调用次数并按次数倒序返回")
@GetMapping(value = "/dashboard/aiConfigCallStats")
public Result<AiConfigCallStatsResponse> getAiConfigCallStats(@Validated AiConfigCallStatsRequest request) {
AiConfigCallStatsResponse response = dashboardService.getAiConfigCallStats(request);
return Result.success("获取成功", response);
}
}
@@ -0,0 +1,29 @@
package com.emotion.dto.request;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import javax.validation.constraints.Max;
import javax.validation.constraints.Min;
/**
* AI配置调用次数统计请求
* 用于管理后台仪表盘:按 t_ai_config 配置统计 t_coze_api_call 调用次数
*
* @author system
* @date 2025-12-24
*/
@Data
@Schema(description = "AI配置调用次数统计请求")
public class AiConfigCallStatsRequest {
/**
* 返回条数限制(默认 20,最大 200)
*/
@Min(1)
@Max(200)
@Schema(description = "返回条数限制(默认20,最大200", example = "20")
private Integer limit;
}
@@ -0,0 +1,45 @@
package com.emotion.dto.response;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
/**
* AI配置调用次数统计项
* 通过 workflowId 关联 t_ai_config 与 t_coze_api_call,统计调用次数并排序展示
*
* @author system
* @date 2025-12-24
*/
@Data
@Schema(description = "AI配置调用次数统计项")
public class AiConfigCallStatsItem {
@Schema(description = "AI配置ID")
private String configId;
@Schema(description = "配置名称")
private String configName;
@Schema(description = "配置键值")
private String configKey;
@Schema(description = "服务提供商")
private String provider;
@Schema(description = "配置类型")
private String configType;
@Schema(description = "Workflow ID")
private String workflowId;
@Schema(description = "是否启用:0-禁用,1-启用")
private Integer isEnabled;
@Schema(description = "是否默认:0-否,1-是")
private Integer isDefault;
@Schema(description = "调用次数")
private Long callCount;
}
@@ -0,0 +1,29 @@
package com.emotion.dto.response;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.List;
/**
* AI配置调用次数统计响应
* 用于管理后台仪表盘展示:各个 AI 配置的接口调用次数(按次数排序)
*
* @author system
* @date 2025-12-24
*/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
@Schema(description = "AI配置调用次数统计响应")
public class AiConfigCallStatsResponse {
@Schema(description = "统计列表(按调用次数倒序)")
private List<AiConfigCallStatsItem> items;
}
@@ -1,9 +1,14 @@
package com.emotion.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.emotion.dto.response.AiConfigCallStatsItem;
import com.emotion.entity.AiConfig;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;
import org.apache.ibatis.annotations.Mapper;
import java.util.List;
/**
* AI配置Mapper接口
*
@@ -12,4 +17,34 @@ import org.apache.ibatis.annotations.Mapper;
*/
@Mapper
public interface AiConfigMapper extends BaseMapper<AiConfig> {
/**
* 按 AI 配置统计 Coze 接口调用次数(通过 workflow_id 关联)
*
* @param limit 返回条数限制
* @return 统计列表(按调用次数倒序)
*/
@Select({
"SELECT",
" c.id AS configId,",
" c.config_name AS configName,",
" c.config_key AS configKey,",
" c.provider AS provider,",
" c.config_type AS configType,",
" c.workflow_id AS workflowId,",
" c.is_enabled AS isEnabled,",
" c.is_default AS isDefault,",
" COALESCE(COUNT(a.id), 0) AS callCount",
"FROM t_ai_config c",
"LEFT JOIN t_coze_api_call a",
" ON a.workflow_id = c.workflow_id",
" AND a.is_deleted = 0",
"WHERE c.is_deleted = 0",
"GROUP BY",
" c.id, c.config_name, c.config_key, c.provider, c.config_type,",
" c.workflow_id, c.is_enabled, c.is_default",
"ORDER BY callCount DESC",
"LIMIT #{limit}"
})
List<AiConfigCallStatsItem> selectAiConfigCallStats(@Param("limit") Integer limit);
}
@@ -1,5 +1,7 @@
package com.emotion.service;
import com.emotion.dto.request.AiConfigCallStatsRequest;
import com.emotion.dto.response.AiConfigCallStatsResponse;
import com.emotion.dto.response.DashboardStatsResponse;
import java.util.List;
@@ -61,4 +63,12 @@ public interface DashboardService {
* @return 最近登录用户列表
*/
List<DashboardStatsResponse.RecentLogin> getRecentLogins(int limit);
/**
* 获取 AI 配置调用次数统计(按调用次数倒序)
*
* @param request 统计请求
* @return AI配置调用次数统计响应
*/
AiConfigCallStatsResponse getAiConfigCallStats(AiConfigCallStatsRequest request);
}
@@ -1,8 +1,12 @@
package com.emotion.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.emotion.dto.request.AiConfigCallStatsRequest;
import com.emotion.dto.response.AiConfigCallStatsResponse;
import com.emotion.dto.response.AiConfigCallStatsItem;
import com.emotion.dto.response.DashboardStatsResponse;
import com.emotion.entity.*;
import com.emotion.mapper.AiConfigMapper;
import com.emotion.service.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
@@ -56,6 +60,9 @@ public class DashboardServiceImpl implements DashboardService {
@Autowired
private AdminService adminService;
@Autowired
private AiConfigMapper aiConfigMapper;
@Autowired
private AchievementService achievementService;
@@ -464,6 +471,26 @@ public class DashboardServiceImpl implements DashboardService {
return recentLogins;
}
@Override
public AiConfigCallStatsResponse getAiConfigCallStats(AiConfigCallStatsRequest request) {
Integer limit = request != null ? request.getLimit() : null;
if (limit == null) {
limit = 20;
}
// 防御性限制,避免过大查询
if (limit > 200) {
limit = 200;
}
if (limit < 1) {
limit = 1;
}
List<AiConfigCallStatsItem> items = aiConfigMapper.selectAiConfigCallStats(limit);
return AiConfigCallStatsResponse.builder()
.items(items)
.build();
}
/**
* 格式化时间描述
*/