feat: 指标管理

This commit is contained in:
zhanghao 2026-02-03 14:23:18 +08:00
parent 87a6cbfc6e
commit e897ad5a83
14 changed files with 598 additions and 2 deletions

View File

@ -72,6 +72,16 @@
<artifactId>cmvr-iot-ti</artifactId> <artifactId>cmvr-iot-ti</artifactId>
</dependency> </dependency>
<!-- 触控交互-->
<dependency>
<groupId>com.cmvr</groupId>
<artifactId>cmvr-iot-evaluate</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot</artifactId>
</dependency>
</dependencies> </dependencies>
<properties> <properties>
<env>dev</env> <env>dev</env>

View File

@ -0,0 +1,52 @@
package com.cmvr.web.controller.evaluate;
import com.cmvr.common.core.controller.BaseController;
import com.cmvr.common.core.domain.AjaxResult;
import com.cmvr.evaluate.dto.IndicatorCreateDTO;
import com.cmvr.evaluate.dto.IndicatorUpdateDTO;
import com.cmvr.evaluate.service.IndicatorService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.*;
import javax.validation.Valid;
@Api(tags = "评价管理--指标库")
@RestController
@RequestMapping("/evaluate/indicator")
@RequiredArgsConstructor
public class IndicatorController extends BaseController {
private final IndicatorService indicatorService;
@ApiOperation("根据父id查询指标")
@GetMapping("/getIndicatorByParentId")
public AjaxResult getIndicatorByParentId(@RequestParam Long parentId, @RequestParam Integer type) {
if (parentId == null || type == null) {
return AjaxResult.error("参数不能为空");
}
return success(indicatorService.selectIndicatorByParentId(parentId, type));
}
@ApiOperation("新增指标")
@PostMapping("/indicator/insert")
public AjaxResult insertIndicator(@Valid @RequestBody IndicatorCreateDTO createDTO) {
return success(indicatorService.saveIndicator(createDTO));
}
@ApiOperation("根据ID级联删除删除当前指标及其所有后代指标子/孙级)")
@DeleteMapping("/{id}")
public AjaxResult removeIndicator(@PathVariable Long id) {
if (id == null) {
return AjaxResult.error("id不能为空");
}
return toAjax(indicatorService.removeIndicator(id));
}
@ApiOperation("修改指标")
@PutMapping
public AjaxResult updateIndicator(@Valid @RequestBody IndicatorUpdateDTO updateDTO) {
return toAjax(indicatorService.updateIndicator(updateDTO));
}
}

View File

@ -1,6 +1,6 @@
server: server:
# 服务器的HTTP端口默认为8080 # 服务器的HTTP端口默认为8080
port: 13080 port: 13081
# 数据源配置 # 数据源配置
spring: spring:
datasource: datasource:

29
cmvr-iot-evaluate/pom.xml Normal file
View File

@ -0,0 +1,29 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.cmvr</groupId>
<artifactId>cmvr-iot</artifactId>
<version>3.8.9</version>
</parent>
<artifactId>cmvr-iot-evaluate</artifactId>
<description>
评价管理模块
</description>
<dependencies>
<!-- 通用工具-->
<dependency>
<groupId>com.cmvr</groupId>
<artifactId>cmvr-iot-common</artifactId>
</dependency>
<!-- 测试流程-->
<dependency>
<groupId>com.cmvr</groupId>
<artifactId>cmvr-iot-test</artifactId>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,57 @@
package com.cmvr.evaluate.dto;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import javax.validation.constraints.DecimalMin;
import javax.validation.constraints.Digits;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import java.math.BigDecimal;
@Data
@ApiModel("新增指标DTO")
public class IndicatorCreateDTO {
@ApiModelProperty(value = "父级指标ID一级指标为0", required = true)
@NotNull(message = "父级指标ID不能为空")
private Long parentId;
@ApiModelProperty(value = "指标层级 1-一级 2-二级 3-三级", required = true)
@NotNull(message = "指标层级不能为空")
private Integer level;
@ApiModelProperty(value = "指标名称", required = true)
@NotBlank(message = "指标名称不能为空")
private String name;
@ApiModelProperty("比较数值1")
@DecimalMin(value = "0.0", inclusive = true, message = "比较数值1不能小于0")
@Digits(integer = 10, fraction = 2, message = "比较数值1整数位最多10位小数位最多2位")
private BigDecimal compareNum1;
@ApiModelProperty("比较符号(=、>、<、>=、<=等)")
private String symbol;
@ApiModelProperty("比较数值2")
@DecimalMin(value = "0.0", inclusive = true, message = "比较数值2不能小于0")
@Digits(integer = 10, fraction = 2, message = "比较数值2整数位最多10位小数位最多2位")
private BigDecimal compareNum2;
@ApiModelProperty("指标分数/满分")
private BigDecimal score;
@ApiModelProperty("指标权重")
private BigDecimal weight;
@ApiModelProperty("备注")
private String remark;
@ApiModelProperty("同层级排序")
private Integer sort;
@ApiModelProperty(value = "类型 0-语音 1-触控", required = true)
@NotNull(message = "类型不能为空")
private Integer type;
}

View File

@ -0,0 +1,57 @@
package com.cmvr.evaluate.dto;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import javax.validation.constraints.DecimalMin;
import javax.validation.constraints.Digits;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import java.math.BigDecimal;
@Data
@ApiModel("修改指标DTO")
public class IndicatorUpdateDTO {
@ApiModelProperty(value = "指标主键ID", required = true)
@NotNull(message = "指标ID不能为空")
private Long id;
@ApiModelProperty(value = "父级指标ID一级指标为0", required = true)
private Long parentId;
@ApiModelProperty(value = "指标层级 1-一级 2-二级 3-三级", required = true)
private Integer level;
@ApiModelProperty(value = "指标名称", required = true)
@NotBlank(message = "指标名称不能为空")
private String name;
@ApiModelProperty("比较数值1")
@DecimalMin(value = "0.0", inclusive = true, message = "比较数值1不能小于0")
@Digits(integer = 10, fraction = 2, message = "比较数值1整数位最多10位小数位最多2位")
private BigDecimal compareNum1;
@ApiModelProperty("比较符号(=、>、<、>=、<=等)")
private String symbol;
@ApiModelProperty("比较数值2")
@DecimalMin(value = "0.0", inclusive = true, message = "比较数值2不能小于0")
@Digits(integer = 10, fraction = 2, message = "比较数值2整数位最多10位小数位最多2位")
private BigDecimal compareNum2;
@ApiModelProperty("指标分数/满分")
private BigDecimal score;
@ApiModelProperty("指标权重")
private BigDecimal weight;
@ApiModelProperty("备注")
private String remark;
@ApiModelProperty("同层级排序")
private Integer sort;
@ApiModelProperty(value = "类型 0-语音 1-触控", required = true)
private Integer type;
}

View File

@ -0,0 +1,55 @@
package com.cmvr.evaluate.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.cmvr.common.core.domain.BaseEntity;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
import javax.validation.constraints.NotNull;
import java.math.BigDecimal;
@Data
@EqualsAndHashCode(callSuper = true)
@TableName("evaluate_indicator")
@ApiModel("评价管理--指标库")
public class IndicatorEntity extends BaseEntity {
private static final long serialVersionUID = 1L;
@ApiModelProperty("指标主键ID")
@TableId(type = IdType.AUTO)
private Long id;
@ApiModelProperty("父级指标ID一级指标为0")
private Long parentId;
@ApiModelProperty("指标层级 1-一级 2-二级 3-三级")
private Integer level;
@ApiModelProperty("指标名称")
private String name;
@ApiModelProperty("比较数值1")
private BigDecimal compareNum1;
@ApiModelProperty("比较符号(=、>、<、>=、<=等)")
private String symbol;
@ApiModelProperty("比较数值2")
private BigDecimal compareNum2;
@ApiModelProperty("指标分数")
private BigDecimal score;
@ApiModelProperty("指标权重")
private BigDecimal weight;
@ApiModelProperty("同层级排序")
private Integer sort;
@ApiModelProperty("类型 0-语音 1-触控")
private Integer type;
}

View File

@ -0,0 +1,13 @@
package com.cmvr.evaluate.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.cmvr.evaluate.entity.IndicatorEntity;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import java.util.List;
@Mapper
public interface IndicatorMapper extends BaseMapper<IndicatorEntity> {
}

View File

@ -0,0 +1,19 @@
package com.cmvr.evaluate.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.cmvr.evaluate.dto.IndicatorCreateDTO;
import com.cmvr.evaluate.dto.IndicatorUpdateDTO;
import com.cmvr.evaluate.entity.IndicatorEntity;
import java.util.List;
public interface IndicatorService extends IService<IndicatorEntity> {
boolean saveIndicator(IndicatorCreateDTO dto);
List<IndicatorEntity> selectIndicatorByParentId(Long parentId, Integer type);
boolean removeIndicator(Long id);
boolean updateIndicator(IndicatorUpdateDTO dto);
}

View File

@ -0,0 +1,196 @@
package com.cmvr.evaluate.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.cmvr.evaluate.dto.IndicatorCreateDTO;
import com.cmvr.evaluate.dto.IndicatorUpdateDTO;
import com.cmvr.evaluate.entity.IndicatorEntity;
import com.cmvr.evaluate.mapper.IndicatorMapper;
import com.cmvr.evaluate.service.IndicatorService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;
import java.util.ArrayList;
import java.util.List;
@Slf4j
@Service
public class IndicatorServiceImpl extends ServiceImpl<IndicatorMapper, IndicatorEntity> implements IndicatorService {
@Override
public boolean saveIndicator(IndicatorCreateDTO createDTO) {
// 1. DTO Entity
IndicatorEntity entity = CreateDTOConvertToEntity(createDTO);
// 3. 调用MyBatis-Plus父类方法完成新增返回执行结果
boolean saveResult = this.save(entity);
// 4. 日志记录新增结果成功/失败
if (saveResult) {
log.info("评价管理---指标库---新增指标成功,指标名称:{},层级:{}", entity.getName(), entity.getLevel());
} else {
log.error("评价管理---指标库---新增指标失败,指标名称:{},层级:{}", entity.getName(), entity.getLevel());
}
return saveResult;
}
@Override
public List<IndicatorEntity> selectIndicatorByParentId(Long parentId, Integer type) {
log.info("评价管理---指标库---开始按父id查询指标查询父id{}", parentId == null ? "所有数据" : parentId);
LambdaQueryWrapper<IndicatorEntity> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(parentId != null, IndicatorEntity::getParentId, parentId)
.eq(type != null, IndicatorEntity::getType, type)
.orderByAsc(IndicatorEntity::getSort);
List<IndicatorEntity> list = this.list(queryWrapper);
// 3. 日志记录查询结果
log.info("评价管理---指标库---按父id查询指标完成查询id{},返回数量:{}",
parentId == null ? "所有数据" : parentId, list.size());
return list;
}
@Override
@Transactional(rollbackFor = Exception.class) // 事务控制所有异常都回滚保证原子性
public boolean removeIndicator(Long id) {
// 1. 参数校验ID不能为空
Assert.notNull(id, "级联删除指标失败待删除指标ID不能为空");
log.info("开始级联删除指标主指标ID{}", id);
// 2. 递归查询所有后代指标ID/孙级无论多少级
List<Long> allDeleteIds = new ArrayList<>();
findAllChildrenIds(id, allDeleteIds); // 收集所有后代ID
// 3. 合并删除ID添加当前指标ID删自身+后代
allDeleteIds.add(id);
log.info("级联删除准备完成主指标ID{},需删除后代数量:{},总删除数量:{}",
id, allDeleteIds.size() - 1, allDeleteIds.size());
// 4. 批量删除一次执行效率高适配逻辑删除/物理删除MP自动处理
if (CollectionUtils.isEmpty(allDeleteIds)) {
log.warn("级联删除指标无数据可删主指标ID{}", id);
return false;
}
boolean deleteResult = this.removeByIds(allDeleteIds);
// 5. 日志记录删除结果
if (deleteResult) {
log.info("级联删除指标成功主指标ID{},成功删除数量:{}", id, allDeleteIds.size());
} else {
log.error("级联删除指标失败主指标ID{}待删除ID集合{}", id, allDeleteIds);
}
return deleteResult;
}
@Override
public boolean updateIndicator(IndicatorUpdateDTO dto) {
// 1. 验证数据是否存在
IndicatorEntity existEntity = this.getById(dto.getId());
if (existEntity == null) {
log.error("评价管理---指标库---修改指标失败指标ID {} 不存在", dto.getId());
return false;
}
IndicatorEntity entity = updateDTOConvertToEntity(dto);
System.out.println("entity = " + entity);
boolean saveResult = this.updateById(entity);
// 4. 日志记录新增结果成功/失败
if (saveResult) {
log.info("评价管理---指标库---修改指标成功,指标名称:{}", entity.getName());
} else {
log.error("评价管理---指标库---修改指标失败,指标名称:{}", entity.getName());
}
return saveResult;
}
/**
* 私有工具方法递归查询指定ID的所有后代指标ID重孙无限级
* @param parentId /祖指标ID
* @param childrenIds 用于收集所有后代ID的集合引用传递
*/
private void findAllChildrenIds(Long parentId, List<Long> childrenIds) {
// 查询当前parentId的直接子指标ID
LambdaQueryWrapper<IndicatorEntity> queryWrapper = new LambdaQueryWrapper<IndicatorEntity>()
.select(IndicatorEntity::getId) // 仅查ID字段减少数据传输
.eq(IndicatorEntity::getParentId, parentId);
// 核心修正使用MP双参数listObjs直接Object转Long无多余参数
List<Long> directChildIds = this.listObjs(
queryWrapper,
// 转换器将查询到的Object类型ID直接强转为Long数据库ID为数值型安全转换
obj -> Long.parseLong(obj.toString())
);
// 无直接子节点递归终止
if (CollectionUtils.isEmpty(directChildIds)) {
return;
}
// 将直接子ID加入集合再递归查询每个子ID的后代ID
childrenIds.addAll(directChildIds);
for (Long childId : directChildIds) {
findAllChildrenIds(childId, childrenIds); // 递归查子节点的子节点
}
}
private IndicatorEntity CreateDTOConvertToEntity(IndicatorCreateDTO dto) {
if (dto == null) {
return null;
}
IndicatorEntity entity = new IndicatorEntity();
entity.setParentId(dto.getParentId());
entity.setLevel(dto.getLevel());
entity.setName(dto.getName());
entity.setCompareNum1(dto.getCompareNum1());
entity.setSymbol(dto.getSymbol());
entity.setCompareNum2(dto.getCompareNum2());
entity.setScore(dto.getScore());
entity.setWeight(dto.getWeight());
entity.setRemark(dto.getRemark());
entity.setSort(dto.getSort());
entity.setType(dto.getType());
return entity;
}
private IndicatorEntity updateDTOConvertToEntity(IndicatorUpdateDTO dto) {
if (dto == null) {
return null;
}
IndicatorEntity entity = new IndicatorEntity();
entity.setId(dto.getId()); // 重要必须设置ID
entity.setParentId(dto.getParentId());
entity.setName(dto.getName());
// 只更新必要的字段不要清空其他字段
if (dto.getLevel() != null) {
entity.setLevel(dto.getLevel());
}
if (dto.getCompareNum1() != null) {
entity.setCompareNum1(dto.getCompareNum1());
}
if (dto.getSymbol() != null) {
entity.setSymbol(dto.getSymbol());
}
if (dto.getCompareNum2() != null) {
entity.setCompareNum2(dto.getCompareNum2());
}
if (dto.getScore() != null) {
entity.setScore(dto.getScore());
}
if (dto.getWeight() != null) {
entity.setWeight(dto.getWeight());
}
if (dto.getRemark() != null) {
entity.setRemark(dto.getRemark());
}
if (dto.getSort() != null) {
entity.setSort(dto.getSort());
}
if (dto.getType() != null) {
entity.setType(dto.getType());
}
return entity;
}
}

View File

@ -0,0 +1,55 @@
package com.cmvr.evaluate.vo;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.math.BigDecimal;
import java.util.Date;
@Data
@ApiModel("指标库VO")
public class IndicatorVO {
@ApiModelProperty("指标库-指标主键ID")
private Long id;
@ApiModelProperty("父级指标ID一级指标为0")
private Long parentId;
@ApiModelProperty("指标层级 1-一级 2-二级 3-三级")
private Integer level;
@ApiModelProperty("指标名称")
private String name;
@ApiModelProperty("比较数值1")
private BigDecimal compareNum1;
@ApiModelProperty("比较符号(=、>、<、>=、<=等)")
private String symbol;
@ApiModelProperty("比较数值2")
private BigDecimal compareNum2;
@ApiModelProperty("指标分数/满分")
private BigDecimal score;
@ApiModelProperty("指标权重")
private BigDecimal weight;
@ApiModelProperty("备注")
private String remark;
@ApiModelProperty("同层级排序")
private Integer sort;
@ApiModelProperty("创建时间")
private Date createTime;
@ApiModelProperty("创建人")
private String createBy;
@ApiModelProperty("类型 0-语音 1-触控")
private Integer type;
}

View File

@ -0,0 +1,38 @@
package com.cmvr;
import junit.framework.Test;
import junit.framework.TestCase;
import junit.framework.TestSuite;
/**
* Unit test for simple App.
*/
public class AppTest
extends TestCase
{
/**
* Create the test case
*
* @param testName name of the test case
*/
public AppTest( String testName )
{
super( testName );
}
/**
* @return the suite of tests being tested
*/
public static Test suite()
{
return new TestSuite( AppTest.class );
}
/**
* Rigourous Test :-)
*/
public void testApp()
{
assertTrue( true );
}
}

View File

@ -28,6 +28,15 @@
<groupId>com.cmvr</groupId> <groupId>com.cmvr</groupId>
<artifactId>cmvr-iot-test</artifactId> <artifactId>cmvr-iot-test</artifactId>
</dependency> </dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.cmvr</groupId>
<artifactId>cmvr-iot-common</artifactId>
</dependency>
<!-- AI评估--> <!-- AI评估-->
<dependency> <dependency>

View File

@ -274,6 +274,13 @@
<version>${cmvr-iot.version}</version> <version>${cmvr-iot.version}</version>
</dependency> </dependency>
<!-- 评价管理-->
<dependency>
<groupId>com.cmvr</groupId>
<artifactId>cmvr-iot-evaluate</artifactId>
<version>${cmvr-iot.version}</version>
</dependency>
<!-- AIp评估--> <!-- AIp评估-->
<dependency> <dependency>
<groupId>com.cmvr</groupId> <groupId>com.cmvr</groupId>
@ -337,7 +344,6 @@
<module>cmvr-iot-api</module> <module>cmvr-iot-api</module>
<module>cmvr-iot-vi</module> <module>cmvr-iot-vi</module>
<module>cmvr-iot-ti</module> <module>cmvr-iot-ti</module>
<module>cmvr-iot-evaluation</module>
</modules> </modules>
<packaging>pom</packaging> <packaging>pom</packaging>