登录增加验证码切换
This commit is contained in:
@@ -50,19 +50,18 @@ public class FileService {
|
||||
|
||||
boolean hasKeyword = keyword != null && !keyword.isEmpty();
|
||||
|
||||
// 根目录:folderId == null 或 0 都视为根目录,统一用 0 查询
|
||||
Long actualFolderId = (folderId == null || folderId == 0L) ? 0L : folderId;
|
||||
|
||||
if (hasKeyword) {
|
||||
// 有搜索关键词:根目录搜索查所有,子目录搜索限当前目录
|
||||
if (folderId != null) {
|
||||
if (!actualFolderId.equals(0L)) {
|
||||
wrapper.eq(FileEntity::getFolderId, folderId);
|
||||
}
|
||||
wrapper.like(FileEntity::getName, keyword);
|
||||
} else {
|
||||
// 无搜索关键词:正常浏览当前目录
|
||||
if (folderId != null) {
|
||||
wrapper.eq(FileEntity::getFolderId, folderId);
|
||||
} else {
|
||||
wrapper.isNull(FileEntity::getFolderId);
|
||||
}
|
||||
wrapper.eq(FileEntity::getFolderId, actualFolderId);
|
||||
}
|
||||
|
||||
wrapper.orderByDesc(FileEntity::getIsFolder)
|
||||
@@ -77,10 +76,13 @@ public class FileService {
|
||||
.eq(FileEntity::getIsDeleted, 1)
|
||||
.orderByDesc(FileEntity::getDeletedAt);
|
||||
|
||||
if (folderId != null) {
|
||||
wrapper.eq(FileEntity::getFolderId, folderId);
|
||||
// 根目录:folderId == null 或 0 都视为根目录
|
||||
Long actualFolderId = (folderId == null || folderId == 0L) ? 0L : folderId;
|
||||
// 根目录在数据库中兼容 null 和 0 两种值
|
||||
if (actualFolderId.equals(0L)) {
|
||||
wrapper.and(w -> w.eq(FileEntity::getFolderId, 0L).or().isNull(FileEntity::getFolderId));
|
||||
} else {
|
||||
wrapper.isNull(FileEntity::getFolderId);
|
||||
wrapper.eq(FileEntity::getFolderId, actualFolderId);
|
||||
}
|
||||
|
||||
return fileMapper.selectList(wrapper);
|
||||
@@ -93,27 +95,46 @@ public class FileService {
|
||||
@Transactional
|
||||
public void moveToTrash(Long id, Long userId) {
|
||||
FileEntity file = fileMapper.selectById(id);
|
||||
if (file != null && file.getUserId().equals(userId)) {
|
||||
// 如果是文件夹,检查是否有子文件
|
||||
if (file == null || !file.getUserId().equals(userId)) return;
|
||||
|
||||
if (file.getIsFolder() != null && file.getIsFolder() == 1) {
|
||||
Long childCount = fileMapper.selectCount(
|
||||
new LambdaQueryWrapper<FileEntity>()
|
||||
.eq(FileEntity::getFolderId, id)
|
||||
.eq(FileEntity::getIsDeleted, 0)
|
||||
.eq(FileEntity::getUserId, userId)
|
||||
);
|
||||
if (childCount != null && childCount > 0) {
|
||||
throw new RuntimeException("请删除该目录下文件后重试");
|
||||
}
|
||||
// 文件夹:递归将所有子文件标记删除,移动到回收站根目录
|
||||
moveChildrenToTrash(id, userId);
|
||||
}
|
||||
|
||||
// 使用 LambdaUpdateWrapper 明确指定要更新的字段
|
||||
// 当前文件/文件夹:移动到回收站根目录
|
||||
LambdaUpdateWrapper<FileEntity> wrapper = new LambdaUpdateWrapper<>();
|
||||
wrapper.eq(FileEntity::getId, id)
|
||||
.set(FileEntity::getFolderId, 0L)
|
||||
.set(FileEntity::getIsDeleted, 1)
|
||||
.set(FileEntity::getDeletedAt, LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
|
||||
fileMapper.update(null, wrapper);
|
||||
}
|
||||
|
||||
/**
|
||||
* 递归将文件夹下所有子文件/子文件夹标记为删除(folderId 保持不变)
|
||||
*/
|
||||
private void moveChildrenToTrash(Long parentFolderId, Long userId) {
|
||||
List<FileEntity> children = fileMapper.selectList(
|
||||
new LambdaQueryWrapper<FileEntity>()
|
||||
.eq(FileEntity::getFolderId, parentFolderId)
|
||||
.eq(FileEntity::getIsDeleted, 0)
|
||||
.eq(FileEntity::getUserId, userId)
|
||||
);
|
||||
|
||||
for (FileEntity child : children) {
|
||||
// 子文件/子文件夹只标删除,folderId 保持原值不变
|
||||
LambdaUpdateWrapper<FileEntity> wrapper = new LambdaUpdateWrapper<>();
|
||||
wrapper.eq(FileEntity::getId, child.getId())
|
||||
.set(FileEntity::getIsDeleted, 1)
|
||||
.set(FileEntity::getDeletedAt, LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
|
||||
fileMapper.update(null, wrapper);
|
||||
|
||||
if (child.getIsFolder() != null && child.getIsFolder() == 1) {
|
||||
// 递归处理子文件夹
|
||||
moveChildrenToTrash(child.getId(), userId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Transactional
|
||||
@@ -121,21 +142,29 @@ public class FileService {
|
||||
FileEntity file = fileMapper.selectById(id);
|
||||
if (file == null || !file.getUserId().equals(userId)) return;
|
||||
|
||||
// 检查父文件夹是否在回收站,如果是,将文件移到根目录
|
||||
Long folderId = file.getFolderId();
|
||||
if (folderId != null) {
|
||||
FileEntity parentFolder = fileMapper.selectById(folderId);
|
||||
if (parentFolder != null && parentFolder.getIsDeleted() == 1) {
|
||||
// 父文件夹在回收站,将文件移到根目录
|
||||
folderId = null;
|
||||
// 检查父文件夹状态,决定还原目标
|
||||
// - folderId == 0 或 null:根目录,还原到根目录(folderId=0)
|
||||
// - 父文件夹存在且未删除:还原到原父文件夹
|
||||
// - 父文件夹不存在或已删除:还原到根目录(folderId=0)
|
||||
Long originalFolderId = file.getFolderId();
|
||||
Long targetFolderId = originalFolderId;
|
||||
|
||||
if (targetFolderId != null && !targetFolderId.equals(0L)) {
|
||||
FileEntity parentFolder = fileMapper.selectById(targetFolderId);
|
||||
if (parentFolder == null || parentFolder.getIsDeleted() == 1) {
|
||||
// 父文件夹不在了,还原到根目录
|
||||
targetFolderId = 0L;
|
||||
}
|
||||
} else if (targetFolderId == null || targetFolderId.equals(0L)) {
|
||||
// 本身就是根目录
|
||||
targetFolderId = 0L;
|
||||
}
|
||||
|
||||
LambdaUpdateWrapper<FileEntity> wrapper = new LambdaUpdateWrapper<>();
|
||||
wrapper.eq(FileEntity::getId, id)
|
||||
.set(FileEntity::getIsDeleted, 0)
|
||||
.set(FileEntity::getDeletedAt, null)
|
||||
.set(FileEntity::getFolderId, folderId);
|
||||
.set(FileEntity::getFolderId, targetFolderId);
|
||||
fileMapper.update(null, wrapper);
|
||||
|
||||
// 如果是文件夹,递归还原所有子文件
|
||||
@@ -169,28 +198,9 @@ public class FileService {
|
||||
FileEntity file = fileMapper.selectById(id);
|
||||
if (file == null || !file.getUserId().equals(userId)) return;
|
||||
|
||||
// 如果是文件夹,检查是否有未删除的子文件
|
||||
if (file.getIsFolder() != null && file.getIsFolder() == 1) {
|
||||
Long undeletedCount = fileMapper.selectCount(
|
||||
new LambdaQueryWrapper<FileEntity>()
|
||||
.eq(FileEntity::getFolderId, id)
|
||||
.eq(FileEntity::getIsDeleted, 0)
|
||||
.eq(FileEntity::getUserId, userId)
|
||||
);
|
||||
if (undeletedCount != null && undeletedCount > 0) {
|
||||
throw new RuntimeException("请先处理该目录下的子文件后重试");
|
||||
}
|
||||
|
||||
// 检查是否有已删除的子文件(在回收站里的)
|
||||
Long deletedChildrenCount = fileMapper.selectCount(
|
||||
new LambdaQueryWrapper<FileEntity>()
|
||||
.eq(FileEntity::getFolderId, id)
|
||||
.eq(FileEntity::getIsDeleted, 1)
|
||||
.eq(FileEntity::getUserId, userId)
|
||||
);
|
||||
if (deletedChildrenCount != null && deletedChildrenCount > 0) {
|
||||
throw new RuntimeException("请先处理该目录下的子文件后重试");
|
||||
}
|
||||
// 递归彻底删除所有子文件/子文件夹
|
||||
deleteChildrenPermanently(id, userId);
|
||||
}
|
||||
|
||||
// 删除当前文件的物理文件并扣减存储
|
||||
@@ -208,11 +218,58 @@ public class FileService {
|
||||
fileMapper.deleteById(id);
|
||||
}
|
||||
|
||||
/**
|
||||
* 递归彻底删除文件夹下所有子文件/子文件夹
|
||||
*/
|
||||
private void deleteChildrenPermanently(Long parentFolderId, Long userId) {
|
||||
List<FileEntity> children = fileMapper.selectList(
|
||||
new LambdaQueryWrapper<FileEntity>()
|
||||
.eq(FileEntity::getFolderId, parentFolderId)
|
||||
.eq(FileEntity::getIsDeleted, 1)
|
||||
.eq(FileEntity::getUserId, userId)
|
||||
);
|
||||
|
||||
for (FileEntity child : children) {
|
||||
if (child.getIsFolder() != null && child.getIsFolder() == 1) {
|
||||
deleteChildrenPermanently(child.getId(), userId);
|
||||
}
|
||||
|
||||
// 删除物理文件并扣减存储
|
||||
if (child.getPath() != null && !child.getPath().isEmpty()) {
|
||||
try {
|
||||
Path filePath = Paths.get(storagePath).toAbsolutePath().resolve("files").resolve(child.getPath());
|
||||
Files.deleteIfExists(filePath);
|
||||
} catch (IOException e) {
|
||||
// ignore
|
||||
}
|
||||
if (child.getSize() != null && child.getSize() > 0) {
|
||||
userService.decreaseStorage(userId, child.getSize());
|
||||
}
|
||||
}
|
||||
fileMapper.deleteById(child.getId());
|
||||
}
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public void emptyTrash(Long userId) {
|
||||
List<FileEntity> trashFiles = getTrashFiles(userId, null);
|
||||
|
||||
// 找出回收站里所有文件夹的 ID
|
||||
java.util.Set<Long> folderIds = trashFiles.stream()
|
||||
.filter(f -> f.getIsFolder() != null && f.getIsFolder() == 1)
|
||||
.map(FileEntity::getId)
|
||||
.collect(java.util.stream.Collectors.toSet());
|
||||
|
||||
for (FileEntity file : trashFiles) {
|
||||
// 跳过子文件(folderId 指向的父文件夹也在回收站中,会被级联删除)
|
||||
if (folderIds.contains(file.getFolderId())) {
|
||||
continue;
|
||||
}
|
||||
try {
|
||||
deletePermanently(file.getId(), userId);
|
||||
} catch (Exception e) {
|
||||
// ignore,级联删除时子文件可能已不存在
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -223,7 +280,8 @@ public class FileService {
|
||||
folder.setType("folder");
|
||||
folder.setIsFolder(1);
|
||||
folder.setUserId(userId);
|
||||
folder.setFolderId(parentId);
|
||||
// 根目录 parentId = null 或 0 → 统一用 0
|
||||
folder.setFolderId((parentId == null || parentId == 0L) ? 0L : parentId);
|
||||
folder.setSize(0L);
|
||||
folder.setIsShared(0);
|
||||
folder.setIsDeleted(0);
|
||||
@@ -498,8 +556,13 @@ public class FileService {
|
||||
throw new RuntimeException("无法移动回收站中的文件");
|
||||
}
|
||||
|
||||
// 检查目标文件夹是否存在(如果不是根目录)
|
||||
if (targetFolderId != null) {
|
||||
// 规范化 targetFolderId:null → 0L(根目录)
|
||||
if (targetFolderId == null) {
|
||||
targetFolderId = 0L;
|
||||
}
|
||||
|
||||
// 检查目标文件夹是否存在(如果不是根目录,folderId=0 视为根目录)
|
||||
if (!targetFolderId.equals(0L)) {
|
||||
FileEntity targetFolder = fileMapper.selectById(targetFolderId);
|
||||
if (targetFolder == null) {
|
||||
throw new RuntimeException("目标文件夹不存在");
|
||||
@@ -529,20 +592,22 @@ public class FileService {
|
||||
}
|
||||
|
||||
// 检查目标位置是否已有同名文件
|
||||
FileEntity existing = fileMapper.selectOne(
|
||||
new LambdaQueryWrapper<FileEntity>()
|
||||
LambdaQueryWrapper<FileEntity> dupWrapper = new LambdaQueryWrapper<FileEntity>()
|
||||
.eq(FileEntity::getUserId, userId)
|
||||
.eq(FileEntity::getFolderId, targetFolderId)
|
||||
.eq(FileEntity::getName, file.getName())
|
||||
.eq(FileEntity::getIsDeleted, 0)
|
||||
.ne(FileEntity::getId, fileId)
|
||||
);
|
||||
.ne(FileEntity::getId, fileId);
|
||||
|
||||
// targetFolderId 为 null 或 0 → 根目录,统一用 eq(0L)
|
||||
Long actualTarget = (targetFolderId == null || targetFolderId == 0L) ? 0L : targetFolderId;
|
||||
dupWrapper.eq(FileEntity::getFolderId, actualTarget);
|
||||
|
||||
FileEntity existing = fileMapper.selectOne(dupWrapper);
|
||||
if (existing != null) {
|
||||
throw new RuntimeException("目标位置已存在同名文件");
|
||||
}
|
||||
|
||||
file.setFolderId(targetFolderId);
|
||||
// 使用直接更新确保 null 值也能被设置
|
||||
// 使用直接更新,folderId=0 表示根目录,null 表示"我的文档"原始状态(已在 moveToTrash 时处理)
|
||||
fileMapper.update(null,
|
||||
new LambdaUpdateWrapper<FileEntity>()
|
||||
.eq(FileEntity::getId, fileId)
|
||||
@@ -700,9 +765,13 @@ public class FileService {
|
||||
private List<FileEntity> buildFolderTree(List<FileEntity> allFolders, Long parentId, List<Long> excludeIds) {
|
||||
List<FileEntity> tree = new ArrayList<>();
|
||||
for (FileEntity folder : allFolders) {
|
||||
// 匹配父级关系
|
||||
boolean isChildOfParent = (parentId == null && folder.getFolderId() == null)
|
||||
|| (parentId != null && parentId.equals(folder.getFolderId()));
|
||||
// 匹配父级关系:parentId == null 或 0 都视为根目录,匹配 folderId == 0 的文件夹
|
||||
boolean isChildOfParent;
|
||||
if (parentId == null || parentId == 0L) {
|
||||
isChildOfParent = (folder.getFolderId() != null && folder.getFolderId() == 0L);
|
||||
} else {
|
||||
isChildOfParent = parentId.equals(folder.getFolderId());
|
||||
}
|
||||
|
||||
if (isChildOfParent) {
|
||||
// 递归构建子文件夹
|
||||
|
||||
@@ -50,7 +50,7 @@ const visible = computed({
|
||||
set: (val) => emit('update:modelValue', val)
|
||||
})
|
||||
|
||||
const targetFolderId = ref(null)
|
||||
const targetFolderId = ref(0)
|
||||
|
||||
// 树形配置
|
||||
const treeProps = {
|
||||
@@ -64,7 +64,7 @@ const folderTreeData = computed(() => {
|
||||
// 根节点
|
||||
const rootNodes = [
|
||||
{
|
||||
id: 'root',
|
||||
id: 0,
|
||||
name: '根目录',
|
||||
children: []
|
||||
}
|
||||
@@ -90,20 +90,21 @@ const folderTreeData = computed(() => {
|
||||
})
|
||||
|
||||
const handleConfirm = () => {
|
||||
// targetFolderId = 0 表示根目录,null 表示未选择
|
||||
emit('confirm', targetFolderId.value)
|
||||
visible.value = false
|
||||
targetFolderId.value = null
|
||||
targetFolderId.value = 0
|
||||
}
|
||||
|
||||
const open = () => {
|
||||
targetFolderId.value = null
|
||||
targetFolderId.value = 0
|
||||
visible.value = true
|
||||
}
|
||||
|
||||
// 重置选中状态
|
||||
watch(visible, (val) => {
|
||||
if (!val) {
|
||||
targetFolderId.value = null
|
||||
targetFolderId.value = 0
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
@@ -623,14 +623,8 @@ const handleBatchMove = async () => {
|
||||
}
|
||||
|
||||
const handleConfirmBatchMove = async (targetFolderId) => {
|
||||
// Handle target folder ID
|
||||
let finalFolderId = null
|
||||
|
||||
if (targetFolderId === 'root' || targetFolderId === '' || targetFolderId === null || targetFolderId === undefined) {
|
||||
finalFolderId = null
|
||||
} else {
|
||||
finalFolderId = targetFolderId
|
||||
}
|
||||
// targetFolderId = 0 表示根目录,null 表示未选择(此时用 0 作为默认值)
|
||||
let finalFolderId = (targetFolderId === null || targetFolderId === undefined) ? 0 : targetFolderId
|
||||
|
||||
let successCount = 0
|
||||
let failCount = 0
|
||||
|
||||
Reference in New Issue
Block a user