package jnpf.tmsService.impl; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import jnpf.exception.DataException; import jnpf.permission.OrganizeApi; import jnpf.permission.UserApi; import jnpf.permission.entity.OrganizeEntity; import jnpf.permission.entity.UserEntity; import jnpf.tmsEntity.TmsPersonTaskEntity; import jnpf.tmsEntity.TmsPracticeEntity; import jnpf.tmsEntity.TmsPracticeItemEntity; import jnpf.tmsEntity.TmsRecordEntity; import jnpf.tmsEntity.TmsRecordSignEntity; import jnpf.tmsEntity.TmsTaskEntity; import jnpf.tmsEntity.enums.TmsEvalMode; import jnpf.tmsEntity.enums.TmsPassFlag; import jnpf.tmsEntity.enums.TmsPersonTaskStatus; import jnpf.tmsEntity.practice.TmsPracticeForm; import jnpf.tmsEntity.practice.TmsPracticeItemForm; import jnpf.tmsMapper.TmsPersonTaskMapper; import jnpf.tmsMapper.TmsPracticeItemMapper; import jnpf.tmsMapper.TmsPracticeMapper; import jnpf.tmsMapper.TmsRecordMapper; import jnpf.tmsMapper.TmsRecordSignMapper; import jnpf.tmsMapper.TmsTaskMapper; import jnpf.tmsService.TmsPracticeService; import jnpf.tmsService.TmsRecordService; import jnpf.util.DateUtil; import jnpf.util.RandomUtil; import jnpf.util.StringUtil; import jnpf.util.UserProvider; import lombok.RequiredArgsConstructor; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Lazy; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import java.math.BigDecimal; import java.util.ArrayList; import java.util.Collections; import java.util.Date; import java.util.HashMap; import java.util.HashSet; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Set; import java.util.stream.Collectors; @Service @RequiredArgsConstructor public class TmsPracticeServiceImpl implements TmsPracticeService { private static final String FMT = "yyyy-MM-dd HH:mm:ss"; private final TmsPracticeMapper practiceMapper; private final TmsPracticeItemMapper practiceItemMapper; private final TmsRecordMapper recordMapper; private final TmsTaskMapper taskMapper; private final TmsPersonTaskMapper personTaskMapper; private final TmsRecordSignMapper recordSignMapper; private final UserApi userApi; private final OrganizeApi organizeApi; @Lazy @Autowired private TmsRecordService recordService; @Override public TmsPracticeForm getByRecordId(String recordId) { TmsRecordEntity record = requireRecord(recordId); TmsPracticeEntity practice = practiceMapper.selectOne(new LambdaQueryWrapper() .eq(TmsPracticeEntity::getRecordId, recordId) .last("LIMIT 1")); TmsPracticeForm form = new TmsPracticeForm(); form.setRecordId(recordId); form.setTaskId(record.getTaskId()); if (practice != null) { form.setId(practice.getId()); form.setTeacherId(practice.getTeacherId()); form.setPracticeTime(formatDate(practice.getPracticeTime())); form.setRemark(practice.getRemark()); form.setItems(listItems(practice.getId())); return form; } form.setTeacherId(UserProvider.getLoginUserId()); form.setItems(buildEmptyItems(record.getTaskId())); return form; } @Override @Transactional(rollbackFor = Exception.class) public String save(TmsPracticeForm form) { if (form == null || StringUtil.isEmpty(form.getRecordId())) { throw new DataException("培训记录不能为空"); } TmsRecordEntity record = requireRecord(form.getRecordId()); TmsTaskEntity task = taskMapper.selectById(record.getTaskId()); if (task == null) { throw new DataException("培训任务不存在"); } if (!TmsEvalMode.PRACTICE.equalsCode(task.getEvalMode()) && !TmsEvalMode.PRACTICE.equalsCode(record.getEvalMode())) { throw new DataException("当前记录非实操考核,无需实操打分"); } List items = form.getItems() == null ? Collections.emptyList() : form.getItems(); if (items.isEmpty()) { throw new DataException("请至少录入一名学员的实操成绩"); } Date now = new Date(); String teacherId = StringUtil.isNotEmpty(form.getTeacherId()) ? form.getTeacherId() : UserProvider.getLoginUserId(); TmsPracticeEntity practice = null; if (StringUtil.isNotEmpty(form.getId())) { practice = practiceMapper.selectById(form.getId()); } if (practice == null) { practice = practiceMapper.selectOne(new LambdaQueryWrapper() .eq(TmsPracticeEntity::getRecordId, record.getId()) .last("LIMIT 1")); } if (practice == null) { practice = new TmsPracticeEntity(); practice.setId(RandomUtil.uuId()); practice.setTaskId(record.getTaskId()); practice.setRecordId(record.getId()); practice.setTeacherId(teacherId); practice.setPracticeTime(parseDate(form.getPracticeTime(), now)); practice.setRemark(form.getRemark()); practice.setCreatorUserId(UserProvider.getLoginUserId()); practice.setCreatorTime(now); practiceMapper.insert(practice); } else { practice.setTeacherId(teacherId); practice.setPracticeTime(parseDate(form.getPracticeTime(), now)); practice.setRemark(form.getRemark()); practice.setLastModifyUserId(UserProvider.getLoginUserId()); practice.setLastModifyTime(now); practiceMapper.updateById(practice); } practiceItemMapper.delete(new LambdaQueryWrapper() .eq(TmsPracticeItemEntity::getForeignId, practice.getId())); BigDecimal passScore = task.getPassScore() == null ? BigDecimal.valueOf(60) : task.getPassScore(); for (TmsPracticeItemForm row : items) { if (row == null || StringUtil.isEmpty(row.getUserId())) { continue; } BigDecimal score = row.getScore() == null ? BigDecimal.ZERO : row.getScore(); String resultFlag = StringUtil.isNotEmpty(row.getResultFlag()) ? TmsPassFlag.normalize(row.getResultFlag()) : TmsPassFlag.ofScore(score, passScore); if (StringUtil.isEmpty(resultFlag)) { resultFlag = score.compareTo(passScore) >= 0 ? TmsPassFlag.PASS.getCode() : TmsPassFlag.FAIL.getCode(); } TmsPracticeItemEntity item = new TmsPracticeItemEntity(); item.setId(RandomUtil.uuId()); item.setForeignId(practice.getId()); item.setUserId(row.getUserId()); item.setContent(row.getContent()); item.setScore(score); item.setResultFlag(resultFlag); item.setCreatorUserId(UserProvider.getLoginUserId()); item.setCreatorTime(now); practiceItemMapper.insert(item); writeBackPerson(record.getTaskId(), record.getId(), row.getUserId(), score, resultFlag, now); } try { recordService.refreshRatesByTaskId(record.getTaskId()); } catch (Exception ignored) { // ignore } return practice.getId(); } private void writeBackPerson(String taskId, String recordId, String userId, BigDecimal score, String passFlag, Date now) { TmsPersonTaskEntity person = personTaskMapper.selectOne(new LambdaQueryWrapper() .eq(TmsPersonTaskEntity::getTaskId, taskId) .eq(TmsPersonTaskEntity::getUserId, userId) .last("LIMIT 1")); if (person != null) { person.setPassFlag(passFlag); if (TmsPassFlag.isPass(passFlag)) { person.setBizStatus(TmsPersonTaskStatus.DONE.getCode()); } person.setLastModifyUserId(UserProvider.getLoginUserId()); person.setLastModifyTime(now); personTaskMapper.updateById(person); } TmsRecordSignEntity sign = recordSignMapper.selectOne(new LambdaQueryWrapper() .eq(TmsRecordSignEntity::getForeignId, recordId) .eq(TmsRecordSignEntity::getUserId, userId) .last("LIMIT 1")); if (sign != null) { sign.setPracticeScore(score); sign.setResultFlag(passFlag); sign.setLastModifyUserId(UserProvider.getLoginUserId()); sign.setLastModifyTime(now); recordSignMapper.updateById(sign); } } private List listItems(String practiceId) { List rows = practiceItemMapper.selectList( new LambdaQueryWrapper() .eq(TmsPracticeItemEntity::getForeignId, practiceId) .orderByAsc(TmsPracticeItemEntity::getCreatorTime)); List userIds = rows.stream().map(TmsPracticeItemEntity::getUserId) .filter(StringUtil::isNotEmpty).distinct().collect(Collectors.toList()); Map names = loadUserNames(userIds); List list = new ArrayList<>(rows.size()); for (TmsPracticeItemEntity row : rows) { TmsPracticeItemForm form = new TmsPracticeItemForm(); form.setId(row.getId()); form.setUserId(row.getUserId()); form.setUserName(names.getOrDefault(row.getUserId(), row.getUserId())); form.setContent(row.getContent()); form.setScore(row.getScore()); form.setResultFlag(row.getResultFlag()); list.add(form); } return list; } private List buildEmptyItems(String taskId) { List persons = personTaskMapper.selectList( new LambdaQueryWrapper() .eq(TmsPersonTaskEntity::getTaskId, taskId) .orderByAsc(TmsPersonTaskEntity::getCreatorTime)); List list = new ArrayList<>(); for (TmsPersonTaskEntity p : persons) { if (p != null && !"1".equals(p.getGuestFlag()) && p.getSignTime() != null) { list.add(p); } } Map names = loadUserNames(list.stream() .map(TmsPersonTaskEntity::getUserId) .filter(StringUtil::isNotEmpty) .distinct() .collect(Collectors.toList())); Set deptIds = new HashSet<>(); for (TmsPersonTaskEntity p : list) { if (StringUtil.isNotEmpty(p.getDeptId())) { deptIds.add(p.getDeptId()); } } Map deptNames = loadDeptNames(deptIds); List items = new ArrayList<>(list.size()); for (TmsPersonTaskEntity p : list) { TmsPracticeItemForm form = new TmsPracticeItemForm(); form.setUserId(p.getUserId()); form.setUserName(names.getOrDefault(p.getUserId(), p.getUserId())); form.setDeptName(deptNames.getOrDefault(p.getDeptId(), "")); form.setResultFlag(p.getPassFlag()); items.add(form); } return items; } private TmsRecordEntity requireRecord(String recordId) { if (StringUtil.isEmpty(recordId)) { throw new DataException("记录ID不能为空"); } TmsRecordEntity record = recordMapper.selectById(recordId); if (record == null) { throw new DataException("培训记录不存在"); } return record; } private Map loadUserNames(List userIds) { if (userIds == null || userIds.isEmpty()) { return Collections.emptyMap(); } try { List users = userApi.getUserName(userIds); if (users == null || users.isEmpty()) { return Collections.emptyMap(); } Map map = new LinkedHashMap<>(); for (UserEntity user : users) { if (user == null || StringUtil.isEmpty(user.getId())) { continue; } String name = StringUtil.isNotEmpty(user.getRealName()) ? user.getRealName() : user.getAccount(); map.put(user.getId(), name); } return map; } catch (Exception ex) { return Collections.emptyMap(); } } private Map loadDeptNames(Set deptIds) { Map map = new HashMap<>(); if (deptIds == null || deptIds.isEmpty()) { return map; } for (String id : deptIds) { try { OrganizeEntity org = organizeApi.getInfoById(id); if (org != null && StringUtil.isNotEmpty(org.getFullName())) { map.put(id, org.getFullName()); } } catch (Exception ignored) { // ignore } } return map; } private Date parseDate(String text, Date fallback) { if (StringUtil.isEmpty(text)) { return fallback; } try { return DateUtil.stringToDate(text); } catch (Exception ex) { return fallback; } } private String formatDate(Date date) { return date == null ? null : DateUtil.dateToString(date, FMT); } }