diff --git a/src/main/java/com/ycwl/basic/handler/NestedMapTypeHandler.java b/src/main/java/com/ycwl/basic/handler/NestedMapTypeHandler.java new file mode 100644 index 00000000..c145b042 --- /dev/null +++ b/src/main/java/com/ycwl/basic/handler/NestedMapTypeHandler.java @@ -0,0 +1,77 @@ +package com.ycwl.basic.handler; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.ObjectMapper; +import lombok.extern.slf4j.Slf4j; +import org.apache.ibatis.type.BaseTypeHandler; +import org.apache.ibatis.type.JdbcType; + +import java.sql.CallableStatement; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.HashMap; +import java.util.Map; + +/** + * 嵌套Map类型的TypeHandler,用于处理JSON字段与Map>的互转 + * 主要用于机位评价功能:外层key为机位ID,内层Map为该机位的各维度评分 + * + * 数据格式示例: + * { + * "12345": {"清晰度": 5, "构图": 4, "色彩": 5, "整体效果": 4}, + * "12346": {"清晰度": 4, "构图": 5, "色彩": 4, "整体效果": 5} + * } + */ +@Slf4j +public class NestedMapTypeHandler extends BaseTypeHandler>> { + + private final ObjectMapper objectMapper = new ObjectMapper(); + private final TypeReference>> typeReference = + new TypeReference>>() {}; + + @Override + public void setNonNullParameter(PreparedStatement ps, int i, Map> parameter, JdbcType jdbcType) throws SQLException { + try { + String json = objectMapper.writeValueAsString(parameter); + ps.setString(i, json); + } catch (JsonProcessingException e) { + log.error("序列化嵌套Map为JSON失败", e); + throw new SQLException("序列化嵌套Map为JSON失败", e); + } + } + + @Override + public Map> getNullableResult(ResultSet rs, String columnName) throws SQLException { + String json = rs.getString(columnName); + return parseJson(json); + } + + @Override + public Map> getNullableResult(ResultSet rs, int columnIndex) throws SQLException { + String json = rs.getString(columnIndex); + return parseJson(json); + } + + @Override + public Map> getNullableResult(CallableStatement cs, int columnIndex) throws SQLException { + String json = cs.getString(columnIndex); + return parseJson(json); + } + + /** + * 解析JSON字符串为嵌套Map + */ + private Map> parseJson(String json) { + if (json == null || json.trim().isEmpty()) { + return new HashMap<>(); + } + try { + return objectMapper.readValue(json, typeReference); + } catch (JsonProcessingException e) { + log.error("解析JSON为嵌套Map失败, json={}", json, e); + return new HashMap<>(); + } + } +} diff --git a/src/main/java/com/ycwl/basic/mapper/VideoReviewMapper.java b/src/main/java/com/ycwl/basic/mapper/VideoReviewMapper.java index 16c148f6..4f8c559f 100644 --- a/src/main/java/com/ycwl/basic/mapper/VideoReviewMapper.java +++ b/src/main/java/com/ycwl/basic/mapper/VideoReviewMapper.java @@ -65,7 +65,7 @@ public interface VideoReviewMapper extends BaseMapper { /** * 查询所有机位评价数据(用于后端计算平均值) * - * @return 机位评价列表 + * @return 机位评价列表(嵌套Map结构) */ - List> selectAllCameraPositionRatings(); + List>> selectAllCameraPositionRatings(); } diff --git a/src/main/java/com/ycwl/basic/model/pc/video/resp/VideoRespVO.java b/src/main/java/com/ycwl/basic/model/pc/video/resp/VideoRespVO.java index 860b81ac..c9d39601 100644 --- a/src/main/java/com/ycwl/basic/model/pc/video/resp/VideoRespVO.java +++ b/src/main/java/com/ycwl/basic/model/pc/video/resp/VideoRespVO.java @@ -63,6 +63,10 @@ public class VideoRespVO { private Date createTime; @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") private Date updateTime; + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") + private Date startTime; + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") + private Date endTime; private Integer height; private Integer width; private BigDecimal duration; diff --git a/src/main/java/com/ycwl/basic/model/pc/videoreview/dto/VideoReviewAddReqDTO.java b/src/main/java/com/ycwl/basic/model/pc/videoreview/dto/VideoReviewAddReqDTO.java index ace12246..13b1cee1 100644 --- a/src/main/java/com/ycwl/basic/model/pc/videoreview/dto/VideoReviewAddReqDTO.java +++ b/src/main/java/com/ycwl/basic/model/pc/videoreview/dto/VideoReviewAddReqDTO.java @@ -26,8 +26,10 @@ public class VideoReviewAddReqDTO { private String content; /** - * 机位快速评价JSON(可选) - * 格式: {"角度":5,"清晰度":4,"构图":5} + * 机位评价JSON(可选) + * 格式: {"12345": {"清晰度":5,"构图":4,"色彩":5,"整体效果":4}, "12346": {...}} + * 外层key为机位ID,内层Map为该机位的各维度评分 + * 评分维度: 清晰度, 构图, 色彩, 整体效果 */ - private Map cameraPositionRating; + private Map> cameraPositionRating; } diff --git a/src/main/java/com/ycwl/basic/model/pc/videoreview/dto/VideoReviewRespDTO.java b/src/main/java/com/ycwl/basic/model/pc/videoreview/dto/VideoReviewRespDTO.java index b336ca3c..dbea914e 100644 --- a/src/main/java/com/ycwl/basic/model/pc/videoreview/dto/VideoReviewRespDTO.java +++ b/src/main/java/com/ycwl/basic/model/pc/videoreview/dto/VideoReviewRespDTO.java @@ -58,9 +58,11 @@ public class VideoReviewRespDTO { private String content; /** - * 机位快速评价JSON + * 机位评价JSON + * 格式: {"12345": {"清晰度":5,"构图":4,"色彩":5,"整体效果":4}, "12346": {...}} + * 外层key为机位ID,内层Map为该机位的各维度评分 */ - private Map cameraPositionRating; + private Map> cameraPositionRating; /** * 创建时间 diff --git a/src/main/java/com/ycwl/basic/model/pc/videoreview/entity/VideoReviewEntity.java b/src/main/java/com/ycwl/basic/model/pc/videoreview/entity/VideoReviewEntity.java index 36480ada..888a64fc 100644 --- a/src/main/java/com/ycwl/basic/model/pc/videoreview/entity/VideoReviewEntity.java +++ b/src/main/java/com/ycwl/basic/model/pc/videoreview/entity/VideoReviewEntity.java @@ -4,7 +4,7 @@ import com.baomidou.mybatisplus.annotation.IdType; import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; -import com.ycwl.basic.handler.MapTypeHandler; +import com.ycwl.basic.handler.NestedMapTypeHandler; import lombok.Data; import org.apache.ibatis.type.JdbcType; @@ -50,11 +50,12 @@ public class VideoReviewEntity { private String content; /** - * 机位快速评价JSON - * 格式: {"角度":5,"清晰度":4,"构图":5} + * 机位评价JSON + * 格式: {"12345": {"清晰度":5,"构图":4,"色彩":5,"整体效果":4}, "12346": {...}} + * 外层key为机位ID,内层Map为该机位的各维度评分 */ - @TableField(typeHandler = MapTypeHandler.class, jdbcType = JdbcType.VARCHAR) - private Map cameraPositionRating; + @TableField(typeHandler = NestedMapTypeHandler.class, jdbcType = JdbcType.VARCHAR) + private Map> cameraPositionRating; /** * 创建时间 diff --git a/src/main/java/com/ycwl/basic/service/impl/VideoReviewServiceImpl.java b/src/main/java/com/ycwl/basic/service/impl/VideoReviewServiceImpl.java index 2dfe27fe..dcd79c43 100644 --- a/src/main/java/com/ycwl/basic/service/impl/VideoReviewServiceImpl.java +++ b/src/main/java/com/ycwl/basic/service/impl/VideoReviewServiceImpl.java @@ -218,7 +218,7 @@ public class VideoReviewServiceImpl implements VideoReviewService { * 计算机位评价各维度的平均值 */ private Map calculateCameraPositionAverage() { - List> allRatings = videoReviewMapper.selectAllCameraPositionRatings(); + List>> allRatings = videoReviewMapper.selectAllCameraPositionRatings(); if (allRatings == null || allRatings.isEmpty()) { return new HashMap<>(); @@ -226,10 +226,15 @@ public class VideoReviewServiceImpl implements VideoReviewService { // 统计各维度的总分和次数 Map> dimensionScores = new HashMap<>(); - for (Map rating : allRatings) { + for (Map> rating : allRatings) { if (rating == null) continue; - for (Map.Entry entry : rating.entrySet()) { - dimensionScores.computeIfAbsent(entry.getKey(), k -> new ArrayList<>()).add(entry.getValue()); + // 遍历每个机位 + for (Map deviceRatings : rating.values()) { + if (deviceRatings == null) continue; + // 遍历该机位的每个维度 + for (Map.Entry entry : deviceRatings.entrySet()) { + dimensionScores.computeIfAbsent(entry.getKey(), k -> new ArrayList<>()).add(entry.getValue()); + } } } diff --git a/src/main/resources/mapper/VideoMapper.xml b/src/main/resources/mapper/VideoMapper.xml index 68a34066..b2373b25 100644 --- a/src/main/resources/mapper/VideoMapper.xml +++ b/src/main/resources/mapper/VideoMapper.xml @@ -76,17 +76,17 @@ )