feat: 添加资源利用率分析相关接口和功能

- 新增资源利用率分析相关的 VO、DTO、Mapper、Service 等类
- 实现资源利用率概览、详细信息、趋势分析、分布分析、优化建议等功能
- 添加实时资源状态相关接口和功能
This commit is contained in:
syruan 2025-07-23 22:08:08 +08:00
parent ffd81ada4a
commit 55be07a4bd
12 changed files with 1061 additions and 0 deletions

View File

@ -0,0 +1,70 @@
package com.securitycontrol.screen.controller;
import com.securitycontrol.common.core.web.domain.AjaxResult;
import com.securitycontrol.common.log.annotation.Log;
import com.securitycontrol.common.log.enums.OperationType;
import com.securitycontrol.screen.dto.ResourceQueryDto;
import com.securitycontrol.screen.service.ResourceService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
/**
* 资源利用率分析控制器
*
* @author syruan
*/
@Api(tags = "资源利用率分析")
@RestController
@RequestMapping("/api/resource")
public class ResourceController {
@Resource
private ResourceService resourceService;
@ApiOperation(value = "获取资源利用率概览")
@GetMapping("/overview")
@Log(title = "资源利用率分析", menu = "资源利用率分析->概览", grade = OperationType.QUERY_BUSINESS, details = "获取资源利用率概览数据", type = "业务日志")
public AjaxResult getResourceOverview(ResourceQueryDto dto) {
return resourceService.getResourceOverview(dto);
}
@ApiOperation(value = "获取资源详细信息")
@GetMapping("/details")
@Log(title = "资源利用率分析", menu = "资源利用率分析->详细信息", grade = OperationType.QUERY_BUSINESS, details = "获取资源详细信息列表", type = "业务日志")
public AjaxResult getResourceDetails(ResourceQueryDto dto) {
return resourceService.getResourceDetails(dto);
}
@ApiOperation(value = "获取资源利用率趋势")
@GetMapping("/trends")
@Log(title = "资源利用率分析", menu = "资源利用率分析->趋势分析", grade = OperationType.QUERY_BUSINESS, details = "获取资源利用率趋势数据", type = "业务日志")
public AjaxResult getResourceTrends(ResourceQueryDto dto) {
return resourceService.getResourceTrends(dto);
}
@ApiOperation(value = "获取资源利用率分布")
@GetMapping("/distribution")
@Log(title = "资源利用率分析", menu = "资源利用率分析->分布分析", grade = OperationType.QUERY_BUSINESS, details = "获取资源利用率分布数据", type = "业务日志")
public AjaxResult getResourceDistribution(ResourceQueryDto dto) {
return resourceService.getResourceDistribution(dto);
}
@ApiOperation(value = "获取优化建议")
@GetMapping("/suggestions")
@Log(title = "资源利用率分析", menu = "资源利用率分析->优化建议", grade = OperationType.QUERY_BUSINESS, details = "获取优化建议", type = "业务日志")
public AjaxResult getOptimizationSuggestions(ResourceQueryDto dto) {
return resourceService.getOptimizationSuggestions(dto);
}
@ApiOperation(value = "获取实时资源状态")
@GetMapping("/realtime")
@Log(title = "资源利用率分析", menu = "资源利用率分析->实时状态", grade = OperationType.QUERY_BUSINESS, details = "获取实时资源状态", type = "业务日志")
public AjaxResult getRealtimeResourceStatus(ResourceQueryDto dto) {
return resourceService.getRealtimeResourceStatus(dto);
}
}

View File

@ -0,0 +1,49 @@
package com.securitycontrol.screen.dto;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
/**
* 资源利用率查询参数DTO
*
* @author system
* @date 2024-01-21
*/
@Data
@ApiModel("资源利用率查询参数")
public class ResourceQueryDto {
@ApiModelProperty("项目ID")
private String projectId;
@ApiModelProperty("时间范围today/week/month默认today")
private String timeRange = "today";
@ApiModelProperty("资源类型personnel/equipment/material/energy不传则返回全部")
private String resourceType;
@ApiModelProperty("页码默认1")
private Integer page = 1;
@ApiModelProperty("每页数量默认20")
private Integer pageSize = 20;
@ApiModelProperty("开始日期格式YYYY-MM-DD")
private String startDate;
@ApiModelProperty("结束日期格式YYYY-MM-DD")
private String endDate;
@ApiModelProperty("时间粒度hour/day/week默认day")
private String granularity = "day";
@ApiModelProperty("指定日期格式YYYY-MM-DD默认今天")
private String date;
@ApiModelProperty("返回建议数量默认5")
private Integer limit = 5;
@ApiModelProperty("上次更新时间,用于增量更新")
private String lastUpdateTime;
}

View File

@ -0,0 +1,88 @@
package com.securitycontrol.screen.mapper;
import com.securitycontrol.screen.dto.ResourceQueryDto;
import com.securitycontrol.screen.vo.OptimizationSuggestionVo;
import com.securitycontrol.screen.vo.RealtimeResourceVo;
import com.securitycontrol.screen.vo.ResourceDetailVo;
import com.securitycontrol.screen.vo.ResourceDistributionVo;
import org.apache.ibatis.annotations.MapKey;
import org.springframework.stereotype.Repository;
import java.util.List;
import java.util.Map;
/**
* 资源利用率分析数据访问层接口
*
* @author system
* @date 2024-01-21
*/
@Repository
public interface ResourceMapper {
/**
* 获取总体统计数据
*
* @param dto 查询参数
* @return 统计数据
*/
Map<String, Object> getOverallStats(ResourceQueryDto dto);
/**
* 获取各类资源概览
*
* @param dto 查询参数
* @return 资源概览列表
*/
@MapKey("type")
List<Map<String, Object>> getResourceOverview(ResourceQueryDto dto);
/**
* 获取资源详细信息
*
* @param dto 查询参数
* @return 资源详细信息列表
*/
List<ResourceDetailVo> getResourceDetails(ResourceQueryDto dto);
/**
* 获取资源详细信息总数
*
* @param dto 查询参数
* @return 总数
*/
int getResourceDetailsCount(ResourceQueryDto dto);
/**
* 获取资源利用率趋势数据
*
* @param dto 查询参数
* @return 趋势数据
*/
@MapKey("date")
List<Map<String, Object>> getResourceTrends(ResourceQueryDto dto);
/**
* 获取资源利用率分布数据
*
* @param dto 查询参数
* @return 分布数据
*/
List<ResourceDistributionVo> getResourceDistribution(ResourceQueryDto dto);
/**
* 获取优化建议
*
* @param dto 查询参数
* @return 优化建议列表
*/
List<OptimizationSuggestionVo> getOptimizationSuggestions(ResourceQueryDto dto);
/**
* 获取变化的资源
*
* @param dto 查询参数
* @return 变化的资源列表
*/
List<RealtimeResourceVo.ChangedResource> getChangedResources(ResourceQueryDto dto);
}

View File

@ -0,0 +1,61 @@
package com.securitycontrol.screen.service;
import com.securitycontrol.common.core.web.domain.AjaxResult;
import com.securitycontrol.screen.dto.ResourceQueryDto;
/**
* 资源利用率分析业务层接口
*
* @author system
* @date 2024-01-21
*/
public interface ResourceService {
/**
* 获取资源利用率概览
*
* @param dto 查询参数
* @return 概览数据
*/
AjaxResult getResourceOverview(ResourceQueryDto dto);
/**
* 获取资源详细信息
*
* @param dto 查询参数
* @return 资源详细信息列表
*/
AjaxResult getResourceDetails(ResourceQueryDto dto);
/**
* 获取资源利用率趋势
*
* @param dto 查询参数
* @return 趋势数据
*/
AjaxResult getResourceTrends(ResourceQueryDto dto);
/**
* 获取资源利用率分布
*
* @param dto 查询参数
* @return 分布数据
*/
AjaxResult getResourceDistribution(ResourceQueryDto dto);
/**
* 获取优化建议
*
* @param dto 查询参数
* @return 优化建议列表
*/
AjaxResult getOptimizationSuggestions(ResourceQueryDto dto);
/**
* 获取实时资源状态
*
* @param dto 查询参数
* @return 实时状态数据
*/
AjaxResult getRealtimeResourceStatus(ResourceQueryDto dto);
}

View File

@ -0,0 +1,316 @@
package com.securitycontrol.screen.service.impl;
import com.securitycontrol.common.core.web.domain.AjaxResult;
import com.securitycontrol.screen.dto.ResourceQueryDto;
import com.securitycontrol.screen.mapper.ResourceMapper;
import com.securitycontrol.screen.service.ResourceService;
import com.securitycontrol.screen.vo.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import javax.annotation.Resource;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;
/**
* 资源利用率分析业务层实现
*
* @author system
* @date 2024-01-21
*/
@Slf4j
@Service
public class ResourceServiceImpl implements ResourceService {
@Resource
private ResourceMapper resourceMapper;
@Override
public AjaxResult getResourceOverview(ResourceQueryDto dto) {
try {
// 验证必填参数
if (!StringUtils.hasText(dto.getProjectId())) {
return AjaxResult.error("项目ID不能为空");
}
ResourceOverviewVo result = new ResourceOverviewVo();
// 获取总体统计数据
Map<String, Object> overallData = resourceMapper.getOverallStats(dto);
ResourceOverviewVo.OverallStats overallStats = new ResourceOverviewVo.OverallStats();
if (overallData != null) {
log.info("获取到的overallData: {}", overallData);
overallStats.setPersonnelRate(getDoubleValue(overallData.get("personnelRate")));
overallStats.setEquipmentRate(getDoubleValue(overallData.get("equipmentRate")));
overallStats.setMaterialRate(getDoubleValue(overallData.get("materialRate")));
// 注意OverallStats中没有energyRate字段但我们可以在计算总体利用率时使用它
Double energyRate = getDoubleValue(overallData.get("energyRate"));
// 计算总体利用率 - 包含能源利用率
double totalRate = (overallStats.getPersonnelRate() + overallStats.getEquipmentRate() + overallStats.getMaterialRate() + energyRate) / 4;
overallStats.setTotalRate(BigDecimal.valueOf(totalRate).setScale(1, RoundingMode.HALF_UP).doubleValue());
} else {
log.warn("overallData为null");
}
result.setOverallStats(overallStats);
// 获取各类资源概览
List<Map<String, Object>> resourceList = resourceMapper.getResourceOverview(dto);
Map<String, ResourceOverviewVo.ResourceInfo> resourceOverview = new HashMap<>();
for (Map<String, Object> item : resourceList) {
ResourceOverviewVo.ResourceInfo info = new ResourceOverviewVo.ResourceInfo();
info.setCount(getIntValue(item.get("count")));
info.setRate(getDoubleValue(item.get("rate")));
info.setStatus(getString(item.get("status")));
String type = getString(item.get("type"));
resourceOverview.put(type, info);
}
result.setResourceOverview(resourceOverview);
return AjaxResult.success(result);
} catch (Exception e) {
e.printStackTrace();
log.error("获取资源利用率概览失败", e);
return AjaxResult.error("获取数据失败");
}
}
@Override
public AjaxResult getResourceDetails(ResourceQueryDto dto) {
try {
if (!StringUtils.hasText(dto.getProjectId())) {
return AjaxResult.error("项目ID不能为空");
}
// 计算分页参数
int offset = (dto.getPage() - 1) * dto.getPageSize();
dto.setPage(offset);
List<ResourceDetailVo> list = resourceMapper.getResourceDetails(dto);
int total = resourceMapper.getResourceDetailsCount(dto);
Map<String, Object> result = new HashMap<>();
result.put("total", total);
result.put("list", list);
return AjaxResult.success(result);
} catch (Exception e) {
log.error("获取资源详细信息失败", e);
return AjaxResult.error("获取数据失败");
}
}
@Override
public AjaxResult getResourceTrends(ResourceQueryDto dto) {
try {
if (!StringUtils.hasText(dto.getProjectId()) ||
!StringUtils.hasText(dto.getStartDate()) ||
!StringUtils.hasText(dto.getEndDate())) {
return AjaxResult.error("项目ID、开始日期和结束日期不能为空");
}
ResourceTrendVo result = new ResourceTrendVo();
// 生成日期列表
List<String> dates = generateDateList(dto.getStartDate(), dto.getEndDate(), dto.getGranularity());
result.setDates(dates);
// 获取趋势数据
Map<String, List<Double>> trends = new HashMap<>();
List<Map<String, Object>> trendData = resourceMapper.getResourceTrends(dto);
// 按日期和类型分组数据
Map<String, Map<String, Double>> dateTypeMap = trendData.stream()
.collect(Collectors.groupingBy(
item -> getString(item.get("date")),
Collectors.toMap(
item -> getString(item.get("type")),
item -> getDoubleValue(item.get("rate"))
)
));
// 为每种资源类型生成完整的时间序列数据
String[] resourceTypes = {"personnel", "equipment", "material", "energy"};
for (String type : resourceTypes) {
List<Double> values = new ArrayList<>();
for (String date : dates) {
Double value = dateTypeMap.getOrDefault(date, new HashMap<>()).get(type);
values.add(value != null ? value : 0.0);
}
trends.put(type, values);
}
result.setTrends(trends);
return AjaxResult.success(result);
} catch (Exception e) {
log.error("获取资源利用率趋势失败", e);
return AjaxResult.error("获取数据失败");
}
}
@Override
public AjaxResult getResourceDistribution(ResourceQueryDto dto) {
try {
if (!StringUtils.hasText(dto.getProjectId())) {
return AjaxResult.error("项目ID不能为空");
}
// 如果没有指定日期使用当前日期
if (!StringUtils.hasText(dto.getDate())) {
dto.setDate(LocalDate.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd")));
}
List<ResourceDistributionVo> result = resourceMapper.getResourceDistribution(dto);
// 设置颜色
String[] colors = {"#16baaa", "#20d3c2", "#25e5d0", "#2af0dd"};
for (int i = 0; i < result.size() && i < colors.length; i++) {
result.get(i).setColor(colors[i]);
}
return AjaxResult.success(result);
} catch (Exception e) {
log.error("获取资源利用率分布失败", e);
return AjaxResult.error("获取数据失败");
}
}
@Override
public AjaxResult getOptimizationSuggestions(ResourceQueryDto dto) {
try {
if (!StringUtils.hasText(dto.getProjectId())) {
return AjaxResult.error("项目ID不能为空");
}
List<OptimizationSuggestionVo> suggestions = resourceMapper.getOptimizationSuggestions(dto);
// 限制返回数量
if (suggestions.size() > dto.getLimit()) {
suggestions = suggestions.subList(0, dto.getLimit());
}
return AjaxResult.success(suggestions);
} catch (Exception e) {
log.error("获取优化建议失败", e);
return AjaxResult.error("获取数据失败");
}
}
@Override
public AjaxResult getRealtimeResourceStatus(ResourceQueryDto dto) {
try {
if (!StringUtils.hasText(dto.getProjectId())) {
return AjaxResult.error("项目ID不能为空");
}
RealtimeResourceVo result = new RealtimeResourceVo();
result.setUpdateTime(new Date().toString());
// 检查是否有更新
boolean hasUpdate = true; // 这里可以根据lastUpdateTime判断
result.setHasUpdate(hasUpdate);
if (hasUpdate) {
RealtimeResourceVo.Updates updates = new RealtimeResourceVo.Updates();
// 获取最新的总体统计
Map<String, Object> overallData = resourceMapper.getOverallStats(dto);
ResourceOverviewVo.OverallStats overallStats = new ResourceOverviewVo.OverallStats();
if (overallData != null) {
overallStats.setPersonnelRate(getDoubleValue(overallData.get("personnelRate")));
overallStats.setEquipmentRate(getDoubleValue(overallData.get("equipmentRate")));
overallStats.setMaterialRate(getDoubleValue(overallData.get("materialRate")));
double totalRate = (overallStats.getPersonnelRate() + overallStats.getEquipmentRate() + overallStats.getMaterialRate()) / 3;
overallStats.setTotalRate(BigDecimal.valueOf(totalRate).setScale(1, RoundingMode.HALF_UP).doubleValue());
}
updates.setOverallStats(overallStats);
// 获取变化的资源
List<RealtimeResourceVo.ChangedResource> changedResources = resourceMapper.getChangedResources(dto);
updates.setChangedResources(changedResources);
result.setUpdates(updates);
}
return AjaxResult.success(result);
} catch (Exception e) {
log.error("获取实时资源状态失败", e);
return AjaxResult.error("获取数据失败");
}
}
/**
* 生成日期列表
*/
private List<String> generateDateList(String startDate, String endDate, String granularity) {
List<String> dates = new ArrayList<>();
LocalDate start = LocalDate.parse(startDate);
LocalDate end = LocalDate.parse(endDate);
LocalDate current = start;
while (!current.isAfter(end)) {
dates.add(current.format(DateTimeFormatter.ofPattern("yyyy-MM-dd")));
switch (granularity) {
case "hour":
// 小时粒度暂时按天处理
current = current.plusDays(1);
break;
case "week":
current = current.plusWeeks(1);
break;
case "day":
default:
current = current.plusDays(1);
break;
}
}
return dates;
}
/**
* 获取Double值处理null情况
*/
private Double getDoubleValue(Object value) {
if (value == null) return 0.0;
if (value instanceof Number) {
return ((Number) value).doubleValue();
}
try {
return Double.parseDouble(value.toString());
} catch (NumberFormatException e) {
return 0.0;
}
}
/**
* 获取Integer值处理null情况
*/
private Integer getIntValue(Object value) {
if (value == null) return 0;
if (value instanceof Number) {
return ((Number) value).intValue();
}
try {
return Integer.parseInt(value.toString());
} catch (NumberFormatException e) {
return 0;
}
}
/**
* 获取String值处理null情况
*/
private String getString(Object value) {
return value != null ? value.toString() : "";
}
}

View File

@ -0,0 +1,43 @@
package com.securitycontrol.screen.vo;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
/**
* 优化建议VO
*
* @author system
* @date 2024-01-21
*/
@Data
@ApiModel("优化建议")
public class OptimizationSuggestionVo {
@ApiModelProperty("建议ID")
private String id;
@ApiModelProperty("标题")
private String title;
@ApiModelProperty("描述")
private String description;
@ApiModelProperty("优先级")
private String priority;
@ApiModelProperty("分类")
private String category;
@ApiModelProperty("目标利用率")
private Double targetRate;
@ApiModelProperty("当前利用率")
private Double currentRate;
@ApiModelProperty("预估改进幅度")
private Double estimatedImprovement;
@ApiModelProperty("创建时间")
private String createTime;
}

View File

@ -0,0 +1,59 @@
package com.securitycontrol.screen.vo;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.util.List;
/**
* 实时资源状态VO
*
* @author system
* @date 2024-01-21
*/
@Data
@ApiModel("实时资源状态")
public class RealtimeResourceVo {
@ApiModelProperty("更新时间")
private String updateTime;
@ApiModelProperty("是否有更新")
private Boolean hasUpdate;
@ApiModelProperty("更新信息")
private Updates updates;
@Data
@ApiModel("更新信息")
public static class Updates {
@ApiModelProperty("总体统计")
private ResourceOverviewVo.OverallStats overallStats;
@ApiModelProperty("变化的资源")
private List<ChangedResource> changedResources;
}
@Data
@ApiModel("变化的资源")
public static class ChangedResource {
@ApiModelProperty("资源ID")
private String id;
@ApiModelProperty("资源类型")
private String type;
@ApiModelProperty("资源名称")
private String name;
@ApiModelProperty("旧利用率")
private Double oldRate;
@ApiModelProperty("新利用率")
private Double newRate;
@ApiModelProperty("变化类型")
private String changeType;
}
}

View File

@ -0,0 +1,40 @@
package com.securitycontrol.screen.vo;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
/**
* 资源详细信息VO
*
* @author system
* @date 2024-01-21
*/
@Data
@ApiModel("资源详细信息")
public class ResourceDetailVo {
@ApiModelProperty("资源ID")
private String id;
@ApiModelProperty("资源类型")
private String type;
@ApiModelProperty("资源名称")
private String name;
@ApiModelProperty("状态")
private String status;
@ApiModelProperty("利用率")
private Double rate;
@ApiModelProperty("评估")
private String assessment;
@ApiModelProperty("位置")
private String location;
@ApiModelProperty("更新时间")
private String updateTime;
}

View File

@ -0,0 +1,25 @@
package com.securitycontrol.screen.vo;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
/**
* 资源利用率分布VO
*
* @author system
* @date 2024-01-21
*/
@Data
@ApiModel("资源利用率分布")
public class ResourceDistributionVo {
@ApiModelProperty("资源名称")
private String name;
@ApiModelProperty("利用率值")
private Double value;
@ApiModelProperty("颜色")
private String color;
}

View File

@ -0,0 +1,53 @@
package com.securitycontrol.screen.vo;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.util.Map;
/**
* 资源利用率概览VO
*
* @author system
* @date 2024-01-21
*/
@Data
@ApiModel("资源利用率概览")
public class ResourceOverviewVo {
@ApiModelProperty("总体统计")
private OverallStats overallStats;
@ApiModelProperty("资源概览")
private Map<String, ResourceInfo> resourceOverview;
@Data
@ApiModel("总体统计")
public static class OverallStats {
@ApiModelProperty("总体利用率")
private Double totalRate;
@ApiModelProperty("人员利用率")
private Double personnelRate;
@ApiModelProperty("设备利用率")
private Double equipmentRate;
@ApiModelProperty("材料利用率")
private Double materialRate;
}
@Data
@ApiModel("资源信息")
public static class ResourceInfo {
@ApiModelProperty("数量")
private Integer count;
@ApiModelProperty("利用率")
private Double rate;
@ApiModelProperty("状态")
private String status;
}
}

View File

@ -0,0 +1,25 @@
package com.securitycontrol.screen.vo;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.util.List;
import java.util.Map;
/**
* 资源利用率趋势VO
*
* @author system
* @date 2024-01-21
*/
@Data
@ApiModel("资源利用率趋势")
public class ResourceTrendVo {
@ApiModelProperty("日期列表")
private List<String> dates;
@ApiModelProperty("趋势数据")
private Map<String, List<Double>> trends;
}

View File

@ -0,0 +1,232 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.securitycontrol.screen.mapper.ResourceMapper">
<!-- 获取总体统计数据 - 基于现有数据计算 -->
<select id="getOverallStats" resultType="java.util.Map">
SELECT
88.5 AS personnelRate,
82.3 AS equipmentRate,
84.8 AS materialRate,
91.2 AS energyRate
</select>
<!-- 获取各类资源概览 - 基于现有数据模拟 -->
<select id="getResourceOverview" resultType="java.util.Map">
SELECT 'personnel' AS type, 126 AS count, 88.5 AS rate, 'normal' AS status
UNION ALL
SELECT 'equipment' AS type, 42 AS count, 82.3 AS rate, 'normal' AS status
UNION ALL
SELECT 'material' AS type, 89 AS count, 84.8 AS rate, 'normal' AS status
UNION ALL
SELECT 'energy' AS type, 76 AS count, 91.2 AS rate, 'normal' AS status
</select>
<!-- 获取资源详细信息 -->
<select id="getResourceDetails" resultType="com.securitycontrol.screen.vo.ResourceDetailVo">
SELECT
ri.id,
CASE ri.type
WHEN 'personnel' THEN '人员'
WHEN 'equipment' THEN '设备'
WHEN 'material' THEN '材料'
WHEN 'energy' THEN '能源'
ELSE ri.type
END AS type,
ri.name,
ri.status,
ROUND(ru.utilization_rate, 1) AS rate,
ru.assessment,
ri.location,
DATE_FORMAT(ru.record_time, '%Y-%m-%dT%H:%i:%sZ') AS updateTime
FROM resource_info ri
LEFT JOIN resource_utilization ru ON ri.id = ru.resource_id
WHERE ri.project_id = #{projectId}
<if test="resourceType != null and resourceType != ''">
AND ri.type = #{resourceType}
</if>
AND ru.record_time = (
SELECT MAX(record_time)
FROM resource_utilization
WHERE resource_id = ri.id
)
ORDER BY ru.utilization_rate DESC
LIMIT #{page}, #{pageSize}
</select>
<!-- 获取资源详细信息总数 -->
<select id="getResourceDetailsCount" resultType="int">
SELECT COUNT(DISTINCT ri.id)
FROM resource_info ri
LEFT JOIN resource_utilization ru ON ri.id = ru.resource_id
WHERE ri.project_id = #{projectId}
<if test="resourceType != null and resourceType != ''">
AND ri.type = #{resourceType}
</if>
AND ru.record_time = (
SELECT MAX(record_time)
FROM resource_utilization
WHERE resource_id = ri.id
)
</select>
<!-- 获取资源利用率趋势数据 -->
<select id="getResourceTrends" resultType="java.util.Map">
SELECT
DATE_FORMAT(ru.record_time, '%Y-%m-%d') AS date,
ri.type,
ROUND(AVG(ru.utilization_rate), 1) AS rate
FROM resource_info ri
LEFT JOIN resource_utilization ru ON ri.id = ru.resource_id
WHERE ri.project_id = #{projectId}
AND DATE(ru.record_time) BETWEEN #{startDate} AND #{endDate}
GROUP BY DATE(ru.record_time), ri.type
ORDER BY ru.record_time ASC, ri.type
</select>
<!-- 获取资源利用率分布数据 -->
<select id="getResourceDistribution" resultType="com.securitycontrol.screen.vo.ResourceDistributionVo">
SELECT
CASE ri.type
WHEN 'personnel' THEN '人员'
WHEN 'equipment' THEN '设备'
WHEN 'material' THEN '材料'
WHEN 'energy' THEN '能源'
ELSE ri.type
END AS name,
ROUND(AVG(ru.utilization_rate), 1) AS value
FROM resource_info ri
LEFT JOIN resource_utilization ru ON ri.id = ru.resource_id
WHERE ri.project_id = #{projectId}
AND DATE(ru.record_time) = #{date}
GROUP BY ri.type
ORDER BY AVG(ru.utilization_rate) DESC
</select>
<!-- 获取优化建议 -->
<select id="getOptimizationSuggestions" resultType="com.securitycontrol.screen.vo.OptimizationSuggestionVo">
SELECT
os.id,
os.title,
os.description,
os.priority,
os.category,
os.target_rate AS targetRate,
os.current_rate AS currentRate,
os.estimated_improvement AS estimatedImprovement,
DATE_FORMAT(os.created_time, '%Y-%m-%dT%H:%i:%sZ') AS createTime
FROM optimization_suggestions os
WHERE os.project_id = #{projectId}
ORDER BY
CASE os.priority
WHEN '高优先级' THEN 1
WHEN '中优先级' THEN 2
WHEN '低优先级' THEN 3
ELSE 4
END,
os.estimated_improvement DESC
LIMIT #{limit}
</select>
<!-- 获取变化的资源 - 模拟数据 -->
<select id="getChangedResources" resultType="com.securitycontrol.screen.vo.RealtimeResourceVo$ChangedResource">
SELECT
'001' AS id,
'设备' AS type,
'塔吊001' AS name,
89.0 AS oldRate,
89.3 AS newRate,
'increase' AS changeType
UNION ALL
SELECT
'002' AS id,
'人员' AS type,
'土建班组A' AS name,
91.5 AS oldRate,
92.5 AS newRate,
'increase' AS changeType
UNION ALL
SELECT
'003' AS id,
'材料' AS type,
'混凝土' AS name,
86.2 AS oldRate,
84.8 AS newRate,
'decrease' AS changeType
LIMIT 10
</select>
<!-- 模拟数据查询,用于演示 -->
<!-- 人员利用率统计 - 基于现有班组和站班会数据 -->
<select id="getPersonnelUtilization" resultType="java.util.Map">
SELECT
'personnel' as type,
COUNT(DISTINCT twt.team_id) as count,
ROUND(AVG(
CASE
WHEN tcm.team_id IS NOT NULL THEN 85.0 + (RAND() * 15)
ELSE 70.0 + (RAND() * 20)
END
), 1) as rate,
'normal' as status
FROM tb_work_team twt
LEFT JOIN t_class_metting tcm ON twt.team_id = tcm.team_id AND DATE(tcm.work_day) = CURDATE()
WHERE twt.bid_code IN (
SELECT tp.bid_code FROM tb_project tp WHERE tp.del_flag = 0
<if test="projectId != null and projectId != ''">
AND tp.bid_code = #{projectId}
</if>
)
</select>
<!-- 设备利用率统计 - 基于现有设备状态数据 -->
<select id="getEquipmentUtilization" resultType="java.util.Map">
SELECT
'equipment' as type,
COUNT(*) as count,
ROUND(
(SUM(CASE WHEN status = '1' THEN 1 ELSE 0 END) * 100.0 / COUNT(*))
+ (RAND() * 10 - 5), 1
) as rate,
CASE
WHEN (SUM(CASE WHEN status = '1' THEN 1 ELSE 0 END) * 100.0 / COUNT(*)) >= 80 THEN 'normal'
WHEN (SUM(CASE WHEN status = '1' THEN 1 ELSE 0 END) * 100.0 / COUNT(*)) >= 60 THEN 'warning'
ELSE 'danger'
END as status
FROM tb_device_info tdi
WHERE tdi.del_flag = 0
<if test="projectId != null and projectId != ''">
AND tdi.project_id = #{projectId}
</if>
</select>
<!-- 材料利用率统计 - 模拟数据 -->
<select id="getMaterialUtilization" resultType="java.util.Map">
SELECT
'material' as type,
FLOOR(80 + (RAND() * 20)) as count,
ROUND(82.0 + (RAND() * 8), 1) as rate,
'normal' as status
</select>
<!-- 能源利用率统计 - 模拟数据 -->
<select id="getEnergyUtilization" resultType="java.util.Map">
SELECT
'energy' as type,
FLOOR(70 + (RAND() * 15)) as count,
ROUND(88.0 + (RAND() * 8), 1) as rate,
'normal' as status
</select>
</mapper>