package com.kaidi.oa.web; import com.kaidi.oa.common.ApiResp; import com.kaidi.oa.common.ApiException; import com.kaidi.oa.common.NotFoundException; import com.kaidi.oa.domain.HrEmpSatisfactionSurvey; import com.kaidi.oa.repository.HrEmpSatisfactionSurveyRepository; 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; /** * 人力资源部员工满意度调查 CRUD。 * * 该模块是「品牌推广部·项目文化评估与反馈」跨模块数据打通的数据源: * 人力资源部每季度发放覆盖全员的敬业度/满意度问卷,系统通过 projectCode 字段 * 把 HR 调查结果关联到具体项目部,再由 CultureAssessmentService 融合读取, * 消除了"只读 CultureSurvey 自有问卷"的缺口(两套维度互补——Culture 侧重文化氛围, * HR 侧重工作满意度/敬业度/管理质量),同时 /kpi-writeback 接口把文化考核得分 * 回写到考核数据供 HR 年度绩效评估引用。 * * 状态机:草稿 → 收集中 → 已完成(关闭冻结评分)。 */ @RestController @RequestMapping("/api/oa/hr-emp-satisfaction") public class HrEmpSatisfactionSurveyController { private final HrEmpSatisfactionSurveyRepository repo; public HrEmpSatisfactionSurveyController(HrEmpSatisfactionSurveyRepository repo) { this.repo = repo; } // ---- 请求体 ---- record CreateReq( String code, String title, String projectCode, String projectName, String period, Integer totalCount, Double scoreJobSatisfaction, Double scoreEngagement, Double scoreManagement, Double scoreTeamwork, Double scoreWellbeing, String issuesSummary, String openDate, String closeDate ) {} record UpdateReq( String title, String projectCode, String projectName, String period, Integer totalCount, Integer respondedCount, Double scoreJobSatisfaction, Double scoreEngagement, Double scoreManagement, Double scoreTeamwork, Double scoreWellbeing, Double hrOverallScore, String issuesSummary, String openDate, String closeDate ) {} // ---- 列表 ---- @GetMapping public ApiResp> list( @RequestParam(required = false) String projectCode, @RequestParam(required = false) String status) { if (projectCode != null && status != null) { return ApiResp.ok(repo.findByProjectCodeAndStatus(projectCode, status)); } if (projectCode != null) { return ApiResp.ok(repo.findByProjectCode(projectCode)); } if (status != null) { return ApiResp.ok(repo.findByStatus(status)); } return ApiResp.ok(repo.findAll()); } // ---- 详情 ---- @GetMapping("/{id}") public ApiResp get(@PathVariable Long id) { return ApiResp.ok(repo.findById(id).orElseThrow(() -> new NotFoundException("HR满意度调查不存在: " + id))); } // ---- 新建 ---- @PostMapping @Transactional public ApiResp create(@RequestBody CreateReq req) { HrEmpSatisfactionSurvey s = new HrEmpSatisfactionSurvey(); s.setCode(req.code()); s.setTitle(req.title()); s.setInitiatorDept("人力资源部"); s.setProjectCode(req.projectCode()); s.setProjectName(req.projectName()); s.setPeriod(req.period()); s.setStatus("草稿"); s.setTotalCount(req.totalCount() == null ? 0 : req.totalCount()); s.setRespondedCount(0); s.setScoreJobSatisfaction(req.scoreJobSatisfaction() == null ? 0.0 : req.scoreJobSatisfaction()); s.setScoreEngagement(req.scoreEngagement() == null ? 0.0 : req.scoreEngagement()); s.setScoreManagement(req.scoreManagement() == null ? 0.0 : req.scoreManagement()); s.setScoreTeamwork(req.scoreTeamwork() == null ? 0.0 : req.scoreTeamwork()); s.setScoreWellbeing(req.scoreWellbeing() == null ? 0.0 : req.scoreWellbeing()); s.setHrOverallScore(0.0); s.setIssuesSummary(req.issuesSummary()); s.setOpenDate(req.openDate()); s.setCloseDate(req.closeDate()); s.setCreatedAt(Instant.now()); return ApiResp.ok(repo.save(s)); } // ---- 更新 ---- @PatchMapping("/{id}") @Transactional public ApiResp update(@PathVariable Long id, @RequestBody UpdateReq req) { HrEmpSatisfactionSurvey s = repo.findById(id) .orElseThrow(() -> new NotFoundException("HR满意度调查不存在: " + id)); if (req.title() != null) s.setTitle(req.title()); if (req.projectCode() != null) s.setProjectCode(req.projectCode()); if (req.projectName() != null) s.setProjectName(req.projectName()); if (req.period() != null) s.setPeriod(req.period()); if (req.totalCount() != null) s.setTotalCount(req.totalCount()); if (req.respondedCount() != null) s.setRespondedCount(req.respondedCount()); if (req.scoreJobSatisfaction() != null) s.setScoreJobSatisfaction(req.scoreJobSatisfaction()); if (req.scoreEngagement() != null) s.setScoreEngagement(req.scoreEngagement()); if (req.scoreManagement() != null) s.setScoreManagement(req.scoreManagement()); if (req.scoreTeamwork() != null) s.setScoreTeamwork(req.scoreTeamwork()); if (req.scoreWellbeing() != null) s.setScoreWellbeing(req.scoreWellbeing()); if (req.issuesSummary() != null) s.setIssuesSummary(req.issuesSummary()); if (req.openDate() != null) s.setOpenDate(req.openDate()); if (req.closeDate() != null) s.setCloseDate(req.closeDate()); // 自动重算综合分(五维均值) if (req.hrOverallScore() != null) { s.setHrOverallScore(req.hrOverallScore()); } else { double overall = (s.getScoreJobSatisfaction() + s.getScoreEngagement() + s.getScoreManagement() + s.getScoreTeamwork() + s.getScoreWellbeing()) / 5.0; s.setHrOverallScore(Math.round(overall * 100.0) / 100.0); } return ApiResp.ok(repo.save(s)); } // ---- 状态迁移 ---- @PostMapping("/{id}/start") @Transactional public ApiResp start(@PathVariable Long id) { HrEmpSatisfactionSurvey s = repo.findById(id) .orElseThrow(() -> new NotFoundException("HR满意度调查不存在: " + id)); if (!"草稿".equals(s.getStatus())) { throw new ApiException(400, "只有草稿状态可以开启收集"); } s.setStatus("收集中"); return ApiResp.ok(repo.save(s)); } @PostMapping("/{id}/close") @Transactional public ApiResp close(@PathVariable Long id) { HrEmpSatisfactionSurvey s = repo.findById(id) .orElseThrow(() -> new NotFoundException("HR满意度调查不存在: " + id)); if (!"收集中".equals(s.getStatus())) { throw new ApiException(400, "只有收集中状态可以关闭"); } // 关闭时自动计算综合分(五维均值) double overall = (s.getScoreJobSatisfaction() + s.getScoreEngagement() + s.getScoreManagement() + s.getScoreTeamwork() + s.getScoreWellbeing()) / 5.0; s.setHrOverallScore(Math.round(overall * 100.0) / 100.0); s.setStatus("已完成"); return ApiResp.ok(repo.save(s)); } // ---- 删除 ---- @DeleteMapping("/{id}") @Transactional public ApiResp delete(@PathVariable Long id) { if (!repo.existsById(id)) { throw new NotFoundException("HR满意度调查不存在: " + id); } repo.deleteById(id); return ApiResp.ok(null); } }