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.WmPromotion; import com.kaidi.oa.repository.IpAssetRepository; import com.kaidi.oa.repository.WmPromotionRepository; import com.kaidi.oa.repository.WorkMethodRepository; 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.time.LocalDate; import java.util.List; /** * 工法/专利推广活动管理(工程管理中心·专利工法办,需求功能8·成果应用与推广)。 * 补深审计 PARTIAL:新建年度推广计划与推广活动记录实体(宣贯会/作业指导书/技术交流等), * 关联工法/专利,记录参与人数/效果评估。 * 端点:/api/oa/wm-promotions * activityType: 宣贯会 / 作业指导书 / 技术交流 / 培训 / 知识共享 / 其他。 * status: 计划中 / 进行中 / 已完成 / 已取消。 */ @RestController @RequestMapping("/api/oa/wm-promotions") public class WmPromotionController { private final WmPromotionRepository promotionRepo; private final WorkMethodRepository methodRepo; private final IpAssetRepository ipAssetRepo; private static final List ACTIVITY_TYPES = List.of( "宣贯会", "作业指导书", "技术交流", "培训", "知识共享", "其他"); private static final List STATUSES = List.of("计划中", "进行中", "已完成", "已取消"); public WmPromotionController(WmPromotionRepository promotionRepo, WorkMethodRepository methodRepo, IpAssetRepository ipAssetRepo) { this.promotionRepo = promotionRepo; this.methodRepo = methodRepo; this.ipAssetRepo = ipAssetRepo; } // ---------- 台账查询 ---------- @GetMapping public ApiResp> list(@RequestParam(required = false) Integer year, @RequestParam(required = false) String status, @RequestParam(required = false) Long methodId, @RequestParam(required = false) Long ipAssetId) { if (methodId != null) return ApiResp.ok(promotionRepo.findByMethodId(methodId)); if (ipAssetId != null) return ApiResp.ok(promotionRepo.findByIpAssetId(ipAssetId)); if (year != null) return ApiResp.ok(promotionRepo.findByYear(year)); if (status != null && !status.isBlank()) return ApiResp.ok(promotionRepo.findByStatus(status)); return ApiResp.ok(promotionRepo.findAll()); } @GetMapping("/{id}") public ApiResp get(@PathVariable Long id) { return ApiResp.ok(find(id)); } // ---------- CRUD ---------- public record PromotionRequest(String name, String activityType, Integer year, Long methodId, Long ipAssetId, String planDate, String location, String organizer, String owner, String remark) { } @PostMapping @Transactional public ApiResp create(@RequestBody PromotionRequest req) { if (req.name() == null || req.name().isBlank()) { throw new ApiException(400, "推广活动名称不能为空"); } if (req.activityType() != null && !ACTIVITY_TYPES.contains(req.activityType())) { throw new ApiException(400, "未知活动类型,可选:" + String.join("/", ACTIVITY_TYPES)); } WmPromotion p = new WmPromotion(); applyEditable(p, req); p.setYear(req.year() == null ? LocalDate.now().getYear() : req.year()); p.setStatus("计划中"); p.setCreatedAt(Instant.now()); p.setUpdatedAt(Instant.now()); return ApiResp.ok(promotionRepo.save(p)); } @PatchMapping("/{id}") @Transactional public ApiResp update(@PathVariable Long id, @RequestBody PromotionRequest req) { WmPromotion p = find(id); if ("已取消".equals(p.getStatus())) { throw new ApiException(409, "已取消的活动不可再编辑"); } applyEditable(p, req); p.setUpdatedAt(Instant.now()); return ApiResp.ok(promotionRepo.save(p)); } public record CompleteRequest(String actualDate, Integer attendeeCount, String effectNote, String materials) { } /** * 完成推广活动:记录实际日期/参与人数/效果评估/推广材料,置 status=已完成。 * (补深需求:「记录推广活动(时间、地点、参与人数、效果评估)」) */ @PostMapping("/{id}/complete") @Transactional public ApiResp complete(@PathVariable Long id, @RequestBody CompleteRequest req) { WmPromotion p = find(id); if ("已取消".equals(p.getStatus()) || "已完成".equals(p.getStatus())) { throw new ApiException(409, "活动已处于终态(" + p.getStatus() + "),不可再操作"); } p.setActualDate(req.actualDate() == null || req.actualDate().isBlank() ? LocalDate.now().toString() : req.actualDate()); if (req.attendeeCount() != null) p.setAttendeeCount(req.attendeeCount()); if (req.effectNote() != null) p.setEffectNote(req.effectNote()); if (req.materials() != null) p.setMaterials(req.materials()); p.setStatus("已完成"); p.setUpdatedAt(Instant.now()); return ApiResp.ok(promotionRepo.save(p)); } @PostMapping("/{id}/cancel") @Transactional public ApiResp cancel(@PathVariable Long id) { WmPromotion p = find(id); if ("已完成".equals(p.getStatus())) { throw new ApiException(409, "已完成的活动不可取消"); } p.setStatus("已取消"); p.setUpdatedAt(Instant.now()); return ApiResp.ok(promotionRepo.save(p)); } @DeleteMapping("/{id}") @Transactional public ApiResp delete(@PathVariable Long id) { WmPromotion p = find(id); if ("已完成".equals(p.getStatus())) { throw new ApiException(409, "已完成的推广活动记录不可删除(存证)"); } promotionRepo.deleteById(id); return ApiResp.ok(null); } // ---------- helpers ---------- private WmPromotion find(Long id) { return promotionRepo.findById(id).orElseThrow(() -> new NotFoundException("推广活动不存在:" + id)); } private void applyEditable(WmPromotion p, PromotionRequest req) { if (req.name() != null && !req.name().isBlank()) p.setName(req.name()); if (req.activityType() != null) p.setActivityType(req.activityType()); if (req.methodId() != null) { p.setMethodId(req.methodId()); methodRepo.findById(req.methodId()).ifPresent(m -> p.setMethodName(m.getName())); } if (req.ipAssetId() != null) { p.setIpAssetId(req.ipAssetId()); ipAssetRepo.findById(req.ipAssetId()).ifPresent(a -> p.setIpAssetName(a.getName())); } if (req.planDate() != null) p.setPlanDate(req.planDate()); if (req.location() != null) p.setLocation(req.location()); if (req.organizer() != null) p.setOrganizer(req.organizer()); if (req.owner() != null) p.setOwner(req.owner()); if (req.remark() != null) p.setRemark(req.remark()); } }