Files
ERP/oa-backend/src/main/java/com/kaidi/oa/web/EmergencyDrillController.java
T
QiufengandClaude Opus 4.8 5e51dc3f56 SNAPSHOT W7 已部署稳定态 — 凯迪ERP+OA一体化平台 (MET 73.3%)
恢复点(restore point)。别人改崩后可 git reset --hard 回到此提交。

== 此快照内容 ==
- 后端 oa-backend: 734 控制器 / 711 实体 (Spring Boot 3.2.5 + SQLite, 端口8091)
- 前端 modern-ui/app: Vue3+Vite, 约700页 (构建产物已在 oa-backend/src/main/resources/static)
- 数据库 oa-backend/data/oa.db: 含全部演示数据 (强制入库, 6.6MB)
- 交接文档 go.md + go-code-reference/endpoints/entities/database.md
- 多代理建设脚本 .claude/wf-*.js

== 状态 ==
- 对 凯迪科技ERP_20260507.xlsx 合规 MET ~73.3% (PARTIAL 75: 34可建+6种子/bug+35外部硬天花板)
- 安全: 5轮红队+5轮复检, default-deny分级鉴权, 连续零可利用
- W3~W7 累计补完436缺口; W8末轮(40缺口)为半成品(源码树可编译但未集成)
- 运行: cd oa-backend; java -jar build/libs/oa-backend-0.1.0.jar --server.port=8091; admin/123456

== 排除(gitignore, 可再生) ==
node_modules / oa-backend/build / .jdks / *.log / Backup-ERP-* / 弃用的OFBiz核心(只保留modern-ui)
完整文件夹备份见同目录 Backup-ERP-20260615-191517/ (含上述全部, 仅缺 node_modules)

时间戳: 20260615-191517

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-15 19:19:15 +08:00

147 lines
6.4 KiB
Java
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package com.kaidi.oa.web;
import com.kaidi.oa.common.ApiException;
import com.kaidi.oa.common.ApiResp;
import com.kaidi.oa.common.NotFoundException;
import com.kaidi.oa.domain.EmergencyDrill;
import com.kaidi.oa.repository.EmergencyDrillRepository;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PatchMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import java.time.Instant;
import java.time.LocalDate;
import java.util.List;
/**
* 质安部·应急预案与演练(需求 §2 应急管理)。补深审计 high 缺口:应急预案 + 演练计划与记录 + 评估效果。
*
* 状态机:计划 → 已演练(record,记录过程/参演人)→ 已评估(evaluate,记录评估结论/评分/发现问题)。
* 写口默认受 AuthInterceptor default-deny(ADMIN/APPROVER) 保护。
*/
@RestController
@RequestMapping("/api/oa/emergency-drills")
public class EmergencyDrillController {
private final EmergencyDrillRepository repo;
public EmergencyDrillController(EmergencyDrillRepository repo) {
this.repo = repo;
}
@GetMapping
public ApiResp<List<EmergencyDrill>> list(@RequestParam(required = false) String status,
@RequestParam(required = false) String planType) {
if (status != null && !status.isBlank()) {
return ApiResp.ok(repo.findByStatus(status));
}
if (planType != null && !planType.isBlank()) {
return ApiResp.ok(repo.findByPlanType(planType));
}
return ApiResp.ok(repo.findAll());
}
@GetMapping("/{id}")
public ApiResp<EmergencyDrill> get(@PathVariable Long id) {
return ApiResp.ok(repo.findById(id)
.orElseThrow(() -> new NotFoundException("drill not found: " + id)));
}
public record DrillRequest(String code, String planName, String planType, String title,
String drillType, String scenario, String dept, String planDate) {
}
@PostMapping
public ApiResp<EmergencyDrill> create(@RequestBody DrillRequest req) {
if (req.title() == null || req.title().isBlank()) {
throw new ApiException(400, "演练主题不能为空");
}
EmergencyDrill d = new EmergencyDrill();
d.setCode(req.code() == null || req.code().isBlank() ? "YJ-" + (repo.count() + 1) : req.code());
d.setPlanName(req.planName());
d.setPlanType(req.planType() == null || req.planType().isBlank() ? "专项预案" : req.planType());
d.setTitle(req.title());
d.setDrillType(req.drillType() == null || req.drillType().isBlank() ? "实战演练" : req.drillType());
d.setScenario(req.scenario());
d.setDept(req.dept());
d.setPlanDate(req.planDate());
d.setStatus("计划");
d.setCreatedAt(Instant.now());
return ApiResp.ok(repo.save(d));
}
@PatchMapping("/{id}")
public ApiResp<EmergencyDrill> update(@PathVariable Long id, @RequestBody DrillRequest req) {
EmergencyDrill d = repo.findById(id)
.orElseThrow(() -> new NotFoundException("drill not found: " + id));
if ("已评估".equals(d.getStatus())) {
throw new ApiException(409, "已评估演练不可编辑");
}
if (req.planName() != null) d.setPlanName(req.planName());
if (req.planType() != null && !req.planType().isBlank()) d.setPlanType(req.planType());
if (req.title() != null && !req.title().isBlank()) d.setTitle(req.title());
if (req.drillType() != null && !req.drillType().isBlank()) d.setDrillType(req.drillType());
if (req.scenario() != null) d.setScenario(req.scenario());
if (req.dept() != null) d.setDept(req.dept());
if (req.planDate() != null) d.setPlanDate(req.planDate());
return ApiResp.ok(repo.save(d));
}
@DeleteMapping("/{id}")
public ApiResp<Void> delete(@PathVariable Long id) {
if (!repo.existsById(id)) {
throw new NotFoundException("drill not found: " + id);
}
repo.deleteById(id);
return ApiResp.ok(null);
}
public record RecordRequest(String drillDate, Integer participants, String process) {
}
/** 记录演练:计划 → 已演练(记录过程/参演人)。 */
@PostMapping("/{id}/record")
public ApiResp<EmergencyDrill> record(@PathVariable Long id, @RequestBody RecordRequest req) {
EmergencyDrill d = repo.findById(id)
.orElseThrow(() -> new NotFoundException("drill not found: " + id));
if (!"计划".equals(d.getStatus())) {
throw new ApiException(409, "仅计划中的演练可记录(当前:" + d.getStatus() + "");
}
d.setDrillDate(req.drillDate() == null || req.drillDate().isBlank()
? LocalDate.now().toString() : req.drillDate());
d.setParticipants(req.participants());
d.setProcess(req.process());
d.setStatus("已演练");
return ApiResp.ok(repo.save(d));
}
public record EvaluateRequest(String evaluation, Integer score, String problems) {
}
/** 评估演练:已演练 → 已评估(记录评估结论/评分/发现问题)。 */
@PostMapping("/{id}/evaluate")
public ApiResp<EmergencyDrill> evaluate(@PathVariable Long id, @RequestBody EvaluateRequest req) {
EmergencyDrill d = repo.findById(id)
.orElseThrow(() -> new NotFoundException("drill not found: " + id));
if (!"已演练".equals(d.getStatus())) {
throw new ApiException(409, "仅已演练的演练可评估(当前:" + d.getStatus() + "");
}
if (req.evaluation() == null || req.evaluation().isBlank()) {
throw new ApiException(400, "评估结论不能为空");
}
d.setEvaluation(req.evaluation());
if (req.score() != null) {
d.setScore(Math.max(0, Math.min(100, req.score())));
}
d.setProblems(req.problems());
d.setStatus("已评估");
return ApiResp.ok(repo.save(d));
}
}