Files
ERP/oa-backend/src/main/java/com/kaidi/oa/web/ExternalRegulationController.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

169 lines
7.6 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.ExternalRegulation;
import com.kaidi.oa.repository.ExternalRegulationRepository;
import com.kaidi.oa.service.NotificationService;
import org.springframework.transaction.annotation.Transactional;
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.util.List;
/**
* 外规内化库(内控部 / 法务风险部 · 合规管理)。
*
* 补齐缺口:外部法规数据库独立实体 + 更新推送机制(法规入库/更新时,自动站内信通知相关部门)。
* 现行 ComplianceObligation 仅承载义务台账,无法规原文/有效期/发布机构等独立字段。
*
* publish 端点:发布法规后自动推送相关部门站内消息,实现"法规变化推送业务部门"。
*/
@RestController
@RequestMapping("/api/oa/external-regulations")
public class ExternalRegulationController {
private final ExternalRegulationRepository repo;
private final NotificationService notifService;
public ExternalRegulationController(ExternalRegulationRepository repo,
NotificationService notifService) {
this.repo = repo;
this.notifService = notifService;
}
@GetMapping
public ApiResp<List<ExternalRegulation>> list(
@RequestParam(required = false) String status,
@RequestParam(required = false) String regType,
@RequestParam(required = false) String priority,
@RequestParam(required = false) String keyword) {
if (keyword != null && !keyword.isBlank()) return ApiResp.ok(repo.findByTitleContaining(keyword.trim()));
if (status != null && !status.isBlank()) return ApiResp.ok(repo.findByStatus(status));
if (regType != null && !regType.isBlank()) return ApiResp.ok(repo.findByRegType(regType));
if (priority != null && !priority.isBlank()) return ApiResp.ok(repo.findByPriority(priority));
return ApiResp.ok(repo.findAll());
}
@GetMapping("/{id}")
public ApiResp<ExternalRegulation> get(@PathVariable Long id) {
return ApiResp.ok(load(id));
}
public record RegRequest(
String regNo, String title, String issuer, String regType,
String issueDate, String effectiveDate, String expireDate,
String impactDescription, String internalMapping, String notifyDepts, String priority) {
}
@PostMapping
@Transactional
public ApiResp<ExternalRegulation> create(@RequestBody RegRequest req) {
if (req.title() == null || req.title().isBlank()) {
throw new ApiException(400, "法规名称(title) 不能为空");
}
ExternalRegulation r = new ExternalRegulation();
r.setRegNo(req.regNo() == null || req.regNo().isBlank()
? "EXT-REG-" + String.format("%04d", repo.count() + 1) : req.regNo());
r.setTitle(req.title());
r.setIssuer(req.issuer());
r.setRegType(req.regType() == null ? "其他" : req.regType());
r.setIssueDate(req.issueDate());
r.setEffectiveDate(req.effectiveDate());
r.setExpireDate(req.expireDate());
r.setStatus("现行有效");
r.setImpactDescription(req.impactDescription());
r.setInternalMapping(req.internalMapping());
r.setNotifyDepts(req.notifyDepts());
r.setPriority(req.priority() == null ? "中" : req.priority());
r.setCreatedAt(Instant.now());
r.setUpdatedAt(Instant.now());
return ApiResp.ok(repo.save(r));
}
@PatchMapping("/{id}")
@Transactional
public ApiResp<ExternalRegulation> update(@PathVariable Long id, @RequestBody RegRequest req) {
ExternalRegulation r = load(id);
if (req.regNo() != null) r.setRegNo(req.regNo());
if (req.title() != null && !req.title().isBlank()) r.setTitle(req.title());
if (req.issuer() != null) r.setIssuer(req.issuer());
if (req.regType() != null) r.setRegType(req.regType());
if (req.issueDate() != null) r.setIssueDate(req.issueDate());
if (req.effectiveDate() != null) r.setEffectiveDate(req.effectiveDate());
if (req.expireDate() != null) r.setExpireDate(req.expireDate());
if (req.impactDescription() != null) r.setImpactDescription(req.impactDescription());
if (req.internalMapping() != null) r.setInternalMapping(req.internalMapping());
if (req.notifyDepts() != null) r.setNotifyDepts(req.notifyDepts());
if (req.priority() != null) r.setPriority(req.priority());
r.setUpdatedAt(Instant.now());
return ApiResp.ok(repo.save(r));
}
@DeleteMapping("/{id}")
@Transactional
public ApiResp<Void> delete(@PathVariable Long id) {
if (!repo.existsById(id)) throw new NotFoundException("外部法规不存在: " + id);
repo.deleteById(id);
return ApiResp.ok(null);
}
/**
* 发布并推送通知:将法规状态标记为「现行有效」,并给 notifyDepts 中的各部门发站内信。
* 补齐"法规变化自动推送相关业务部门"联动(原 ComplianceObligation 无此推送)。
*/
@PostMapping("/{id}/publish-notify")
@Transactional
public ApiResp<ExternalRegulation> publishNotify(@PathVariable Long id,
@RequestBody PublishNotifyRequest req) {
ExternalRegulation r = load(id);
r.setStatus("现行有效");
if (req.effectiveDate() != null) r.setEffectiveDate(req.effectiveDate());
r.setUpdatedAt(Instant.now());
ExternalRegulation saved = repo.save(r);
// 自动推送:给 notifyDepts 中每个部门负责人发站内消息
String depts = r.getNotifyDepts();
if (depts != null && !depts.isBlank()) {
String[] parts = depts.split("[,\\s]+");
String msgTitle = "【法规更新】" + r.getTitle();
String msgBody = "外部法规《" + r.getTitle() + "》(" + r.getRegNo() + ")已更新发布,"
+ "请合规自查相关业务是否符合新要求。发布日期:" + r.getIssueDate()
+ ",生效日期:" + r.getEffectiveDate();
for (String dept : parts) {
String d = dept.trim();
if (!d.isBlank()) {
notifService.notify(d, "法规更新", msgTitle, msgBody,
"external_regulation", saved.getId());
}
}
}
return ApiResp.ok(saved);
}
public record PublishNotifyRequest(String effectiveDate) {}
/** 标记失效:现行有效 → 已失效(如已被新版替代或废止)。 */
@PostMapping("/{id}/invalidate")
@Transactional
public ApiResp<ExternalRegulation> invalidate(@PathVariable Long id) {
ExternalRegulation r = load(id);
r.setStatus("已失效");
r.setUpdatedAt(Instant.now());
return ApiResp.ok(repo.save(r));
}
private ExternalRegulation load(Long id) {
return repo.findById(id).orElseThrow(() -> new NotFoundException("外部法规不存在: " + id));
}
}