Compare commits

...

3 Commits

Author SHA1 Message Date
6063256883 fix: 优化评估报告模块权限控制
- 查询接口支持多权限验证(template:query, report:query)
- 维度CRUD操作统一使用 template:update 权限
- 维度数据CRUD操作统一使用 report:update 权限

🤖 Generated with [Claude Code](https://claude.com/claude-code)
2026-01-21 00:49:12 +08:00
76bdb3a931 feat: 新增AI监控仪表盘功能和监管对象位置字段
- 新增AI监控仪表盘相关接口(监狱概况统计、重点人员查询)
- 新增监管对象位置字段(province/city/district)到各DO实体
- 新增重点人员页面相关VO(FocusPersonPageReqVO、FocusPersonVO)
- 新增AI监控入口菜单SQL脚本
- 新增监管对象位置升级SQL脚本
- 完善监控仪表盘服务实现(实时数据、统计分析、风险预警)

Co-Authored-By: Claude <noreply@anthropic.com>
2026-01-21 00:17:53 +08:00
0984924431 chore: 提交本地修改后更新子模块 2026-01-20 20:58:33 +08:00
79 changed files with 2277 additions and 79 deletions

View File

@ -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>

View File

@ -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 '创建者',

View File

@ -15,6 +15,8 @@ import java.util.*;
import java.io.IOException;
import cn.iocoder.yudao.framework.common.pojo.PageParam;
import cn.iocoder.yudao.module.prison.controller.admin.vo.ImportRespVO;
import org.springframework.web.multipart.MultipartFile;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
@ -108,4 +110,31 @@ public class PrisonConsumptionController {
ExcelUtils.write(response, "消费订单.xls", "数据", ConsumptionRespVO.class, list);
}
@GetMapping("/get-import-template")
@Operation(summary = "获取消费记录导入模板")
public void getImportTemplate(HttpServletResponse response) throws IOException {
// 手动创建导出 demo
List<ConsumptionImportExcelVO> list = Arrays.asList(
ConsumptionImportExcelVO.builder()
.prisonerNo("ZF20230001")
.type(1)
.totalAmount(new java.math.BigDecimal("50.00"))
.tradeTime("2024-01-15 10:30:00")
.status(1)
.remark("示例数据")
.build()
);
// 输出
ExcelUtils.write(response, "消费记录导入模板.xls", "消费记录", ConsumptionImportExcelVO.class, list);
}
@PostMapping("/import")
@Operation(summary = "导入消费记录")
@PreAuthorize("@ss.hasPermission('prison:consumption:import')")
public CommonResult<ImportRespVO> importExcel(@RequestParam("file") MultipartFile file) throws Exception {
List<ConsumptionImportExcelVO> list = ExcelUtils.read(file, ConsumptionImportExcelVO.class);
ImportRespVO respVO = consumptionService.importConsumption(list);
return success(respVO);
}
}

View File

@ -0,0 +1,40 @@
package cn.iocoder.yudao.module.prison.controller.admin.consumption.vo;
import cn.idev.excel.annotation.ExcelProperty;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.math.BigDecimal;
/**
* 消费记录导入 Excel VO
*/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
@Schema(description = "消费记录导入 Excel VO")
public class ConsumptionImportExcelVO {
@ExcelProperty("罪犯编号")
private String prisonerNo;
@ExcelProperty("类型(1-购物 2-餐饮 3-医疗 4-通讯 5-其他)")
private Integer type;
@ExcelProperty("订单总金额")
private BigDecimal totalAmount;
@ExcelProperty("交易时间(yyyy-MM-dd HH:mm:ss)")
private String tradeTime;
@ExcelProperty("状态(1-成功 2-失败)")
private Integer status;
@ExcelProperty("备注")
private String remark;
}

View File

@ -1,15 +1,22 @@
package cn.iocoder.yudao.module.prison.controller.admin.dashboard;
import cn.iocoder.yudao.module.prison.controller.admin.dashboard.vo.DashboardStatisticsVO;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
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;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
/**
* 管理后台 - 监管看板
*
@ -30,4 +37,26 @@ public class PrisonDashboardController {
return dashboardService.getDashboardStatistics();
}
@GetMapping("/prisoner-stats")
@Operation(summary = "获取罪犯工作台统计数据")
@Parameter(name = "prisonerId", description = "罪犯ID", required = true, example = "1")
@PreAuthorize("@ss.hasPermission('prison:dashboard:query')")
public CommonResult<PrisonerDashboardStatsRespVO> getPrisonerStats(@RequestParam("prisonerId") Long prisonerId) {
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));
}
}

View File

@ -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;
}
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -0,0 +1,222 @@
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;
/**
* 罪犯工作台统计响应 VO
*/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
@Schema(description = "管理后台 - 罪犯工作台统计 Response VO")
public class PrisonerDashboardStatsRespVO {
@Schema(description = "罪犯姓名", example = "张三")
private String prisonerName;
@Schema(description = "监区信息", example = "一监区一分监区")
private String prisonArea;
@Schema(description = "罪犯编号", example = "ZF20230001")
private String prisonerNo;
@Schema(description = "入狱时间", example = "2023-01-15")
private String imprisonmentDate;
@Schema(description = "出狱时间", example = "2028-01-14")
private String releaseDate;
@Schema(description = "已服刑天数", example = "365")
private Integer servedDays;
@Schema(description = "年龄", example = "35")
private Integer age;
@Schema(description = "籍贯", example = "浙江省杭州市")
private String nativePlace;
@Schema(description = "文化程度", example = "大专")
private String education;
@Schema(description = "婚姻状况", example = "已婚")
private String maritalStatus;
@Schema(description = "子女情况", example = "一子一女")
private String children;
@Schema(description = "出生日期", example = "1990-05-20")
private String birthDate;
@Schema(description = "犯罪类型", example = "盗窃罪")
private String crimeType;
@Schema(description = "前科次数", example = "0")
private String previousConvictions;
@Schema(description = "刑期", example = "5年")
private String sentence;
@Schema(description = "风险评估分", example = "35")
private Integer riskScore;
@Schema(description = "风险等级1-低风险 2-中风险 3-高风险 4-极高风险", example = "1")
private Integer riskLevel;
@Schema(description = "中心左侧数据")
private CenterLeftData centerLeftData;
@Schema(description = "中心右侧数据")
private CenterRightData centerRightData;
@Schema(description = "月度消费数据")
private List<MonthlyConsumptionData> consumptionMonthlyData;
@Schema(description = "消费汇总")
private ConsumptionSummary consumptionSummary;
@Schema(description = "心理访谈记录")
private List<InterviewRecord> interviewRecords;
@Schema(description = "近期奖惩记录")
private List<RewardsPunishment> rewardsPunishments;
@Schema(description = "计分考核记录")
private List<ScoreRecord> scoreRecords;
@Schema(description = "消费记录")
private List<ConsumptionRecord> consumptionRecords;
@Schema(description = "汇款记录")
private List<RemittanceRecord> remittanceRecords;
@Schema(description = "关系人信息")
private List<RelationshipInfo> relationships;
// ==================== 内部类定义 ====================
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public static class CenterLeftData {
private String topValue;
private String topLabel;
private String middleLeftValue;
private String middleLeftLabel;
private String middleRightValue;
private String middleRightLabel;
private String bottomValue;
private String bottomLabel;
}
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public static class CenterRightData {
private String topValue;
private String topLabel;
private String middleLeftValue;
private String middleLeftLabel;
private String middleRightValue;
private String middleRightLabel;
private String bottomLeftValue;
private String bottomLeftLabel;
private String bottomRightValue;
private String bottomRightLabel;
}
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public static class MonthlyConsumptionData {
private String category;
private Integer monthlyStandard;
private Integer perCapita;
}
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public static class ConsumptionSummary {
private Integer inProgress;
private Integer toWarehouse;
private Integer outWarehouse;
}
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public static class InterviewRecord {
private String date;
private String content;
}
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public static class RewardsPunishment {
private String date;
private String type;
private String typeText;
private String content;
}
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public static class ScoreRecord {
private String date;
private String score;
private String scoreType;
private Integer finalScore;
private String level;
private String levelText;
}
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public static class ConsumptionRecord {
private String date;
private String name;
private String nameColor;
private String category;
private Integer amount;
}
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public static class RemittanceRecord {
private String date;
private String name;
private String nameColor;
private String category;
private Integer amount;
}
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public static class RelationshipInfo {
private String name;
private String relate;
private String color;
}
}

View File

@ -81,7 +81,7 @@ public class EvaluationReportController {
@GetMapping("/template/get")
@Operation(summary = "获得评估模板")
@Parameter(name = "id", description = "编号", required = true, example = "1024")
@PreAuthorize("@ss.hasPermission('prison:evaluation-report:template:query')")
@PreAuthorize("@ss.hasAnyPermissions('prison:evaluation-report:template:query', 'prison:evaluation-report:report:query')")
public CommonResult<EvaluationTemplateRespVO> getTemplate(@RequestParam("id") Long id) {
EvaluationTemplateDO template = evaluationReportService.getTemplate(id);
return success(BeanUtils.toBean(template, EvaluationTemplateRespVO.class));
@ -89,7 +89,7 @@ public class EvaluationReportController {
@GetMapping("/template/page")
@Operation(summary = "获得评估模板分页")
@PreAuthorize("@ss.hasPermission('prison:evaluation-report:template:query')")
@PreAuthorize("@ss.hasAnyPermissions('prison:evaluation-report:template:query', 'prison:evaluation-report:report:query')")
public CommonResult<PageResult<EvaluationTemplateRespVO>> getTemplatePage(@Valid EvaluationTemplatePageReqVO pageReqVO) {
PageResult<EvaluationTemplateDO> pageResult = evaluationReportService.getTemplatePage(pageReqVO);
// 转换为 VO 并填充枚举名称
@ -124,7 +124,7 @@ public class EvaluationReportController {
@GetMapping("/template/list-enabled")
@Operation(summary = "获取启用的模板列表")
@PreAuthorize("@ss.hasPermission('prison:evaluation-report:template:query')")
@PreAuthorize("@ss.hasAnyPermissions('prison:evaluation-report:template:query', 'prison:evaluation-report:report:query')")
public CommonResult<List<EvaluationTemplateRespVO>> getEnabledTemplateList() {
List<EvaluationTemplateDO> list = evaluationReportService.getEnabledTemplateList();
return success(BeanUtils.toBean(list, EvaluationTemplateRespVO.class));
@ -146,14 +146,14 @@ public class EvaluationReportController {
@PostMapping("/dimension/create")
@Operation(summary = "创建评估维度")
@PreAuthorize("@ss.hasPermission('prison:evaluation-report:dimension:create')")
@PreAuthorize("@ss.hasPermission('prison:evaluation-report:template:update')")
public CommonResult<Long> createDimension(@Valid @RequestBody EvaluationDimensionSaveReqVO createReqVO) {
return success(evaluationReportService.createDimension(createReqVO));
}
@PutMapping("/dimension/update")
@Operation(summary = "更新评估维度")
@PreAuthorize("@ss.hasPermission('prison:evaluation-report:dimension:update')")
@PreAuthorize("@ss.hasPermission('prison:evaluation-report:template:update')")
public CommonResult<Boolean> updateDimension(@Valid @RequestBody EvaluationDimensionSaveReqVO updateReqVO) {
evaluationReportService.updateDimension(updateReqVO);
return success(true);
@ -162,7 +162,7 @@ public class EvaluationReportController {
@DeleteMapping("/dimension/delete")
@Operation(summary = "删除评估维度")
@Parameter(name = "id", description = "编号", required = true)
@PreAuthorize("@ss.hasPermission('prison:evaluation-report:dimension:delete')")
@PreAuthorize("@ss.hasPermission('prison:evaluation-report:template:update')")
public CommonResult<Boolean> deleteDimension(@NotNull(message = "编号不能为空") @RequestParam("id") Long id) {
evaluationReportService.deleteDimension(id);
return success(true);
@ -171,7 +171,7 @@ public class EvaluationReportController {
@DeleteMapping("/dimension/delete-list")
@Operation(summary = "批量删除评估维度")
@Parameter(name = "ids", description = "编号", required = true)
@PreAuthorize("@ss.hasPermission('prison:evaluation-report:dimension:delete')")
@PreAuthorize("@ss.hasPermission('prison:evaluation-report:template:update')")
public CommonResult<Boolean> deleteDimensionList(@NotEmpty(message = "编号列表不能为空") @RequestParam("ids") List<Long> ids) {
evaluationReportService.deleteDimensionListByIds(ids);
return success(true);
@ -180,7 +180,7 @@ public class EvaluationReportController {
@GetMapping("/dimension/get")
@Operation(summary = "获得评估维度")
@Parameter(name = "id", description = "编号", required = true, example = "1024")
@PreAuthorize("@ss.hasPermission('prison:evaluation-report:dimension:query')")
@PreAuthorize("@ss.hasAnyPermissions('prison:evaluation-report:template:query', 'prison:evaluation-report:report:query')")
public CommonResult<EvaluationDimensionRespVO> getDimension(@RequestParam("id") Long id) {
EvaluationDimensionDO dimension = evaluationReportService.getDimension(id);
return success(BeanUtils.toBean(dimension, EvaluationDimensionRespVO.class));
@ -188,7 +188,7 @@ public class EvaluationReportController {
@GetMapping("/dimension/page")
@Operation(summary = "获得评估维度分页")
@PreAuthorize("@ss.hasPermission('prison:evaluation-report:dimension:query')")
@PreAuthorize("@ss.hasAnyPermissions('prison:evaluation-report:template:query', 'prison:evaluation-report:report:query')")
public CommonResult<PageResult<EvaluationDimensionRespVO>> getDimensionPage(@Valid EvaluationDimensionPageReqVO pageReqVO) {
PageResult<EvaluationDimensionDO> pageResult = evaluationReportService.getDimensionPage(pageReqVO);
return success(BeanUtils.toBean(pageResult, EvaluationDimensionRespVO.class));
@ -197,7 +197,7 @@ public class EvaluationReportController {
@GetMapping("/dimension/list-by-template")
@Operation(summary = "根据模板ID获取维度列表")
@Parameter(name = "templateId", description = "模板ID", required = true)
@PreAuthorize("@ss.hasPermission('prison:evaluation-report:dimension:query')")
@PreAuthorize("@ss.hasAnyPermissions('prison:evaluation-report:template:query', 'prison:evaluation-report:report:query')")
public CommonResult<List<EvaluationDimensionRespVO>> getDimensionsByTemplateId(@RequestParam("templateId") Long templateId) {
List<EvaluationDimensionDO> list = evaluationReportService.getDimensionsByTemplateId(templateId);
return success(BeanUtils.toBean(list, EvaluationDimensionRespVO.class));
@ -207,7 +207,7 @@ public class EvaluationReportController {
@Operation(summary = "获取维度数据源")
@Parameter(name = "dimensionId", description = "维度ID", required = true)
@Parameter(name = "prisonerId", description = "罪犯ID", required = true)
@PreAuthorize("@ss.hasPermission('prison:evaluation-report:dimension:query')")
@PreAuthorize("@ss.hasAnyPermissions('prison:evaluation-report:template:query', 'prison:evaluation-report:report:query')")
public CommonResult<DimensionDataSourcesRespDTO> getDimensionDataSources(
@RequestParam("dimensionId") Long dimensionId,
@RequestParam("prisonerId") Long prisonerId) {
@ -221,7 +221,7 @@ public class EvaluationReportController {
@Parameter(name = "prisonerId", description = "罪犯ID", required = true)
@Parameter(name = "customPrompt", description = "自定义提示词(可选)")
@Parameter(name = "systemPrompt", description = "系统提示词(可选)")
@PreAuthorize("@ss.hasPermission('prison:evaluation-report:dimension:create')")
@PreAuthorize("@ss.hasAnyPermissions('prison:evaluation-report:template:update', 'prison:evaluation-report:report:update')")
public SseEmitter streamGenerateDimension(
@RequestParam("dimensionId") Long dimensionId,
@RequestParam("prisonerId") Long prisonerId,
@ -268,7 +268,7 @@ public class EvaluationReportController {
@GetMapping("/report/get")
@Operation(summary = "获得评估报告")
@Parameter(name = "id", description = "编号", required = true, example = "1024")
@PreAuthorize("@ss.hasPermission('prison:evaluation-report:report:query')")
@PreAuthorize("@ss.hasAnyPermissions('prison:evaluation-report:report:query', 'prison:evaluation-report:template:query')")
public CommonResult<EvaluationReportRespVO> getReport(@RequestParam("id") Long id) {
EvaluationReportDO report = evaluationReportService.getReport(id);
return success(BeanUtils.toBean(report, EvaluationReportRespVO.class));
@ -276,7 +276,7 @@ public class EvaluationReportController {
@GetMapping("/report/page")
@Operation(summary = "获得评估报告分页")
@PreAuthorize("@ss.hasPermission('prison:evaluation-report:report:query')")
@PreAuthorize("@ss.hasAnyPermissions('prison:evaluation-report:report:query', 'prison:evaluation-report:template:query')")
public CommonResult<PageResult<EvaluationReportRespVO>> getReportPage(@Valid EvaluationReportPageReqVO pageReqVO) {
PageResult<EvaluationReportDO> pageResult = evaluationReportService.getReportPage(pageReqVO);
return success(BeanUtils.toBean(pageResult, EvaluationReportRespVO.class));
@ -285,7 +285,7 @@ public class EvaluationReportController {
@GetMapping("/report/get-by-report-no")
@Operation(summary = "根据报告编号获取报告")
@Parameter(name = "reportNo", description = "报告编号", required = true)
@PreAuthorize("@ss.hasPermission('prison:evaluation-report:report:query')")
@PreAuthorize("@ss.hasAnyPermissions('prison:evaluation-report:report:query', 'prison:evaluation-report:template:query')")
public CommonResult<EvaluationReportRespVO> getReportByReportNo(@RequestParam("reportNo") String reportNo) {
EvaluationReportDO report = evaluationReportService.getReportByReportNo(reportNo);
return success(BeanUtils.toBean(report, EvaluationReportRespVO.class));
@ -294,7 +294,7 @@ public class EvaluationReportController {
@GetMapping("/report/list-by-prisoner")
@Operation(summary = "根据罪犯ID获取报告列表")
@Parameter(name = "prisonerId", description = "罪犯ID", required = true)
@PreAuthorize("@ss.hasPermission('prison:evaluation-report:report:query')")
@PreAuthorize("@ss.hasAnyPermissions('prison:evaluation-report:report:query', 'prison:evaluation-report:template:query')")
public CommonResult<List<EvaluationReportRespVO>> getReportsByPrisonerId(@RequestParam("prisonerId") Long prisonerId) {
List<EvaluationReportDO> list = evaluationReportService.getReportsByPrisonerId(prisonerId);
return success(BeanUtils.toBean(list, EvaluationReportRespVO.class));
@ -340,14 +340,14 @@ public class EvaluationReportController {
@PostMapping("/dimension-data/create")
@Operation(summary = "创建维度数据")
@PreAuthorize("@ss.hasPermission('prison:evaluation-report:dimension-data:create')")
@PreAuthorize("@ss.hasPermission('prison:evaluation-report:report:update')")
public CommonResult<Long> createDimensionData(@Valid @RequestBody EvaluationDimensionDataSaveReqVO createReqVO) {
return success(evaluationReportService.createDimensionData(createReqVO));
}
@PutMapping("/dimension-data/update")
@Operation(summary = "更新维度数据")
@PreAuthorize("@ss.hasPermission('prison:evaluation-report:dimension-data:update')")
@PreAuthorize("@ss.hasPermission('prison:evaluation-report:report:update')")
public CommonResult<Boolean> updateDimensionData(@Valid @RequestBody EvaluationDimensionDataSaveReqVO updateReqVO) {
evaluationReportService.updateDimensionData(updateReqVO);
return success(true);
@ -356,7 +356,7 @@ public class EvaluationReportController {
@DeleteMapping("/dimension-data/delete")
@Operation(summary = "删除维度数据")
@Parameter(name = "id", description = "编号", required = true)
@PreAuthorize("@ss.hasPermission('prison:evaluation-report:dimension-data:delete')")
@PreAuthorize("@ss.hasPermission('prison:evaluation-report:report:update')")
public CommonResult<Boolean> deleteDimensionData(@NotNull(message = "编号不能为空") @RequestParam("id") Long id) {
evaluationReportService.deleteDimensionData(id);
return success(true);
@ -365,7 +365,7 @@ public class EvaluationReportController {
@GetMapping("/dimension-data/list-by-report")
@Operation(summary = "根据报告ID获取维度数据列表")
@Parameter(name = "reportId", description = "报告ID", required = true)
@PreAuthorize("@ss.hasPermission('prison:evaluation-report:dimension-data:query')")
@PreAuthorize("@ss.hasAnyPermissions('prison:evaluation-report:report:query', 'prison:evaluation-report:template:query')")
public CommonResult<List<EvaluationDimensionDataRespVO>> getDimensionDataListByReportId(@RequestParam("reportId") Long reportId) {
List<EvaluationDimensionDataDO> list = evaluationReportService.getDimensionDataListByReportId(reportId);
return success(BeanUtils.toBean(list, EvaluationDimensionDataRespVO.class));

View File

@ -1,9 +1,11 @@
package cn.iocoder.yudao.module.prison.controller.admin.risk;
import java.util.*;
import java.io.IOException;
import java.time.LocalDateTime;
import cn.iocoder.yudao.module.prison.controller.admin.risk.vo.*;
import cn.iocoder.yudao.module.prison.controller.admin.vo.ImportRespVO;
import cn.iocoder.yudao.module.prison.dal.dataobject.risk.RiskDO;
import cn.iocoder.yudao.module.prison.service.risk.RiskService;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
@ -11,6 +13,7 @@ import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.pojo.PageParam;
import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.multipart.MultipartFile;
import cn.iocoder.yudao.module.prison.convert.risk.RiskConvert;
import io.swagger.v3.oas.annotations.Operation;
@ -100,4 +103,34 @@ public class RiskController {
RiskConvert.INSTANCE.convertList(list));
}
@GetMapping("/get-import-template")
@Operation(summary = "获取风险评估导入模板")
public void getImportTemplate(HttpServletResponse response) throws IOException {
// 手动创建导出 demo
List<RiskImportExcelVO> list = Arrays.asList(
RiskImportExcelVO.builder()
.prisonerNo("ZF20230001")
.assessmentDate("2024-01-15")
.riskScore(new java.math.BigDecimal("45"))
.riskLevel(2)
.riskDescription("中等风险人员")
.riskFactors("有脱逃倾向,近期情绪异常")
.suggestions("加强监管,定期心理疏导")
.assessorName("王警官")
.remark("示例数据")
.build()
);
// 输出
ExcelUtils.write(response, "风险评估导入模板.xls", "风险评估", RiskImportExcelVO.class, list);
}
@PostMapping("/import")
@Operation(summary = "导入风险评估")
@PreAuthorize("@ss.hasPermission('prison:risk:import')")
public CommonResult<ImportRespVO> importExcel(@RequestParam("file") MultipartFile file) throws Exception {
List<RiskImportExcelVO> list = ExcelUtils.read(file, RiskImportExcelVO.class);
ImportRespVO respVO = riskService.importRisk(list);
return success(respVO);
}
}

View File

@ -0,0 +1,49 @@
package cn.iocoder.yudao.module.prison.controller.admin.risk.vo;
import cn.idev.excel.annotation.ExcelProperty;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.math.BigDecimal;
/**
* 风险评估导入 Excel VO
*/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
@Schema(description = "风险评估导入 Excel VO")
public class RiskImportExcelVO {
@ExcelProperty("罪犯编号")
private String prisonerNo;
@ExcelProperty("评估日期(yyyy-MM-dd)")
private String assessmentDate;
@ExcelProperty("风险分数")
private BigDecimal riskScore;
@ExcelProperty("风险等级(1-低风险 2-中风险 3-高风险 4-极高风险)")
private Integer riskLevel;
@ExcelProperty("风险描述")
private String riskDescription;
@ExcelProperty("风险因素")
private String riskFactors;
@ExcelProperty("管控建议")
private String suggestions;
@ExcelProperty("评估人姓名")
private String assessorName;
@ExcelProperty("备注")
private String remark;
}

View File

@ -1,15 +1,18 @@
package cn.iocoder.yudao.module.prison.controller.admin.riskassessment;
import java.util.*;
import java.io.IOException;
import java.time.LocalDateTime;
import cn.iocoder.yudao.module.prison.controller.admin.riskassessment.vo.*;
import cn.iocoder.yudao.module.prison.controller.admin.vo.ImportRespVO;
import cn.iocoder.yudao.module.prison.service.riskassessment.RiskAssessmentService;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.pojo.PageParam;
import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.multipart.MultipartFile;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
@ -99,4 +102,36 @@ public class RiskAssessmentController {
}
}
@GetMapping("/get-import-template")
@Operation(summary = "获取危险评估导入模板")
public void getImportTemplate(HttpServletResponse response) throws IOException {
// 手动创建导出 demo
List<RiskAssessmentImportExcelVO> list = Arrays.asList(
RiskAssessmentImportExcelVO.builder()
.prisonerNo("ZF20230001")
.assessmentType(1)
.assessmentDate("2024-01-15")
.violenceScore(new java.math.BigDecimal("20"))
.escapeScore(new java.math.BigDecimal("15"))
.suicideScore(new java.math.BigDecimal("10"))
.totalScore(new java.math.BigDecimal("45"))
.riskLevel(2)
.riskFactors("有暴力倾向")
.suggestions("加强监管")
.assessorName("李警官")
.build()
);
// 输出
ExcelUtils.write(response, "危险评估导入模板.xls", "危险评估", RiskAssessmentImportExcelVO.class, list);
}
@PostMapping("/import")
@Operation(summary = "导入危险评估")
@PreAuthorize("@ss.hasPermission('prison:risk-assessment:import')")
public CommonResult<ImportRespVO> importExcel(@RequestParam("file") MultipartFile file) throws Exception {
List<RiskAssessmentImportExcelVO> list = ExcelUtils.read(file, RiskAssessmentImportExcelVO.class);
ImportRespVO respVO = riskAssessmentService.importRiskAssessment(list);
return success(respVO);
}
}

View File

@ -0,0 +1,55 @@
package cn.iocoder.yudao.module.prison.controller.admin.riskassessment.vo;
import cn.idev.excel.annotation.ExcelProperty;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.math.BigDecimal;
/**
* 危险评估导入 Excel VO
*/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
@Schema(description = "危险评估导入 Excel VO")
public class RiskAssessmentImportExcelVO {
@ExcelProperty("罪犯编号")
private String prisonerNo;
@ExcelProperty("评估类型(1-入狱评估 2-定期评估 3-专项评估)")
private Integer assessmentType;
@ExcelProperty("评估日期(yyyy-MM-dd)")
private String assessmentDate;
@ExcelProperty("暴力倾向得分")
private BigDecimal violenceScore;
@ExcelProperty("脱逃倾向得分")
private BigDecimal escapeScore;
@ExcelProperty("自杀倾向得分")
private BigDecimal suicideScore;
@ExcelProperty("综合得分")
private BigDecimal totalScore;
@ExcelProperty("风险等级(1-低风险 2-中风险 3-高风险 4-极高风险)")
private Integer riskLevel;
@ExcelProperty("风险因素")
private String riskFactors;
@ExcelProperty("管控建议")
private String suggestions;
@ExcelProperty("评估人姓名")
private String assessorName;
}

View File

@ -15,6 +15,8 @@ import java.util.*;
import java.io.IOException;
import cn.iocoder.yudao.framework.common.pojo.PageParam;
import cn.iocoder.yudao.module.prison.controller.admin.vo.ImportRespVO;
import org.springframework.web.multipart.MultipartFile;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
@ -96,4 +98,34 @@ public class PrisonScoreController {
ExcelUtils.write(response, "计分考核.xls", "数据", ScoreRespVO.class, list);
}
@GetMapping("/get-import-template")
@Operation(summary = "获取计分考核导入模板")
public void getImportTemplate(HttpServletResponse response) throws IOException {
// 手动创建导出 demo
List<ScoreImportExcelVO> list = Arrays.asList(
ScoreImportExcelVO.builder()
.prisonerNo("ZF20230001")
.year(2024)
.month(1)
.baseScore(new java.math.BigDecimal("80"))
.rewardScore(new java.math.BigDecimal("5"))
.penaltyScore(new java.math.BigDecimal("2"))
.level(2)
.assessorName("张警官")
.remark("示例数据")
.build()
);
// 输出
ExcelUtils.write(response, "计分考核导入模板.xls", "计分考核", ScoreImportExcelVO.class, list);
}
@PostMapping("/import")
@Operation(summary = "导入计分考核")
@PreAuthorize("@ss.hasPermission('prison:score:import')")
public CommonResult<ImportRespVO> importExcel(@RequestParam("file") MultipartFile file) throws Exception {
List<ScoreImportExcelVO> list = ExcelUtils.read(file, ScoreImportExcelVO.class);
ImportRespVO respVO = scoreService.importScore(list);
return success(respVO);
}
}

View File

@ -0,0 +1,49 @@
package cn.iocoder.yudao.module.prison.controller.admin.score.vo;
import cn.idev.excel.annotation.ExcelProperty;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.math.BigDecimal;
/**
* 计分考核导入 Excel VO
*/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
@Schema(description = "计分考核导入 Excel VO")
public class ScoreImportExcelVO {
@ExcelProperty("罪犯编号")
private String prisonerNo;
@ExcelProperty("考核年份")
private Integer year;
@ExcelProperty("考核月份")
private Integer month;
@ExcelProperty("基础分")
private BigDecimal baseScore;
@ExcelProperty("加分")
private BigDecimal rewardScore;
@ExcelProperty("扣分")
private BigDecimal penaltyScore;
@ExcelProperty("考核等级(1-优秀 2-良好 3-合格 4-不合格)")
private Integer level;
@ExcelProperty("考核人姓名")
private String assessorName;
@ExcelProperty("备注")
private String remark;
}

View File

@ -1,9 +1,11 @@
package cn.iocoder.yudao.module.prison.controller.admin.situation;
import java.util.*;
import java.io.IOException;
import java.time.LocalDateTime;
import cn.iocoder.yudao.module.prison.controller.admin.situation.vo.*;
import cn.iocoder.yudao.module.prison.controller.admin.vo.ImportRespVO;
import cn.iocoder.yudao.module.prison.dal.dataobject.situation.SituationDO;
import cn.iocoder.yudao.module.prison.service.situation.SituationService;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
@ -11,6 +13,7 @@ import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.pojo.PageParam;
import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.multipart.MultipartFile;
import cn.iocoder.yudao.module.prison.convert.situation.SituationConvert;
import io.swagger.v3.oas.annotations.Operation;
@ -109,4 +112,34 @@ public class SituationController {
SituationConvert.INSTANCE.convertList(list));
}
@GetMapping("/get-import-template")
@Operation(summary = "获取狱情收集导入模板")
public void getImportTemplate(HttpServletResponse response) throws IOException {
// 手动创建导出 demo
List<SituationImportExcelVO> list = Arrays.asList(
SituationImportExcelVO.builder()
.title("监室内发生争吵")
.type(2)
.level(1)
.content("某日上午一监区101室发生罪犯争吵")
.occurTime("2024-01-15 10:30:00")
.location("一监区101室")
.involvedPrisonerNos("ZF20230001,ZF20230002")
.reporter("张警官")
.remark("示例数据")
.build()
);
// 输出
ExcelUtils.write(response, "狱情收集导入模板.xls", "狱情收集", SituationImportExcelVO.class, list);
}
@PostMapping("/import")
@Operation(summary = "导入狱情收集")
@PreAuthorize("@ss.hasPermission('prison:situation:import')")
public CommonResult<ImportRespVO> importExcel(@RequestParam("file") MultipartFile file) throws Exception {
List<SituationImportExcelVO> list = ExcelUtils.read(file, SituationImportExcelVO.class);
ImportRespVO respVO = situationService.importSituation(list);
return success(respVO);
}
}

View File

@ -0,0 +1,47 @@
package cn.iocoder.yudao.module.prison.controller.admin.situation.vo;
import cn.idev.excel.annotation.ExcelProperty;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* 狱情收集导入 Excel VO
*/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
@Schema(description = "狱情收集导入 Excel VO")
public class SituationImportExcelVO {
@ExcelProperty("标题")
private String title;
@ExcelProperty("狱情类型(1-安全类 2-监管类 3-改造类 4-生产类 5-生活卫生类 6-其他)")
private Integer type;
@ExcelProperty("狱情等级(1-一般 2-重要 3-紧急 4-严重)")
private Integer level;
@ExcelProperty("内容")
private String content;
@ExcelProperty("发生时间(yyyy-MM-dd HH:mm:ss)")
private String occurTime;
@ExcelProperty("发生地点")
private String location;
@ExcelProperty("涉及罪犯编号(多个用逗号分隔)")
private String involvedPrisonerNos;
@ExcelProperty("报告人")
private String reporter;
@ExcelProperty("备注")
private String remark;
}

View File

@ -0,0 +1,27 @@
package cn.iocoder.yudao.module.prison.controller.admin.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Builder;
import lombok.Data;
import java.util.List;
import java.util.Map;
/**
* 通用导入结果 VO
*/
@Data
@Builder
@Schema(description = "管理后台 - 通用导入结果 Response VO")
public class ImportRespVO {
@Schema(description = "成功导入条数", example = "10")
private Integer successCount;
@Schema(description = "失败导入条数", example = "2")
private Integer failureCount;
@Schema(description = "失败记录详情key为行号value为失败原因")
private Map<Integer, String> failureRecords;
}

View File

@ -1,9 +1,11 @@
package cn.iocoder.yudao.module.prison.controller.admin.warning;
import java.util.*;
import java.io.IOException;
import java.time.LocalDateTime;
import cn.iocoder.yudao.module.prison.controller.admin.warning.vo.*;
import cn.iocoder.yudao.module.prison.controller.admin.vo.ImportRespVO;
import cn.iocoder.yudao.module.prison.dal.dataobject.warning.WarningDO;
import cn.iocoder.yudao.module.prison.service.warning.WarningService;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
@ -11,6 +13,7 @@ import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.pojo.PageParam;
import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.multipart.MultipartFile;
import cn.iocoder.yudao.module.prison.convert.warning.WarningConvert;
import io.swagger.v3.oas.annotations.Operation;
@ -100,4 +103,33 @@ public class WarningController {
WarningConvert.INSTANCE.convertList(list));
}
@GetMapping("/get-import-template")
@Operation(summary = "获取预警信息导入模板")
public void getImportTemplate(HttpServletResponse response) throws IOException {
// 手动创建导出 demo
List<WarningImportExcelVO> list = Arrays.asList(
WarningImportExcelVO.builder()
.title("发现可疑行为")
.content("某罪犯在放风期间有异常行为")
.type(1)
.level(2)
.source(1)
.alertTime("2024-01-15 10:30:00")
.occurTime("2024-01-15 10:00:00")
.remark("示例数据")
.build()
);
// 输出
ExcelUtils.write(response, "预警信息导入模板.xls", "预警信息", WarningImportExcelVO.class, list);
}
@PostMapping("/import")
@Operation(summary = "导入预警信息")
@PreAuthorize("@ss.hasPermission('prison:warning:import')")
public CommonResult<ImportRespVO> importExcel(@RequestParam("file") MultipartFile file) throws Exception {
List<WarningImportExcelVO> list = ExcelUtils.read(file, WarningImportExcelVO.class);
ImportRespVO respVO = warningService.importWarning(list);
return success(respVO);
}
}

View File

@ -0,0 +1,44 @@
package cn.iocoder.yudao.module.prison.controller.admin.warning.vo;
import cn.idev.excel.annotation.ExcelProperty;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* 预警管理导入 Excel VO
*/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
@Schema(description = "预警管理导入 Excel VO")
public class WarningImportExcelVO {
@ExcelProperty("预警标题")
private String title;
@ExcelProperty("预警内容")
private String content;
@ExcelProperty("预警类型(1-安全预警 2-监管预警 3-改造预警 4-生产预警 5-生活卫生预警 6-其他)")
private Integer type;
@ExcelProperty("预警等级(1-一般 2-重要 3-紧急 4-严重)")
private Integer level;
@ExcelProperty("预警来源(1-民警报告 2-监控系统 3-举报 4-罪犯自首 5-智能分析 6-其他)")
private Integer source;
@ExcelProperty("预警时间(yyyy-MM-dd HH:mm:ss)")
private String alertTime;
@ExcelProperty("发生时间(yyyy-MM-dd HH:mm:ss)")
private String occurTime;
@ExcelProperty("备注")
private String remark;
}

View File

@ -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

View File

@ -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;
}
}

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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;
}
}

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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;
}

View File

@ -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

View File

@ -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);
/**
* 统计某监区含子监区下的罪犯数量
*

View File

@ -28,9 +28,12 @@ public class ErrorCodeConstants {
// ========== 计分考核 4xxxx ==========
public static final ErrorCode PRISON_SCORE_NOT_EXISTS = new ErrorCode(4_000_001, "计分记录不存在");
public static final ErrorCode SCORE_IMPORT_LIST_IS_EMPTY = new ErrorCode(4_000_002, "计分考核导入数据不能为空");
// ========== 危险评估 5xxxx ==========
public static final ErrorCode PRISON_RISK_NOT_EXISTS = new ErrorCode(5_000_001, "评估记录不存在");
public static final ErrorCode RISK_ASSESSMENT_IMPORT_LIST_IS_EMPTY = new ErrorCode(5_000_002, "危险评估导入数据不能为空");
public static final ErrorCode RISK_IMPORT_LIST_IS_EMPTY = new ErrorCode(5_000_003, "风险评估导入数据不能为空");
// ========== 问卷管理 6xxxx ==========
public static final ErrorCode PRISON_QUESTIONNAIRE_NOT_EXISTS = new ErrorCode(6_000_001, "问卷不存在");
@ -42,6 +45,7 @@ public class ErrorCodeConstants {
public static final ErrorCode PRISON_CONSUMPTION_AMOUNT_MISMATCH = new ErrorCode(7_000_002, "消费明细金额与订单总金额不一致");
public static final ErrorCode PRISON_CONSUMPTION_DETAIL_EMPTY = new ErrorCode(7_000_003, "消费明细不能为空");
public static final ErrorCode PRISON_CONSUMPTION_DETAIL_INVALID = new ErrorCode(7_000_004, "消费明细数据不合法,请检查商品名称、单价和数量");
public static final ErrorCode CONSUMPTION_IMPORT_LIST_IS_EMPTY = new ErrorCode(7_000_005, "消费记录导入数据不能为空");
// ========== 罪犯监区变动记录 8xxxx ==========
public static final ErrorCode PRISONER_AREA_LOG_NOT_EXISTS = new ErrorCode(8_000_001, "罪犯监区变动记录不存在");
@ -56,9 +60,11 @@ public class ErrorCodeConstants {
// ========== 狱情收集 11xxxx ==========
public static final ErrorCode PRISON_SITUATION_NOT_EXISTS = new ErrorCode(11_000_001, "狱情记录不存在");
public static final ErrorCode SITUATION_IMPORT_LIST_IS_EMPTY = new ErrorCode(11_000_002, "狱情收集导入数据不能为空");
// ========== 预警管理 12xxxx ==========
public static final ErrorCode PRISON_WARNING_NOT_EXISTS = new ErrorCode(12_000_001, "预警记录不存在");
public static final ErrorCode WARNING_IMPORT_LIST_IS_EMPTY = new ErrorCode(12_000_002, "预警信息导入数据不能为空");
// ========== 别名 (兼容codegen生成的代码) ==========
public static final ErrorCode AREA_NOT_EXISTS = PRISON_AREA_NOT_EXISTS;

View File

@ -3,6 +3,7 @@ package cn.iocoder.yudao.module.prison.service.consumption;
import java.util.*;
import jakarta.validation.*;
import cn.iocoder.yudao.module.prison.controller.admin.consumption.vo.*;
import cn.iocoder.yudao.module.prison.controller.admin.vo.ImportRespVO;
import cn.iocoder.yudao.module.prison.dal.dataobject.consumption.ConsumptionDetailDO;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.pojo.PageParam;
@ -67,4 +68,12 @@ public interface ConsumptionService {
*/
List<ConsumptionDetailDO> getConsumptionDetailList(Long consumptionId);
/**
* 导入消费记录
*
* @param list 导入数据列表
* @return 导入结果
*/
ImportRespVO importConsumption(List<ConsumptionImportExcelVO> list);
}

View File

@ -11,8 +11,11 @@ import java.util.*;
import java.math.BigDecimal;
import cn.iocoder.yudao.module.prison.controller.admin.consumption.vo.*;
import cn.iocoder.yudao.module.prison.controller.admin.vo.ImportRespVO;
import cn.iocoder.yudao.module.prison.dal.dataobject.PrisonerDO;
import cn.iocoder.yudao.module.prison.dal.dataobject.consumption.ConsumptionDO;
import cn.iocoder.yudao.module.prison.dal.dataobject.consumption.ConsumptionDetailDO;
import cn.iocoder.yudao.module.prison.dal.mysql.PrisonerMapper;
import cn.iocoder.yudao.module.prison.dal.mysql.consumption.ConsumptionMapper;
import cn.iocoder.yudao.module.prison.dal.mysql.consumption.ConsumptionDetailMapper;
import cn.iocoder.yudao.module.prison.convert.consumption.ConsumptionConvert;
@ -40,6 +43,9 @@ public class ConsumptionServiceImpl implements ConsumptionService {
@Resource
private ConsumptionDetailMapper consumptionDetailMapper;
@Resource
private PrisonerMapper prisonerMapper;
@Override
@Transactional(rollbackFor = Exception.class)
public Long createConsumption(ConsumptionSaveReqVO createReqVO) {
@ -150,4 +156,67 @@ public class ConsumptionServiceImpl implements ConsumptionService {
return "CS" + System.currentTimeMillis();
}
@Override
@Transactional(rollbackFor = Exception.class)
public ImportRespVO importConsumption(List<ConsumptionImportExcelVO> list) {
if (CollUtil.isEmpty(list)) {
throw exception(CONSUMPTION_IMPORT_LIST_IS_EMPTY);
}
int successCount = 0;
Map<Integer, String> failureRecords = new LinkedHashMap<>();
for (int i = 0; i < list.size(); i++) {
ConsumptionImportExcelVO importVO = list.get(i);
int rowNum = i + 2; // Excel行号从2开始1是表头
try {
// 1. 校验罪犯编号
if (StrUtil.isBlank(importVO.getPrisonerNo())) {
failureRecords.put(rowNum, "罪犯编号不能为空");
continue;
}
// 2. 根据罪犯编号查询罪犯
PrisonerDO prisoner = prisonerMapper.selectByPrisonerNo(importVO.getPrisonerNo());
if (prisoner == null) {
failureRecords.put(rowNum, "罪犯编号不存在:" + importVO.getPrisonerNo());
continue;
}
// 3. 创建消费记录
ConsumptionDO consumption = new ConsumptionDO();
consumption.setPrisonerId(prisoner.getId());
consumption.setPrisonerNo(prisoner.getPrisonerNo());
consumption.setOrderNo(generateOrderNo());
consumption.setType(importVO.getType());
consumption.setTotalAmount(importVO.getTotalAmount());
consumption.setStatus(importVO.getStatus() != null ? importVO.getStatus() : 1);
consumption.setRemark(importVO.getRemark());
// 处理交易时间
if (StrUtil.isNotBlank(importVO.getTradeTime())) {
try {
consumption.setTradeTime(java.time.LocalDateTime.parse(importVO.getTradeTime(),
java.time.format.DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
} catch (Exception e) {
consumption.setTradeTime(java.time.LocalDateTime.now());
}
} else {
consumption.setTradeTime(java.time.LocalDateTime.now());
}
consumptionMapper.insert(consumption);
successCount++;
} catch (Exception e) {
failureRecords.put(rowNum, "导入失败:" + e.getMessage());
}
}
return ImportRespVO.builder()
.successCount(successCount)
.failureCount(failureRecords.size())
.failureRecords(failureRecords)
.build();
}
}

View File

@ -1,6 +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.framework.common.pojo.PageResult;
import cn.iocoder.yudao.module.prison.controller.admin.dashboard.vo.*;
/**
* 监管看板 Service 接口
@ -16,4 +17,27 @@ public interface PrisonDashboardService {
*/
DashboardStatisticsVO getDashboardStatistics();
/**
* 获取罪犯工作台统计数据
*
* @param prisonerId 罪犯ID
* @return 罪犯工作台统计数据
*/
PrisonerDashboardStatsRespVO getPrisonerStats(Long prisonerId);
/**
* 获取AI心航360°统计数据
*
* @return AI心航360°统计数据
*/
AiDashEntryStatisticsVO getAiDashEntryStatistics();
/**
* 获取重点关注对象分页列表
*
* @param reqVO 分页请求参数
* @return 重点关注对象分页列表
*/
PageResult<FocusPersonVO> getFocusPersonPage(FocusPersonPageReqVO reqVO);
}

View File

@ -1,17 +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 实现
@ -24,6 +50,13 @@ import java.util.Map;
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";
@ -142,4 +175,570 @@ public class PrisonDashboardServiceImpl implements PrisonDashboardService {
return provinceMap.getOrDefault(provinceCode, provinceCode);
}
@Override
public PrisonerDashboardStatsRespVO getPrisonerStats(Long prisonerId) {
// 获取罪犯基本信息
PrisonerDO prisoner = prisonerMapper.selectById(prisonerId);
if (prisoner == null) {
return null;
}
PrisonerDashboardStatsRespVO vo = new PrisonerDashboardStatsRespVO();
// 基本信息
vo.setPrisonerName(prisoner.getName());
vo.setPrisonerNo(prisoner.getPrisonerNo());
vo.setNativePlace(prisoner.getNativePlace());
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());
// 计算年龄
if (prisoner.getBirthDate() != null) {
vo.setBirthDate(prisoner.getBirthDate().toString());
vo.setAge(Period.between(prisoner.getBirthDate(), LocalDate.now()).getYears());
}
// 入狱和出狱时间
if (prisoner.getImprisonmentDate() != null) {
vo.setImprisonmentDate(prisoner.getImprisonmentDate().toString());
vo.setServedDays((int) ChronoUnit.DAYS.between(prisoner.getImprisonmentDate(), LocalDate.now()));
}
if (prisoner.getReleaseDate() != null) {
vo.setReleaseDate(prisoner.getReleaseDate().toString());
}
// 监区信息简单拼接
vo.setPrisonArea(prisoner.getAreaId() != null ? "监区" + prisoner.getAreaId() : "未分配");
// ==================== 查询关联数据 ====================
// 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(String.valueOf((int) monthlyTotal))
.topLabel("本月消费")
.middleLeftValue(String.valueOf((int) monthlyReward))
.middleLeftLabel("本月奖励")
.middleRightValue(String.valueOf((int) monthlyPenalty))
.middleRightLabel("本月惩罚")
.bottomValue(latestBalance != null ? String.valueOf(latestBalance.intValue()) : "0")
.bottomLabel("账户余额")
.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());
}
// ==================== 构建消费月度数据 ====================
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());
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);
}
}

View File

@ -3,6 +3,7 @@ package cn.iocoder.yudao.module.prison.service.risk;
import java.util.*;
import jakarta.validation.*;
import cn.iocoder.yudao.module.prison.controller.admin.risk.vo.*;
import cn.iocoder.yudao.module.prison.controller.admin.vo.ImportRespVO;
import cn.iocoder.yudao.module.prison.dal.dataobject.risk.RiskDO;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.pojo.PageParam;
@ -59,4 +60,12 @@ public interface RiskService {
*/
PageResult<RiskDO> getRiskPage(RiskPageReqVO pageReqVO);
/**
* 导入风险评估
*
* @param list 导入数据列表
* @return 导入结果
*/
ImportRespVO importRisk(List<RiskImportExcelVO> list);
}

View File

@ -1,19 +1,26 @@
package cn.iocoder.yudao.module.prison.service.risk.impl;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import org.springframework.stereotype.Service;
import jakarta.annotation.Resource;
import org.springframework.validation.annotation.Validated;
import org.springframework.transaction.annotation.Transactional;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.*;
import cn.iocoder.yudao.module.prison.controller.admin.risk.vo.*;
import cn.iocoder.yudao.module.prison.controller.admin.vo.ImportRespVO;
import cn.iocoder.yudao.module.prison.dal.dataobject.PrisonerDO;
import cn.iocoder.yudao.module.prison.dal.dataobject.risk.RiskDO;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.pojo.PageParam;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.module.prison.dal.mysql.risk.RiskMapper;
import cn.iocoder.yudao.module.prison.dal.mysql.PrisonerMapper;
import cn.iocoder.yudao.module.prison.service.risk.RiskService;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
@ -31,6 +38,9 @@ public class RiskServiceImpl implements RiskService {
@Resource
private RiskMapper riskMapper;
@Resource
private PrisonerMapper prisonerMapper;
@Override
public Long createRisk(RiskSaveReqVO createReqVO) {
// 插入
@ -79,4 +89,67 @@ public class RiskServiceImpl implements RiskService {
return riskMapper.selectPage(pageReqVO);
}
@Override
@Transactional(rollbackFor = Exception.class)
public ImportRespVO importRisk(List<RiskImportExcelVO> list) {
if (CollUtil.isEmpty(list)) {
throw exception(RISK_IMPORT_LIST_IS_EMPTY);
}
int successCount = 0;
Map<Integer, String> failureRecords = new LinkedHashMap<>();
for (int i = 0; i < list.size(); i++) {
RiskImportExcelVO importVO = list.get(i);
int rowNum = i + 2;
try {
if (StrUtil.isBlank(importVO.getPrisonerNo())) {
failureRecords.put(rowNum, "罪犯编号不能为空");
continue;
}
PrisonerDO prisoner = prisonerMapper.selectByPrisonerNo(importVO.getPrisonerNo());
if (prisoner == null) {
failureRecords.put(rowNum, "罪犯编号不存在:" + importVO.getPrisonerNo());
continue;
}
RiskDO risk = new RiskDO();
risk.setPrisonerId(prisoner.getId());
risk.setPrisonerNo(prisoner.getPrisonerNo());
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());
risk.setSuggestions(importVO.getSuggestions());
risk.setAssessorName(importVO.getAssessorName());
risk.setRemark(importVO.getRemark());
risk.setStatus(1);
if (StrUtil.isNotBlank(importVO.getAssessmentDate())) {
try {
risk.setAssessmentDate(LocalDate.parse(importVO.getAssessmentDate(),
DateTimeFormatter.ofPattern("yyyy-MM-dd")));
} catch (Exception e) {
risk.setAssessmentDate(LocalDate.now());
}
} else {
risk.setAssessmentDate(LocalDate.now());
}
riskMapper.insert(risk);
successCount++;
} catch (Exception e) {
failureRecords.put(rowNum, "导入失败:" + e.getMessage());
}
}
return ImportRespVO.builder()
.successCount(successCount)
.failureCount(failureRecords.size())
.failureRecords(failureRecords)
.build();
}
}

View File

@ -3,6 +3,7 @@ package cn.iocoder.yudao.module.prison.service.riskassessment;
import java.util.*;
import jakarta.validation.*;
import cn.iocoder.yudao.module.prison.controller.admin.riskassessment.vo.*;
import cn.iocoder.yudao.module.prison.controller.admin.vo.ImportRespVO;
import cn.iocoder.yudao.module.prison.dal.dataobject.riskassessment.RiskAssessmentDO;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.pojo.PageParam;
@ -59,4 +60,12 @@ public interface RiskAssessmentService {
*/
PageResult<RiskAssessmentRespVO> getRiskAssessmentPage(RiskAssessmentPageReqVO pageReqVO);
/**
* 导入危险评估
*
* @param list 导入数据列表
* @return 导入结果
*/
ImportRespVO importRiskAssessment(List<RiskAssessmentImportExcelVO> list);
}

View File

@ -1,6 +1,7 @@
package cn.iocoder.yudao.module.prison.service.riskassessment;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import jakarta.annotation.Resource;
@ -8,14 +9,19 @@ import org.springframework.validation.annotation.Validated;
import org.springframework.transaction.annotation.Transactional;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.*;
import cn.iocoder.yudao.module.prison.controller.admin.riskassessment.vo.*;
import cn.iocoder.yudao.module.prison.controller.admin.vo.ImportRespVO;
import cn.iocoder.yudao.module.prison.dal.dataobject.PrisonerDO;
import cn.iocoder.yudao.module.prison.dal.dataobject.riskassessment.RiskAssessmentDO;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.pojo.PageParam;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.module.prison.dal.mysql.riskassessment.RiskAssessmentMapper;
import cn.iocoder.yudao.module.prison.dal.mysql.PrisonerMapper;
import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
@ -36,6 +42,9 @@ public class RiskAssessmentServiceImpl implements RiskAssessmentService {
@Resource
private RiskAssessmentMapper riskAssessmentMapper;
@Resource
private PrisonerMapper prisonerMapper;
@Override
@Transactional(rollbackFor = Exception.class)
public Long createRiskAssessment(RiskAssessmentSaveReqVO createReqVO) {
@ -173,4 +182,69 @@ public class RiskAssessmentServiceImpl implements RiskAssessmentService {
return new PageResult<>(list, (long) list.size());
}
@Override
@Transactional(rollbackFor = Exception.class)
public ImportRespVO importRiskAssessment(List<RiskAssessmentImportExcelVO> list) {
if (CollUtil.isEmpty(list)) {
throw exception(RISK_ASSESSMENT_IMPORT_LIST_IS_EMPTY);
}
int successCount = 0;
Map<Integer, String> failureRecords = new LinkedHashMap<>();
for (int i = 0; i < list.size(); i++) {
RiskAssessmentImportExcelVO importVO = list.get(i);
int rowNum = i + 2;
try {
if (StrUtil.isBlank(importVO.getPrisonerNo())) {
failureRecords.put(rowNum, "罪犯编号不能为空");
continue;
}
PrisonerDO prisoner = prisonerMapper.selectByPrisonerNo(importVO.getPrisonerNo());
if (prisoner == null) {
failureRecords.put(rowNum, "罪犯编号不存在:" + importVO.getPrisonerNo());
continue;
}
RiskAssessmentDO assessment = new RiskAssessmentDO();
assessment.setPrisonerId(prisoner.getId());
assessment.setPrisonerNo(prisoner.getPrisonerNo());
assessment.setAssessmentType(importVO.getAssessmentType());
if (StrUtil.isNotBlank(importVO.getAssessmentDate())) {
try {
assessment.setAssessmentDate(LocalDate.parse(importVO.getAssessmentDate(), DateTimeFormatter.ofPattern("yyyy-MM-dd")));
} catch (Exception e) {
assessment.setAssessmentDate(LocalDate.now());
}
} else {
assessment.setAssessmentDate(LocalDate.now());
}
assessment.setViolenceScore(importVO.getViolenceScore());
assessment.setEscapeScore(importVO.getEscapeScore());
assessment.setSuicideScore(importVO.getSuicideScore());
assessment.setTotalScore(importVO.getTotalScore() != null ? importVO.getTotalScore() :
calculateTotalScore(importVO.getViolenceScore(), importVO.getEscapeScore(), importVO.getSuicideScore()));
assessment.setRiskLevel(importVO.getRiskLevel());
assessment.setRiskFactors(importVO.getRiskFactors());
assessment.setSuggestions(importVO.getSuggestions());
assessment.setAssessorName(importVO.getAssessorName());
assessment.setStatus(1);
riskAssessmentMapper.insert(assessment);
successCount++;
} catch (Exception e) {
failureRecords.put(rowNum, "导入失败:" + e.getMessage());
}
}
return ImportRespVO.builder()
.successCount(successCount)
.failureCount(failureRecords.size())
.failureRecords(failureRecords)
.build();
}
}

View File

@ -3,6 +3,7 @@ package cn.iocoder.yudao.module.prison.service.score;
import java.util.*;
import jakarta.validation.*;
import cn.iocoder.yudao.module.prison.controller.admin.score.vo.*;
import cn.iocoder.yudao.module.prison.controller.admin.vo.ImportRespVO;
import cn.iocoder.yudao.module.prison.dal.dataobject.score.ScoreDO;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.pojo.PageParam;
@ -59,4 +60,12 @@ public interface ScoreService {
*/
PageResult<ScoreRespVO> getScorePage(ScorePageReqVO pageReqVO);
/**
* 导入计分考核
*
* @param list 导入数据列表
* @return 导入结果
*/
ImportRespVO importScore(List<ScoreImportExcelVO> list);
}

View File

@ -6,7 +6,11 @@ import org.springframework.validation.annotation.Validated;
import org.springframework.transaction.annotation.Transactional;
import java.util.*;
import java.math.BigDecimal;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import cn.iocoder.yudao.module.prison.controller.admin.score.vo.*;
import cn.iocoder.yudao.module.prison.controller.admin.vo.ImportRespVO;
import cn.iocoder.yudao.module.prison.dal.dataobject.score.ScoreDO;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
@ -115,4 +119,58 @@ public class ScoreServiceImpl implements ScoreService {
return new PageResult<>(list, (long) list.size());
}
@Override
@Transactional(rollbackFor = Exception.class)
public ImportRespVO importScore(List<ScoreImportExcelVO> list) {
if (CollUtil.isEmpty(list)) {
throw exception(SCORE_IMPORT_LIST_IS_EMPTY);
}
int successCount = 0;
Map<Integer, String> failureRecords = new LinkedHashMap<>();
for (int i = 0; i < list.size(); i++) {
ScoreImportExcelVO importVO = list.get(i);
int rowNum = i + 2;
try {
if (StrUtil.isBlank(importVO.getPrisonerNo())) {
failureRecords.put(rowNum, "罪犯编号不能为空");
continue;
}
PrisonerDO prisoner = prisonerMapper.selectByPrisonerNo(importVO.getPrisonerNo());
if (prisoner == null) {
failureRecords.put(rowNum, "罪犯编号不存在:" + importVO.getPrisonerNo());
continue;
}
ScoreDO score = new ScoreDO();
score.setPrisonerId(prisoner.getId());
score.setPrisonerNo(prisoner.getPrisonerNo());
score.setPrisonAreaId(prisoner.getPrisonAreaId());
score.setPrisonCellId(prisoner.getPrisonCellId());
score.setYear(importVO.getYear());
score.setMonth(importVO.getMonth());
score.setBaseScore(importVO.getBaseScore() != null ? importVO.getBaseScore() : BigDecimal.valueOf(80));
score.setRewardScore(importVO.getRewardScore() != null ? importVO.getRewardScore() : BigDecimal.ZERO);
score.setPenaltyScore(importVO.getPenaltyScore() != null ? importVO.getPenaltyScore() : BigDecimal.ZERO);
score.setTotalScore(score.getBaseScore().add(score.getRewardScore()).subtract(score.getPenaltyScore()));
score.setLevel(importVO.getLevel());
score.setStatus(1); // 待审核
score.setRemark(importVO.getRemark());
scoreMapper.insert(score);
successCount++;
} catch (Exception e) {
failureRecords.put(rowNum, "导入失败:" + e.getMessage());
}
}
return ImportRespVO.builder()
.successCount(successCount)
.failureCount(failureRecords.size())
.failureRecords(failureRecords)
.build();
}
}

View File

@ -3,6 +3,7 @@ package cn.iocoder.yudao.module.prison.service.situation;
import java.util.*;
import jakarta.validation.*;
import cn.iocoder.yudao.module.prison.controller.admin.situation.vo.*;
import cn.iocoder.yudao.module.prison.controller.admin.vo.ImportRespVO;
import cn.iocoder.yudao.module.prison.dal.dataobject.situation.SituationDO;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.pojo.PageParam;
@ -59,4 +60,12 @@ public interface SituationService {
*/
PageResult<SituationDO> getSituationPage(SituationPageReqVO pageReqVO);
/**
* 导入狱情收集
*
* @param list 导入数据列表
* @return 导入结果
*/
ImportRespVO importSituation(List<SituationImportExcelVO> list);
}

View File

@ -1,13 +1,17 @@
package cn.iocoder.yudao.module.prison.service.situation.impl;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import org.springframework.stereotype.Service;
import jakarta.annotation.Resource;
import org.springframework.validation.annotation.Validated;
import org.springframework.transaction.annotation.Transactional;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import cn.iocoder.yudao.module.prison.controller.admin.situation.vo.*;
import cn.iocoder.yudao.module.prison.controller.admin.vo.ImportRespVO;
import cn.iocoder.yudao.module.prison.dal.dataobject.situation.SituationDO;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.pojo.PageParam;
@ -94,4 +98,56 @@ public class SituationServiceImpl implements SituationService {
return pageResult;
}
@Override
@Transactional(rollbackFor = Exception.class)
public ImportRespVO importSituation(List<SituationImportExcelVO> list) {
if (CollUtil.isEmpty(list)) {
throw exception(SITUATION_IMPORT_LIST_IS_EMPTY);
}
int successCount = 0;
Map<Integer, String> failureRecords = new LinkedHashMap<>();
for (int i = 0; i < list.size(); i++) {
SituationImportExcelVO importVO = list.get(i);
int rowNum = i + 2;
try {
if (StrUtil.isBlank(importVO.getTitle())) {
failureRecords.put(rowNum, "标题不能为空");
continue;
}
SituationDO situation = new SituationDO();
situation.setTitle(importVO.getTitle());
situation.setType(importVO.getType() != null ? String.valueOf(importVO.getType()) : null);
situation.setLevel(importVO.getLevel());
situation.setContent(importVO.getContent());
situation.setLocation(importVO.getLocation());
situation.setReporter(importVO.getReporter());
situation.setRemark(importVO.getRemark());
situation.setStatus(1);
if (StrUtil.isNotBlank(importVO.getOccurTime())) {
try {
situation.setOccurTime(LocalDateTime.parse(importVO.getOccurTime(),
DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
} catch (Exception e) {
situation.setOccurTime(LocalDateTime.now());
}
}
situationMapper.insert(situation);
successCount++;
} catch (Exception e) {
failureRecords.put(rowNum, "导入失败:" + e.getMessage());
}
}
return ImportRespVO.builder()
.successCount(successCount)
.failureCount(failureRecords.size())
.failureRecords(failureRecords)
.build();
}
}

View File

@ -3,6 +3,7 @@ package cn.iocoder.yudao.module.prison.service.warning;
import java.util.*;
import jakarta.validation.*;
import cn.iocoder.yudao.module.prison.controller.admin.warning.vo.*;
import cn.iocoder.yudao.module.prison.controller.admin.vo.ImportRespVO;
import cn.iocoder.yudao.module.prison.dal.dataobject.warning.WarningDO;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.pojo.PageParam;
@ -59,4 +60,12 @@ public interface WarningService {
*/
PageResult<WarningDO> getWarningPage(WarningPageReqVO pageReqVO);
/**
* 导入预警信息
*
* @param list 导入数据列表
* @return 导入结果
*/
ImportRespVO importWarning(List<WarningImportExcelVO> list);
}

View File

@ -1,13 +1,17 @@
package cn.iocoder.yudao.module.prison.service.warning.impl;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import org.springframework.stereotype.Service;
import jakarta.annotation.Resource;
import org.springframework.validation.annotation.Validated;
import org.springframework.transaction.annotation.Transactional;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import cn.iocoder.yudao.module.prison.controller.admin.warning.vo.*;
import cn.iocoder.yudao.module.prison.controller.admin.vo.ImportRespVO;
import cn.iocoder.yudao.module.prison.dal.dataobject.warning.WarningDO;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.pojo.PageParam;
@ -79,4 +83,64 @@ public class WarningServiceImpl implements WarningService {
return warningMapper.selectPage(pageReqVO);
}
@Override
@Transactional(rollbackFor = Exception.class)
public ImportRespVO importWarning(List<WarningImportExcelVO> list) {
if (CollUtil.isEmpty(list)) {
throw exception(WARNING_IMPORT_LIST_IS_EMPTY);
}
int successCount = 0;
Map<Integer, String> failureRecords = new LinkedHashMap<>();
for (int i = 0; i < list.size(); i++) {
WarningImportExcelVO importVO = list.get(i);
int rowNum = i + 2;
try {
if (StrUtil.isBlank(importVO.getTitle())) {
failureRecords.put(rowNum, "预警标题不能为空");
continue;
}
WarningDO warning = new WarningDO();
warning.setTitle(importVO.getTitle());
warning.setContent(importVO.getContent());
warning.setType(importVO.getType());
warning.setLevel(importVO.getLevel());
warning.setSource(importVO.getSource());
warning.setRemark(importVO.getRemark());
warning.setStatus(1);
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
if (StrUtil.isNotBlank(importVO.getAlertTime())) {
try {
warning.setAlertTime(LocalDateTime.parse(importVO.getAlertTime(), formatter));
} catch (Exception e) {
warning.setAlertTime(LocalDateTime.now());
}
} else {
warning.setAlertTime(LocalDateTime.now());
}
if (StrUtil.isNotBlank(importVO.getOccurTime())) {
try {
warning.setOccurTime(LocalDateTime.parse(importVO.getOccurTime(), formatter));
} catch (Exception e) {
// ignore
}
}
warningMapper.insert(warning);
successCount++;
} catch (Exception e) {
failureRecords.put(rowNum, "导入失败:" + e.getMessage());
}
}
return ImportRespVO.builder()
.successCount(successCount)
.failureCount(failureRecords.size())
.failureRecords(failureRecords)
.build();
}
}

View File

@ -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>

View File

@ -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);

View File

@ -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

View File

@ -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;