团队项目安全管理子系统-历史回溯
要求:此模块支持风险项历史版本追溯与对比,详细记录更新人、更新时间、原值/新值)等。
1、创建两个实体类SafetyRisk和SafetyRiskHistory
SafetyRisk
package com.lianxi.safety7.entity;
import cn.hutool.core.annotation.Alias;
import jakarta.persistence.*;
import lombok.Data;
import java.util.Date;
@Entity
@Data // 自动生成getter/setter/tostring/hashcode/equals方法
@Table(name="safetyrisk")
public class SafetyRisk {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Alias("编号")
private Integer id; // 编号
@Alias("风险编码")
private String risk_code; // 风险编码
@Alias("责任部门/分区")
private String department; // 责任部门/工区
@Alias("专业系统")
private String professional_system; // 专业系统
@Alias("风险类别")
private String risk_category; // 风险类别
@Alias("风险项目")
private String risk_item; // 风险项目
@Alias("风险项点")
private String risk_point; // 风险项点
@Alias("风险等级")
private String risk_level; // 风险等级
@Alias("危害程度")
private String harm_degree; // 危害程度
@Alias("管控措施")
private String control_measures; // 管控措施
@Alias("管控岗位")
private String control_position; // 管控岗位
@Alias("管控人员")
private String control_personnel; // 管控人员
@Alias("量化要求")
private String quantified_requirements; // 量化要求
@Alias("开始录入时间")
private Date entry_start_date; // 开始录入日期
@Alias("结束录入时间")
private Date entry_end_date; // 结束录入日期
@Alias("审核状态")
private String review_status; // 审核状态
@Alias("审核日期")
private Date review_date; // 审核日期
private String updateUser; // 新增字段
private String entry_start_date_str;
private String entry_end_date_str;
private String review_date_str;
public String getUpdateUser() {
return updateUser;
}
public void setUpdateUser(String updateUser) {
this.updateUser = updateUser;
}
public String getEntry_start_date_str() {
return entry_start_date_str;
}
public void setEntry_start_date_str(String entry_start_date_str) {
this.entry_start_date_str = entry_start_date_str;
}
public String getEntry_end_date_str() {
return entry_end_date_str;
}
public void setEntry_end_date_str(String entry_end_date_str) {
this.entry_end_date_str = entry_end_date_str;
}
public String getReview_date_str() {
return review_date_str;
}
public void setReview_date_str(String review_date_str) {
this.review_date_str = review_date_str;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getRisk_code() {
return risk_code;
}
public void setRisk_code(String risk_code) {
this.risk_code = risk_code;
}
public String getDepartment() {
return department;
}
public void setDepartment(String department) {
this.department = department;
}
public String getProfessional_system() {
return professional_system;
}
public void setProfessional_system(String professional_system) {
this.professional_system = professional_system;
}
public String getRisk_category() {
return risk_category;
}
public void setRisk_category(String risk_category) {
this.risk_category = risk_category;
}
public String getRisk_item() {
return risk_item;
}
public void setRisk_item(String risk_item) {
this.risk_item = risk_item;
}
public String getRisk_point() {
return risk_point;
}
public void setRisk_point(String risk_point) {
this.risk_point = risk_point;
}
public String getRisk_level() {
return risk_level;
}
public void setRisk_level(String risk_level) {
this.risk_level = risk_level;
}
public String getHarm_degree() {
return harm_degree;
}
public void setHarm_degree(String harm_degree) {
this.harm_degree = harm_degree;
}
public String getControl_measures() {
return control_measures;
}
public void setControl_measures(String control_measures) {
this.control_measures = control_measures;
}
public String getControl_position() {
return control_position;
}
public void setControl_position(String control_position) {
this.control_position = control_position;
}
public String getControl_personnel() {
return control_personnel;
}
public void setControl_personnel(String control_personnel) {
this.control_personnel = control_personnel;
}
public String getQuantified_requirements() {
return quantified_requirements;
}
public void setQuantified_requirements(String quantified_requirements) {
this.quantified_requirements = quantified_requirements;
}
public Date getEntry_start_date() {
return entry_start_date;
}
public void setEntry_start_date(Date entry_start_date) {
this.entry_start_date = entry_start_date;
}
public Date getEntry_end_date() {
return entry_end_date;
}
public void setEntry_end_date(Date entry_end_date) {
this.entry_end_date = entry_end_date;
}
public String getReview_status() {
return review_status;
}
public void setReview_status(String review_status) {
this.review_status = review_status;
}
public Date getReview_date() {
return review_date;
}
public void setReview_date(Date review_date) {
this.review_date = review_date;
}
}
SafetyRiskHistory
package com.lianxi.safety7.entity;
import jakarta.persistence.*;
import java.util.Date;
@Entity
@Table(name = "safetyriskhistory")
public class SafetyRiskHistory {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "history_id")
private int historyId;
@ManyToOne
@JoinColumn(name = "risk_id", nullable = false)
private SafetyRisk safetyRisk;
@Column(name = "update_user", nullable = false, length = 100)
private String updateUser;
@Column(name = "update_time", nullable = false)
private Date updateTime;
@Column(name = "old_value", columnDefinition = "LONGTEXT")
private String oldValue;
@Column(name = "new_value", columnDefinition = "LONGTEXT")
private String newValue;
private String updateTime_str;
private String oldValue_str;
private String newValue_str;
public String getUpdateTime_str() {
return updateTime_str;
}
public void setUpdateTime_str(String updateTime_str) {
this.updateTime_str = updateTime_str;
}
public String getOldValue_str() {
return oldValue_str;
}
public void setOldValue_str(String oldValue_str) {
this.oldValue_str = oldValue_str;
}
public String getNewValue_str() {
return newValue_str;
}
public void setNewValue_str(String newValue_str) {
this.newValue_str = newValue_str;
}
// Getters and Setters
public int getHistoryId() {
return historyId;
}
public void setHistoryId(int historyId) {
this.historyId = historyId;
}
public SafetyRisk getSafetyRisk() {
return safetyRisk;
}
public void setSafetyRisk(SafetyRisk safetyRisk) {
this.safetyRisk = safetyRisk;
}
public String getUpdateUser() {
return updateUser;
}
public void setUpdateUser(String updateUser) {
this.updateUser = updateUser;
}
public Date getUpdateTime() {
return updateTime;
}
public void setUpdateTime(Date updateTime) {
this.updateTime = updateTime;
}
public String getOldValue() {
return oldValue;
}
public void setOldValue(String oldValue) {
this.oldValue = oldValue;
}
public String getNewValue() {
return newValue;
}
public void setNewValue(String newValue) {
this.newValue = newValue;
}
}
2、controller
SafetyriskController
package com.lianxi.safety7.controller;
import com.lianxi.safety7.entity.SafetyRisk;
import com.lianxi.safety7.entity.SafetyRiskHistory;
import com.lianxi.safety7.service.SafetyRiskHistoryService;
import com.lianxi.safety7.service.SafetyRiskService;
import org.springframework.beans.BeanUtils; // 添加这行导入 BeanUtils 类
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.data.domain.Page;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.Date;
import java.util.Map;
@RestController
@RequestMapping("/safetyrisk")
@CrossOrigin
public class SafetyriskController {
@Autowired
private SafetyRiskService safetyRiskService;
@Autowired
private SafetyRiskHistoryService safetyRiskHistoryService;
@PostMapping
public ResponseEntity<SafetyRisk> saveSafetyRisk(@RequestBody SafetyRisk safetyRisk) {
SafetyRisk savedRisk = safetyRiskService.saveSafetyRisk(safetyRisk);
return ResponseEntity.ok(savedRisk);
}
@PostMapping("/revert/{riskCode}")
public ResponseEntity<?> revertSafetyRisk(
@PathVariable String riskCode,
@RequestBody Map<String, Object> requestData) {
try {
// 验证风险代码格式
if (riskCode.contains(":")) {
return ResponseEntity.badRequest().body("风险代码格式不正确");
}
// 获取现有风险记录
SafetyRisk existingRisk = safetyRiskService.getByRiskCode(riskCode)
.orElseThrow(() -> new IllegalArgumentException("找不到风险代码: " + riskCode));
// 创建要保存的对象
SafetyRisk revertedRisk = new SafetyRisk();
// 复制所有可识别属性
BeanUtils.copyProperties(existingRisk, revertedRisk); // 先复制现有值
// 从请求数据更新字段
if (requestData.containsKey("department")) {
revertedRisk.setDepartment((String) requestData.get("department"));
}
// 为所有字段添加类似逻辑...
// 确保关键字段不被覆盖
revertedRisk.setId(existingRisk.getId());
revertedRisk.setRisk_code(riskCode);
// 保存数据
SafetyRisk savedRisk = safetyRiskService.saveSafetyRisk(revertedRisk);
// 记录历史
SafetyRiskHistory history = new SafetyRiskHistory();
history.setSafetyRisk(savedRisk);
history.setUpdateUser("system-revert");
history.setUpdateTime(new Date());
history.setOldValue(convertRiskToJson(existingRisk));
history.setNewValue(convertRiskToJson(savedRisk));
safetyRiskHistoryService.saveSafetyRiskHistory(history);
return ResponseEntity.ok(savedRisk);
} catch (IllegalArgumentException e) {
return ResponseEntity.badRequest().body(e.getMessage());
} catch (Exception e) {
return ResponseEntity.internalServerError().body("服务器内部错误");
}
}
@GetMapping("/all")
public ResponseEntity<Page<SafetyRisk>> getAllSafetyRisks(
@RequestParam(defaultValue = "1") int page,
@RequestParam(defaultValue = "10") int size) {
Page<SafetyRisk> pageResult = safetyRiskService.getAllSafetyRisks(page, size);
pageResult.getContent().forEach(this::beautifyDates);
return ResponseEntity.ok(pageResult);
}
@GetMapping("/byRiskCode")
public ResponseEntity<Page<SafetyRisk>> getSafetyRisksByRiskCode(
@RequestParam String riskCode,
@RequestParam(defaultValue = "1") int page,
@RequestParam(defaultValue = "10") int size
) {
Page<SafetyRisk> pageResult = safetyRiskService.getSafetyRisksByRiskCode(riskCode, page, size);
pageResult.getContent().forEach(this::beautifyDates);
return ResponseEntity.ok(pageResult);
}
@DeleteMapping("/{id}")
public ResponseEntity<Void> deleteSafetyRisk(@PathVariable int id) {
safetyRiskService.deleteSafetyRisk(id);
return ResponseEntity.noContent().build();
}
@GetMapping
public ResponseEntity<Page<SafetyRisk>> getSafetyRisksByQuery(
@RequestParam(required = false) Integer id,
@RequestParam(required = false) String risk_code,
@RequestParam(required = false) String department,
@RequestParam(required = false) String professional_system,
@RequestParam(required = false) String risk_category,
@RequestParam(required = false) String risk_item,
@RequestParam(required = false) String risk_point,
@RequestParam(required = false) String risk_level,
@RequestParam(required = false) String harm_degree,
@RequestParam(required = false) String control_measures,
@RequestParam(required = false) String control_position,
@RequestParam(required = false) String control_personnel,
@RequestParam(required = false) String quantified_requirements,
@RequestParam(required = false) @DateTimeFormat(pattern = "yyyy-MM-dd") Date entry_start_date,
@RequestParam(required = false) @DateTimeFormat(pattern = "yyyy-MM-dd") Date entry_end_date,
@RequestParam(required = false) String review_status,
@RequestParam(required = false) @DateTimeFormat(pattern = "yyyy-MM-dd") Date review_date,
@RequestParam(defaultValue = "1") int page,
@RequestParam(defaultValue = "10") int size
) {
Page<SafetyRisk> pageResult = safetyRiskService.getSafetyRisksByQuery(
id, risk_code, department, professional_system, risk_category,
risk_item, risk_point, risk_level, harm_degree, control_measures,
control_position, control_personnel, quantified_requirements,
entry_start_date, entry_end_date, review_status, review_date,
page, size
);
pageResult.getContent().forEach(this::beautifyDates);
return ResponseEntity.ok(pageResult);
}
@PutMapping("/{id}")
public ResponseEntity<SafetyRisk> update(@PathVariable("id") int id, @RequestBody SafetyRisk updatedRisk) {
SafetyRisk existingRisk = safetyRiskService.getById(id)
.orElseThrow(() -> new IllegalArgumentException("安全风险记录ID [" + id + "] 不存在"));
existingRisk.setRisk_code(updatedRisk.getRisk_code());
existingRisk.setDepartment(updatedRisk.getDepartment());
existingRisk.setProfessional_system(updatedRisk.getProfessional_system());
existingRisk.setRisk_category(updatedRisk.getRisk_category());
existingRisk.setRisk_item(updatedRisk.getRisk_item());
existingRisk.setRisk_point(updatedRisk.getRisk_point());
existingRisk.setRisk_level(updatedRisk.getRisk_level());
existingRisk.setHarm_degree(updatedRisk.getHarm_degree());
existingRisk.setControl_measures(updatedRisk.getControl_measures());
existingRisk.setControl_position(updatedRisk.getControl_position());
existingRisk.setControl_personnel(updatedRisk.getControl_personnel());
existingRisk.setQuantified_requirements(updatedRisk.getQuantified_requirements());
existingRisk.setEntry_start_date(updatedRisk.getEntry_start_date());
existingRisk.setEntry_end_date(updatedRisk.getEntry_end_date());
existingRisk.setReview_status(updatedRisk.getReview_status());
existingRisk.setReview_date(updatedRisk.getReview_date());
SafetyRisk savedRisk = safetyRiskService.saveSafetyRisk(existingRisk);
beautifyDates(savedRisk);
return ResponseEntity.ok(savedRisk);
}
private void beautifyDates(SafetyRisk risk) {
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
if (risk.getEntry_start_date() != null) {
LocalDateTime localDateTime = risk.getEntry_start_date().toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime();
risk.setEntry_start_date_str(localDateTime.format(formatter));
}
if (risk.getEntry_end_date() != null) {
LocalDateTime localDateTime = risk.getEntry_end_date().toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime();
risk.setEntry_end_date_str(localDateTime.format(formatter));
}
if (risk.getReview_date() != null) {
LocalDateTime localDateTime = risk.getReview_date().toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime();
risk.setReview_date_str(localDateTime.format(formatter));
}
}
private String convertRiskToJson(SafetyRisk risk) {
if (risk == null) {
return "{}";
}
return String.format(
"{\"id\":%d,\"risk_code\":\"%s\",\"department\":\"%s\",\"professional_system\":\"%s\"," +
"\"risk_category\":\"%s\",\"risk_item\":\"%s\",\"risk_point\":\"%s\",\"risk_level\":\"%s\"," +
"\"harm_degree\":\"%s\",\"control_measures\":\"%s\",\"control_position\":\"%s\"," +
"\"control_personnel\":\"%s\",\"quantified_requirements\":\"%s\",\"entry_start_date\":\"%s\"," +
"\"entry_end_date\":\"%s\",\"review_status\":\"%s\",\"review_date\":\"%s\"}",
risk.getId(),
escapeJson(risk.getRisk_code()),
escapeJson(risk.getDepartment()),
escapeJson(risk.getProfessional_system()),
escapeJson(risk.getRisk_category()),
escapeJson(risk.getRisk_item()),
escapeJson(risk.getRisk_point()),
escapeJson(risk.getRisk_level()),
escapeJson(risk.getHarm_degree()),
escapeJson(risk.getControl_measures()),
escapeJson(risk.getControl_position()),
escapeJson(risk.getControl_personnel()),
escapeJson(risk.getQuantified_requirements()),
risk.getEntry_start_date() != null ? risk.getEntry_start_date().toString() : "",
risk.getEntry_end_date() != null ? risk.getEntry_end_date().toString() : "",
escapeJson(risk.getReview_status()),
risk.getReview_date() != null ? risk.getReview_date().toString() : ""
);
}
private String escapeJson(String str) {
if (str == null) {
return "";
}
return str.replace("\\", "\\\\")
.replace("\"", "\\\"")
.replace("\b", "\\b")
.replace("\f", "\\f")
.replace("\n", "\\n")
.replace("\r", "\\r")
.replace("\t", "\\t");
}
}
2、SafetyRiskHistoryController
package com.lianxi.safety7.controller;
import com.lianxi.safety7.entity.SafetyRisk;
import com.lianxi.safety7.entity.SafetyRiskHistory;
import com.lianxi.safety7.service.SafetyRiskHistoryService;
import com.lianxi.safety7.service.SafetyRiskService;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.data.domain.Page;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.Date;
import java.util.Map;
@RestController
@RequestMapping("/safetyriskhistory")
@CrossOrigin
public class SafetyRiskHistoryController {
@Autowired
private SafetyRiskHistoryService safetyRiskHistoryService;
@Autowired
private SafetyRiskService safetyRiskService;
// 获取系统自动更新的历史记录
@GetMapping("/system")
public ResponseEntity<Page<SafetyRiskHistory>> getSystemGeneratedHistories(
@RequestParam(defaultValue = "1") int page,
@RequestParam(defaultValue = "10") int size) {
Page<SafetyRiskHistory> pageResult = safetyRiskHistoryService.getSystemGeneratedHistories(page, size);
beautifyPageData(pageResult);
return ResponseEntity.ok(pageResult);
}
// 按更新时间范围查询系统记录
@GetMapping("/system/byUpdateTime")
public ResponseEntity<Page<SafetyRiskHistory>> getSystemHistoriesByUpdateTime(
@RequestParam @DateTimeFormat(pattern = "yyyy-MM-dd") Date startTime,
@RequestParam @DateTimeFormat(pattern = "yyyy-MM-dd") Date endTime,
@RequestParam(defaultValue = "1") int page,
@RequestParam(defaultValue = "10") int size) {
if (startTime.after(endTime)) {
throw new IllegalArgumentException("开始时间不能晚于结束时间");
}
Page<SafetyRiskHistory> pageResult = safetyRiskHistoryService.getSystemHistoriesByUpdateTime(
startTime, endTime, page, size);
beautifyPageData(pageResult);
return ResponseEntity.ok(pageResult);
}
// 回溯到指定历史记录
@PostMapping("/revert/{riskCode}")
public ResponseEntity<?> revertSafetyRisk(
@PathVariable String riskCode,
@RequestBody Map<String, Object> requestData) {
try {
// 1. 验证风险代码并获取现有记录
if (riskCode == null || riskCode.isEmpty()) {
throw new IllegalArgumentException("风险代码不能为空");
}
SafetyRisk existingRisk = safetyRiskService.getByRiskCode(riskCode)
.orElseThrow(() -> new IllegalArgumentException("找不到风险代码: " + riskCode));
// 2. 创建要保存的对象并复制属性
SafetyRisk revertedRisk = new SafetyRisk();
BeanUtils.copyProperties(existingRisk, revertedRisk);
// 3. 从请求数据更新所有字段
updateRiskFromRequestData(revertedRisk, requestData);
// 4. 确保关键字段不被覆盖
revertedRisk.setId(existingRisk.getId());
revertedRisk.setRisk_code(riskCode);
// 5. 保存数据
SafetyRisk savedRisk = safetyRiskService.saveSafetyRisk(revertedRisk);
// 6. 记录历史
recordHistory(existingRisk, savedRisk);
return ResponseEntity.ok(Map.of(
"success", true,
"data", savedRisk
));
} catch (Exception e) {
return ResponseEntity.badRequest().body(Map.of(
"success", false,
"message", e.getMessage()
));
}
}
// 从请求数据更新风险对象
private void updateRiskFromRequestData(SafetyRisk risk, Map<String, Object> requestData) {
if (requestData.containsKey("department")) {
risk.setDepartment((String) requestData.get("department"));
}
if (requestData.containsKey("professional_system")) {
risk.setProfessional_system((String) requestData.get("professional_system"));
}
if (requestData.containsKey("risk_category")) {
risk.setRisk_category((String) requestData.get("risk_category"));
}
if (requestData.containsKey("risk_item")) {
risk.setRisk_item((String) requestData.get("risk_item"));
}
if (requestData.containsKey("risk_point")) {
risk.setRisk_point((String) requestData.get("risk_point"));
}
if (requestData.containsKey("risk_level")) {
risk.setRisk_level((String) requestData.get("risk_level"));
}
if (requestData.containsKey("harm_degree")) {
risk.setHarm_degree((String) requestData.get("harm_degree"));
}
if (requestData.containsKey("control_measures")) {
risk.setControl_measures((String) requestData.get("control_measures"));
}
if (requestData.containsKey("control_position")) {
risk.setControl_position((String) requestData.get("control_position"));
}
if (requestData.containsKey("control_personnel")) {
risk.setControl_personnel((String) requestData.get("control_personnel"));
}
if (requestData.containsKey("quantified_requirements")) {
risk.setQuantified_requirements((String) requestData.get("quantified_requirements"));
}
if (requestData.containsKey("entry_start_date")) {
risk.setEntry_start_date(new Date((Long) requestData.get("entry_start_date")));
}
if (requestData.containsKey("entry_end_date")) {
risk.setEntry_end_date(new Date((Long) requestData.get("entry_end_date")));
}
if (requestData.containsKey("review_status")) {
risk.setReview_status((String) requestData.get("review_status"));
}
if (requestData.containsKey("review_date")) {
risk.setReview_date(new Date((Long) requestData.get("review_date")));
}
}
// 记录历史变更
private void recordHistory(SafetyRisk oldRisk, SafetyRisk newRisk) {
SafetyRiskHistory history = new SafetyRiskHistory();
history.setSafetyRisk(newRisk);
history.setUpdateUser("system-revert");
history.setUpdateTime(new Date());
history.setOldValue(convertRiskToJson(oldRisk));
history.setNewValue(convertRiskToJson(newRisk));
safetyRiskHistoryService.saveSafetyRiskHistory(history);
}
// 美化页面数据
private void beautifyPageData(Page<SafetyRiskHistory> pageResult) {
pageResult.getContent().forEach(this::beautifyDates);
pageResult.getContent().forEach(this::beautifyValues);
}
// 美化日期显示
private void beautifyDates(SafetyRiskHistory history) {
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
if (history.getUpdateTime() != null) {
LocalDateTime localDateTime = history.getUpdateTime().toInstant()
.atZone(ZoneId.systemDefault()).toLocalDateTime();
history.setUpdateTime_str(localDateTime.format(formatter));
}
}
// 美化值显示
private void beautifyValues(SafetyRiskHistory history) {
if (history.getOldValue() != null) {
history.setOldValue_str(truncateString(history.getOldValue(), 50));
}
if (history.getNewValue() != null) {
history.setNewValue_str(truncateString(history.getNewValue(), 50));
}
}
private String truncateString(String str, int maxLength) {
if (str == null || str.length() <= maxLength) {
return str;
}
return str.substring(0, maxLength) + "...";
}
private String convertRiskToJson(SafetyRisk risk) {
if (risk == null) {
return "{}";
}
return String.format(
"{\"id\":%d,\"risk_code\":\"%s\",\"department\":\"%s\",\"professional_system\":\"%s\"," +
"\"risk_category\":\"%s\",\"risk_item\":\"%s\",\"risk_point\":\"%s\",\"risk_level\":\"%s\"," +
"\"harm_degree\":\"%s\",\"control_measures\":\"%s\",\"control_position\":\"%s\"," +
"\"control_personnel\":\"%s\",\"quantified_requirements\":\"%s\",\"entry_start_date\":\"%s\"," +
"\"entry_end_date\":\"%s\",\"review_status\":\"%s\",\"review_date\":\"%s\"}",
risk.getId(),
escapeJson(risk.getRisk_code()),
escapeJson(risk.getDepartment()),
escapeJson(risk.getProfessional_system()),
escapeJson(risk.getRisk_category()),
escapeJson(risk.getRisk_item()),
escapeJson(risk.getRisk_point()),
escapeJson(risk.getRisk_level()),
escapeJson(risk.getHarm_degree()),
escapeJson(risk.getControl_measures()),
escapeJson(risk.getControl_position()),
escapeJson(risk.getControl_personnel()),
escapeJson(risk.getQuantified_requirements()),
risk.getEntry_start_date() != null ? risk.getEntry_start_date().toString() : "",
risk.getEntry_end_date() != null ? risk.getEntry_end_date().toString() : "",
escapeJson(risk.getReview_status()),
risk.getReview_date() != null ? risk.getReview_date().toString() : ""
);
}
private String escapeJson(String str) {
if (str == null) {
return "";
}
return str.replace("\\", "\\\\")
.replace("\"", "\\\"")
.replace("\b", "\\b")
.replace("\f", "\\f")
.replace("\n", "\\n")
.replace("\r", "\\r")
.replace("\t", "\\t");
}
}
3、repository代码
SafetyRiskHistoryRepository
package com.lianxi.safety7.repository;
import com.lianxi.safety7.entity.SafetyRiskHistory;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import org.springframework.stereotype.Repository;
import java.util.Date;
import java.util.List;
@Repository
public interface SafetyRiskHistoryRepository extends JpaRepository<SafetyRiskHistory, Integer> {
@Query("SELECT s FROM SafetyRiskHistory s WHERE (:historyId IS NULL OR s.historyId = :historyId) AND (:riskId IS NULL OR s.safetyRisk.id = :riskId)")
Page<SafetyRiskHistory> findByHistoryIdAndRiskId(@Param("historyId") Integer historyId, @Param("riskId") Integer riskId, Pageable pageable);
Page<SafetyRiskHistory> findAllByHistoryId(Integer historyId, Pageable pageable);
Page<SafetyRiskHistory> findByUpdateTimeBetween(Date startTime, Date endTime, Pageable pageable);
Page<SafetyRiskHistory> findByUpdateTimeAfter(Date startTime, Pageable pageable);
Page<SafetyRiskHistory> findByUpdateTimeBefore(Date endTime, Pageable pageable);
@Query("SELECT h FROM SafetyRiskHistory h WHERE h.safetyRisk.risk_code LIKE :riskCode")
Page<SafetyRiskHistory> findByRiskCodeContaining(@Param("riskCode") String riskCode, Pageable pageable);
@Query("SELECT s FROM SafetyRiskHistory s WHERE " +
"(:historyId IS NULL OR s.historyId = :historyId) AND " +
"(:riskId IS NULL OR s.safetyRisk.id = :riskId) AND " +
"(:riskCode IS NULL OR s.safetyRisk.risk_code LIKE :riskCode) AND " +
"(:updateUser IS NULL OR s.updateUser = :updateUser) AND " +
"(:updateTime IS NULL OR s.updateTime = :updateTime) AND " +
"(:oldValue IS NULL OR s.oldValue = :oldValue) AND " +
"(:newValue IS NULL OR s.newValue = :newValue)")
Page<SafetyRiskHistory> findByMultipleConditions(
@Param("historyId") Integer historyId,
@Param("riskId") Integer riskId,
@Param("riskCode") String riskCode,
@Param("updateUser") String updateUser,
@Param("updateTime") Date updateTime,
@Param("oldValue") String oldValue,
@Param("newValue") String newValue,
Pageable pageable
);
@Query("SELECT s FROM SafetyRiskHistory s WHERE s.safetyRisk.id = :riskId")
Page<SafetyRiskHistory> findByRiskId(@Param("riskId") Integer riskId, Pageable pageable);
Page<SafetyRiskHistory> findByUpdateUserIn(List<String> updateUsers, Pageable pageable);
Page<SafetyRiskHistory> findByUpdateUserInAndUpdateTimeBetween(List<String> updateUsers, Date startTime, Date endTime, Pageable pageable);
}
SafetyRiskRepository
package com.lianxi.safety7.repository;
import com.lianxi.safety7.entity.SafetyRisk;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import org.springframework.stereotype.Repository;
import java.util.Date;
import java.util.List;
import java.util.Optional;
@Repository
public interface SafetyRiskRepository extends JpaRepository<SafetyRisk, Integer> {
@Query("SELECT s FROM SafetyRisk s WHERE (:id IS NULL OR s.id = :id) AND (:riskLevel IS NULL OR :riskLevel = '' OR s.risk_level = :riskLevel)")
List<SafetyRisk> findByIdAndRiskLevel(@Param("id") Integer id, @Param("riskLevel") String riskLevel);
List<SafetyRisk> findAllById(Integer id);
@Query("SELECT s FROM SafetyRisk s WHERE (:riskCode IS NULL OR s.risk_code LIKE %:riskCode%)")
Page<SafetyRisk> findByRiskCodeContaining(@Param("riskCode") String riskCode, Pageable pageable);
@Query("SELECT s FROM SafetyRisk s WHERE " +
"(:id IS NULL OR s.id = :id) AND " +
"(:risk_code IS NULL OR s.risk_code LIKE %:risk_code%) AND " +
"(:department IS NULL OR s.department = :department) AND " +
"(:professional_system IS NULL OR s.professional_system = :professional_system) AND " +
"(:risk_category IS NULL OR s.risk_category = :risk_category) AND " +
"(:risk_item IS NULL OR s.risk_item = :risk_item) AND " +
"(:risk_point IS NULL OR s.risk_point = :risk_point) AND " +
"(:risk_level IS NULL OR s.risk_level = :risk_level) AND " +
"(:harm_degree IS NULL OR s.harm_degree = :harm_degree) AND " +
"(:control_measures IS NULL OR s.control_measures = :control_measures) AND " +
"(:control_position IS NULL OR s.control_position = :control_position) AND " +
"(:control_personnel IS NULL OR s.control_personnel = :control_personnel) AND " +
"(:quantified_requirements IS NULL OR s.quantified_requirements = :quantified_requirements) AND " +
"(:entry_start_date IS NULL OR s.entry_start_date = :entry_start_date) AND " +
"(:entry_end_date IS NULL OR s.entry_end_date = :entry_end_date) AND " +
"(:review_status IS NULL OR s.review_status = :review_status) AND " +
"(:review_date IS NULL OR s.review_date = :review_date)")
Page<SafetyRisk> findByMultipleConditions(
@Param("id") Integer id,
@Param("risk_code") String risk_code,
@Param("department") String department,
@Param("professional_system") String professional_system,
@Param("risk_category") String risk_category,
@Param("risk_item") String risk_item,
@Param("risk_point") String risk_point,
@Param("risk_level") String risk_level,
@Param("harm_degree") String harm_degree,
@Param("control_measures") String control_measures,
@Param("control_position") String control_position,
@Param("control_personnel") String control_personnel,
@Param("quantified_requirements") String quantified_requirements,
@Param("entry_start_date") Date entry_start_date,
@Param("entry_end_date") Date entry_end_date,
@Param("review_status") String review_status,
@Param("review_date") Date review_date,
Pageable pageable
);
@Query("SELECT s FROM SafetyRisk s WHERE s.risk_level = :riskLevel")
List<SafetyRisk> findByRiskLevel(@Param("riskLevel") String riskLevel);
@Query("SELECT s FROM SafetyRisk s " +
"WHERE (:id IS NULL OR s.id = :id) AND " +
"(:risk_code IS NULL OR s.risk_code LIKE %:risk_code%) AND " +
"(:department IS NULL OR s.department = :department) AND " +
"(:professional_system IS NULL OR s.professional_system = :professional_system) AND " +
"(:risk_category IS NULL OR s.risk_category = :risk_category) AND " +
"(:risk_item IS NULL OR s.risk_item = :risk_item) AND " +
"(:risk_point IS NULL OR s.risk_point = :risk_point) AND " +
"(:risk_level IS NULL OR s.risk_level = :risk_level) AND " +
"(:harm_degree IS NULL OR s.harm_degree = :harm_degree) AND " +
"(:control_measures IS NULL OR s.control_measures = :control_measures) AND " +
"(:control_position IS NULL OR s.control_position = :control_position) AND " +
"(:control_personnel IS NULL OR s.control_personnel = :control_personnel) AND " +
"(:quantified_requirements IS NULL OR s.quantified_requirements = :quantified_requirements) AND " +
"(:entry_start_date IS NULL OR s.entry_start_date = :entry_start_date) AND " +
"(:entry_end_date IS NULL OR s.entry_end_date = :entry_end_date) AND " +
"(:review_status IS NULL OR s.review_status = :review_status) AND " +
"(:review_date IS NULL OR s.review_date = :review_date)")
List<SafetyRisk> findByMultipleConditions(
@Param("id") Integer id,
@Param("risk_code") String risk_code,
@Param("department") String department,
@Param("professional_system") String professional_system,
@Param("risk_category") String risk_category,
@Param("risk_item") String risk_item,
@Param("risk_point") String risk_point,
@Param("risk_level") String risk_level,
@Param("harm_degree") String harm_degree,
@Param("control_measures") String control_measures,
@Param("control_position") String control_position,
@Param("control_personnel") String control_personnel,
@Param("quantified_requirements") String quantified_requirements,
@Param("entry_start_date") Date entry_start_date,
@Param("entry_end_date") Date entry_end_date,
@Param("review_status") String review_status,
@Param("review_date") Date review_date
);
// 添加 findByRiskCode 方法
@Query("SELECT s FROM SafetyRisk s WHERE s.risk_code = :riskCode")
Optional<SafetyRisk> findByRiskCode(@Param("riskCode") String riskCode);
}
4、service
SafetyRiskHistoryService
package com.lianxi.safety7.service;
import com.lianxi.safety7.entity.SafetyRisk;
import com.lianxi.safety7.entity.SafetyRiskHistory;
import com.lianxi.safety7.repository.SafetyRiskHistoryRepository;
import com.lianxi.safety7.repository.SafetyRiskRepository;
import jakarta.persistence.EntityManager;
import jakarta.persistence.PersistenceContext;
import jakarta.transaction.Transactional;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.Optional;
@Service
public class SafetyRiskHistoryService {
@PersistenceContext
private EntityManager entityManager;
@Autowired
private SafetyRiskHistoryRepository safetyRiskHistoryRepository;
@Autowired
private SafetyRiskRepository safetyRiskRepository;
public SafetyRiskHistory saveSafetyRiskHistory(SafetyRiskHistory safetyRiskHistory) {
if (safetyRiskHistory.getSafetyRisk() != null && safetyRiskHistory.getSafetyRisk().getId() != null) {
Optional<SafetyRisk> safetyRiskOptional = safetyRiskRepository.findById(safetyRiskHistory.getSafetyRisk().getId());
if (safetyRiskOptional.isPresent()) {
safetyRiskHistory.setSafetyRisk(safetyRiskOptional.get());
} else {
throw new IllegalArgumentException("关联的风险记录不存在,id: " + safetyRiskHistory.getSafetyRisk().getId());
}
} else {
throw new IllegalArgumentException("关联的风险记录不能为空");
}
Integer historyId = safetyRiskHistory.getHistoryId();
if (historyId == null) {
return safetyRiskHistoryRepository.save(safetyRiskHistory);
} else {
return safetyRiskHistoryRepository.findById(historyId)
.map(existingHistory -> {
existingHistory.setSafetyRisk(safetyRiskHistory.getSafetyRisk());
existingHistory.setUpdateUser(safetyRiskHistory.getUpdateUser());
existingHistory.setUpdateTime(safetyRiskHistory.getUpdateTime());
existingHistory.setOldValue(safetyRiskHistory.getOldValue());
existingHistory.setNewValue(safetyRiskHistory.getNewValue());
return safetyRiskHistoryRepository.save(existingHistory);
})
.orElseGet(() -> {
System.out.println("未找到 ID 为 " + historyId + " 的记录,将创建新记录");
return safetyRiskHistoryRepository.save(safetyRiskHistory);
});
}
}
public Page<SafetyRiskHistory> getAllSafetyRiskHistories(int page, int size) {
Pageable pageable = PageRequest.of(page - 1, size);
System.out.println("获取所有风险历史数据,页码: " + page + ", 每页数量: " + size);
Page<SafetyRiskHistory> result = safetyRiskHistoryRepository.findAll(pageable);
System.out.println("查询结果数量: " + result.getTotalElements());
return result;
}
public void deleteSafetyRiskHistory(int id) {
safetyRiskHistoryRepository.deleteById(id);
}
public Page<SafetyRiskHistory> getSafetyRiskHistoriesByQuery(
Integer historyId,
Integer riskId,
String riskCode,
String updateUser,
Date updateTime,
String oldValue,
String newValue,
int page,
int size
) {
Pageable pageable = PageRequest.of(page - 1, size);
System.out.println("查询条件: historyId=" + historyId + ", riskId=" + riskId + ", riskCode=" + riskCode +
", updateUser=" + updateUser + ", updateTime=" + updateTime + ", oldValue=" + oldValue +
", newValue=" + newValue + ", 页码: " + page + ", 每页数量: " + size);
Page<SafetyRiskHistory> result = safetyRiskHistoryRepository.findByMultipleConditions(
historyId, riskId, riskCode, updateUser, updateTime, oldValue, newValue, pageable
);
System.out.println("查询结果数量: " + result.getTotalElements());
return result;
}
public Page<SafetyRiskHistory> getSafetyRiskHistoriesByRiskCode(String riskCode, int page, int size) {
Pageable pageable = PageRequest.of(page - 1, size);
return safetyRiskHistoryRepository.findByRiskCodeContaining(riskCode, pageable);
}
// 新增方法:按照更新时间范围查询
public Page<SafetyRiskHistory> getSafetyRiskHistoriesByUpdateTime(Date startTime, Date endTime, int page, int size) {
Pageable pageable = PageRequest.of(page - 1, size);
System.out.println("按更新时间范围查询: startTime=" + startTime + ", endTime=" + endTime +
", 页码: " + page + ", 每页数量: " + size);
return safetyRiskHistoryRepository.findByUpdateTimeBetween(startTime, endTime, pageable);
}
// 新增方法:灵活的时间范围查询
public Page<SafetyRiskHistory> getSafetyRiskHistoriesByUpdateTimeRange(Date startTime, Date endTime, int page, int size) {
Pageable pageable = PageRequest.of(page - 1, size);
System.out.println("按灵活更新时间范围查询: startTime=" + startTime + ", endTime=" + endTime +
", 页码: " + page + ", 每页数量: " + size);
if (startTime != null && endTime != null) {
return safetyRiskHistoryRepository.findByUpdateTimeBetween(startTime, endTime, pageable);
} else if (startTime != null) {
return safetyRiskHistoryRepository.findByUpdateTimeAfter(startTime, pageable);
} else if (endTime != null) {
return safetyRiskHistoryRepository.findByUpdateTimeBefore(endTime, pageable);
} else {
return safetyRiskHistoryRepository.findAll(pageable);
}
}
public List<SafetyRiskHistory> list() {
return safetyRiskHistoryRepository.findAll();
}
@Transactional
public void saveBatch(List<SafetyRiskHistory> historyList) {
try {
for (SafetyRiskHistory history : historyList) {
saveSafetyRiskHistory(history);
}
} catch (Exception e) {
System.out.println("数据批量保存失败:" + e.getMessage());
e.printStackTrace();
throw new RuntimeException("数据批量保存失败", e);
}
}
public Optional<SafetyRiskHistory> getById(Integer id) {
return safetyRiskHistoryRepository.findById(id);
}
// 新增方法
public Page<SafetyRiskHistory> getSystemGeneratedHistories(int page, int size) {
Pageable pageable = PageRequest.of(page - 1, size);
return safetyRiskHistoryRepository.findByUpdateUserIn(Arrays.asList("system", "root@localhost"), pageable);
}
// 新增方法 getSystemHistoriesByUpdateTime
public Page<SafetyRiskHistory> getSystemHistoriesByUpdateTime(Date startTime, Date endTime, int page, int size) {
Pageable pageable = PageRequest.of(page - 1, size);
return safetyRiskHistoryRepository.findByUpdateUserInAndUpdateTimeBetween(
Arrays.asList("system", "root@localhost"), startTime, endTime, pageable
);
}
}
SafetyRiskService
package com.lianxi.safety7.service;
import com.lianxi.safety7.entity.SafetyRisk;
import com.lianxi.safety7.entity.SafetyRiskHistory;
import com.lianxi.safety7.repository.SafetyRiskRepository;
import jakarta.persistence.EntityManager;
import jakarta.persistence.PersistenceContext;
import jakarta.transaction.Transactional;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import java.util.Date;
import java.util.List;
import java.util.Optional;
@Service
public class SafetyRiskService {
@PersistenceContext
private EntityManager entityManager;
@Autowired
private SafetyRiskRepository safetyRiskRepository;
@Autowired
private SafetyRiskHistoryService safetyRiskHistoryService;
@Transactional
public SafetyRisk saveSafetyRisk(SafetyRisk safetyRisk) {
if (safetyRisk.getId() == null) {
return safetyRiskRepository.save(safetyRisk);
} else {
return safetyRiskRepository.findById(safetyRisk.getId())
.map(existingRisk -> {
// 如果是系统回溯操作,直接保存不创建历史记录
if (!"system-revert".equals(safetyRisk.getUpdateUser())) {
SafetyRiskHistory history = new SafetyRiskHistory();
history.setSafetyRisk(existingRisk);
history.setUpdateUser("system");
history.setUpdateTime(new Date());
history.setOldValue(convertRiskToJson(existingRisk));
history.setNewValue(convertRiskToJson(safetyRisk));
safetyRiskHistoryService.saveSafetyRiskHistory(history);
}
// 更新现有记录
existingRisk.setRisk_code(safetyRisk.getRisk_code());
existingRisk.setDepartment(safetyRisk.getDepartment());
existingRisk.setProfessional_system(safetyRisk.getProfessional_system());
existingRisk.setRisk_category(safetyRisk.getRisk_category());
existingRisk.setRisk_item(safetyRisk.getRisk_item());
existingRisk.setRisk_point(safetyRisk.getRisk_point());
existingRisk.setRisk_level(safetyRisk.getRisk_level());
existingRisk.setHarm_degree(safetyRisk.getHarm_degree());
existingRisk.setControl_measures(safetyRisk.getControl_measures());
existingRisk.setControl_position(safetyRisk.getControl_position());
existingRisk.setControl_personnel(safetyRisk.getControl_personnel());
existingRisk.setQuantified_requirements(safetyRisk.getQuantified_requirements());
existingRisk.setEntry_start_date(safetyRisk.getEntry_start_date());
existingRisk.setEntry_end_date(safetyRisk.getEntry_end_date());
existingRisk.setReview_status(safetyRisk.getReview_status());
existingRisk.setReview_date(safetyRisk.getReview_date());
return safetyRiskRepository.save(existingRisk);
})
.orElseGet(() -> {
System.out.println("未找到 ID 为 " + safetyRisk.getId() + " 的记录,将创建新记录");
return safetyRiskRepository.save(safetyRisk);
});
}
}
private String convertRiskToJson(SafetyRisk risk) {
if (risk == null) {
return "{}";
}
return String.format(
"{\"id\":%d,\"risk_code\":\"%s\",\"department\":\"%s\",\"professional_system\":\"%s\"," +
"\"risk_category\":\"%s\",\"risk_item\":\"%s\",\"risk_point\":\"%s\",\"risk_level\":\"%s\"," +
"\"harm_degree\":\"%s\",\"control_measures\":\"%s\",\"control_position\":\"%s\"," +
"\"control_personnel\":\"%s\",\"quantified_requirements\":\"%s\",\"entry_start_date\":\"%s\"," +
"\"entry_end_date\":\"%s\",\"review_status\":\"%s\",\"review_date\":\"%s\"}",
risk.getId(),
escapeJson(risk.getRisk_code()),
escapeJson(risk.getDepartment()),
escapeJson(risk.getProfessional_system()),
escapeJson(risk.getRisk_category()),
escapeJson(risk.getRisk_item()),
escapeJson(risk.getRisk_point()),
escapeJson(risk.getRisk_level()),
escapeJson(risk.getHarm_degree()),
escapeJson(risk.getControl_measures()),
escapeJson(risk.getControl_position()),
escapeJson(risk.getControl_personnel()),
escapeJson(risk.getQuantified_requirements()),
risk.getEntry_start_date() != null ? risk.getEntry_start_date().toString() : "",
risk.getEntry_end_date() != null ? risk.getEntry_end_date().toString() : "",
escapeJson(risk.getReview_status()),
risk.getReview_date() != null ? risk.getReview_date().toString() : ""
);
}
private String escapeJson(String str) {
if (str == null) {
return "";
}
return str.replace("\\", "\\\\")
.replace("\"", "\\\"")
.replace("\b", "\\b")
.replace("\f", "\\f")
.replace("\n", "\\n")
.replace("\r", "\\r")
.replace("\t", "\\t");
}
public Page<SafetyRisk> getAllSafetyRisks(int page, int size) {
Pageable pageable = PageRequest.of(page - 1, size);
System.out.println("获取所有风险数据,页码: " + page + ", 每页数量: " + size);
Page<SafetyRisk> result = safetyRiskRepository.findAll(pageable);
System.out.println("查询结果数量: " + result.getTotalElements());
return result;
}
public void deleteSafetyRisk(int id) {
safetyRiskRepository.deleteById(id);
}
public Page<SafetyRisk> getSafetyRisksByQuery(
Integer id,
String risk_code,
String department,
String professional_system,
String risk_category,
String risk_item,
String risk_point,
String risk_level,
String harm_degree,
String control_measures,
String control_position,
String control_personnel,
String quantified_requirements,
Date entry_start_date,
Date entry_end_date,
String review_status,
Date review_date,
int page,
int size
) {
Pageable pageable = PageRequest.of(page - 1, size);
System.out.println("查询条件: id=" + id + ", risk_code=" + risk_code + ", department=" + department +
", professional_system=" + professional_system + ", risk_category=" + risk_category +
", risk_item=" + risk_item + ", risk_point=" + risk_point + ", risk_level=" + risk_level +
", harm_degree=" + harm_degree + ", control_measures=" + control_measures +
", control_position=" + control_position + ", control_personnel=" + control_personnel +
", quantified_requirements=" + quantified_requirements + ", entry_start_date=" + entry_start_date +
", entry_end_date=" + entry_end_date + ", review_status=" + review_status +
", review_date=" + review_date + ", 页码: " + page + ", 每页数量: " + size);
Page<SafetyRisk> result = safetyRiskRepository.findByMultipleConditions(
id, risk_code, department, professional_system, risk_category,
risk_item, risk_point, risk_level, harm_degree, control_measures,
control_position, control_personnel, quantified_requirements,
entry_start_date, entry_end_date, review_status, review_date,
pageable
);
System.out.println("查询结果数量: " + result.getTotalElements());
return result;
}
public Page<SafetyRisk> getSafetyRisksByRiskCode(String riskCode, int page, int size) {
Pageable pageable = PageRequest.of(page - 1, size);
return safetyRiskRepository.findByRiskCodeContaining(riskCode, pageable);
}
public List<SafetyRisk> list() {
return safetyRiskRepository.findAll();
}
@Transactional
public void saveBatch(List<SafetyRisk> riskList) {
try {
for (SafetyRisk risk : riskList) {
saveSafetyRisk(risk);
}
} catch (Exception e) {
System.out.println("数据批量保存失败:" + e.getMessage());
e.printStackTrace();
throw new RuntimeException("数据批量保存失败", e);
}
}
public Optional<SafetyRisk> getById(Integer id) {
return safetyRiskRepository.findById(id);
}
public Optional<SafetyRisk> getByRiskCode(String riskCode) {
return safetyRiskRepository.findByRiskCode(riskCode);
}
}
5、前端代码
HomeView.vue
<template>
<div>
<el-button @click="add" type="primary">添加数据</el-button>
<el-dialog v-model="dialogVisible" :title="form.id ? '编辑风险记录' : '新增风险记录'" width="50%" :before-close="handleClose">
<el-form :label-position="labelPosition" label-width="150px" :model="form" style="max-width: 600px">
<el-form-item v-if="form.id" label="编号">
<el-input v-model="form.id" disabled />
</el-form-item>
<el-form-item label="风险代码">
<el-input v-model="form.risk_code" />
</el-form-item>
<el-form-item label="部门">
<el-input v-model="form.department" />
</el-form-item>
<el-form-item label="专业系统">
<el-input v-model="form.professional_system" />
</el-form-item>
<el-form-item label="风险类别">
<el-input v-model="form.risk_category" />
</el-form-item>
<el-form-item label="风险事项">
<el-input v-model="form.risk_item" />
</el-form-item>
<el-form-item label="风险点">
<el-input v-model="form.risk_point" type="textarea" :rows="2" />
</el-form-item>
<el-form-item label="风险等级">
<el-select v-model="form.risk_level" placeholder="请选择风险等级">
<el-option label="重大" value="MAJOR" />
<el-option label="较大" value="LARGER" />
<el-option label="一般" value="GENERAL" />
<el-option label="低" value="LOW" />
</el-select>
</el-form-item>
<el-form-item label="危害程度">
<el-select v-model="form.harm_degree" placeholder="请选择危害程度">
<el-option label="极高" value="VERY_HIGH" />
<el-option label="高" value="HIGH" />
<el-option label="中" value="MEDIUM" />
<el-option label="低" value="LOW" />
</el-select>
</el-form-item>
<el-form-item label="控制措施">
<el-input v-model="form.control_measures" type="textarea" :rows="3" />
</el-form-item>
<el-form-item label="控制位置">
<el-input v-model="form.control_position" />
</el-form-item>
<el-form-item label="控制人员">
<el-input v-model="form.control_personnel" />
</el-form-item>
<el-form-item label="量化要求">
<el-input v-model="form.quantified_requirements" type="textarea" :rows="2" />
</el-form-item>
<el-form-item label="录入开始日期">
<el-date-picker
v-model="form.entry_start_date"
type="date"
placeholder="选择开始日期"
value-format="YYYY-MM-DD"
/>
</el-form-item>
<el-form-item label="录入结束日期">
<el-date-picker
v-model="form.entry_end_date"
type="date"
placeholder="选择结束日期"
value-format="YYYY-MM-DD"
/>
</el-form-item>
<el-form-item label="审核状态">
<el-select v-model="form.review_status" placeholder="请选择审核状态">
<el-option label="待审核" value="PENDING" />
<el-option label="已通过" value="APPROVED" />
<el-option label="已拒绝" value="REJECTED" />
</el-select>
</el-form-item>
<el-form-item label="审核日期">
<el-date-picker
v-model="form.review_date"
type="date"
placeholder="选择审核日期"
value-format="YYYY-MM-DD"
/>
</el-form-item>
</el-form>
<template #footer>
<span class="dialog-footer">
<el-button @click="dialogVisible = false">取消</el-button>
<el-button type="primary" @click="save">确认</el-button>
</span>
</template>
</el-dialog>
<el-table :data="tableData" stripe style="width: 100%">
<!-- 添加序号列 -->
<el-table-column label="序号" width="60" fixed>
<template #default="scope">
{{ scope.$index + 1 }}
</template>
</el-table-column>
<el-table-column prop="id" label="数据库ID" width="80" />
<el-table-column prop="risk_code" label="风险代码" />
<el-table-column prop="department" label="部门" />
<el-table-column prop="professional_system" label="专业系统" />
<el-table-column prop="risk_category" label="风险类别" />
<el-table-column prop="risk_item" label="风险事项" />
<el-table-column prop="risk_point" label="风险点" />
<el-table-column prop="risk_level" label="风险等级">
<template #default="scope">
<el-tag :type="getRiskLevelTagType(scope.row.risk_level)">
{{ formatRiskLevel(scope.row.risk_level) }}
</el-tag>
</template>
</el-table-column>
<el-table-column prop="harm_degree" label="危害程度">
<template #default="scope">
<el-tag :type="getHarmDegreeTagType(scope.row.harm_degree)">
{{ formatHarmDegree(scope.row.harm_degree) }}
</el-tag>
</template>
</el-table-column>
<el-table-column prop="control_measures" label="控制措施" show-overflow-tooltip />
<el-table-column prop="control_position" label="控制位置" />
<el-table-column prop="control_personnel" label="控制人员" />
<el-table-column prop="quantified_requirements" label="量化要求" show-overflow-tooltip />
<el-table-column prop="entry_start_date" label="录入开始日期" width="120" />
<el-table-column prop="entry_end_date" label="录入结束日期" width="120" />
<el-table-column prop="review_status" label="审核状态">
<template #default="scope">
<el-tag :type="getStatusTagType(scope.row.review_status)">
{{ formatReviewStatus(scope.row.review_status) }}
</el-tag>
</template>
</el-table-column>
<el-table-column prop="review_date" label="审核日期" width="120" />
<el-table-column fixed="right" label="操作" width="150">
<template #default="scope">
<el-button type="primary" size="small" @click="handleEdit(scope.row)">编辑</el-button>
<el-popconfirm title="确认删除?" @confirm="handleDelete(scope.row.id)">
<template #reference>
<el-button type="danger" size="small">删除</el-button>
</template>
</el-popconfirm>
</template>
</el-table-column>
</el-table>
</div>
</template>
<script>
import request from '@/utils/request'
export default {
name: 'SafetyRiskView',
data() {
return {
form: {
id: null,
risk_code: '',
department: '',
professional_system: '',
risk_category: '',
risk_item: '',
risk_point: '',
risk_level: '',
harm_degree: '',
control_measures: '',
control_position: '',
control_personnel: '',
quantified_requirements: '',
entry_start_date: null,
entry_end_date: null,
review_status: 'PENDING',
review_date: null,
},
dialogVisible: false,
tableData: [],
labelPosition: 'right'
}
},
created() {
this.load();
},
methods: {
add() {
this.form = {
id: null,
risk_code: '',
department: '',
professional_system: '',
risk_category: '',
risk_item: '',
risk_point: '',
risk_level: '',
harm_degree: '',
control_measures: '',
control_position: '',
control_personnel: '',
quantified_requirements: '',
entry_start_date: null,
entry_end_date: null,
review_status: 'PENDING',
review_date: null,
};
this.dialogVisible = true;
},
load() {
request.get("http://localhost:9090/safetyrisk/all").then(res => {
this.tableData = res.content;
});
},
save() {
const api = this.form.id
? `http://localhost:9090/safetyrisk/${this.form.id}`
: "http://localhost:9090/safetyrisk";
request[this.form.id ? 'put' : 'post'](api, this.form).then(() => {
this.$message.success(this.form.id ? '更新成功' : '添加成功');
this.load();
this.dialogVisible = false;
}).catch(error => {
this.$message.error('操作失败: ' + (error.response?.data?.message || error.message));
});
},
handleEdit(row) {
this.form = JSON.parse(JSON.stringify(row));
this.dialogVisible = true;
},
handleDelete(id) {
request.delete(`http://localhost:9090/safetyrisk/${id}`).then(() => {
this.$message.success('删除成功');
this.load();
}).catch(error => {
this.$message.error('删除失败: ' + (error.response?.data?.message || error.message));
});
},
handleClose(done) {
done();
},
formatRiskLevel(level) {
const map = {
'MAJOR': '重大',
'LARGER': '较大',
'GENERAL': '一般',
'LOW': '低'
}
return map[level] || level;
},
formatHarmDegree(degree) {
const map = {
'VERY_HIGH': '极高',
'HIGH': '高',
'MEDIUM': '中',
'LOW': '低'
}
return map[degree] || degree;
},
formatReviewStatus(status) {
const map = {
'PENDING': '待审核',
'APPROVED': '已通过',
'REJECTED': '已拒绝'
}
return map[status] || status;
},
getRiskLevelTagType(level) {
const map = {
'MAJOR': 'danger',
'LARGER': 'warning',
'GENERAL': '',
'LOW': 'success'
}
return map[level] || '';
},
getHarmDegreeTagType(degree) {
const map = {
'VERY_HIGH': 'danger',
'HIGH': 'warning',
'MEDIUM': '',
'LOW': 'success'
}
return map[degree] || '';
},
getStatusTagType(status) {
const map = {
'PENDING': 'warning',
'APPROVED': 'success',
'REJECTED': 'danger'
}
return map[status] || '';
}
}
}
</script>
<style scoped>
.dialog-footer {
display: flex;
justify-content: flex-end;
}
</style>
AboutView.vue
<template>
<div>
<!-- 搜索区域 - 只保留时间范围查询 -->
<div class="search-container">
<el-form :inline="true" :model="searchForm" class="search-form">
<el-form-item label="系统更新时间范围">
<el-date-picker
v-model="searchForm.timeRange"
type="datetimerange"
range-separator="至"
start-placeholder="开始时间"
end-placeholder="结束时间"
value-format="YYYY-MM-DD HH:mm:ss"
style="width: 380px"
/>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="handleSearch">查询系统记录</el-button>
<el-button @click="resetSearch">重置</el-button>
</el-form-item>
</el-form>
</div>
<!-- 表格展示系统历史记录 -->
<el-table
:data="tableData"
stripe
style="width: 100%"
v-loading="loading"
>
<el-table-column label="序号" width="60">
<template #default="scope">
{{ scope.$index + 1 }}
</template>
</el-table-column>
<el-table-column prop="historyId" label="记录ID" width="100" />
<el-table-column prop="safetyRisk.risk_code" label="风险代码" />
<!-- 操作来源列 -->
<el-table-column label="操作来源" width="150">
<template #default="scope">
<div class="operator-cell">
<el-icon class="system-icon">
<Cpu />
</el-icon>
<span class="system-operator">
{{ formatOperator(scope.row.updateUser) }}
</span>
</div>
</template>
</el-table-column>
<el-table-column label="更新时间" width="180">
<template #default="scope">
{{ scope.row.updateTime_str || '无' }}
</template>
</el-table-column>
<el-table-column label="值对比">
<template #default="scope">
<div class="value-comparison-container">
<div class="value-header">
<div class="value-title old-value-title">旧值</div>
<div class="value-title new-value-title">新值</div>
</div>
<div class="value-diff-container">
<div
v-for="(diff, index) in getValueDiffs(scope.row)"
:key="index"
class="value-row"
>
<div class="value-cell old-value-cell">
<span class="property-name">{{ diff.property }}:</span>
<span>{{ diff.oldValue || '无' }}</span>
</div>
<div class="value-cell new-value-cell">
<span class="property-name">{{ diff.property }}:</span>
<span>{{ diff.newValue || '无' }}</span>
</div>
</div>
</div>
</div>
</template>
</el-table-column>
<!-- 添加回溯操作列 -->
<el-table-column fixed="right" label="操作" width="120">
<template #default="scope">
<el-popconfirm
title="确认回溯到该历史记录?"
@confirm="handleRevert(scope.row)"
>
<template #reference>
<el-button type="primary" size="small">回溯</el-button>
</template>
</el-popconfirm>
</template>
</el-table-column>
</el-table>
<!-- 分页组件 -->
<div class="pagination-container">
<el-pagination
v-model:current-page="pagination.current"
v-model:page-size="pagination.size"
:total="pagination.total"
:page-sizes="[10, 20, 50, 100]"
layout="total, sizes, prev, pager, next, jumper"
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
/>
</div>
</div>
</template>
<script setup>
/* eslint-disable */
import { ref, onMounted } from 'vue'
import { Cpu } from '@element-plus/icons-vue'
import request from '@/utils/request'
import { ElMessage } from 'element-plus'
// 数据定义
const searchForm = ref({
timeRange: []
})
const tableData = ref([])
const loading = ref(false)
// 分页数据
const pagination = ref({
current: 1,
size: 10,
total: 0
})
// 操作来源格式化
const formatOperator = (operator) => {
const map = {
'system': '系统自动',
'root@localhost': '系统管理员',
'system-revert': '系统回溯'
}
return map[operator] || operator
}
// 数据加载方法
const loadSystemData = async () => {
loading.value = true
try {
let url = "http://localhost:9090/safetyriskhistory/system"
let params = {
page: pagination.value.current,
size: pagination.value.size
}
// 如果有时间范围,使用时间范围查询
if (searchForm.value.timeRange?.length === 2) {
url = "http://localhost:9090/safetyriskhistory/system/byUpdateTime"
params.startTime = searchForm.value.timeRange[0]
params.endTime = searchForm.value.timeRange[1]
}
const res = await request.get(url, { params })
tableData.value = res.content
pagination.value.total = res.totalElements
} catch (error) {
console.error('加载系统数据失败:', error)
ElMessage.error('加载系统数据失败')
} finally {
loading.value = false
}
}
// 回溯方法
const handleRevert = async (historyRecord) => {
try {
loading.value = true;
// 直接从历史记录获取风险代码
const riskCode = historyRecord.safetyRisk?.risk_code;
if (!riskCode) {
throw new Error('无法从历史记录中获取风险代码');
}
// 解析旧值数据
let revertData = {};
try {
revertData = JSON.parse(historyRecord.oldValue || '{}');
} catch (e) {
console.error('解析历史记录失败:', e);
throw new Error('解析历史记录数据失败');
}
// 发送请求到正确的端点
const response = await request.post(
`/safetyriskhistory/revert/${encodeURIComponent(riskCode)}`,
revertData,
{
headers: {
'Content-Type': 'application/json'
}
}
);
ElMessage.success('追溯成功');
loadSystemData();
} catch (error) {
console.error('追溯错误:', error);
ElMessage.error(`追溯失败: ${error.response?.data?.message || error.message}`);
} finally {
loading.value = false;
}
};
// 搜索相关方法
const handleSearch = () => {
pagination.value.current = 1
loadSystemData()
}
const resetSearch = () => {
searchForm.value.timeRange = []
pagination.value.current = 1
loadSystemData()
}
// 分页方法
const handleSizeChange = (val) => {
pagination.value.size = val
loadSystemData()
}
const handleCurrentChange = (val) => {
pagination.value.current = val
loadSystemData()
}
// 值对比方法
const getValueDiffs = (row) => {
try {
const oldObj = JSON.parse(row.oldValue || '{}')
const newObj = JSON.parse(row.newValue || '{}')
const allProperties = new Set([...Object.keys(oldObj), ...Object.keys(newObj)])
return Array.from(allProperties).map(prop => ({
property: formatPropertyName(prop),
oldValue: formatValue(oldObj[prop]),
newValue: formatValue(newObj[prop])
}))
} catch (e) {
return [{
property: '原始数据',
oldValue: row.oldValue || '无',
newValue: row.newValue || '无'
}]
}
}
const formatPropertyName = (prop) => {
const nameMap = {
'risk_code': '风险编码',
'department': '责任部门',
'professional_system': '专业系统',
'risk_category': '风险类别',
'risk_item': '风险事项',
'risk_point': '风险点',
'risk_level': '风险等级',
'harm_degree': '危害程度',
'control_measures': '控制措施',
'control_position': '控制位置',
'control_personnel': '控制人员',
'quantified_requirements': '量化要求',
'entry_start_date': '录入开始日期',
'entry_end_date': '录入结束日期',
'review_status': '审核状态',
'review_date': '审核日期'
}
return nameMap[prop] || prop
}
const formatValue = (value) => {
if (value === null || value === undefined) return '无'
return String(value)
}
// 初始化加载
onMounted(() => {
loadSystemData()
})
</script>
<style scoped>
.search-container {
margin-bottom: 20px;
padding: 20px;
background-color: #f5f7fa;
border-radius: 4px;
}
.operator-cell {
display: flex;
align-items: center;
gap: 8px;
}
.system-icon {
color: #909399;
}
.system-operator {
color: #606266;
font-weight: 500;
}
.value-comparison-container {
border: 1px solid #ebeef5;
border-radius: 4px;
}
.value-header {
display: flex;
background-color: #f5f7fa;
font-weight: bold;
}
.value-title {
flex: 1;
padding: 8px 12px;
text-align: center;
}
.old-value-title {
background-color: #fef0f0;
color: #f56c6c;
}
.new-value-title {
background-color: #f0f9eb;
color: #67c23a;
}
.value-diff-container {
max-height: 300px;
overflow-y: auto;
}
.value-row {
display: flex;
border-bottom: 1px solid #ebeef5;
}
.value-cell {
flex: 1;
padding: 8px 12px;
}
.old-value-cell {
border-right: 1px solid #ebeef5;
background-color: #fef0f0;
}
.new-value-cell {
background-color: #f0f9eb;
}
.property-name {
font-weight: bold;
color: #606266;
}
.pagination-container {
margin-top: 20px;
display: flex;
justify-content: flex-end;
}
</style>
浙公网安备 33010602011771号