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