package jnpf.tmsService.impl; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.ObjectMapper; import jnpf.exception.DataException; import jnpf.permission.UserApi; import jnpf.permission.entity.UserEntity; import jnpf.tmsEntity.TmsMaterialEntity; import jnpf.tmsEntity.TmsPersonTaskEntity; import jnpf.tmsEntity.TmsRecordEntity; import jnpf.tmsEntity.TmsTaskEntity; import jnpf.tmsEntity.TmsTaskFileEntity; import jnpf.tmsEntity.record.TmsRecordAttachmentForm; import jnpf.tmsEntity.record.TmsRecordForm; import jnpf.tmsEntity.record.TmsRecordParticipantForm; import jnpf.tmsEntity.record.TmsRecordQuery; import jnpf.tmsEntity.record.TmsRecordSignForm; import jnpf.tmsMapper.TmsMaterialMapper; import jnpf.tmsMapper.TmsPersonTaskMapper; import jnpf.tmsMapper.TmsRecordMapper; import jnpf.tmsMapper.TmsTaskFileMapper; import jnpf.tmsMapper.TmsTaskMapper; import jnpf.tmsService.TmsRecordService; import jnpf.util.DateUtil; import jnpf.util.StringUtil; import jnpf.util.UserProvider; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import java.util.ArrayList; import java.util.Collections; import java.util.Date; import java.util.HashMap; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.stream.Collectors; @Service @RequiredArgsConstructor public class TmsRecordServiceImpl implements TmsRecordService { private static final String FMT = "yyyy-MM-dd HH:mm:ss"; private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper(); private final TmsRecordMapper recordMapper; private final TmsTaskMapper taskMapper; private final TmsTaskFileMapper taskFileMapper; private final TmsMaterialMapper materialMapper; private final TmsPersonTaskMapper personTaskMapper; private final UserApi userApi; @Override public List getList(TmsRecordQuery query) { LambdaQueryWrapper qw = new LambdaQueryWrapper<>(); applyListMode(qw, query); if (StringUtil.isNotEmpty(query.getRecordNo())) { qw.like(TmsRecordEntity::getRecordNo, query.getRecordNo().trim()); } if (StringUtil.isNotEmpty(query.getCategory())) { qw.like(TmsRecordEntity::getCategory, query.getCategory().trim()); } if (StringUtil.isNotEmpty(query.getKeyword()) && !"null".equalsIgnoreCase(query.getKeyword())) { String kw = query.getKeyword().trim(); qw.and(w -> w.like(TmsRecordEntity::getRecordNo, kw) .or().like(TmsRecordEntity::getSubject, kw)); } qw.orderByDesc(TmsRecordEntity::getStartTime).orderByDesc(TmsRecordEntity::getCreatorTime); long current = query.getCurrentPage() > 0 ? query.getCurrentPage() : 1; long size = query.getPageSize() > 0 ? query.getPageSize() : 20; Page page = recordMapper.selectPage(new Page<>(current, size), qw); List rows = page.getRecords(); Map names = loadUserNames(rows.stream() .map(TmsRecordEntity::getTeacherId) .filter(StringUtil::isNotEmpty) .distinct() .collect(Collectors.toList())); List list = new ArrayList<>(rows.size()); String trainerFilter = StringUtil.isNotEmpty(query.getTrainerName()) ? query.getTrainerName().trim() : null; for (TmsRecordEntity row : rows) { TmsRecordForm form = toListForm(row, names); if (trainerFilter != null) { String name = form.getTrainerName() == null ? "" : form.getTrainerName(); if (!name.contains(trainerFilter)) { continue; } } list.add(form); } query.setData(list, page.getTotal()); return list; } @Override public TmsRecordForm getInfo(String id) { TmsRecordEntity entity = requireOne(id); Map teacherNames = loadUserNames( StringUtil.isEmpty(entity.getTeacherId()) ? Collections.emptyList() : Collections.singletonList(entity.getTeacherId())); TmsRecordForm form = toListForm(entity, teacherNames); TmsTaskEntity task = StringUtil.isEmpty(entity.getTaskId()) ? null : taskMapper.selectById(entity.getTaskId()); if (task != null) { form.setKeyPoints(task.getKeyPoints()); form.setPlaceName(task.getPlaceName()); if (StringUtil.isEmpty(form.getTrainType()) && StringUtil.isNotEmpty(task.getTrainType())) { form.setTrainType(task.getTrainType()); } if (StringUtil.isEmpty(form.getTrainMode()) && StringUtil.isNotEmpty(task.getTrainMode())) { form.setTrainMode(task.getTrainMode()); } } List persons = StringUtil.isEmpty(entity.getTaskId()) ? Collections.emptyList() : personTaskMapper.selectList(new LambdaQueryWrapper() .eq(TmsPersonTaskEntity::getTaskId, entity.getTaskId()) .orderByAsc(TmsPersonTaskEntity::getCreatorTime)); Map userNames = loadUserNames(persons.stream() .map(TmsPersonTaskEntity::getUserId) .filter(StringUtil::isNotEmpty) .distinct() .collect(Collectors.toList())); List participants = new ArrayList<>(persons.size()); List signs = new ArrayList<>(); List traineeNames = new ArrayList<>(); for (TmsPersonTaskEntity p : persons) { String userName = userNames.getOrDefault(p.getUserId(), p.getUserId()); traineeNames.add(userName); TmsRecordParticipantForm pf = new TmsRecordParticipantForm(); pf.setId(p.getId()); pf.setUserId(p.getUserId()); pf.setUserName(userName); pf.setSignDate(formatDate(p.getSignTime())); pf.setExamScore(p.getExamScore()); pf.setPassFlag(p.getPassFlag()); participants.add(pf); if (p.getSignTime() != null) { TmsRecordSignForm sf = new TmsRecordSignForm(); sf.setId(p.getId()); sf.setUserName(userName); sf.setSignTime(formatDate(p.getSignTime())); sf.setSignMode(p.getSignMode()); sf.setGuestFlag(p.getGuestFlag()); signs.add(sf); } } form.setParticipants(participants); form.setSignList(signs); form.setTrainees(String.join(",", traineeNames)); form.setAttachments(loadAttachments(entity.getTaskId())); form.setRemark(entity.getRemark()); return form; } @Override @Transactional(rollbackFor = Exception.class) public void update(String id, TmsRecordForm form) { TmsRecordEntity entity = requireOne(id); if (form == null) { throw new DataException("表单不能为空"); } if (StringUtil.isNotEmpty(form.getSubject())) { entity.setSubject(form.getSubject().trim()); } if (form.getCategory() != null) { entity.setCategory(form.getCategory()); } if (form.getTrainType() != null) { entity.setTrainType(form.getTrainType()); } if (form.getTrainMode() != null) { entity.setTrainMode(form.getTrainMode()); } if (form.getEvalMode() != null) { entity.setEvalMode(form.getEvalMode()); } entity.setRemark(form.getRemark()); entity.setLastModifyUserId(UserProvider.getLoginUserId()); entity.setLastModifyTime(new Date()); recordMapper.updateById(entity); } @Override @Transactional(rollbackFor = Exception.class) public int archive(List ids) { if (ids == null || ids.isEmpty()) { throw new DataException("请选择要归档的记录"); } int count = 0; Date now = new Date(); String userId = UserProvider.getLoginUserId(); for (String id : ids) { if (StringUtil.isEmpty(id)) { continue; } TmsRecordEntity entity = recordMapper.selectById(id); if (entity == null) { continue; } entity.setArchiveStatus("archived"); entity.setLastModifyUserId(userId); entity.setLastModifyTime(now); recordMapper.updateById(entity); count++; } return count; } @Override @Transactional(rollbackFor = Exception.class) public void delete(List ids) { if (ids == null || ids.isEmpty()) { throw new DataException("请选择要删除的记录"); } for (String id : ids) { if (StringUtil.isEmpty(id)) { continue; } recordMapper.deleteById(id); } } private void applyListMode(LambdaQueryWrapper qw, TmsRecordQuery query) { String archiveStatus = query.getArchiveStatus(); if (StringUtil.isNotEmpty(archiveStatus)) { qw.eq(TmsRecordEntity::getArchiveStatus, archiveStatus); return; } String mode = query.getListMode(); if ("ready".equals(mode)) { qw.eq(TmsRecordEntity::getArchiveStatus, "ready"); } else if ("archived".equals(mode)) { qw.eq(TmsRecordEntity::getArchiveStatus, "archived"); } else { // 主列表:待归档 / 进行中 qw.and(w -> w.eq(TmsRecordEntity::getArchiveStatus, "pending") .or().isNull(TmsRecordEntity::getArchiveStatus)); } } private TmsRecordForm toListForm(TmsRecordEntity entity, Map names) { TmsRecordForm form = new TmsRecordForm(); form.setId(entity.getId()); form.setRecordNo(entity.getRecordNo()); form.setTaskId(entity.getTaskId()); form.setTaskNo(entity.getTaskNo()); form.setCategory(entity.getCategory()); form.setSubject(entity.getSubject()); form.setTeacherId(entity.getTeacherId()); form.setTrainerName(names.getOrDefault(entity.getTeacherId(), StringUtil.isEmpty(entity.getTeacherId()) ? "-" : entity.getTeacherId())); form.setTrainType(StringUtil.isNotEmpty(entity.getTrainType()) ? entity.getTrainType() : entity.getTrainMode()); form.setTrainMode(entity.getTrainMode()); form.setEvalMode(entity.getEvalMode()); form.setStartTime(formatDate(entity.getStartTime())); form.setEndTime(formatDate(entity.getEndTime())); form.setCloseTime(formatDate(entity.getCloseTime())); form.setArchiveStatus(entity.getArchiveStatus()); form.setSignRate(entity.getSignRate()); form.setPassRate(entity.getPassRate()); form.setRemark(entity.getRemark()); return form; } private List loadAttachments(String taskId) { if (StringUtil.isEmpty(taskId)) { return Collections.emptyList(); } List files = taskFileMapper.selectList( new LambdaQueryWrapper() .eq(TmsTaskFileEntity::getForeignId, taskId) .orderByAsc(TmsTaskFileEntity::getCreatorTime)); if (files.isEmpty()) { return Collections.emptyList(); } List materialIds = files.stream() .map(TmsTaskFileEntity::getMaterialId) .filter(StringUtil::isNotEmpty) .distinct() .collect(Collectors.toList()); Map materialMap = new HashMap<>(); if (!materialIds.isEmpty()) { for (TmsMaterialEntity material : materialMapper.selectBatchIds(materialIds)) { materialMap.put(material.getId(), material); } } List list = new ArrayList<>(); for (TmsTaskFileEntity file : files) { String url = extractUrl(file.getFileJson()); if (StringUtil.isEmpty(url) && StringUtil.isNotEmpty(file.getMaterialId())) { TmsMaterialEntity material = materialMap.get(file.getMaterialId()); if (material != null) { url = extractUrl(material.getFileJson()); } } TmsRecordAttachmentForm item = new TmsRecordAttachmentForm(); item.setId(file.getId()); item.setName(file.getFileName()); item.setUrl(url); list.add(item); } return list; } private String extractUrl(String fileJson) { if (StringUtil.isEmpty(fileJson)) { return null; } try { String text = fileJson.trim(); if (text.startsWith("[")) { List> arr = OBJECT_MAPPER.readValue(text, new TypeReference>>() { }); if (arr == null || arr.isEmpty()) { return null; } Object url = arr.get(0).get("url"); return url == null ? null : String.valueOf(url); } Map map = OBJECT_MAPPER.readValue(text, new TypeReference>() { }); Object url = map.get("url"); return url == null ? null : String.valueOf(url); } catch (Exception ex) { return null; } } private Map loadUserNames(List userIds) { if (userIds == null || userIds.isEmpty()) { return Collections.emptyMap(); } List ids = userIds.stream().filter(StringUtil::isNotEmpty).distinct().collect(Collectors.toList()); if (ids.isEmpty()) { return Collections.emptyMap(); } try { List users = userApi.getUserName(ids); 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 TmsRecordEntity requireOne(String id) { if (StringUtil.isEmpty(id)) { throw new DataException("记录ID不能为空"); } TmsRecordEntity entity = recordMapper.selectById(id); if (entity == null) { throw new DataException("培训记录不存在"); } return entity; } private String formatDate(Date date) { return date == null ? null : DateUtil.dateToString(date, FMT); } }