You've already forked FrameTour-BE
refactor(videoreview): 简化机位评价数据结构
- 修改机位评价数据结构从嵌套Map改为简单Map - 更新数据库映射文件中的类型处理器配置 - 调整评价统计逻辑以适应新的数据结构 - 优化导出功能以支持新格式的机位评价展示 - 更新相关实体类、DTO类及Mapper接口定义 - 移除不再使用的嵌套Map相关代码和依赖
This commit is contained in:
@@ -65,7 +65,7 @@ public interface VideoReviewMapper extends BaseMapper<VideoReviewEntity> {
|
|||||||
/**
|
/**
|
||||||
* 查询所有机位评价数据(用于后端计算平均值)
|
* 查询所有机位评价数据(用于后端计算平均值)
|
||||||
*
|
*
|
||||||
* @return 机位评价列表(嵌套Map结构)
|
* @return 机位评价列表(Map结构: 机位ID -> 评分)
|
||||||
*/
|
*/
|
||||||
List<Map<String, Map<String, Integer>>> selectAllCameraPositionRatings();
|
List<Map<String, Integer>> selectAllCameraPositionRatings();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,9 +27,8 @@ public class VideoReviewAddReqDTO {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* 机位评价JSON(可选)
|
* 机位评价JSON(可选)
|
||||||
* 格式: {"12345": {"清晰度":5,"构图":4,"色彩":5,"整体效果":4}, "12346": {...}}
|
* 格式: {"12345": 5, "12346": 4}
|
||||||
* 外层key为机位ID,内层Map为该机位的各维度评分
|
* key为机位ID,value为该机位的评分(1-5)
|
||||||
* 评分维度: 清晰度, 构图, 色彩, 整体效果
|
|
||||||
*/
|
*/
|
||||||
private Map<String, Map<String, Integer>> cameraPositionRating;
|
private Map<String, Integer> cameraPositionRating;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -69,10 +69,10 @@ public class VideoReviewRespDTO {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* 机位评价JSON
|
* 机位评价JSON
|
||||||
* 格式: {"12345": {"清晰度":5,"构图":4,"色彩":5,"整体效果":4}, "12346": {...}}
|
* 格式: {"12345": 5, "12346": 4}
|
||||||
* 外层key为机位ID,内层Map为该机位的各维度评分
|
* key为机位ID,value为该机位的评分(1-5)
|
||||||
*/
|
*/
|
||||||
private Map<String, Map<String, Integer>> cameraPositionRating;
|
private Map<String, Integer> cameraPositionRating;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 创建时间
|
* 创建时间
|
||||||
|
|||||||
@@ -40,8 +40,8 @@ public class VideoReviewStatisticsRespDTO {
|
|||||||
private List<ScenicReviewRank> scenicRankList;
|
private List<ScenicReviewRank> scenicRankList;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 机位评价维度统计
|
* 机位评价统计
|
||||||
* key: 维度名称, value: 平均分
|
* key: 机位ID, value: 该机位的平均评分
|
||||||
*/
|
*/
|
||||||
private Map<String, BigDecimal> cameraPositionAverage;
|
private Map<String, BigDecimal> cameraPositionAverage;
|
||||||
|
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import com.baomidou.mybatisplus.annotation.IdType;
|
|||||||
import com.baomidou.mybatisplus.annotation.TableField;
|
import com.baomidou.mybatisplus.annotation.TableField;
|
||||||
import com.baomidou.mybatisplus.annotation.TableId;
|
import com.baomidou.mybatisplus.annotation.TableId;
|
||||||
import com.baomidou.mybatisplus.annotation.TableName;
|
import com.baomidou.mybatisplus.annotation.TableName;
|
||||||
import com.ycwl.basic.handler.NestedMapTypeHandler;
|
import com.ycwl.basic.handler.MapTypeHandler;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import org.apache.ibatis.type.JdbcType;
|
import org.apache.ibatis.type.JdbcType;
|
||||||
|
|
||||||
@@ -51,11 +51,11 @@ public class VideoReviewEntity {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* 机位评价JSON
|
* 机位评价JSON
|
||||||
* 格式: {"12345": {"清晰度":5,"构图":4,"色彩":5,"整体效果":4}, "12346": {...}}
|
* 格式: {"12345": 5, "12346": 4}
|
||||||
* 外层key为机位ID,内层Map为该机位的各维度评分
|
* key为机位ID,value为该机位的评分(1-5)
|
||||||
*/
|
*/
|
||||||
@TableField(typeHandler = NestedMapTypeHandler.class, jdbcType = JdbcType.VARCHAR)
|
@TableField(typeHandler = MapTypeHandler.class, jdbcType = JdbcType.VARCHAR)
|
||||||
private Map<String, Map<String, Integer>> cameraPositionRating;
|
private Map<String, Integer> cameraPositionRating;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 创建时间
|
* 创建时间
|
||||||
|
|||||||
@@ -31,7 +31,6 @@ import java.math.BigDecimal;
|
|||||||
import java.math.RoundingMode;
|
import java.math.RoundingMode;
|
||||||
import java.text.SimpleDateFormat;
|
import java.text.SimpleDateFormat;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.stream.Collectors;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 视频评价Service实现类
|
* 视频评价Service实现类
|
||||||
@@ -160,7 +159,7 @@ public class VideoReviewServiceImpl implements VideoReviewService {
|
|||||||
// 2. 收集所有机位ID并批量查询机位名称
|
// 2. 收集所有机位ID并批量查询机位名称
|
||||||
Set<Long> allDeviceIds = new LinkedHashSet<>();
|
Set<Long> allDeviceIds = new LinkedHashSet<>();
|
||||||
for (VideoReviewRespDTO review : list) {
|
for (VideoReviewRespDTO review : list) {
|
||||||
Map<String, Map<String, Integer>> cameraRating = review.getCameraPositionRating();
|
Map<String, Integer> cameraRating = review.getCameraPositionRating();
|
||||||
if (cameraRating != null && !cameraRating.isEmpty()) {
|
if (cameraRating != null && !cameraRating.isEmpty()) {
|
||||||
// 收集机位ID (按顺序)
|
// 收集机位ID (按顺序)
|
||||||
for (String deviceIdStr : cameraRating.keySet()) {
|
for (String deviceIdStr : cameraRating.keySet()) {
|
||||||
@@ -195,12 +194,7 @@ public class VideoReviewServiceImpl implements VideoReviewService {
|
|||||||
headerStyle.setFillForegroundColor(IndexedColors.GREY_25_PERCENT.getIndex());
|
headerStyle.setFillForegroundColor(IndexedColors.GREY_25_PERCENT.getIndex());
|
||||||
headerStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND);
|
headerStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND);
|
||||||
|
|
||||||
// 5. 创建单元格自动换行样式
|
// 5. 生成动态表头 - 使用机位名称作为表头
|
||||||
CellStyle wrapStyle = workbook.createCellStyle();
|
|
||||||
wrapStyle.setWrapText(true);
|
|
||||||
wrapStyle.setVerticalAlignment(VerticalAlignment.TOP);
|
|
||||||
|
|
||||||
// 6. 生成动态表头 - 使用机位名称作为表头
|
|
||||||
Row headerRow = sheet.createRow(0);
|
Row headerRow = sheet.createRow(0);
|
||||||
List<String> headerList = new ArrayList<>();
|
List<String> headerList = new ArrayList<>();
|
||||||
headerList.add("评价ID");
|
headerList.add("评价ID");
|
||||||
@@ -228,7 +222,7 @@ public class VideoReviewServiceImpl implements VideoReviewService {
|
|||||||
cell.setCellStyle(headerStyle);
|
cell.setCellStyle(headerStyle);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 7. 填充数据
|
// 6. 填充数据
|
||||||
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
|
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
|
||||||
int rowNum = 1;
|
int rowNum = 1;
|
||||||
|
|
||||||
@@ -246,37 +240,21 @@ public class VideoReviewServiceImpl implements VideoReviewService {
|
|||||||
row.createCell(colIndex++).setCellValue(review.getContent());
|
row.createCell(colIndex++).setCellValue(review.getContent());
|
||||||
|
|
||||||
// 机位评价列 - 按表头顺序填充
|
// 机位评价列 - 按表头顺序填充
|
||||||
Map<String, Map<String, Integer>> cameraRating = review.getCameraPositionRating();
|
Map<String, Integer> cameraRating = review.getCameraPositionRating();
|
||||||
for (Long deviceId : sortedDeviceIds) {
|
for (Long deviceId : sortedDeviceIds) {
|
||||||
String deviceIdStr = String.valueOf(deviceId);
|
String deviceIdStr = String.valueOf(deviceId);
|
||||||
Map<String, Integer> dimensions = null;
|
Integer rating = null;
|
||||||
|
|
||||||
if (cameraRating != null && cameraRating.containsKey(deviceIdStr)) {
|
if (cameraRating != null && cameraRating.containsKey(deviceIdStr)) {
|
||||||
dimensions = cameraRating.get(deviceIdStr);
|
rating = cameraRating.get(deviceIdStr);
|
||||||
}
|
|
||||||
|
|
||||||
// 构建单元格内容: 只显示评分维度(不再重复机位名称)
|
|
||||||
StringBuilder cellContent = new StringBuilder();
|
|
||||||
|
|
||||||
if (dimensions != null && !dimensions.isEmpty()) {
|
|
||||||
// 按维度名排序,保证一致性
|
|
||||||
List<Map.Entry<String, Integer>> sortedDimensions = dimensions.entrySet().stream()
|
|
||||||
.sorted(Map.Entry.comparingByKey())
|
|
||||||
.collect(Collectors.toList());
|
|
||||||
|
|
||||||
boolean first = true;
|
|
||||||
for (Map.Entry<String, Integer> dimEntry : sortedDimensions) {
|
|
||||||
if (!first) {
|
|
||||||
cellContent.append("\n");
|
|
||||||
}
|
|
||||||
cellContent.append(dimEntry.getKey()).append(":").append(dimEntry.getValue());
|
|
||||||
first = false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Cell cell = row.createCell(colIndex++);
|
Cell cell = row.createCell(colIndex++);
|
||||||
cell.setCellValue(cellContent.toString());
|
if (rating != null) {
|
||||||
cell.setCellStyle(wrapStyle);
|
cell.setCellValue(rating);
|
||||||
|
} else {
|
||||||
|
cell.setCellValue("");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 时间列
|
// 时间列
|
||||||
@@ -284,17 +262,12 @@ public class VideoReviewServiceImpl implements VideoReviewService {
|
|||||||
row.createCell(colIndex).setCellValue(review.getUpdateTime() != null ? sdf.format(review.getUpdateTime()) : "");
|
row.createCell(colIndex).setCellValue(review.getUpdateTime() != null ? sdf.format(review.getUpdateTime()) : "");
|
||||||
}
|
}
|
||||||
|
|
||||||
// 8. 自动调整列宽
|
// 7. 自动调整列宽
|
||||||
for (int i = 0; i < headerList.size(); i++) {
|
for (int i = 0; i < headerList.size(); i++) {
|
||||||
sheet.autoSizeColumn(i);
|
sheet.autoSizeColumn(i);
|
||||||
// 对于机位列,设置最小宽度以便换行内容显示完整
|
|
||||||
if (i >= 7 && i < 7 + sortedDeviceIds.size()) {
|
|
||||||
int currentWidth = sheet.getColumnWidth(i);
|
|
||||||
sheet.setColumnWidth(i, Math.max(currentWidth, 5000)); // 最小25个字符宽度
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 9. 写入输出流
|
// 8. 写入输出流
|
||||||
workbook.write(outputStream);
|
workbook.write(outputStream);
|
||||||
workbook.close();
|
workbook.close();
|
||||||
|
|
||||||
@@ -302,32 +275,28 @@ public class VideoReviewServiceImpl implements VideoReviewService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 计算机位评价各维度的平均值
|
* 计算各机位的平均评分
|
||||||
*/
|
*/
|
||||||
private Map<String, BigDecimal> calculateCameraPositionAverage() {
|
private Map<String, BigDecimal> calculateCameraPositionAverage() {
|
||||||
List<Map<String, Map<String, Integer>>> allRatings = videoReviewMapper.selectAllCameraPositionRatings();
|
List<Map<String, Integer>> allRatings = videoReviewMapper.selectAllCameraPositionRatings();
|
||||||
|
|
||||||
if (allRatings == null || allRatings.isEmpty()) {
|
if (allRatings == null || allRatings.isEmpty()) {
|
||||||
return new HashMap<>();
|
return new HashMap<>();
|
||||||
}
|
}
|
||||||
|
|
||||||
// 统计各维度的总分和次数
|
// 统计各机位的总分和次数
|
||||||
Map<String, List<Integer>> dimensionScores = new HashMap<>();
|
Map<String, List<Integer>> deviceScores = new HashMap<>();
|
||||||
for (Map<String, Map<String, Integer>> rating : allRatings) {
|
for (Map<String, Integer> rating : allRatings) {
|
||||||
if (rating == null) continue;
|
if (rating == null) continue;
|
||||||
// 遍历每个机位
|
// 遍历每个机位的评分
|
||||||
for (Map<String, Integer> deviceRatings : rating.values()) {
|
for (Map.Entry<String, Integer> entry : rating.entrySet()) {
|
||||||
if (deviceRatings == null) continue;
|
deviceScores.computeIfAbsent(entry.getKey(), k -> new ArrayList<>()).add(entry.getValue());
|
||||||
// 遍历该机位的每个维度
|
|
||||||
for (Map.Entry<String, Integer> entry : deviceRatings.entrySet()) {
|
|
||||||
dimensionScores.computeIfAbsent(entry.getKey(), k -> new ArrayList<>()).add(entry.getValue());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 计算平均值
|
// 计算平均值
|
||||||
Map<String, BigDecimal> result = new HashMap<>();
|
Map<String, BigDecimal> result = new HashMap<>();
|
||||||
for (Map.Entry<String, List<Integer>> entry : dimensionScores.entrySet()) {
|
for (Map.Entry<String, List<Integer>> entry : deviceScores.entrySet()) {
|
||||||
double avg = entry.getValue().stream().mapToInt(Integer::intValue).average().orElse(0.0);
|
double avg = entry.getValue().stream().mapToInt(Integer::intValue).average().orElse(0.0);
|
||||||
result.put(entry.getKey(), BigDecimal.valueOf(avg).setScale(2, RoundingMode.HALF_UP));
|
result.put(entry.getKey(), BigDecimal.valueOf(avg).setScale(2, RoundingMode.HALF_UP));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,7 +16,7 @@
|
|||||||
<result property="rating" column="rating"/>
|
<result property="rating" column="rating"/>
|
||||||
<result property="content" column="content"/>
|
<result property="content" column="content"/>
|
||||||
<result property="cameraPositionRating" column="camera_position_rating"
|
<result property="cameraPositionRating" column="camera_position_rating"
|
||||||
typeHandler="com.ycwl.basic.handler.NestedMapTypeHandler"/>
|
typeHandler="com.ycwl.basic.handler.MapTypeHandler"/>
|
||||||
<result property="createTime" column="create_time"/>
|
<result property="createTime" column="create_time"/>
|
||||||
<result property="updateTime" column="update_time"/>
|
<result property="updateTime" column="update_time"/>
|
||||||
</resultMap>
|
</resultMap>
|
||||||
|
|||||||
Reference in New Issue
Block a user