diff --git a/apps/server/src/models/share-code/share-code.router.ts b/apps/server/src/models/share-code/share-code.router.ts index ac82db8..1924d2d 100644 --- a/apps/server/src/models/share-code/share-code.router.ts +++ b/apps/server/src/models/share-code/share-code.router.ts @@ -62,5 +62,9 @@ export class ShareCodeRouter { .query(async ({ input }) => { return this.shareCodeService.findShareCodes(input); }), + getAllreadlyDeletedShareCodes:this.trpc.procedure + .query(async () => { + return this.shareCodeService.getAllreadlyDeletedShareCodes(); + }) }); } \ No newline at end of file diff --git a/apps/server/src/models/share-code/share-code.service.ts b/apps/server/src/models/share-code/share-code.service.ts index 660f184..e8b4fd0 100755 --- a/apps/server/src/models/share-code/share-code.service.ts +++ b/apps/server/src/models/share-code/share-code.service.ts @@ -106,24 +106,45 @@ export class ShareCodeService extends BaseService { throw new NotFoundException('文件不存在'); } const { filename, filetype, size } = resource.meta as any as ResourceMeta - // 生成分享码 - const code = this.generateCode(); - // 查找是否已有分享码记录 - const existingShareCode = await super.findUnique({ - where: { fileId }, - }); + // 生成分享码(修改的逻辑保证分享码的唯一性) + let code = this.generateCode(); + let existingShareCode; + do { + // 查找是否已有相同 shareCode 或者相同 FileID 的分享码记录 + existingShareCode = await super.findFirst({ + where: { + OR: [ + { code }, + { fileId } + ] + }, + }); + // 如果找到的是已经被删除的码,则可以使用并更新其他信息,否则重新生成 + if(!existingShareCode){ + break + } + if (existingShareCode.deleteAt !== null) { + break + } + if (existingShareCode && existingShareCode.code === code) { + code = this.generateCode(); + } + } while (existingShareCode && existingShareCode.code === code); if (existingShareCode) { // 更新现有记录,但保留原有文件名 await super.update({ - where: { fileId }, + where: { id: existingShareCode.id }, data: { code, expiresAt, canUseTimes, isUsed: false, + fileId, fileName: filename || "downloaded_file", uploadIp, + createdAt: new Date(), + deletedAt: null }, }); } else { @@ -218,24 +239,25 @@ export class ShareCodeService extends BaseService { } }) this.logger.log('需要清理的分享码:', shareCodes); + //文件资源硬删除 shareCodes.forEach(code => { this.cleanupUploadFolder(code.fileId); }) - const result = await super.deleteMany({ + //数据库资源软删除 + const result = await super.softDeleteByIds( + [...shareCodes.map(code => code.id)] + ); + const deleteResource = await this.resourceService.updateMany({ where: { fileId: { in: shareCodes.map(code => code.fileId) } }, - }); - const deleteResource = await this.resourceService.deleteMany({ - where: { - fileId: { - in: shareCodes.map(code => code.fileId) - } + data: { + deletedAt: new Date() } }) - this.logger.log(`Cleaned up ${result.count} ${deleteResource.count} expired share codes`); + this.logger.log(`Cleaned up ${result} ${deleteResource.count} expired share codes`); } catch (error) { this.logger.error('Failed to cleanup expired share codes', error); } @@ -384,38 +406,7 @@ export class ShareCodeService extends BaseService { }, select: { ...ShareCodeSelect } }); - - // 计算总大小和资源数量 - let totalSize = 0; - let resourceCount = 0; - - shareCodes.forEach(shareCode => { - - if ((shareCode as any as GenerateShareCodeResponse).resource && (shareCode as any as GenerateShareCodeResponse).resource.meta) { - const meta = (shareCode as any as GenerateShareCodeResponse).resource.meta as any; - if (meta.size) { - // 如果size是字符串格式(如 "1024"或"1 MB"),需要转换 - let sizeValue: number; - if (typeof meta.size === 'string') { - // 尝试直接解析数字 - sizeValue = parseInt(meta.size, 10); - // 如果解析失败,可能需要更复杂的处理 - if (isNaN(sizeValue)) { - // 简单处理,实际应用中可能需要更复杂的单位转换 - this.logger.warn(`无法解析资源大小: ${meta.size}`); - sizeValue = 0; - } - } else if (typeof meta.size === 'number') { - sizeValue = meta.size; - } else { - sizeValue = 0; - } - - totalSize += sizeValue; - resourceCount++; - } - } - }); + const {totalSize, resourceCount} = this.calculateTotalSize(shareCodes as any as GenerateShareCodeResponse[]); this.logger.log(`资源总大小: ${totalSize}, 资源数量: ${resourceCount}`); return { totalSize, resourceCount }; @@ -458,38 +449,7 @@ export class ShareCodeService extends BaseService { ...ShareCodeSelect } }); - - // 计算总大小和资源数量 - let totalSize = 0; - let resourceCount = 0; - - shareCodes.forEach(shareCode => { - if ((shareCode as any as GenerateShareCodeResponse).resource && (shareCode as any as GenerateShareCodeResponse).resource.meta) { - const meta = (shareCode as any as GenerateShareCodeResponse).resource.meta as any; - if (meta.size) { - // 如果size是字符串格式(如 "1024"或"1 MB"),需要转换 - let sizeValue: number; - if (typeof meta.size === 'string') { - // 尝试直接解析数字 - sizeValue = parseInt(meta.size, 10); - // 如果解析失败,可能需要更复杂的处理 - if (isNaN(sizeValue)) { - // 简单处理,实际应用中可能需要更复杂的单位转换 - this.logger.warn(`无法解析资源大小: ${meta.size}`); - sizeValue = 0; - } - } else if (typeof meta.size === 'number') { - sizeValue = meta.size; - } else { - sizeValue = 0; - } - - totalSize += sizeValue; - resourceCount++; - } - } - }); - + const {totalSize, resourceCount} = this.calculateTotalSize(shareCodes as any as GenerateShareCodeResponse[]); this.logger.log(`${dateType}资源总大小: ${totalSize}, 资源数量: ${resourceCount}`); return { totalSize, resourceCount }; } catch (error) { @@ -576,7 +536,7 @@ export class ShareCodeService extends BaseService { throw error; } } - + /** * 获取分享码列表,使用ShareCodeSelect并按创建时间倒序排序 * @param args 查询参数 @@ -595,4 +555,56 @@ export class ShareCodeService extends BaseService { throw error; } } + async getAllreadlyDeletedShareCodes(args?: Omit):Promise<{ totalSize: number; resourceCount: number; }> { + try { + const result = await super.findMany({ + ...args, + where: { + deletedAt: { + not: null + } + }, + select: ShareCodeSelect, + }); + // 计算总大小和资源数量 + const { totalSize, resourceCount } = this.calculateTotalSize(result as unknown as GenerateShareCodeResponse[]); + this.logger.log(`获取已删除分享码列表成功, 数量: ${resourceCount}, 总大小: ${totalSize}`); + return {totalSize,resourceCount} + } catch (err) { + this.logger.error('获取已删除分享码列表失败', err) + throw err + } + + } + calculateTotalSize(shareCodes: GenerateShareCodeResponse[]): { totalSize: number; resourceCount: number } { + let totalSize = 0; + let resourceCount = 0; + shareCodes.forEach(shareCode => { + if ((shareCode as any as GenerateShareCodeResponse).resource && (shareCode as any as GenerateShareCodeResponse).resource.meta) { + const meta = (shareCode as any as GenerateShareCodeResponse).resource.meta as any; + if (meta.size) { + // 如果size是字符串格式(如 "1024"或"1 MB"),需要转换 + let sizeValue: number; + if (typeof meta.size === 'string') { + // 尝试直接解析数字 + sizeValue = parseInt(meta.size, 10); + // 如果解析失败,可能需要更复杂的处理 + if (isNaN(sizeValue)) { + // 简单处理,实际应用中可能需要更复杂的单位转换 + this.logger.warn(`无法解析资源大小: ${meta.size}`); + sizeValue = 0; + } + } else if (typeof meta.size === 'number') { + sizeValue = meta.size; + } else { + sizeValue = 0; + } + + totalSize += sizeValue; + resourceCount++; + } + } + }) + return { totalSize, resourceCount } + } } diff --git a/apps/web/src/app/admin/dashboard/DashboardContext.tsx b/apps/web/src/app/admin/dashboard/DashboardContext.tsx index 81899be..f76ece3 100644 --- a/apps/web/src/app/admin/dashboard/DashboardContext.tsx +++ b/apps/web/src/app/admin/dashboard/DashboardContext.tsx @@ -12,6 +12,8 @@ interface DashboardContextType { isDistinctUploadIPsLoading: boolean; shareCodeList: ShareCodeResponse[]; isShareCodeListLoading: boolean; + deletedData: { totalSize?: number; resourceCount?: number; }; + isDeletedLoading: boolean; } interface ShareCodeResourcesSizeByDateRange { totalSize: number; @@ -45,6 +47,7 @@ export const DashboardProvider = ({ children }: { children: React.ReactNode }) = createdAt: 'desc', }, }) + const {data:deletedData , isLoading:isDeletedLoading} = api.shareCode.getAllreadlyDeletedShareCodes.useQuery() return <> {children} diff --git a/apps/web/src/app/admin/dashboard/components/Board.tsx b/apps/web/src/app/admin/dashboard/components/Board.tsx index 0a2e39f..10e3178 100644 --- a/apps/web/src/app/admin/dashboard/components/Board.tsx +++ b/apps/web/src/app/admin/dashboard/components/Board.tsx @@ -7,13 +7,13 @@ const { Title, Text } = Typography; export default function Board() { const { shareCodeAll, shareCodeToday, shareCodeYesterday, isShareCodeAllLoading, isShareCodeTodayLoading, isShareCodeYesterdayLoading, - distinctUploadIPs, isDistinctUploadIPsLoading } = useDashboardContext(); + distinctUploadIPs, isDistinctUploadIPsLoading,deletedData,isDeletedLoading } = useDashboardContext(); const [serverUptime, setServerUptime] = useState(''); useEffect(() => { const calculateTimeDifference = () => { const now = new Date(); const targetDate = new Date('2025-04-09T15:00:00'); - const diffMs = now.getTime()- targetDate.getTime(); + const diffMs = now.getTime() - targetDate.getTime(); // 如果是负数,表示目标日期已过 if (diffMs < 0) { @@ -133,6 +133,25 @@ export default function Board() { + {/* 删除状态卡片 */} + {/* + + + 已清理文件数 + + } + className="h-full" + > +
+ +
+ 已经清理文件大小: {isDeletedLoading? 0 : `${(deletedData.totalSize / 1024 / 1024 / 1024).toFixed(2)}GB`} +
+
+
+ */} } \ No newline at end of file