feat: 新增AI监控仪表盘功能和监管对象位置字段
- 新增AI监控仪表盘相关接口(监狱概况统计、重点人员查询) - 新增监管对象位置字段(province/city/district)到各DO实体 - 新增重点人员页面相关VO(FocusPersonPageReqVO、FocusPersonVO) - 新增AI监控入口菜单SQL脚本 - 新增监管对象位置升级SQL脚本 - 完善监控仪表盘服务实现(实时数据、统计分析、风险预警) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
parent
0984924431
commit
76bdb3a931
5
pom.xml
5
pom.xml
@ -46,6 +46,11 @@
|
||||
<spring.boot.version>3.5.9</spring.boot.version>
|
||||
<mapstruct.version>1.6.3</mapstruct.version>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
|
||||
<!-- 编译速度优化配置 -->
|
||||
<maven.compiler.fork>false</maven.compiler.fork>
|
||||
<maven.compiler.incremental>true</maven.compiler.incremental>
|
||||
<maven.test.skip>true</maven.test.skip>
|
||||
</properties>
|
||||
|
||||
<dependencyManagement>
|
||||
|
||||
@ -27,10 +27,17 @@ CREATE TABLE IF NOT EXISTS `prison_prisoner` (
|
||||
`original_sentence` varchar(100) DEFAULT NULL COMMENT '原判刑期',
|
||||
`imprisonment_date` date DEFAULT NULL COMMENT '入狱日期',
|
||||
`release_date` date DEFAULT NULL COMMENT '释放日期',
|
||||
`release_type` tinyint DEFAULT 0 COMMENT '释放类型:0-未知 1-刑满释放 2-假释 3-保外就医 4-减刑 5-暂予监外执行 6-特赦 7-死亡 8-其他',
|
||||
`release_reason` varchar(500) DEFAULT NULL COMMENT '释放原因',
|
||||
`photo` varchar(512) DEFAULT NULL COMMENT '照片URL',
|
||||
`supervision_level` tinyint DEFAULT 2 COMMENT '监管等级:1-严管 2-普管 3-宽管',
|
||||
`risk_level` tinyint DEFAULT 1 COMMENT '风险等级:1-低风险 2-中风险 3-高风险 4-极高风险',
|
||||
`prison_area_id` bigint DEFAULT NULL COMMENT '监区ID',
|
||||
`sub_area_id` bigint DEFAULT NULL COMMENT '分区ID',
|
||||
`prison_cell_id` bigint DEFAULT NULL COMMENT '监室ID',
|
||||
`marital_status` tinyint DEFAULT NULL COMMENT '婚姻状态:1-未婚 2-已婚 3-离异 4-丧偶',
|
||||
`crime_type` varchar(100) DEFAULT NULL COMMENT '罪名类型',
|
||||
`sentence` varchar(100) DEFAULT NULL COMMENT '刑期',
|
||||
`status` tinyint NOT NULL DEFAULT 1 COMMENT '状态:1-在押 2-已释放 3-已死亡 4-假释',
|
||||
`remark` varchar(500) DEFAULT NULL COMMENT '备注',
|
||||
`creator` varchar(64) DEFAULT '' COMMENT '创建者',
|
||||
|
||||
0
yudao-framework/yudao-spring-boot-starter-monitor/src/main/java/cn/iocoder/yudao/framework/tracer/config/TracerProperties.java
Normal file → Executable file
0
yudao-framework/yudao-spring-boot-starter-monitor/src/main/java/cn/iocoder/yudao/framework/tracer/config/TracerProperties.java
Normal file → Executable file
0
yudao-framework/yudao-spring-boot-starter-monitor/src/main/java/cn/iocoder/yudao/framework/tracer/core/annotation/BizTrace.java
Normal file → Executable file
0
yudao-framework/yudao-spring-boot-starter-monitor/src/main/java/cn/iocoder/yudao/framework/tracer/core/annotation/BizTrace.java
Normal file → Executable file
0
yudao-framework/yudao-spring-boot-starter-monitor/src/main/java/cn/iocoder/yudao/framework/tracer/core/aop/BizTraceAspect.java
Normal file → Executable file
0
yudao-framework/yudao-spring-boot-starter-monitor/src/main/java/cn/iocoder/yudao/framework/tracer/core/aop/BizTraceAspect.java
Normal file → Executable file
0
yudao-framework/yudao-spring-boot-starter-monitor/src/main/java/cn/iocoder/yudao/framework/tracer/core/filter/TraceFilter.java
Normal file → Executable file
0
yudao-framework/yudao-spring-boot-starter-monitor/src/main/java/cn/iocoder/yudao/framework/tracer/core/filter/TraceFilter.java
Normal file → Executable file
0
yudao-framework/yudao-spring-boot-starter-monitor/src/main/java/cn/iocoder/yudao/framework/tracer/package-info.java
Normal file → Executable file
0
yudao-framework/yudao-spring-boot-starter-monitor/src/main/java/cn/iocoder/yudao/framework/tracer/package-info.java
Normal file → Executable file
0
yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/mq/producer/package-info.java
Normal file → Executable file
0
yudao-module-infra/src/main/java/cn/iocoder/yudao/module/infra/mq/producer/package-info.java
Normal file → Executable file
@ -1,12 +1,13 @@
|
||||
package cn.iocoder.yudao.module.prison.controller.admin.dashboard;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
|
||||
import cn.iocoder.yudao.module.prison.controller.admin.dashboard.vo.DashboardStatisticsVO;
|
||||
import cn.iocoder.yudao.module.prison.controller.admin.dashboard.vo.PrisonerDashboardStatsRespVO;
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||
import cn.iocoder.yudao.module.prison.controller.admin.dashboard.vo.*;
|
||||
import cn.iocoder.yudao.module.prison.service.dashboard.PrisonDashboardService;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.validation.Valid;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
@ -44,4 +45,18 @@ public class PrisonDashboardController {
|
||||
return success(dashboardService.getPrisonerStats(prisonerId));
|
||||
}
|
||||
|
||||
@GetMapping("/ai-dash-entry/statistics")
|
||||
@Operation(summary = "获取AI心航360°统计数据")
|
||||
@PreAuthorize("@ss.hasPermission('prison:ai-dash-entry:query')")
|
||||
public CommonResult<AiDashEntryStatisticsVO> getAiDashEntryStatistics() {
|
||||
return success(dashboardService.getAiDashEntryStatistics());
|
||||
}
|
||||
|
||||
@GetMapping("/ai-dash-entry/focus-person-page")
|
||||
@Operation(summary = "获取重点关注对象分页列表")
|
||||
@PreAuthorize("@ss.hasPermission('prison:ai-dash-entry:query')")
|
||||
public CommonResult<PageResult<FocusPersonVO>> getFocusPersonPage(@Valid FocusPersonPageReqVO reqVO) {
|
||||
return success(dashboardService.getFocusPersonPage(reqVO));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -0,0 +1,97 @@
|
||||
package cn.iocoder.yudao.module.prison.controller.admin.dashboard.vo;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Schema(description = "管理后台 - AI心航360°统计 Response VO")
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class AiDashEntryStatisticsVO {
|
||||
|
||||
// ==================== 统计卡片数据 ====================
|
||||
|
||||
@Schema(description = "全部人员数量")
|
||||
private Integer totalCount;
|
||||
|
||||
@Schema(description = "本月新增人员数量")
|
||||
private Integer monthlyNewCount;
|
||||
|
||||
@Schema(description = "本月较上月变化")
|
||||
private Integer monthlyChange;
|
||||
|
||||
@Schema(description = "高危人员数量")
|
||||
private Integer highRiskCount;
|
||||
|
||||
@Schema(description = "高危本月新增")
|
||||
private Integer highRiskMonthlyNew;
|
||||
|
||||
@Schema(description = "高危本月变化")
|
||||
private Integer highRiskMonthlyChange;
|
||||
|
||||
@Schema(description = "预警人员数量")
|
||||
private Integer warningCount;
|
||||
|
||||
@Schema(description = "预警本月新增")
|
||||
private Integer warningMonthlyNew;
|
||||
|
||||
@Schema(description = "预警本月变化")
|
||||
private Integer warningMonthlyChange;
|
||||
|
||||
@Schema(description = "普通人员数量")
|
||||
private Integer normalCount;
|
||||
|
||||
@Schema(description = "普通本月新增")
|
||||
private Integer normalMonthlyNew;
|
||||
|
||||
@Schema(description = "普通本月变化")
|
||||
private Integer normalMonthlyChange;
|
||||
|
||||
// ==================== 图表数据 ====================
|
||||
|
||||
@Schema(description = "风险等级分布")
|
||||
private List<RiskDistributionVO> riskDistribution;
|
||||
|
||||
@Schema(description = "风险趋势数据")
|
||||
private List<RiskTrendVO> riskTrendData;
|
||||
|
||||
/**
|
||||
* 风险等级分布数据
|
||||
*/
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public static class RiskDistributionVO {
|
||||
@Schema(description = "名称")
|
||||
private String name;
|
||||
@Schema(description = "数量")
|
||||
private Integer value;
|
||||
@Schema(description = "颜色")
|
||||
private String color;
|
||||
}
|
||||
|
||||
/**
|
||||
* 风险趋势数据
|
||||
*/
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public static class RiskTrendVO {
|
||||
@Schema(description = "月份")
|
||||
private String month;
|
||||
@Schema(description = "高危人数")
|
||||
private Integer highRisk;
|
||||
@Schema(description = "预警人数")
|
||||
private Integer warning;
|
||||
@Schema(description = "普通人数")
|
||||
private Integer normal;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,23 @@
|
||||
package cn.iocoder.yudao.module.prison.controller.admin.dashboard.vo;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageParam;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.ToString;
|
||||
|
||||
@Schema(description = "管理后台 - 重点关注对象分页 Request VO")
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@ToString(callSuper = true)
|
||||
public class FocusPersonPageReqVO extends PageParam {
|
||||
|
||||
@Schema(description = "风险等级类型:high-高危, warning-预警, normal-普通, 空为全部")
|
||||
private String riskLevelType;
|
||||
|
||||
@Schema(description = "罪犯姓名,模糊匹配")
|
||||
private String name;
|
||||
|
||||
@Schema(description = "监区ID")
|
||||
private Long areaId;
|
||||
}
|
||||
@ -0,0 +1,42 @@
|
||||
package cn.iocoder.yudao.module.prison.controller.admin.dashboard.vo;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
@Schema(description = "管理后台 - 重点关注对象 Response VO")
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class FocusPersonVO {
|
||||
|
||||
@Schema(description = "罪犯ID")
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "罪犯姓名")
|
||||
private String name;
|
||||
|
||||
@Schema(description = "性别")
|
||||
private String gender;
|
||||
|
||||
@Schema(description = "年龄")
|
||||
private Integer age;
|
||||
|
||||
@Schema(description = "风险等级:high-高危, warning-预警, normal-普通")
|
||||
private String riskLevelType;
|
||||
|
||||
@Schema(description = "风险等级文本")
|
||||
private String riskLevel;
|
||||
|
||||
@Schema(description = "监区")
|
||||
private String supervisionArea;
|
||||
|
||||
@Schema(description = "心理风险等级")
|
||||
private String psychologicalRiskLevel;
|
||||
|
||||
@Schema(description = "是否新增")
|
||||
private Boolean isNew;
|
||||
}
|
||||
@ -1,6 +1,6 @@
|
||||
package cn.iocoder.yudao.module.prison.dal.dataobject;
|
||||
|
||||
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
|
||||
import cn.iocoder.yudao.framework.tenant.core.db.TenantBaseDO;
|
||||
import com.baomidou.mybatisplus.annotation.KeySequence;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.*;
|
||||
@ -19,7 +19,7 @@ import java.time.LocalDateTime;
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class PrisonerAreaLogDO extends BaseDO {
|
||||
public class PrisonerAreaLogDO extends TenantBaseDO {
|
||||
|
||||
/**
|
||||
* 主键ID
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
package cn.iocoder.yudao.module.prison.dal.dataobject;
|
||||
|
||||
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
|
||||
import cn.iocoder.yudao.framework.tenant.core.db.TenantBaseDO;
|
||||
import cn.iocoder.yudao.module.prison.enums.*;
|
||||
import com.baomidou.mybatisplus.annotation.KeySequence;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
@ -20,7 +20,7 @@ import java.time.LocalDate;
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class PrisonerDO extends BaseDO {
|
||||
public class PrisonerDO extends TenantBaseDO {
|
||||
|
||||
/**
|
||||
* 主键ID
|
||||
@ -172,6 +172,26 @@ public class PrisonerDO extends BaseDO {
|
||||
*/
|
||||
private Long prisonCellId;
|
||||
|
||||
/**
|
||||
* 婚姻状态:1-未婚 2-已婚 3-离异 4-丧偶
|
||||
*/
|
||||
private Integer maritalStatus;
|
||||
|
||||
/**
|
||||
* 罪名类型
|
||||
*/
|
||||
private String crimeType;
|
||||
|
||||
/**
|
||||
* 刑期
|
||||
*/
|
||||
private String sentence;
|
||||
|
||||
/**
|
||||
* 子女情况
|
||||
*/
|
||||
private String children;
|
||||
|
||||
/**
|
||||
* 状态
|
||||
*/
|
||||
@ -182,4 +202,30 @@ public class PrisonerDO extends BaseDO {
|
||||
*/
|
||||
private String remark;
|
||||
|
||||
// ========== 兼容方法 ==========
|
||||
|
||||
public LocalDate getBirthDate() {
|
||||
return this.birthday;
|
||||
}
|
||||
|
||||
public Long getAreaId() {
|
||||
return this.prisonAreaId;
|
||||
}
|
||||
|
||||
public Integer getMaritalStatus() {
|
||||
return this.maritalStatus;
|
||||
}
|
||||
|
||||
public String getCrimeType() {
|
||||
return this.crimeType;
|
||||
}
|
||||
|
||||
public String getSentence() {
|
||||
return this.sentence;
|
||||
}
|
||||
|
||||
public String getChildren() {
|
||||
return this.children;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -5,7 +5,7 @@ import java.util.*;
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDateTime;
|
||||
import com.baomidou.mybatisplus.annotation.*;
|
||||
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
|
||||
import cn.iocoder.yudao.framework.tenant.core.db.TenantBaseDO;
|
||||
|
||||
/**
|
||||
* 问卷答题记录 DO
|
||||
@ -20,7 +20,7 @@ import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class AnswerDO extends BaseDO {
|
||||
public class AnswerDO extends TenantBaseDO {
|
||||
|
||||
/**
|
||||
* 答题记录ID
|
||||
|
||||
@ -4,7 +4,7 @@ import lombok.*;
|
||||
import java.util.*;
|
||||
import java.time.LocalDateTime;
|
||||
import com.baomidou.mybatisplus.annotation.*;
|
||||
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
|
||||
import cn.iocoder.yudao.framework.tenant.core.db.TenantBaseDO;
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
|
||||
/**
|
||||
@ -20,7 +20,7 @@ import com.baomidou.mybatisplus.annotation.TableField;
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class AreaDO extends BaseDO {
|
||||
public class AreaDO extends TenantBaseDO {
|
||||
|
||||
/**
|
||||
* 监区ID
|
||||
|
||||
@ -5,7 +5,7 @@ import java.util.*;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.LocalDateTime;
|
||||
import com.baomidou.mybatisplus.annotation.*;
|
||||
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
|
||||
import cn.iocoder.yudao.framework.tenant.core.db.TenantBaseDO;
|
||||
|
||||
/**
|
||||
* 监室信息 DO
|
||||
@ -20,7 +20,7 @@ import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class CellDO extends BaseDO {
|
||||
public class CellDO extends TenantBaseDO {
|
||||
|
||||
/**
|
||||
* 监室ID
|
||||
|
||||
@ -5,7 +5,7 @@ import java.util.*;
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDateTime;
|
||||
import com.baomidou.mybatisplus.annotation.*;
|
||||
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
|
||||
import cn.iocoder.yudao.framework.tenant.core.db.TenantBaseDO;
|
||||
|
||||
/**
|
||||
* 消费订单 DO
|
||||
@ -20,7 +20,7 @@ import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class ConsumptionDO extends BaseDO {
|
||||
public class ConsumptionDO extends TenantBaseDO {
|
||||
|
||||
/**
|
||||
* 消费ID
|
||||
|
||||
@ -4,7 +4,7 @@ import lombok.*;
|
||||
import java.util.*;
|
||||
import java.math.BigDecimal;
|
||||
import com.baomidou.mybatisplus.annotation.*;
|
||||
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
|
||||
import cn.iocoder.yudao.framework.tenant.core.db.TenantBaseDO;
|
||||
|
||||
/**
|
||||
* 消费明细 DO
|
||||
@ -19,7 +19,7 @@ import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class ConsumptionDetailDO extends BaseDO {
|
||||
public class ConsumptionDetailDO extends TenantBaseDO {
|
||||
|
||||
/**
|
||||
* 明细ID
|
||||
|
||||
@ -5,7 +5,7 @@ import java.util.*;
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDateTime;
|
||||
import com.baomidou.mybatisplus.annotation.*;
|
||||
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
|
||||
import cn.iocoder.yudao.framework.tenant.core.db.TenantBaseDO;
|
||||
import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler;
|
||||
|
||||
/**
|
||||
@ -21,7 +21,7 @@ import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler;
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class EvaluationDimensionDO extends BaseDO {
|
||||
public class EvaluationDimensionDO extends TenantBaseDO {
|
||||
|
||||
/**
|
||||
* 维度ID
|
||||
|
||||
@ -5,7 +5,7 @@ import java.util.*;
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDateTime;
|
||||
import com.baomidou.mybatisplus.annotation.*;
|
||||
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
|
||||
import cn.iocoder.yudao.framework.tenant.core.db.TenantBaseDO;
|
||||
|
||||
/**
|
||||
* 报告维度数据 DO
|
||||
@ -20,7 +20,7 @@ import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class EvaluationDimensionDataDO extends BaseDO {
|
||||
public class EvaluationDimensionDataDO extends TenantBaseDO {
|
||||
|
||||
/**
|
||||
* 数据ID
|
||||
|
||||
@ -5,7 +5,7 @@ import java.util.*;
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDateTime;
|
||||
import com.baomidou.mybatisplus.annotation.*;
|
||||
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
|
||||
import cn.iocoder.yudao.framework.tenant.core.db.TenantBaseDO;
|
||||
|
||||
/**
|
||||
* 评估报告 DO
|
||||
@ -20,7 +20,7 @@ import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class EvaluationReportDO extends BaseDO {
|
||||
public class EvaluationReportDO extends TenantBaseDO {
|
||||
|
||||
/**
|
||||
* 报告ID
|
||||
|
||||
@ -5,7 +5,7 @@ import java.util.*;
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDateTime;
|
||||
import com.baomidou.mybatisplus.annotation.*;
|
||||
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
|
||||
import cn.iocoder.yudao.framework.tenant.core.db.TenantBaseDO;
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
|
||||
/**
|
||||
@ -21,7 +21,7 @@ import com.baomidou.mybatisplus.annotation.TableField;
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class EvaluationTemplateDO extends BaseDO {
|
||||
public class EvaluationTemplateDO extends TenantBaseDO {
|
||||
|
||||
/**
|
||||
* 模板ID
|
||||
|
||||
@ -4,7 +4,7 @@ import lombok.*;
|
||||
import java.util.*;
|
||||
import java.time.LocalDateTime;
|
||||
import com.baomidou.mybatisplus.annotation.*;
|
||||
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
|
||||
import cn.iocoder.yudao.framework.tenant.core.db.TenantBaseDO;
|
||||
|
||||
/**
|
||||
* 快捷评语库 DO
|
||||
@ -19,7 +19,7 @@ import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class ReportCommentDO extends BaseDO {
|
||||
public class ReportCommentDO extends TenantBaseDO {
|
||||
|
||||
/**
|
||||
* 评语ID
|
||||
|
||||
@ -5,7 +5,7 @@ import java.util.*;
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDateTime;
|
||||
import com.baomidou.mybatisplus.annotation.*;
|
||||
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
|
||||
import cn.iocoder.yudao.framework.tenant.core.db.TenantBaseDO;
|
||||
|
||||
/**
|
||||
* 问卷问题 DO
|
||||
@ -20,7 +20,7 @@ import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class QuestionDO extends BaseDO {
|
||||
public class QuestionDO extends TenantBaseDO {
|
||||
|
||||
/**
|
||||
* 问题ID
|
||||
|
||||
@ -5,7 +5,7 @@ import java.util.*;
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDateTime;
|
||||
import com.baomidou.mybatisplus.annotation.*;
|
||||
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
|
||||
import cn.iocoder.yudao.framework.tenant.core.db.TenantBaseDO;
|
||||
|
||||
/**
|
||||
* 问卷模板 DO
|
||||
@ -20,7 +20,7 @@ import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class QuestionnaireDO extends BaseDO {
|
||||
public class QuestionnaireDO extends TenantBaseDO {
|
||||
|
||||
/**
|
||||
* 问卷ID
|
||||
|
||||
@ -5,7 +5,7 @@ import java.util.*;
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDateTime;
|
||||
import com.baomidou.mybatisplus.annotation.*;
|
||||
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
|
||||
import cn.iocoder.yudao.framework.tenant.core.db.TenantBaseDO;
|
||||
|
||||
/**
|
||||
* 问卷答题记录 / 测评记录 DO
|
||||
@ -20,7 +20,7 @@ import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class QuestionnaireRecordDO extends BaseDO {
|
||||
public class QuestionnaireRecordDO extends TenantBaseDO {
|
||||
|
||||
/**
|
||||
* 记录ID
|
||||
|
||||
@ -4,7 +4,7 @@ import lombok.*;
|
||||
import java.util.*;
|
||||
import java.time.LocalDateTime;
|
||||
import com.baomidou.mybatisplus.annotation.*;
|
||||
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
|
||||
import cn.iocoder.yudao.framework.tenant.core.db.TenantBaseDO;
|
||||
|
||||
/**
|
||||
* 快捷评语分类 DO
|
||||
@ -19,7 +19,7 @@ import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class CommentCategoryDO extends BaseDO {
|
||||
public class CommentCategoryDO extends TenantBaseDO {
|
||||
|
||||
/**
|
||||
* 分类ID
|
||||
|
||||
@ -4,7 +4,7 @@ import lombok.*;
|
||||
import java.util.*;
|
||||
import java.time.LocalDateTime;
|
||||
import com.baomidou.mybatisplus.annotation.*;
|
||||
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
|
||||
import cn.iocoder.yudao.framework.tenant.core.db.TenantBaseDO;
|
||||
|
||||
/**
|
||||
* 快捷评语 DO
|
||||
@ -19,7 +19,7 @@ import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class QuickCommentDO extends BaseDO {
|
||||
public class QuickCommentDO extends TenantBaseDO {
|
||||
|
||||
/**
|
||||
* 评语ID
|
||||
|
||||
@ -5,7 +5,7 @@ import java.util.*;
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalDateTime;
|
||||
import com.baomidou.mybatisplus.annotation.*;
|
||||
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
|
||||
import cn.iocoder.yudao.framework.tenant.core.db.TenantBaseDO;
|
||||
|
||||
/**
|
||||
* 释放登记记录 DO
|
||||
@ -20,7 +20,7 @@ import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class ReleaseDO extends BaseDO {
|
||||
public class ReleaseDO extends TenantBaseDO {
|
||||
|
||||
/**
|
||||
* 记录ID
|
||||
|
||||
@ -5,7 +5,7 @@ import java.util.*;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.LocalDate;
|
||||
import com.baomidou.mybatisplus.annotation.*;
|
||||
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
|
||||
import cn.iocoder.yudao.framework.tenant.core.db.TenantBaseDO;
|
||||
|
||||
/**
|
||||
* 评估报告 DO
|
||||
@ -20,7 +20,7 @@ import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class ReportDO extends BaseDO {
|
||||
public class ReportDO extends TenantBaseDO {
|
||||
|
||||
/**
|
||||
* 报告ID
|
||||
|
||||
@ -4,7 +4,7 @@ import lombok.*;
|
||||
import java.util.*;
|
||||
import java.time.LocalDateTime;
|
||||
import com.baomidou.mybatisplus.annotation.*;
|
||||
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
|
||||
import cn.iocoder.yudao.framework.tenant.core.db.TenantBaseDO;
|
||||
|
||||
/**
|
||||
* 评估报告模板 DO
|
||||
@ -19,7 +19,7 @@ import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class ReportTemplateDO extends BaseDO {
|
||||
public class ReportTemplateDO extends TenantBaseDO {
|
||||
|
||||
/**
|
||||
* 模板ID
|
||||
|
||||
@ -5,7 +5,7 @@ import java.util.*;
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDate;
|
||||
import com.baomidou.mybatisplus.annotation.*;
|
||||
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
|
||||
import cn.iocoder.yudao.framework.tenant.core.db.TenantBaseDO;
|
||||
|
||||
/**
|
||||
* 风险评估 DO
|
||||
@ -20,7 +20,7 @@ import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class RiskDO extends BaseDO {
|
||||
public class RiskDO extends TenantBaseDO {
|
||||
|
||||
/**
|
||||
* 评估ID
|
||||
@ -121,4 +121,64 @@ public class RiskDO extends BaseDO {
|
||||
*/
|
||||
private String remark;
|
||||
|
||||
/**
|
||||
* 风险评分
|
||||
*/
|
||||
private Integer riskScore;
|
||||
|
||||
/**
|
||||
* 风险描述
|
||||
*/
|
||||
private String riskDescription;
|
||||
|
||||
/**
|
||||
* 风险因素
|
||||
*/
|
||||
private String riskFactors;
|
||||
|
||||
/**
|
||||
* 建议措施
|
||||
*/
|
||||
private String suggestions;
|
||||
|
||||
/**
|
||||
* 评估人姓名
|
||||
*/
|
||||
private String assessorName;
|
||||
|
||||
/**
|
||||
* 状态:1-待评估 2-评估中 3-已完成 4-已取消
|
||||
*/
|
||||
private Integer status;
|
||||
|
||||
// ========== 兼容方法 ==========
|
||||
|
||||
public void setPrisonerNo(String prisonerNo) {
|
||||
this.prisonerCode = prisonerNo;
|
||||
}
|
||||
|
||||
public void setRiskScore(Integer riskScore) {
|
||||
this.riskScore = riskScore;
|
||||
}
|
||||
|
||||
public void setRiskDescription(String riskDescription) {
|
||||
this.riskDescription = riskDescription;
|
||||
}
|
||||
|
||||
public void setRiskFactors(String riskFactors) {
|
||||
this.riskFactors = riskFactors;
|
||||
}
|
||||
|
||||
public void setSuggestions(String suggestions) {
|
||||
this.suggestions = suggestions;
|
||||
}
|
||||
|
||||
public void setAssessorName(String assessorName) {
|
||||
this.assessorName = assessorName;
|
||||
}
|
||||
|
||||
public void setStatus(Integer status) {
|
||||
this.status = status;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -6,7 +6,7 @@ import java.math.BigDecimal;
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalDateTime;
|
||||
import com.baomidou.mybatisplus.annotation.*;
|
||||
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
|
||||
import cn.iocoder.yudao.framework.tenant.core.db.TenantBaseDO;
|
||||
|
||||
/**
|
||||
* 危险评估 DO
|
||||
@ -21,7 +21,7 @@ import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class RiskAssessmentDO extends BaseDO {
|
||||
public class RiskAssessmentDO extends TenantBaseDO {
|
||||
|
||||
/**
|
||||
* 评估ID
|
||||
|
||||
@ -9,7 +9,7 @@ import java.math.BigDecimal;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.LocalDateTime;
|
||||
import com.baomidou.mybatisplus.annotation.*;
|
||||
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
|
||||
import cn.iocoder.yudao.framework.tenant.core.db.TenantBaseDO;
|
||||
|
||||
/**
|
||||
* 计分考核 DO
|
||||
@ -24,7 +24,7 @@ import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class ScoreDO extends BaseDO {
|
||||
public class ScoreDO extends TenantBaseDO {
|
||||
|
||||
/**
|
||||
* 记录ID
|
||||
|
||||
@ -5,7 +5,7 @@ import java.util.*;
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDate;
|
||||
import com.baomidou.mybatisplus.annotation.*;
|
||||
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
|
||||
import cn.iocoder.yudao.framework.tenant.core.db.TenantBaseDO;
|
||||
|
||||
/**
|
||||
* 考核记录明细 DO
|
||||
@ -20,7 +20,7 @@ import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class ScoreDetailDO extends BaseDO {
|
||||
public class ScoreDetailDO extends TenantBaseDO {
|
||||
|
||||
/**
|
||||
* 记录ID
|
||||
|
||||
@ -4,7 +4,7 @@ import lombok.*;
|
||||
import java.util.*;
|
||||
import java.math.BigDecimal;
|
||||
import com.baomidou.mybatisplus.annotation.*;
|
||||
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
|
||||
import cn.iocoder.yudao.framework.tenant.core.db.TenantBaseDO;
|
||||
|
||||
/**
|
||||
* 考核规则配置 DO
|
||||
@ -19,7 +19,7 @@ import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class ScoreRuleDO extends BaseDO {
|
||||
public class ScoreRuleDO extends TenantBaseDO {
|
||||
|
||||
/**
|
||||
* 规则ID
|
||||
|
||||
@ -4,7 +4,7 @@ import lombok.*;
|
||||
import java.util.*;
|
||||
import java.time.LocalDateTime;
|
||||
import com.baomidou.mybatisplus.annotation.*;
|
||||
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
|
||||
import cn.iocoder.yudao.framework.tenant.core.db.TenantBaseDO;
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
|
||||
/**
|
||||
@ -20,7 +20,7 @@ import com.baomidou.mybatisplus.annotation.TableField;
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class SituationDO extends BaseDO {
|
||||
public class SituationDO extends TenantBaseDO {
|
||||
|
||||
/**
|
||||
* 狱情ID
|
||||
@ -104,4 +104,14 @@ public class SituationDO extends BaseDO {
|
||||
*/
|
||||
private LocalDateTime occurTime;
|
||||
|
||||
/**
|
||||
* 类型
|
||||
*/
|
||||
private String type;
|
||||
|
||||
/**
|
||||
* 地点
|
||||
*/
|
||||
private String location;
|
||||
|
||||
}
|
||||
|
||||
@ -4,7 +4,7 @@ import lombok.*;
|
||||
import java.util.*;
|
||||
import java.time.LocalDateTime;
|
||||
import com.baomidou.mybatisplus.annotation.*;
|
||||
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
|
||||
import cn.iocoder.yudao.framework.tenant.core.db.TenantBaseDO;
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
|
||||
/**
|
||||
@ -20,7 +20,7 @@ import com.baomidou.mybatisplus.annotation.TableField;
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class WarningDO extends BaseDO {
|
||||
public class WarningDO extends TenantBaseDO {
|
||||
|
||||
/**
|
||||
* 预警ID
|
||||
|
||||
@ -13,6 +13,14 @@ import org.apache.ibatis.annotations.Param;
|
||||
@Mapper
|
||||
public interface PrisonerMapper extends BaseMapperX<PrisonerDO> {
|
||||
|
||||
/**
|
||||
* 根据罪犯编号查询
|
||||
*
|
||||
* @param prisonerNo 罪犯编号
|
||||
* @return 服刑人员信息
|
||||
*/
|
||||
PrisonerDO selectByPrisonerNo(@Param("prisonerNo") String prisonerNo);
|
||||
|
||||
/**
|
||||
* 统计某监区(含子监区)下的罪犯数量
|
||||
*
|
||||
|
||||
@ -186,6 +186,7 @@ public class ConsumptionServiceImpl implements ConsumptionService {
|
||||
// 3. 创建消费记录
|
||||
ConsumptionDO consumption = new ConsumptionDO();
|
||||
consumption.setPrisonerId(prisoner.getId());
|
||||
consumption.setPrisonerNo(prisoner.getPrisonerNo());
|
||||
consumption.setOrderNo(generateOrderNo());
|
||||
consumption.setType(importVO.getType());
|
||||
consumption.setTotalAmount(importVO.getTotalAmount());
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
package cn.iocoder.yudao.module.prison.service.dashboard;
|
||||
|
||||
import cn.iocoder.yudao.module.prison.controller.admin.dashboard.vo.DashboardStatisticsVO;
|
||||
import cn.iocoder.yudao.module.prison.controller.admin.dashboard.vo.PrisonerDashboardStatsRespVO;
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||
import cn.iocoder.yudao.module.prison.controller.admin.dashboard.vo.*;
|
||||
|
||||
/**
|
||||
* 监管看板 Service 接口
|
||||
@ -25,4 +25,19 @@ public interface PrisonDashboardService {
|
||||
*/
|
||||
PrisonerDashboardStatsRespVO getPrisonerStats(Long prisonerId);
|
||||
|
||||
/**
|
||||
* 获取AI心航360°统计数据
|
||||
*
|
||||
* @return AI心航360°统计数据
|
||||
*/
|
||||
AiDashEntryStatisticsVO getAiDashEntryStatistics();
|
||||
|
||||
/**
|
||||
* 获取重点关注对象分页列表
|
||||
*
|
||||
* @param reqVO 分页请求参数
|
||||
* @return 重点关注对象分页列表
|
||||
*/
|
||||
PageResult<FocusPersonVO> getFocusPersonPage(FocusPersonPageReqVO reqVO);
|
||||
|
||||
}
|
||||
|
||||
@ -1,23 +1,43 @@
|
||||
package cn.iocoder.yudao.module.prison.service.dashboard.impl;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||
import cn.iocoder.yudao.module.prison.controller.admin.dashboard.vo.*;
|
||||
import cn.iocoder.yudao.module.prison.dal.dataobject.PrisonerDO;
|
||||
import cn.iocoder.yudao.module.prison.dal.dataobject.area.AreaDO;
|
||||
import cn.iocoder.yudao.module.prison.dal.dataobject.consumption.ConsumptionDO;
|
||||
import cn.iocoder.yudao.module.prison.dal.dataobject.evaluationreport.EvaluationReportDO;
|
||||
import cn.iocoder.yudao.module.prison.dal.dataobject.riskassessment.RiskAssessmentDO;
|
||||
import cn.iocoder.yudao.module.prison.dal.dataobject.score.ScoreDO;
|
||||
import cn.iocoder.yudao.module.prison.dal.dataobject.situation.SituationDO;
|
||||
import cn.iocoder.yudao.module.prison.dal.mysql.dashboard.PrisonDashboardMapper;
|
||||
import cn.iocoder.yudao.module.prison.dal.mysql.PrisonerMapper;
|
||||
import cn.iocoder.yudao.module.prison.dal.mysql.area.AreaMapper;
|
||||
import cn.iocoder.yudao.module.prison.dal.mysql.consumption.ConsumptionMapper;
|
||||
import cn.iocoder.yudao.module.prison.dal.mysql.evaluationreport.EvaluationReportMapper;
|
||||
import cn.iocoder.yudao.module.prison.dal.mysql.riskassessment.RiskAssessmentMapper;
|
||||
import cn.iocoder.yudao.module.prison.dal.mysql.score.ScoreMapper;
|
||||
import cn.iocoder.yudao.module.prison.dal.mysql.situation.SituationMapper;
|
||||
import cn.iocoder.yudao.module.prison.enums.GenderEnum;
|
||||
import cn.iocoder.yudao.module.prison.service.dashboard.PrisonDashboardService;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.cache.annotation.Cacheable;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.math.RoundingMode;
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.Period;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.time.temporal.ChronoUnit;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* 监管看板 Service 实现
|
||||
@ -31,6 +51,12 @@ public class PrisonDashboardServiceImpl implements PrisonDashboardService {
|
||||
|
||||
private final PrisonDashboardMapper dashboardMapper;
|
||||
private final PrisonerMapper prisonerMapper;
|
||||
private final ConsumptionMapper consumptionMapper;
|
||||
private final ScoreMapper scoreMapper;
|
||||
private final RiskAssessmentMapper riskAssessmentMapper;
|
||||
private final SituationMapper situationMapper;
|
||||
private final AreaMapper areaMapper;
|
||||
private final EvaluationReportMapper evaluationReportMapper;
|
||||
|
||||
private static final String CACHE_KEY = "prison:dashboard:statistics";
|
||||
|
||||
@ -163,8 +189,9 @@ public class PrisonDashboardServiceImpl implements PrisonDashboardService {
|
||||
vo.setPrisonerName(prisoner.getName());
|
||||
vo.setPrisonerNo(prisoner.getPrisonerNo());
|
||||
vo.setNativePlace(prisoner.getNativePlace());
|
||||
vo.setEducation(prisoner.getEducation());
|
||||
vo.setMaritalStatus(prisoner.getMaritalStatus());
|
||||
vo.setEducation(prisoner.getEducation() != null ? prisoner.getEducation().getName() : null);
|
||||
vo.setMaritalStatus(prisoner.getMaritalStatus() != null ? String.valueOf(prisoner.getMaritalStatus()) : null);
|
||||
vo.setChildren(prisoner.getChildren());
|
||||
vo.setCrimeType(prisoner.getCrimeType());
|
||||
vo.setSentence(prisoner.getSentence());
|
||||
|
||||
@ -186,50 +213,532 @@ public class PrisonDashboardServiceImpl implements PrisonDashboardService {
|
||||
// 监区信息(简单拼接)
|
||||
vo.setPrisonArea(prisoner.getAreaId() != null ? "监区" + prisoner.getAreaId() : "未分配");
|
||||
|
||||
// 默认风险等级
|
||||
vo.setRiskScore(0);
|
||||
vo.setRiskLevel(1);
|
||||
// ==================== 查询关联数据 ====================
|
||||
|
||||
// 构建中心数据(使用默认值)
|
||||
// 1. 查询最新危险评估
|
||||
RiskAssessmentDO latestAssessment = riskAssessmentMapper.selectOne(new LambdaQueryWrapper<RiskAssessmentDO>()
|
||||
.eq(RiskAssessmentDO::getPrisonerId, prisonerId)
|
||||
.eq(RiskAssessmentDO::getStatus, 1)
|
||||
.orderByDesc(RiskAssessmentDO::getAssessmentDate)
|
||||
.last("LIMIT 1"));
|
||||
if (latestAssessment != null) {
|
||||
vo.setRiskScore(latestAssessment.getTotalScore() != null ? latestAssessment.getTotalScore().intValue() : 0);
|
||||
vo.setRiskLevel(latestAssessment.getRiskLevel() != null ? latestAssessment.getRiskLevel() : 1);
|
||||
}
|
||||
|
||||
// 2. 查询本月消费数据
|
||||
LocalDate now = LocalDate.now();
|
||||
int currentYear = now.getYear();
|
||||
int currentMonth = now.getMonthValue();
|
||||
List<ConsumptionDO> monthlyConsumptions = consumptionMapper.selectList(new LambdaQueryWrapper<ConsumptionDO>()
|
||||
.eq(ConsumptionDO::getPrisonerId, prisonerId)
|
||||
.eq(ConsumptionDO::getStatus, 1)
|
||||
.eq(ConsumptionDO::getType, 1) // 消费类型
|
||||
.apply("YEAR(trade_time) = {0} AND MONTH(trade_time) = {1}", currentYear, currentMonth)
|
||||
.orderByDesc(ConsumptionDO::getTradeTime));
|
||||
|
||||
// 计算本月消费总额
|
||||
double monthlyTotal = monthlyConsumptions.stream()
|
||||
.mapToDouble(c -> c.getTotalAmount() != null ? c.getTotalAmount().doubleValue() : 0)
|
||||
.sum();
|
||||
|
||||
// 获取最新余额
|
||||
Double latestBalance = null;
|
||||
if (!monthlyConsumptions.isEmpty() && monthlyConsumptions.get(0).getBalance() != null) {
|
||||
latestBalance = monthlyConsumptions.get(0).getBalance().doubleValue();
|
||||
}
|
||||
if (latestBalance == null) {
|
||||
ConsumptionDO latestConsumption = consumptionMapper.selectOne(new LambdaQueryWrapper<ConsumptionDO>()
|
||||
.eq(ConsumptionDO::getPrisonerId, prisonerId)
|
||||
.eq(ConsumptionDO::getStatus, 1)
|
||||
.orderByDesc(ConsumptionDO::getTradeTime)
|
||||
.last("LIMIT 1"));
|
||||
if (latestConsumption != null && latestConsumption.getBalance() != null) {
|
||||
latestBalance = latestConsumption.getBalance().doubleValue();
|
||||
}
|
||||
}
|
||||
|
||||
// 3. 查询本月计分考核
|
||||
List<ScoreDO> monthlyScores = scoreMapper.selectList(new LambdaQueryWrapper<ScoreDO>()
|
||||
.eq(ScoreDO::getPrisonerId, prisonerId)
|
||||
.eq(ScoreDO::getStatus, 1)
|
||||
.eq(ScoreDO::getYear, currentYear)
|
||||
.eq(ScoreDO::getMonth, currentMonth)
|
||||
.last("LIMIT 1"));
|
||||
|
||||
ScoreDO currentMonthScore = monthlyScores.isEmpty() ? null : monthlyScores.get(0);
|
||||
|
||||
// 4. 查询最近6个月的计分考核记录
|
||||
List<ScoreDO> recentScores = scoreMapper.selectList(new LambdaQueryWrapper<ScoreDO>()
|
||||
.eq(ScoreDO::getPrisonerId, prisonerId)
|
||||
.eq(ScoreDO::getStatus, 1)
|
||||
.orderByDesc(ScoreDO::getYear)
|
||||
.orderByDesc(ScoreDO::getMonth)
|
||||
.last("LIMIT 6"));
|
||||
|
||||
// 5. 查询最近6个月消费记录
|
||||
List<ConsumptionDO> recentConsumptions = consumptionMapper.selectList(new LambdaQueryWrapper<ConsumptionDO>()
|
||||
.eq(ConsumptionDO::getPrisonerId, prisonerId)
|
||||
.eq(ConsumptionDO::getStatus, 1)
|
||||
.orderByDesc(ConsumptionDO::getTradeTime)
|
||||
.last("LIMIT 20"));
|
||||
|
||||
// 6. 查询最近6个月的危险评估
|
||||
List<RiskAssessmentDO> recentAssessments = riskAssessmentMapper.selectList(new LambdaQueryWrapper<RiskAssessmentDO>()
|
||||
.eq(RiskAssessmentDO::getPrisonerId, prisonerId)
|
||||
.eq(RiskAssessmentDO::getStatus, 1)
|
||||
.orderByDesc(RiskAssessmentDO::getAssessmentDate)
|
||||
.last("LIMIT 6"));
|
||||
|
||||
// 7. 查询狱情收集(心理访谈记录),按监区查询
|
||||
List<SituationDO> situations = situationMapper.selectList(new LambdaQueryWrapper<SituationDO>()
|
||||
.eq(SituationDO::getAreaId, prisoner.getAreaId())
|
||||
.eq(SituationDO::getStatus, 3) // 已处理
|
||||
.eq(SituationDO::getCategory, 2) // 教育改造类型
|
||||
.orderByDesc(SituationDO::getOccurTime)
|
||||
.last("LIMIT 10"));
|
||||
|
||||
// ==================== 构建中心数据 ====================
|
||||
|
||||
// 左侧数据:本月消费、奖励、惩罚、余额
|
||||
double monthlyReward = 0;
|
||||
double monthlyPenalty = 0;
|
||||
if (currentMonthScore != null) {
|
||||
monthlyReward = currentMonthScore.getRewardScore() != null ? currentMonthScore.getRewardScore().doubleValue() : 0;
|
||||
monthlyPenalty = currentMonthScore.getPenaltyScore() != null ? currentMonthScore.getPenaltyScore().doubleValue() : 0;
|
||||
}
|
||||
vo.setCenterLeftData(PrisonerDashboardStatsRespVO.CenterLeftData.builder()
|
||||
.topValue("0")
|
||||
.topValue(String.valueOf((int) monthlyTotal))
|
||||
.topLabel("本月消费")
|
||||
.middleLeftValue("0")
|
||||
.middleLeftValue(String.valueOf((int) monthlyReward))
|
||||
.middleLeftLabel("本月奖励")
|
||||
.middleRightValue("0")
|
||||
.middleRightValue(String.valueOf((int) monthlyPenalty))
|
||||
.middleRightLabel("本月惩罚")
|
||||
.bottomValue("0")
|
||||
.bottomValue(latestBalance != null ? String.valueOf(latestBalance.intValue()) : "0")
|
||||
.bottomLabel("账户余额")
|
||||
.build());
|
||||
|
||||
vo.setCenterRightData(PrisonerDashboardStatsRespVO.CenterRightData.builder()
|
||||
.topValue("0")
|
||||
.topLabel("本月得分")
|
||||
.middleLeftValue("0")
|
||||
.middleLeftLabel("基础分")
|
||||
.middleRightValue("0")
|
||||
.middleRightLabel("加分项")
|
||||
.bottomLeftValue("0")
|
||||
.bottomLeftLabel("扣分项")
|
||||
.bottomRightValue("良好")
|
||||
.bottomRightLabel("考核等级")
|
||||
.build());
|
||||
// 右侧数据:本月得分、基础分、加分项、扣分项、考核等级
|
||||
String levelText = "良好";
|
||||
if (currentMonthScore != null) {
|
||||
if (currentMonthScore.getLevel() != null) {
|
||||
levelText = switch (currentMonthScore.getLevel()) {
|
||||
case 1 -> "优秀";
|
||||
case 2 -> "良好";
|
||||
case 3 -> "合格";
|
||||
case 4 -> "不合格";
|
||||
default -> "良好";
|
||||
};
|
||||
}
|
||||
vo.setCenterRightData(PrisonerDashboardStatsRespVO.CenterRightData.builder()
|
||||
.topValue(currentMonthScore.getTotalScore() != null ?
|
||||
String.valueOf(currentMonthScore.getTotalScore().intValue()) : "0")
|
||||
.topLabel("本月得分")
|
||||
.middleLeftValue(currentMonthScore.getBaseScore() != null ?
|
||||
String.valueOf(currentMonthScore.getBaseScore().intValue()) : "0")
|
||||
.middleLeftLabel("基础分")
|
||||
.middleRightValue(String.valueOf((int) monthlyReward))
|
||||
.middleRightLabel("加分项")
|
||||
.bottomLeftValue(String.valueOf((int) monthlyPenalty))
|
||||
.bottomLeftLabel("扣分项")
|
||||
.bottomRightValue(levelText)
|
||||
.bottomRightLabel("考核等级")
|
||||
.build());
|
||||
} else {
|
||||
vo.setCenterRightData(PrisonerDashboardStatsRespVO.CenterRightData.builder()
|
||||
.topValue("0")
|
||||
.topLabel("本月得分")
|
||||
.middleLeftValue("0")
|
||||
.middleLeftLabel("基础分")
|
||||
.middleRightValue("0")
|
||||
.middleRightLabel("加分项")
|
||||
.bottomLeftValue("0")
|
||||
.bottomLeftLabel("扣分项")
|
||||
.bottomRightValue("暂无")
|
||||
.bottomRightLabel("考核等级")
|
||||
.build());
|
||||
}
|
||||
|
||||
// 初始化空列表
|
||||
vo.setConsumptionMonthlyData(new ArrayList<>());
|
||||
// ==================== 构建消费月度数据 ====================
|
||||
List<PrisonerDashboardStatsRespVO.MonthlyConsumptionData> monthlyDataList = new ArrayList<>();
|
||||
// 按月份汇总消费
|
||||
Map<String, Double> monthlyConsumptionMap = recentConsumptions.stream()
|
||||
.filter(c -> c.getTradeTime() != null)
|
||||
.collect(Collectors.groupingBy(
|
||||
c -> c.getTradeTime().getYear() + "-" + String.format("%02d", c.getTradeTime().getMonthValue()),
|
||||
Collectors.summingDouble(c -> c.getTotalAmount() != null ? c.getTotalAmount().doubleValue() : 0)
|
||||
));
|
||||
for (Map.Entry<String, Double> entry : monthlyConsumptionMap.entrySet()) {
|
||||
monthlyDataList.add(PrisonerDashboardStatsRespVO.MonthlyConsumptionData.builder()
|
||||
.category(entry.getKey())
|
||||
.perCapita(entry.getValue().intValue())
|
||||
.build());
|
||||
}
|
||||
vo.setConsumptionMonthlyData(monthlyDataList);
|
||||
|
||||
// ==================== 构建计分考核记录 ====================
|
||||
List<PrisonerDashboardStatsRespVO.ScoreRecord> scoreRecords = recentScores.stream()
|
||||
.map(s -> {
|
||||
String level = s.getLevel() != null ? switch (s.getLevel()) {
|
||||
case 1 -> "优秀";
|
||||
case 2 -> "良好";
|
||||
case 3 -> "合格";
|
||||
case 4 -> "不合格";
|
||||
default -> "";
|
||||
} : "";
|
||||
return PrisonerDashboardStatsRespVO.ScoreRecord.builder()
|
||||
.date(s.getYear() + "-" + String.format("%02d", s.getMonth()))
|
||||
.score(s.getTotalScore() != null ? String.valueOf(s.getTotalScore().intValue()) : "0")
|
||||
.scoreType(s.getRewardScore().doubleValue() > 0 ? "加分" : (s.getPenaltyScore().doubleValue() > 0 ? "扣分" : "正常"))
|
||||
.finalScore(s.getTotalScore() != null ? s.getTotalScore().intValue() : 0)
|
||||
.level(level)
|
||||
.levelText(level)
|
||||
.build();
|
||||
})
|
||||
.collect(Collectors.toList());
|
||||
vo.setScoreRecords(scoreRecords);
|
||||
|
||||
// ==================== 构建消费记录 ====================
|
||||
List<PrisonerDashboardStatsRespVO.ConsumptionRecord> consumptionRecords = recentConsumptions.stream()
|
||||
.limit(10)
|
||||
.map(c -> {
|
||||
String typeName = c.getType() == 1 ? "消费" : "存款";
|
||||
return PrisonerDashboardStatsRespVO.ConsumptionRecord.builder()
|
||||
.date(c.getTradeTime() != null ? c.getTradeTime().toLocalDate().toString() : "")
|
||||
.name(typeName)
|
||||
.nameColor(c.getType() == 1 ? "#f56c6c" : "#67c23a")
|
||||
.category("普通消费")
|
||||
.amount(c.getTotalAmount() != null ? c.getTotalAmount().intValue() : 0)
|
||||
.build();
|
||||
})
|
||||
.collect(Collectors.toList());
|
||||
vo.setConsumptionRecords(consumptionRecords);
|
||||
|
||||
// ==================== 构建危险评估记录 ====================
|
||||
List<PrisonerDashboardStatsRespVO.RewardsPunishment> rewardsPunishments = recentAssessments.stream()
|
||||
.map(a -> {
|
||||
return PrisonerDashboardStatsRespVO.RewardsPunishment.builder()
|
||||
.date(a.getAssessmentDate() != null ? a.getAssessmentDate().toString() : "")
|
||||
.type("danger")
|
||||
.typeText("危险评估")
|
||||
.content("暴力倾向:" + (a.getViolenceScore() != null ? a.getViolenceScore() : 0) +
|
||||
" | 脱逃倾向:" + (a.getEscapeScore() != null ? a.getEscapeScore() : 0) +
|
||||
" | 自杀倾向:" + (a.getSuicideScore() != null ? a.getSuicideScore() : 0))
|
||||
.build();
|
||||
})
|
||||
.collect(Collectors.toList());
|
||||
vo.setRewardsPunishments(rewardsPunishments);
|
||||
|
||||
// ==================== 构建心理访谈记录 ====================
|
||||
List<PrisonerDashboardStatsRespVO.InterviewRecord> interviewRecords = situations.stream()
|
||||
.filter(s -> s.getCategory() == 1) // 只取心理访谈类型
|
||||
.map(s -> PrisonerDashboardStatsRespVO.InterviewRecord.builder()
|
||||
.date(s.getOccurTime() != null ? s.getOccurTime().toLocalDate().toString() : "")
|
||||
.content(s.getContent() != null ? s.getContent() : s.getTitle())
|
||||
.build())
|
||||
.collect(Collectors.toList());
|
||||
vo.setInterviewRecords(interviewRecords);
|
||||
|
||||
// ==================== 构建汇款记录 ====================
|
||||
List<PrisonerDashboardStatsRespVO.RemittanceRecord> remittanceRecords = recentConsumptions.stream()
|
||||
.filter(c -> c.getType() == 2) // 存款类型
|
||||
.limit(10)
|
||||
.map(c -> PrisonerDashboardStatsRespVO.RemittanceRecord.builder()
|
||||
.date(c.getTradeTime() != null ? c.getTradeTime().toLocalDate().toString() : "")
|
||||
.name("存款")
|
||||
.nameColor("#409eff")
|
||||
.category("亲属汇款")
|
||||
.amount(c.getTotalAmount() != null ? c.getTotalAmount().intValue() : 0)
|
||||
.build())
|
||||
.collect(Collectors.toList());
|
||||
vo.setRemittanceRecords(remittanceRecords);
|
||||
|
||||
// ==================== 构建关系人信息(模拟数据) ====================
|
||||
List<PrisonerDashboardStatsRespVO.RelationshipInfo> relationships = new ArrayList<>();
|
||||
relationships.add(PrisonerDashboardStatsRespVO.RelationshipInfo.builder()
|
||||
.name("李四")
|
||||
.relate("配偶")
|
||||
.color("#909399")
|
||||
.build());
|
||||
relationships.add(PrisonerDashboardStatsRespVO.RelationshipInfo.builder()
|
||||
.name("张父")
|
||||
.relate("父亲")
|
||||
.color("#909399")
|
||||
.build());
|
||||
vo.setRelationships(relationships);
|
||||
|
||||
// ==================== 消费汇总 ====================
|
||||
vo.setConsumptionSummary(PrisonerDashboardStatsRespVO.ConsumptionSummary.builder()
|
||||
.inProgress(0)
|
||||
.toWarehouse(0)
|
||||
.outWarehouse(0)
|
||||
.build());
|
||||
vo.setInterviewRecords(new ArrayList<>());
|
||||
vo.setRewardsPunishments(new ArrayList<>());
|
||||
vo.setScoreRecords(new ArrayList<>());
|
||||
vo.setConsumptionRecords(new ArrayList<>());
|
||||
vo.setRemittanceRecords(new ArrayList<>());
|
||||
vo.setRelationships(new ArrayList<>());
|
||||
|
||||
return vo;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AiDashEntryStatisticsVO getAiDashEntryStatistics() {
|
||||
AiDashEntryStatisticsVO vo = new AiDashEntryStatisticsVO();
|
||||
LocalDate now = LocalDate.now();
|
||||
LocalDate firstDayOfMonth = now.withDayOfMonth(1);
|
||||
LocalDate firstDayOfLastMonth = now.minusMonths(1).withDayOfMonth(1);
|
||||
|
||||
// 获取所有有心理评估的罪犯的最新评估记录
|
||||
// 风险等级:1-低风险(普通) 2-中风险(预警) 3-高风险(高危) 4-极高风险(高危)
|
||||
List<EvaluationReportDO> allReports = evaluationReportMapper.selectList(new LambdaQueryWrapper<EvaluationReportDO>()
|
||||
.eq(EvaluationReportDO::getStatus, 3) // 已审核
|
||||
.eq(EvaluationReportDO::getEvaluationType, 1) // 心理评估
|
||||
.isNotNull(EvaluationReportDO::getRiskLevel)
|
||||
.orderByDesc(EvaluationReportDO::getEvaluationDate));
|
||||
|
||||
// 按罪犯ID分组,取最新的评估记录
|
||||
Map<Long, EvaluationReportDO> latestReportMap = allReports.stream()
|
||||
.collect(Collectors.toMap(
|
||||
EvaluationReportDO::getPrisonerId,
|
||||
r -> r,
|
||||
(existing, replacement) -> existing // 保留第一个(最新的)
|
||||
));
|
||||
List<EvaluationReportDO> latestReports = new ArrayList<>(latestReportMap.values());
|
||||
|
||||
// 统计各风险等级人数
|
||||
int highRiskCount = 0; // 高危:3-高风险 4-极高风险
|
||||
int warningCount = 0; // 预警:2-中风险
|
||||
int normalCount = 0; // 普通:1-低风险
|
||||
|
||||
for (EvaluationReportDO report : latestReports) {
|
||||
Integer riskLevel = report.getRiskLevel();
|
||||
if (riskLevel == null) continue;
|
||||
switch (riskLevel) {
|
||||
case 3, 4 -> highRiskCount++;
|
||||
case 2 -> warningCount++;
|
||||
case 1 -> normalCount++;
|
||||
}
|
||||
}
|
||||
|
||||
int totalCount = highRiskCount + warningCount + normalCount;
|
||||
vo.setTotalCount(totalCount);
|
||||
vo.setHighRiskCount(highRiskCount);
|
||||
vo.setWarningCount(warningCount);
|
||||
vo.setNormalCount(normalCount);
|
||||
|
||||
// 本月新增统计
|
||||
List<EvaluationReportDO> thisMonthReports = allReports.stream()
|
||||
.filter(r -> r.getEvaluationDate() != null && !r.getEvaluationDate().toLocalDate().isBefore(firstDayOfMonth))
|
||||
.toList();
|
||||
|
||||
// 按罪犯ID分组,取本月第一次评估
|
||||
Map<Long, EvaluationReportDO> thisMonthNewMap = thisMonthReports.stream()
|
||||
.filter(r -> !latestReportMap.containsKey(r.getPrisonerId()) ||
|
||||
latestReportMap.get(r.getPrisonerId()).getEvaluationDate().toLocalDate().isAfter(firstDayOfMonth.minusDays(1)))
|
||||
.collect(Collectors.toMap(
|
||||
EvaluationReportDO::getPrisonerId,
|
||||
r -> r,
|
||||
(existing, replacement) -> existing
|
||||
));
|
||||
|
||||
int monthlyNewHighRisk = 0, monthlyNewWarning = 0, monthlyNewNormal = 0;
|
||||
for (EvaluationReportDO report : thisMonthNewMap.values()) {
|
||||
Integer riskLevel = report.getRiskLevel();
|
||||
if (riskLevel == null) continue;
|
||||
switch (riskLevel) {
|
||||
case 3, 4 -> monthlyNewHighRisk++;
|
||||
case 2 -> monthlyNewWarning++;
|
||||
case 1 -> monthlyNewNormal++;
|
||||
}
|
||||
}
|
||||
|
||||
int monthlyNewCount = monthlyNewHighRisk + monthlyNewWarning + monthlyNewNormal;
|
||||
vo.setMonthlyNewCount(monthlyNewCount);
|
||||
vo.setMonthlyChange(monthlyNewCount);
|
||||
vo.setHighRiskMonthlyNew(monthlyNewHighRisk);
|
||||
vo.setHighRiskMonthlyChange(monthlyNewHighRisk);
|
||||
vo.setWarningMonthlyNew(monthlyNewWarning);
|
||||
vo.setWarningMonthlyChange(monthlyNewWarning);
|
||||
vo.setNormalMonthlyNew(monthlyNewNormal);
|
||||
vo.setNormalMonthlyChange(monthlyNewNormal);
|
||||
|
||||
// 风险等级分布
|
||||
List<AiDashEntryStatisticsVO.RiskDistributionVO> riskDistribution = new ArrayList<>();
|
||||
riskDistribution.add(AiDashEntryStatisticsVO.RiskDistributionVO.builder()
|
||||
.name("普通").value(normalCount).color("#5470c6").build());
|
||||
riskDistribution.add(AiDashEntryStatisticsVO.RiskDistributionVO.builder()
|
||||
.name("预警").value(warningCount).color("#fac858").build());
|
||||
riskDistribution.add(AiDashEntryStatisticsVO.RiskDistributionVO.builder()
|
||||
.name("高危").value(highRiskCount).color("#ee6666").build());
|
||||
vo.setRiskDistribution(riskDistribution);
|
||||
|
||||
// 风险趋势数据(最近7个月)
|
||||
List<AiDashEntryStatisticsVO.RiskTrendVO> riskTrendData = new ArrayList<>();
|
||||
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM");
|
||||
for (int i = 6; i >= 0; i--) {
|
||||
LocalDate month = now.minusMonths(i).withDayOfMonth(1);
|
||||
LocalDate nextMonth = month.plusMonths(1);
|
||||
String monthStr = month.format(formatter);
|
||||
|
||||
// 统计该月末时各风险等级的人数(取该月最后一条评估记录)
|
||||
final LocalDate monthEnd = nextMonth.minusDays(1);
|
||||
List<EvaluationReportDO> monthEndReports = allReports.stream()
|
||||
.filter(r -> r.getEvaluationDate() != null &&
|
||||
!r.getEvaluationDate().toLocalDate().isAfter(monthEnd))
|
||||
.toList();
|
||||
|
||||
Map<Long, EvaluationReportDO> monthEndLatestMap = monthEndReports.stream()
|
||||
.collect(Collectors.toMap(
|
||||
EvaluationReportDO::getPrisonerId,
|
||||
r -> r,
|
||||
(existing, replacement) -> existing
|
||||
));
|
||||
|
||||
int monthHigh = 0, monthWarning = 0, monthNormal = 0;
|
||||
for (EvaluationReportDO report : monthEndLatestMap.values()) {
|
||||
Integer riskLevel = report.getRiskLevel();
|
||||
if (riskLevel == null) continue;
|
||||
switch (riskLevel) {
|
||||
case 3, 4 -> monthHigh++;
|
||||
case 2 -> monthWarning++;
|
||||
case 1 -> monthNormal++;
|
||||
}
|
||||
}
|
||||
|
||||
riskTrendData.add(AiDashEntryStatisticsVO.RiskTrendVO.builder()
|
||||
.month(monthStr)
|
||||
.highRisk(monthHigh)
|
||||
.warning(monthWarning)
|
||||
.normal(monthNormal)
|
||||
.build());
|
||||
}
|
||||
vo.setRiskTrendData(riskTrendData);
|
||||
|
||||
return vo;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PageResult<FocusPersonVO> getFocusPersonPage(FocusPersonPageReqVO reqVO) {
|
||||
// 查询有心理评估的罪犯列表
|
||||
LambdaQueryWrapper<EvaluationReportDO> wrapper = new LambdaQueryWrapper<EvaluationReportDO>()
|
||||
.eq(EvaluationReportDO::getStatus, 3) // 已审核
|
||||
.eq(EvaluationReportDO::getEvaluationType, 1) // 心理评估
|
||||
.isNotNull(EvaluationReportDO::getRiskLevel);
|
||||
|
||||
// 根据风险类型过滤
|
||||
if (StringUtils.hasText(reqVO.getRiskLevelType())) {
|
||||
switch (reqVO.getRiskLevelType()) {
|
||||
case "high" -> wrapper.in(EvaluationReportDO::getRiskLevel, 3, 4);
|
||||
case "warning" -> wrapper.eq(EvaluationReportDO::getRiskLevel, 2);
|
||||
case "normal" -> wrapper.eq(EvaluationReportDO::getRiskLevel, 1);
|
||||
}
|
||||
}
|
||||
|
||||
if (StringUtils.hasText(reqVO.getName())) {
|
||||
wrapper.like(EvaluationReportDO::getPrisonerName, reqVO.getName());
|
||||
}
|
||||
|
||||
if (reqVO.getAreaId() != null) {
|
||||
wrapper.eq(EvaluationReportDO::getAreaId, reqVO.getAreaId());
|
||||
}
|
||||
|
||||
wrapper.orderByDesc(EvaluationReportDO::getEvaluationDate);
|
||||
|
||||
// 获取所有符合条件的记录
|
||||
List<EvaluationReportDO> allReports = evaluationReportMapper.selectList(wrapper);
|
||||
|
||||
// 按罪犯ID去重,保留最新的评估记录
|
||||
Map<Long, EvaluationReportDO> latestReportMap = allReports.stream()
|
||||
.collect(Collectors.toMap(
|
||||
EvaluationReportDO::getPrisonerId,
|
||||
r -> r,
|
||||
(existing, replacement) -> existing
|
||||
));
|
||||
List<EvaluationReportDO> uniqueReports = new ArrayList<>(latestReportMap.values());
|
||||
|
||||
// 手动分页
|
||||
int total = uniqueReports.size();
|
||||
int start = (reqVO.getPageNo() - 1) * reqVO.getPageSize();
|
||||
int end = Math.min(start + reqVO.getPageSize(), total);
|
||||
List<EvaluationReportDO> pagedReports = start < total ? uniqueReports.subList(start, end) : new ArrayList<>();
|
||||
|
||||
// 获取罪犯详细信息
|
||||
List<Long> prisonerIds = pagedReports.stream()
|
||||
.map(EvaluationReportDO::getPrisonerId)
|
||||
.toList();
|
||||
Map<Long, PrisonerDO> prisonerMap = prisonerIds.isEmpty() ? Map.of() :
|
||||
prisonerMapper.selectBatchIds(prisonerIds).stream()
|
||||
.collect(Collectors.toMap(PrisonerDO::getId, p -> p));
|
||||
|
||||
// 获取监区信息
|
||||
List<Long> areaIds = pagedReports.stream()
|
||||
.map(EvaluationReportDO::getAreaId)
|
||||
.filter(id -> id != null)
|
||||
.distinct()
|
||||
.toList();
|
||||
Map<Long, AreaDO> areaMap = areaIds.isEmpty() ? Map.of() :
|
||||
areaMapper.selectBatchIds(areaIds).stream()
|
||||
.collect(Collectors.toMap(AreaDO::getId, a -> a));
|
||||
|
||||
// 判断本月新增
|
||||
LocalDate firstDayOfMonth = LocalDate.now().withDayOfMonth(1);
|
||||
|
||||
// 转换为 VO
|
||||
List<FocusPersonVO> voList = pagedReports.stream()
|
||||
.map(report -> {
|
||||
PrisonerDO prisoner = prisonerMap.get(report.getPrisonerId());
|
||||
String riskLevelType = switch (report.getRiskLevel()) {
|
||||
case 3, 4 -> "high";
|
||||
case 2 -> "warning";
|
||||
default -> "normal";
|
||||
};
|
||||
String riskLevelText = switch (report.getRiskLevel()) {
|
||||
case 4 -> "极高危";
|
||||
case 3 -> "高危";
|
||||
case 2 -> "预警";
|
||||
default -> "普通";
|
||||
};
|
||||
String psychLevel = switch (report.getRiskLevel()) {
|
||||
case 4 -> "一级风险";
|
||||
case 3 -> "一级风险";
|
||||
case 2 -> "二级风险";
|
||||
default -> "三级风险";
|
||||
};
|
||||
|
||||
// 判断是否本月新增
|
||||
boolean isNew = report.getEvaluationDate() != null &&
|
||||
!report.getEvaluationDate().toLocalDate().isBefore(firstDayOfMonth);
|
||||
|
||||
// 获取监区名称
|
||||
String areaName = report.getAreaName();
|
||||
if (!StringUtils.hasText(areaName) && report.getAreaId() != null) {
|
||||
AreaDO area = areaMap.get(report.getAreaId());
|
||||
areaName = area != null ? area.getName() : "未分配";
|
||||
}
|
||||
|
||||
// 计算年龄
|
||||
Integer age = null;
|
||||
if (prisoner != null && prisoner.getBirthDate() != null) {
|
||||
age = Period.between(prisoner.getBirthDate(), LocalDate.now()).getYears();
|
||||
}
|
||||
|
||||
// 获取性别
|
||||
String gender = "未知";
|
||||
if (prisoner != null && prisoner.getGender() != null) {
|
||||
gender = GenderEnum.MALE.getValue().equals(prisoner.getGender().getValue()) ? "男" : "女";
|
||||
}
|
||||
|
||||
return FocusPersonVO.builder()
|
||||
.id(report.getPrisonerId())
|
||||
.name(report.getPrisonerName())
|
||||
.gender(gender)
|
||||
.age(age)
|
||||
.riskLevelType(riskLevelType)
|
||||
.riskLevel(riskLevelText)
|
||||
.supervisionArea(areaName)
|
||||
.psychologicalRiskLevel(psychLevel)
|
||||
.isNew(isNew)
|
||||
.build();
|
||||
})
|
||||
.toList();
|
||||
|
||||
return new PageResult<>(voList, (long) total);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -117,7 +117,8 @@ public class RiskServiceImpl implements RiskService {
|
||||
RiskDO risk = new RiskDO();
|
||||
risk.setPrisonerId(prisoner.getId());
|
||||
risk.setPrisonerNo(prisoner.getPrisonerNo());
|
||||
risk.setRiskScore(importVO.getRiskScore() != null ? importVO.getRiskScore() : BigDecimal.ZERO);
|
||||
risk.setPrisonerName(prisoner.getName()); // 设置罪犯姓名
|
||||
risk.setRiskScore(importVO.getRiskScore() != null ? importVO.getRiskScore().intValue() : 0);
|
||||
risk.setRiskLevel(importVO.getRiskLevel());
|
||||
risk.setRiskDescription(importVO.getRiskDescription());
|
||||
risk.setRiskFactors(importVO.getRiskFactors());
|
||||
|
||||
@ -146,6 +146,7 @@ public class ScoreServiceImpl implements ScoreService {
|
||||
|
||||
ScoreDO score = new ScoreDO();
|
||||
score.setPrisonerId(prisoner.getId());
|
||||
score.setPrisonerNo(prisoner.getPrisonerNo());
|
||||
score.setPrisonAreaId(prisoner.getPrisonAreaId());
|
||||
score.setPrisonCellId(prisoner.getPrisonCellId());
|
||||
score.setYear(importVO.getYear());
|
||||
|
||||
@ -119,7 +119,7 @@ public class SituationServiceImpl implements SituationService {
|
||||
|
||||
SituationDO situation = new SituationDO();
|
||||
situation.setTitle(importVO.getTitle());
|
||||
situation.setType(importVO.getType());
|
||||
situation.setType(importVO.getType() != null ? String.valueOf(importVO.getType()) : null);
|
||||
situation.setLevel(importVO.getLevel());
|
||||
situation.setContent(importVO.getContent());
|
||||
situation.setLocation(importVO.getLocation());
|
||||
|
||||
@ -34,6 +34,9 @@
|
||||
<result property="prisonAreaId" column="prison_area_id"/>
|
||||
<result property="subAreaId" column="sub_area_id"/>
|
||||
<result property="prisonCellId" column="prison_cell_id"/>
|
||||
<result property="maritalStatus" column="marital_status"/>
|
||||
<result property="crimeType" column="crime_type"/>
|
||||
<result property="sentence" column="sentence"/>
|
||||
<result property="status" column="status"/>
|
||||
<result property="remark" column="remark"/>
|
||||
<result property="creator" column="creator"/>
|
||||
@ -65,4 +68,13 @@
|
||||
AND prison_area_id = #{areaId}
|
||||
</select>
|
||||
|
||||
<!-- 根据罪犯编号查询 -->
|
||||
<select id="selectByPrisonerNo" resultMap="BaseResultMap">
|
||||
SELECT *
|
||||
FROM prison_prisoner
|
||||
WHERE deleted = 0
|
||||
AND prisoner_no = #{prisonerNo}
|
||||
LIMIT 1
|
||||
</select>
|
||||
|
||||
</mapper>
|
||||
|
||||
@ -0,0 +1,36 @@
|
||||
-- 菜单 SQL - AI心航360°
|
||||
-- 请根据实际的父菜单ID调整 parent_id
|
||||
|
||||
-- 菜单: AI心航360° (类型: 菜单)
|
||||
INSERT INTO system_menu(
|
||||
name, permission, type, sort, parent_id,
|
||||
path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted
|
||||
)
|
||||
VALUES (
|
||||
'AI心航360°', '', 2, 0, 0,
|
||||
'ai-dash-entry', 'ep:data-analysis', 'views/DashEntry/DashEntry', 'AiDashEntry',
|
||||
0, true, true, true, '1', NOW(), '1', NOW(), '0'
|
||||
);
|
||||
|
||||
-- 获取刚插入的菜单ID
|
||||
SET @menuId = LAST_INSERT_ID();
|
||||
|
||||
-- 按钮: 查询 (类型: 按钮)
|
||||
INSERT INTO system_menu(
|
||||
name, permission, type, sort, parent_id,
|
||||
path, icon, component, component_name, status, visible, keep_alive, always_show, creator, create_time, updater, update_time, deleted
|
||||
)
|
||||
VALUES (
|
||||
'查询', 'prison:ai-dash-entry:query', 3, 1, @menuId,
|
||||
'', '', '', NULL, 0, true, true, true, '1', NOW(), '1', NOW(), '0'
|
||||
);
|
||||
|
||||
-- 如果需要将菜单放到监狱管理下面,请执行以下SQL更新parent_id
|
||||
-- 假设监狱管理的菜单ID是2600,请根据实际情况调整
|
||||
-- UPDATE system_menu SET parent_id = 2600 WHERE id = @menuId;
|
||||
|
||||
-- =====================================================
|
||||
-- 如果你的系统使用租户,还需要插入 system_tenant_menu
|
||||
-- =====================================================
|
||||
-- INSERT INTO system_tenant_menu(tenant_id, menu_id) VALUES (1, @menuId);
|
||||
-- INSERT INTO system_tenant_menu(tenant_id, menu_id) VALUES (1, @menuId + 1);
|
||||
@ -370,11 +370,18 @@ INSERT INTO system_menu (name, permission, type, sort, parent_id, path, icon, co
|
||||
VALUES ('狱情收集导出', 'prison:situation:export', 3, 5, @situationParentId, '', '', '', 0);
|
||||
|
||||
-- =====================================================
|
||||
-- 10. 数据结构迁移 SQL (2026-01-14)
|
||||
-- 10. 数据结构迁移 SQL (2026-01-20)
|
||||
-- =====================================================
|
||||
-- 移除 prison_prisoner 表中的 sub_area_id 字段
|
||||
-- 补充 prison_prisoner 表缺失字段
|
||||
-- 执行此迁移前请备份数据库
|
||||
ALTER TABLE `prison_prisoner` DROP COLUMN IF EXISTS `sub_area_id`;
|
||||
ALTER TABLE `prison_prisoner`
|
||||
ADD COLUMN IF NOT EXISTS `release_type` tinyint DEFAULT 0 COMMENT '释放类型:0-未知 1-刑满释放 2-假释 3-保外就医 4-减刑 5-暂予监外执行 6-特赦 7-死亡 8-其他',
|
||||
ADD COLUMN IF NOT EXISTS `release_reason` varchar(500) DEFAULT NULL COMMENT '释放原因',
|
||||
ADD COLUMN IF NOT EXISTS `photo` varchar(512) DEFAULT NULL COMMENT '照片URL',
|
||||
ADD COLUMN IF NOT EXISTS `sub_area_id` bigint DEFAULT NULL COMMENT '分区ID',
|
||||
ADD COLUMN IF NOT EXISTS `marital_status` tinyint DEFAULT NULL COMMENT '婚姻状态:1-未婚 2-已婚 3-离异 4-丧偶',
|
||||
ADD COLUMN IF NOT EXISTS `crime_type` varchar(100) DEFAULT NULL COMMENT '罪名类型',
|
||||
ADD COLUMN IF NOT EXISTS `sentence` varchar(100) DEFAULT NULL COMMENT '刑期';
|
||||
|
||||
-- =====================================================
|
||||
-- 10. 字典数据 SQL
|
||||
|
||||
@ -0,0 +1,12 @@
|
||||
-- =====================================================
|
||||
-- 升级脚本:添加 prison_situation 表的 location 字段
|
||||
-- 执行时间:2026-01-20
|
||||
-- 原因:SituationDO 实体类有 location 字段,但数据库表缺少该字段
|
||||
-- =====================================================
|
||||
|
||||
-- 添加 location 字段(地点)
|
||||
ALTER TABLE `prison_situation`
|
||||
ADD COLUMN `location` varchar(200) DEFAULT NULL COMMENT '地点' AFTER `occur_time`;
|
||||
|
||||
-- 验证字段是否添加成功
|
||||
-- SELECT `location` FROM `prison_situation` LIMIT 1;
|
||||
0
yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/mq/producer/mail/MailProducer.java
Normal file → Executable file
0
yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/mq/producer/mail/MailProducer.java
Normal file → Executable file
0
yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/mq/producer/sms/SmsProducer.java
Normal file → Executable file
0
yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/mq/producer/sms/SmsProducer.java
Normal file → Executable file
Loading…
x
Reference in New Issue
Block a user