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

189 lines
8.3 KiB
Java

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<HrEmpSatisfactionSurvey>> 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<HrEmpSatisfactionSurvey> get(@PathVariable Long id) {
return ApiResp.ok(repo.findById(id).orElseThrow(() -> new NotFoundException("HR满意度调查不存在: " + id)));
}
// ---- 新建 ----
@PostMapping
@Transactional
public ApiResp<HrEmpSatisfactionSurvey> 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<HrEmpSatisfactionSurvey> 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<HrEmpSatisfactionSurvey> 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<HrEmpSatisfactionSurvey> 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<Void> delete(@PathVariable Long id) {
if (!repo.existsById(id)) {
throw new NotFoundException("HR满意度调查不存在: " + id);
}
repo.deleteById(id);
return ApiResp.ok(null);
}
}