package com.ruoyi.satisfaction.controller;
|
|
import com.ruoyi.common.annotation.AddOrgId;
|
import com.ruoyi.common.core.controller.BaseController;
|
import com.ruoyi.satisfaction.domain.ServiceSubtaskDetailRatioExport;
|
import com.ruoyi.satisfaction.domain.dto.QuestionResultDTO;
|
import com.ruoyi.satisfaction.domain.row.SatisfactionSubtaskQuery;
|
import com.ruoyi.satisfaction.domain.row.SatisfactionSubtaskRef;
|
import com.ruoyi.satisfaction.domain.vo.MydTrendReqVO;
|
import com.ruoyi.satisfaction.domain.vo.MzMydScoreRankVO;
|
import com.ruoyi.satisfaction.domain.vo.QuestionCountKsOrBqVO;
|
import com.ruoyi.satisfaction.domain.vo.SltdMydTotalVO;
|
import com.ruoyi.satisfaction.service.SatisfactionSubtaskService;
|
import com.ruoyi.satisfaction.service.strategy.SatisfactionScoreStrategyResolver;
|
import com.ruoyi.satisfaction.service.strategy.SatisfactionSites;
|
import io.swagger.annotations.Api;
|
import io.swagger.annotations.ApiOperation;
|
import org.apache.commons.collections4.CollectionUtils;
|
import org.springframework.beans.factory.annotation.Autowired;
|
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.RestController;
|
|
import java.math.BigDecimal;
|
import java.util.ArrayList;
|
import java.util.List;
|
import java.util.Map;
|
import java.util.stream.Collectors;
|
|
/**
|
* 省立同德 / 门诊满意度统计 Controller(已迁入 ruoyi-satisfaction 模块)。
|
* <p>
|
* ⚠️ <b>URL 与出入参一字未改</b>:这些端点原本挂在
|
* {@code ServiceSubtaskDetailController}({@code /smartor/serviceSubtaskDetail})下,
|
* 迁移后 {@code @RequestMapping} 与全部 {@code @PostMapping} 路径保持原样,前端无需任何改动。
|
* <p>
|
* 迁移时唯一调整的一处:{@code sltdMydTotalByScore} 原本调用
|
* {@code serviceSubtaskService.getServiceSubtasks(...)}(随访主干 Service,不能搬),
|
* 现改为调用满意度模块自带的 {@link SatisfactionSubtaskService#getMydSubtaskRefs};
|
* 查询条件与后续统计口径逐字保持一致(见各方法内注释)。
|
* <p>
|
* <b>开关</b>:本 Controller 始终注册(不随 {@code satisfaction.enabled} 消失)。
|
* 模块被关闭时由 {@code SatisfactionAvailabilityInterceptor}
|
* (见 {@code config/SatisfactionWebConfig})在进入方法前抛出 {@code ServiceException},
|
* 调用方会拿到<b>明确的错误提示</b>(而不是 404)。
|
* 注意:同一前缀 {@code /smartor/serviceSubtaskDetail} 下的<b>随访明细</b>端点不受影响
|
* —— 拦截器只挂在本类的 5 个满意度路径上。
|
*/
|
@Api(description = "省立同德满意度统计")
|
@RestController
|
@RequestMapping("/smartor/serviceSubtaskDetail")
|
public class SltdSatisfactionController extends BaseController {
|
|
/**
|
* 站点口径策略解析器:综合满意度得分按站点(省立同德)取策略计算,
|
* 不再把算法与常量写在 Controller 里。
|
*/
|
@Autowired
|
private SatisfactionScoreStrategyResolver satisfactionScoreStrategyResolver;
|
|
@Autowired
|
private SatisfactionSubtaskService satisfactionSubtaskService;
|
|
// ================================================================ 端点(URL 原样)
|
|
/**
|
* 省立同德满意度数据统计(按题目统计选项数量/占比,并给出该题的综合得分)
|
* <p>
|
* 综合满意度 = (很满意项数×1 + 满意项数×0.8 + 一般项数×0.6 + 不满意项数×0.4 + 很不满意项数×0.2)
|
* / (很满意项数 + 满意项数 + 一般项数 + 不满意项数 + 很不满意项数) × 100%;
|
* 「未经历」「不适用」等不在五档里的选项既不进分子也不进分母。
|
*/
|
@ApiOperation("省立同德满意度数据统计")
|
@AddOrgId(field = "orgid", paramIndex = 0, campusField = "campusid")
|
@PostMapping("/sltdMydTotalByScore")
|
public Map<String, Object> sltdMydTotalByScore(@RequestBody SltdMydTotalVO sltdMydTotalVO) {
|
List<SatisfactionSubtaskRef> subtaskRefs = null;
|
if (CollectionUtils.isNotEmpty(sltdMydTotalVO.getServiceTypeList())) {
|
//serviceType可能会出现多个,不想多写方法了,一个一个查询吧
|
for (String st : sltdMydTotalVO.getServiceTypeList()) {
|
SatisfactionSubtaskQuery query = new SatisfactionSubtaskQuery();
|
query.setServiceType(st);
|
query.setEndOutHospTime(sltdMydTotalVO.getEndOutHospTime());
|
query.setStartOutHospTime(sltdMydTotalVO.getStartOutHospTime());
|
query.setDeptOrDistrict(sltdMydTotalVO.getDeptOrDistrict());
|
query.setLeavehospitaldistrictcodes(sltdMydTotalVO.getLeavehospitaldistrictcodes());
|
query.setLeaveldeptcodes(sltdMydTotalVO.getLeaveldeptcodes());
|
//机构/院区由 @AddOrgId 注入,落到查询条件上,避免跨机构取数
|
query.setOrgid(sltdMydTotalVO.getOrgid());
|
query.setCampusid(sltdMydTotalVO.getCampusid());
|
List<SatisfactionSubtaskRef> refs = satisfactionSubtaskService.getMydSubtaskRefs(query);
|
if (CollectionUtils.isNotEmpty(subtaskRefs)) {
|
subtaskRefs.addAll(refs);
|
} else {
|
if (CollectionUtils.isEmpty(subtaskRefs)) subtaskRefs = refs;
|
}
|
}
|
}
|
// 按 questiontext 分组后转换为 QuestionResultVO
|
List<QuestionResultDTO> result = new ArrayList<>();
|
if (CollectionUtils.isNotEmpty(subtaskRefs)) {
|
List<ServiceSubtaskDetailRatioExport> detailList =
|
satisfactionSubtaskService.getDetailRatio(sltdMydTotalVO, subtaskRefs);
|
|
if (detailList == null) {
|
//serviceType 组合不在支持范围内(如同时含随访 2 和满意度 6/14),给明确提示而不是悄悄返回空数组
|
return error("当前 serviceType 组合暂不支持统计问题占比,请分开查询(仅支持随访 2 或满意度 6/14)");
|
}
|
if (CollectionUtils.isNotEmpty(detailList)) {
|
Map<String, List<ServiceSubtaskDetailRatioExport>> groupedMap =
|
detailList.stream().collect(Collectors.groupingBy(ServiceSubtaskDetailRatioExport::getQuestiontext));
|
|
groupedMap.forEach((questionText, exportList) -> {
|
QuestionResultDTO questionResultDTO = new QuestionResultDTO();
|
questionResultDTO.setQeustionText(questionText);
|
questionResultDTO.setSubtaskDetailRatioExportList(exportList);
|
//综合得分:(很满意×1 + 满意×0.8 + 一般×0.6 + 不满意×0.4 + 很不满意×0.2) / 五档项数之和 × 100%
|
questionResultDTO.setAvgScore(calcMydScore(exportList));
|
result.add(questionResultDTO);
|
});
|
}
|
}
|
|
return success(result);
|
}
|
|
@ApiOperation("省立同德满意度数据统计通过科室或病区")
|
@PostMapping("/statQuestionOptionByKsOrBq")
|
public Map<String, Object> statQuestionOptionByKsOrBq(@RequestBody QuestionCountKsOrBqVO questionResultVO) {
|
return success(satisfactionSubtaskService.statQuestionOptionByKsOrBq(questionResultVO));
|
}
|
|
@ApiOperation("省立同德患者满意度趋势")
|
@PostMapping("/mydTrend")
|
public Map<String, Object> mydTrend(@RequestBody MydTrendReqVO mydTrendReqVO) {
|
return success(satisfactionSubtaskService.mydTrend(mydTrendReqVO));
|
}
|
|
@ApiOperation("省立同德患者满意度维护")
|
@PostMapping("/sltdMydTotalByDimension")
|
public Map<String, Object> sltdMydTotalByDimension(@RequestBody MydTrendReqVO mydTrendReqVO) {
|
return success(satisfactionSubtaskService.sltdMydTotalByDimension(mydTrendReqVO));
|
}
|
|
@ApiOperation("门诊满意度综合得分排名(按科室或病区)")
|
@AddOrgId(field = "orgid", paramIndex = 0, campusField = "campusid")
|
@PostMapping("/mzMydScoreRank")
|
public Map<String, Object> mzMydScoreRank(@RequestBody MzMydScoreRankVO mzMydScoreRankVO) {
|
return success(satisfactionSubtaskService.mzMydScoreRank(mzMydScoreRankVO));
|
}
|
|
// ================================================================ 综评计算(改走站点策略)
|
|
/**
|
* 计算一道题的满意度综合得分(百分制,保留两位小数)。
|
* <p>
|
* <b>策略化改造</b>:算法本身已原样搬到
|
* {@link com.ruoyi.satisfaction.service.strategy.SltdSatisfactionScoreStrategy}
|
* (省立同德口径),本方法只负责"按站点取策略 + 把 null 呈现为 0.00"。
|
* 计算过程与返回值与迁移前<b>完全一致</b>。
|
*
|
* @param exportList 同一道题目的选项统计明细
|
* @return 百分制综合得分,无有效项数时返回 "0.00"
|
*/
|
private String calcMydScore(List<ServiceSubtaskDetailRatioExport> exportList) {
|
BigDecimal score = satisfactionScoreStrategyResolver
|
.resolve(SatisfactionSites.SLTD)
|
.comprehensiveScore(exportList);
|
return score == null ? "0.00" : score.toPlainString();
|
}
|
}
|