package com.ruoyi.business.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ruoyi.basic.entity.StorageAttachment;
import com.ruoyi.basic.entity.StorageBlob;
import com.ruoyi.basic.entity.dto.StorageBlobDTO;
import com.ruoyi.basic.mapper.StorageAttachmentMapper;
import com.ruoyi.basic.mapper.StorageBlobMapper;
import com.ruoyi.basic.service.StorageAttachmentService;
import com.ruoyi.business.dto.ArchiveDto;
import com.ruoyi.business.entity.Archive;
import com.ruoyi.business.mapper.ArchiveMapper;
import com.ruoyi.business.service.ArchiveService;
import com.ruoyi.common.utils.bean.BeanUtils;
import com.ruoyi.common.utils.file.MinioUtils;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;
import static com.ruoyi.common.constant.StorageAttachmentConstants.StorageAttachmentFile;
import static com.ruoyi.common.enums.StorageAttachmentRecordType.Archives;
/**
*
* 档案信息表,记录系统中各类档案的基本信息 服务实现类
*
*
* @author ruoyi
* @since 2025-06-10
*/
@Service
@RequiredArgsConstructor
public class ArchiveServiceImpl extends ServiceImpl implements ArchiveService {
private final ArchiveMapper archiveMapper;
private final StorageAttachmentService storageAttachmentService;
private final StorageBlobMapper storageBlobMapper;
private final StorageAttachmentMapper storageAttachmentMapper;
private final MinioUtils minioUtils;
@Override
public IPage selectArchiveList(Page page, ArchiveDto archiveDto) {
// 1. 分页查询主数据
LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.orderByDesc(Archive::getCreateTime);
IPage archivePage = archiveMapper.selectPage(page, queryWrapper);
// 2. 无数据提前返回
if (CollectionUtils.isEmpty(archivePage.getRecords())) {
return new Page<>(archivePage.getCurrent(), archivePage.getSize(), archivePage.getTotal());
}
// 3. 批量获取所有档案ID
List archiveIds = archivePage.getRecords()
.stream()
.map(Archive::getId)
.collect(Collectors.toList());
// 4. 批量查询附件映射关系(避免N+1)
List storageAttachments = storageAttachmentMapper
.selectList(new LambdaQueryWrapper()
.in(StorageAttachment::getRecordId, archiveIds)
.eq(StorageAttachment::getRecordType, Archives.ordinal())
);
Map> attachmentsMap = storageAttachmentMapper
.selectList(new LambdaQueryWrapper()
.in(StorageAttachment::getRecordId, archiveIds)
.eq(StorageAttachment::getRecordType, Archives.ordinal())
).stream()
.collect(Collectors.groupingBy(StorageAttachment::getRecordId));
// 5. 批量查询所有需要的文件数据
Set blobIds = attachmentsMap.values()
.stream()
.flatMap(List::stream)
.map(StorageAttachment::getStorageBlobId)
.collect(Collectors.toSet());
Map blobMap = blobIds.isEmpty()
? Collections.emptyMap()
: storageBlobMapper.selectList(new LambdaQueryWrapper().in(StorageBlob::getId, blobIds))
.stream()
.collect(Collectors.toMap(StorageBlob::getId, Function.identity()));
// 6. 组装DTO(单次循环完成数据装配)
List dtoList = archivePage.getRecords().stream().map(archive -> {
ArchiveDto dto = new ArchiveDto();
BeanUtils.copyProperties(archive, dto); // 复制主对象属性
// 按需添加附件信息
List blobDTOs = Optional.ofNullable(attachmentsMap.get(archive.getId()))
.orElse(Collections.emptyList())
.stream()
.map(att -> blobMap.get(att.getStorageBlobId()))
.filter(Objects::nonNull)
.map(blob -> {
StorageBlobDTO blobDTO = new StorageBlobDTO();
BeanUtils.copyProperties(blob, blobDTO);
// 动态生成预览地址和下载地址
// 设置预览URL
blobDTO.setUrl(minioUtils.getPreviewUrls(
blob.getBucketFilename(),
blob.getBucketName(),
true
));
// 设置下载URL
blobDTO.setDownloadUrl(minioUtils.getDownloadUrls(
blob.getBucketFilename(),
blob.getBucketName(),
blob.getOriginalFilename(), // 原始文件名
true
));
return blobDTO;
})
.collect(Collectors.toList());
dto.setStorageBlobDTO(blobDTOs);
return dto;
}).collect(Collectors.toList());
// 7. 构建返回分页对象
IPage resultPage = new Page<>();
resultPage.setRecords(dtoList);
return resultPage;
}
@Override
public int addOrEditArchive(ArchiveDto archiveDto) {
Archive archive = new Archive();
BeanUtils.copyProperties(archiveDto, archive);
int i;
if (Objects.isNull(archiveDto.getId())) {
i = archiveMapper.insert(archive);
} else {
i = archiveMapper.updateById(archive);
}
if (archiveDto.getStorageBlobDTO() != null && !archiveDto.getStorageBlobDTO().isEmpty()) {
List attachments = new ArrayList<>();
for (StorageBlobDTO storageBlobDTO : archiveDto.getStorageBlobDTO()) {
StorageAttachment storageAttachment = new StorageAttachment(
StorageAttachmentFile,
(long) Archives.ordinal(),
archive.getId()
);
storageAttachment.setStorageBlobDTO(storageBlobDTO);
attachments.add(storageAttachment);
}
storageAttachmentService.saveStorageAttachment(attachments, archive.getId(), Archives, StorageAttachmentFile);
}
return i;
}
@Override
public int delByIds(Long[] ids) {
// 检查参数
if (ids == null || ids.length == 0) {
return 0;
}
// 构造更新条件
UpdateWrapper updateWrapper = new UpdateWrapper<>();
updateWrapper.in("id", ids)
.set("deleted", 1); // 设置 deleted 为 1 表示已删除
// 执行批量逻辑删除
return archiveMapper.update(null, updateWrapper);
}
@Override
public List fileList(ArchiveDto archiveDto) {
List storageAttachments = storageAttachmentService.selectStorageAttachments(archiveDto.getId(), Archives, StorageAttachmentFile);
return storageAttachments;
}
}