feat(followup): T9.4 随访管理 — AppService(generatePlan/assignTasks/recordFollowup) + 新端点

This commit is contained in:
2026-06-18 14:19:33 +08:00
parent d863e54ff0
commit 0e27b9f8df
3 changed files with 168 additions and 0 deletions

View File

@@ -0,0 +1,14 @@
package com.healthlink.his.web.followup.appservice;
import com.healthlink.his.followup.domain.FollowupPlan;
import com.healthlink.his.followup.domain.FollowupRecord;
import com.healthlink.his.followup.domain.FollowupTask;
import java.util.List;
import java.util.Map;
public interface IFollowupAppService {
FollowupPlan generatePlan(FollowupPlan plan);
List<FollowupTask> assignTasks(Long planId, List<String> operatorNames);
FollowupRecord recordFollowup(FollowupRecord record);
Map<String, Object> getTaskList(Long planId, String result, int pageNo, int pageSize);
}

View File

@@ -0,0 +1,122 @@
package com.healthlink.his.web.followup.appservice.impl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.healthlink.his.followup.domain.FollowupPlan;
import com.healthlink.his.followup.domain.FollowupRecord;
import com.healthlink.his.followup.domain.FollowupTask;
import com.healthlink.his.followup.service.IFollowupPlanService;
import com.healthlink.his.followup.service.IFollowupRecordService;
import com.healthlink.his.followup.service.IFollowupTaskService;
import com.healthlink.his.web.followup.appservice.IFollowupAppService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;
import java.time.LocalDate;
import java.util.*;
import java.util.stream.Collectors;
@Service
public class FollowupAppServiceImpl implements IFollowupAppService {
@Autowired
private IFollowupPlanService planService;
@Autowired
private IFollowupTaskService taskService;
@Autowired
private IFollowupRecordService recordService;
@Override
@Transactional(rollbackFor = Exception.class)
public FollowupPlan generatePlan(FollowupPlan plan) {
if (!StringUtils.hasText(plan.getStatus())) {
plan.setStatus("ACTIVE");
}
plan.setCompletedTimes(0);
planService.save(plan);
// 根据计划自动生成随访任务
if (plan.getStartDate() != null && plan.getTotalTimes() != null && plan.getTotalTimes() > 0) {
int total = plan.getTotalTimes();
LocalDate base = plan.getStartDate();
for (int i = 0; i < total; i++) {
FollowupTask task = new FollowupTask();
task.setPlanId(plan.getId());
task.setPatientId(plan.getPatientId());
task.setPatientName(plan.getPatientName());
task.setScheduledDate(base.plusWeeks(i));
task.setContactMethod(plan.getFollowupType());
task.setCreateTime(new Date());
taskService.save(task);
}
}
return plan;
}
@Override
@Transactional(rollbackFor = Exception.class)
public List<FollowupTask> assignTasks(Long planId, List<String> operatorNames) {
// 查找该计划下未分配的随访任务
LambdaQueryWrapper<FollowupTask> w = new LambdaQueryWrapper<>();
w.eq(FollowupTask::getPlanId, planId)
.and(inner -> inner.isNull(FollowupTask::getOperatorName).or().eq(FollowupTask::getOperatorName, ""));
List<FollowupTask> tasks = taskService.list(w);
if (tasks.isEmpty()) {
return Collections.emptyList();
}
// 轮询分配给指定的随访人员
List<FollowupTask> assigned = new ArrayList<>();
for (int i = 0; i < tasks.size(); i++) {
FollowupTask task = tasks.get(i);
String operator = operatorNames.get(i % operatorNames.size());
task.setOperatorName(operator);
taskService.updateById(task);
assigned.add(task);
}
return assigned;
}
@Override
@Transactional(rollbackFor = Exception.class)
public FollowupRecord recordFollowup(FollowupRecord record) {
record.setOperateTime(new Date());
recordService.save(record);
// 联动更新任务状态为SUCCESS
if (record.getTaskId() != null) {
FollowupTask task = taskService.getById(record.getTaskId());
if (task != null) {
task.setResult("SUCCESS");
task.setActualDate(LocalDate.now());
taskService.updateById(task);
// 更新随访计划的已完成次数
if (task.getPlanId() != null) {
FollowupPlan plan = planService.getById(task.getPlanId());
if (plan != null) {
plan.setCompletedTimes((plan.getCompletedTimes() == null ? 0 : plan.getCompletedTimes()) + 1);
planService.updateById(plan);
}
}
}
}
return record;
}
@Override
public Map<String, Object> getTaskList(Long planId, String result, int pageNo, int pageSize) {
LambdaQueryWrapper<FollowupTask> w = new LambdaQueryWrapper<>();
w.eq(planId != null, FollowupTask::getPlanId, planId)
.eq(StringUtils.hasText(result), FollowupTask::getResult, result)
.orderByAsc(FollowupTask::getScheduledDate);
Page<FollowupTask> page = taskService.page(new Page<>(pageNo, pageSize), w);
Map<String, Object> data = new HashMap<>();
data.put("records", page.getRecords());
data.put("total", page.getTotal());
return data;
}
}

View File

@@ -5,6 +5,7 @@ import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.core.common.core.domain.R;
import com.healthlink.his.followup.domain.*;
import com.healthlink.his.followup.service.*;
import com.healthlink.his.web.followup.appservice.IFollowupAppService;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.format.annotation.DateTimeFormat;
@@ -44,6 +45,7 @@ public class FollowupController {
private final IFollowupRecordService recordService;
private final ISatisfactionSurveyService surveyService;
private final IComplaintRecordService complaintService;
private final IFollowupAppService followupAppService;
// ==================== 随访计划 ====================
@@ -408,4 +410,34 @@ public class FollowupController {
complaintService.removeById(id);
return R.ok();
}
// ==================== AppService 端点 ====================
@PostMapping("/plan/generate")
@Transactional(rollbackFor = Exception.class)
public R<?> generatePlan(@RequestBody FollowupPlan plan) {
return R.ok(followupAppService.generatePlan(plan));
}
@PostMapping("/task/assign")
@Transactional(rollbackFor = Exception.class)
public R<?> assignTasks(@RequestParam("planId") Long planId,
@RequestBody List<String> operatorNames) {
return R.ok(followupAppService.assignTasks(planId, operatorNames));
}
@PostMapping("/record/followup")
@Transactional(rollbackFor = Exception.class)
public R<?> recordFollowup(@RequestBody FollowupRecord record) {
return R.ok(followupAppService.recordFollowup(record));
}
@GetMapping("/task/list")
public R<?> getTaskList(
@RequestParam(value = "planId", required = false) Long planId,
@RequestParam(value = "result", required = false) String result,
@RequestParam(value = "pageNo", defaultValue = "1") Integer pageNo,
@RequestParam(value = "pageSize", defaultValue = "20") Integer pageSize) {
return R.ok(followupAppService.getTaskList(planId, result, pageNo, pageSize));
}
}