Merge branch 'main' of http://113.45.67.59:3003/raohaotian/quick-file
This commit is contained in:
commit
348c6780ff
|
@ -62,5 +62,9 @@ export class ShareCodeRouter {
|
||||||
.query(async ({ input }) => {
|
.query(async ({ input }) => {
|
||||||
return this.shareCodeService.findShareCodes(input);
|
return this.shareCodeService.findShareCodes(input);
|
||||||
}),
|
}),
|
||||||
|
getAllreadlyDeletedShareCodes:this.trpc.procedure
|
||||||
|
.query(async () => {
|
||||||
|
return this.shareCodeService.getAllreadlyDeletedShareCodes();
|
||||||
|
})
|
||||||
});
|
});
|
||||||
}
|
}
|
|
@ -106,24 +106,45 @@ export class ShareCodeService extends BaseService<Prisma.ShareCodeDelegate> {
|
||||||
throw new NotFoundException('文件不存在');
|
throw new NotFoundException('文件不存在');
|
||||||
}
|
}
|
||||||
const { filename, filetype, size } = resource.meta as any as ResourceMeta
|
const { filename, filetype, size } = resource.meta as any as ResourceMeta
|
||||||
// 生成分享码
|
// 生成分享码(修改的逻辑保证分享码的唯一性)
|
||||||
const code = this.generateCode();
|
let code = this.generateCode();
|
||||||
// 查找是否已有分享码记录
|
let existingShareCode;
|
||||||
const existingShareCode = await super.findUnique({
|
do {
|
||||||
where: { fileId },
|
// 查找是否已有相同 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) {
|
if (existingShareCode) {
|
||||||
// 更新现有记录,但保留原有文件名
|
// 更新现有记录,但保留原有文件名
|
||||||
await super.update({
|
await super.update({
|
||||||
where: { fileId },
|
where: { id: existingShareCode.id },
|
||||||
data: {
|
data: {
|
||||||
code,
|
code,
|
||||||
expiresAt,
|
expiresAt,
|
||||||
canUseTimes,
|
canUseTimes,
|
||||||
isUsed: false,
|
isUsed: false,
|
||||||
|
fileId,
|
||||||
fileName: filename || "downloaded_file",
|
fileName: filename || "downloaded_file",
|
||||||
uploadIp,
|
uploadIp,
|
||||||
|
createdAt: new Date(),
|
||||||
|
deletedAt: null
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
|
@ -218,24 +239,25 @@ export class ShareCodeService extends BaseService<Prisma.ShareCodeDelegate> {
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
this.logger.log('需要清理的分享码:', shareCodes);
|
this.logger.log('需要清理的分享码:', shareCodes);
|
||||||
|
//文件资源硬删除
|
||||||
shareCodes.forEach(code => {
|
shareCodes.forEach(code => {
|
||||||
this.cleanupUploadFolder(code.fileId);
|
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: {
|
where: {
|
||||||
fileId: {
|
fileId: {
|
||||||
in: shareCodes.map(code => code.fileId)
|
in: shareCodes.map(code => code.fileId)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
});
|
data: {
|
||||||
const deleteResource = await this.resourceService.deleteMany({
|
deletedAt: new Date()
|
||||||
where: {
|
|
||||||
fileId: {
|
|
||||||
in: shareCodes.map(code => code.fileId)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
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) {
|
} catch (error) {
|
||||||
this.logger.error('Failed to cleanup expired share codes', error);
|
this.logger.error('Failed to cleanup expired share codes', error);
|
||||||
}
|
}
|
||||||
|
@ -384,38 +406,7 @@ export class ShareCodeService extends BaseService<Prisma.ShareCodeDelegate> {
|
||||||
},
|
},
|
||||||
select: { ...ShareCodeSelect }
|
select: { ...ShareCodeSelect }
|
||||||
});
|
});
|
||||||
|
const {totalSize, resourceCount} = this.calculateTotalSize(shareCodes as any as GenerateShareCodeResponse[]);
|
||||||
// 计算总大小和资源数量
|
|
||||||
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++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
this.logger.log(`资源总大小: ${totalSize}, 资源数量: ${resourceCount}`);
|
this.logger.log(`资源总大小: ${totalSize}, 资源数量: ${resourceCount}`);
|
||||||
return { totalSize, resourceCount };
|
return { totalSize, resourceCount };
|
||||||
|
@ -458,38 +449,7 @@ export class ShareCodeService extends BaseService<Prisma.ShareCodeDelegate> {
|
||||||
...ShareCodeSelect
|
...ShareCodeSelect
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
const {totalSize, resourceCount} = this.calculateTotalSize(shareCodes as any as GenerateShareCodeResponse[]);
|
||||||
// 计算总大小和资源数量
|
|
||||||
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++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
this.logger.log(`${dateType}资源总大小: ${totalSize}, 资源数量: ${resourceCount}`);
|
this.logger.log(`${dateType}资源总大小: ${totalSize}, 资源数量: ${resourceCount}`);
|
||||||
return { totalSize, resourceCount };
|
return { totalSize, resourceCount };
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
@ -595,4 +555,56 @@ export class ShareCodeService extends BaseService<Prisma.ShareCodeDelegate> {
|
||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
async getAllreadlyDeletedShareCodes(args?: Omit<Prisma.ShareCodeFindManyArgs, 'select' | 'orderBy'>):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 }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,6 +12,8 @@ interface DashboardContextType {
|
||||||
isDistinctUploadIPsLoading: boolean;
|
isDistinctUploadIPsLoading: boolean;
|
||||||
shareCodeList: ShareCodeResponse[];
|
shareCodeList: ShareCodeResponse[];
|
||||||
isShareCodeListLoading: boolean;
|
isShareCodeListLoading: boolean;
|
||||||
|
deletedData: { totalSize?: number; resourceCount?: number; };
|
||||||
|
isDeletedLoading: boolean;
|
||||||
}
|
}
|
||||||
interface ShareCodeResourcesSizeByDateRange {
|
interface ShareCodeResourcesSizeByDateRange {
|
||||||
totalSize: number;
|
totalSize: number;
|
||||||
|
@ -45,6 +47,7 @@ export const DashboardProvider = ({ children }: { children: React.ReactNode }) =
|
||||||
createdAt: 'desc',
|
createdAt: 'desc',
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
const {data:deletedData , isLoading:isDeletedLoading} = api.shareCode.getAllreadlyDeletedShareCodes.useQuery()
|
||||||
return <>
|
return <>
|
||||||
<DashboardContext.Provider value={{
|
<DashboardContext.Provider value={{
|
||||||
shareCodeAll,
|
shareCodeAll,
|
||||||
|
@ -56,7 +59,9 @@ export const DashboardProvider = ({ children }: { children: React.ReactNode }) =
|
||||||
distinctUploadIPs,
|
distinctUploadIPs,
|
||||||
isDistinctUploadIPsLoading,
|
isDistinctUploadIPsLoading,
|
||||||
shareCodeList,
|
shareCodeList,
|
||||||
isShareCodeListLoading
|
isShareCodeListLoading,
|
||||||
|
deletedData,
|
||||||
|
isDeletedLoading
|
||||||
}}>
|
}}>
|
||||||
{children}
|
{children}
|
||||||
</DashboardContext.Provider>
|
</DashboardContext.Provider>
|
||||||
|
|
|
@ -7,13 +7,13 @@ const { Title, Text } = Typography;
|
||||||
export default function Board() {
|
export default function Board() {
|
||||||
const { shareCodeAll, shareCodeToday, shareCodeYesterday,
|
const { shareCodeAll, shareCodeToday, shareCodeYesterday,
|
||||||
isShareCodeAllLoading, isShareCodeTodayLoading, isShareCodeYesterdayLoading,
|
isShareCodeAllLoading, isShareCodeTodayLoading, isShareCodeYesterdayLoading,
|
||||||
distinctUploadIPs, isDistinctUploadIPsLoading } = useDashboardContext();
|
distinctUploadIPs, isDistinctUploadIPsLoading,deletedData,isDeletedLoading } = useDashboardContext();
|
||||||
const [serverUptime, setServerUptime] = useState('');
|
const [serverUptime, setServerUptime] = useState('');
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const calculateTimeDifference = () => {
|
const calculateTimeDifference = () => {
|
||||||
const now = new Date();
|
const now = new Date();
|
||||||
const targetDate = new Date('2025-04-09T15:00:00');
|
const targetDate = new Date('2025-04-09T15:00:00');
|
||||||
const diffMs = now.getTime()- targetDate.getTime();
|
const diffMs = now.getTime() - targetDate.getTime();
|
||||||
|
|
||||||
// 如果是负数,表示目标日期已过
|
// 如果是负数,表示目标日期已过
|
||||||
if (diffMs < 0) {
|
if (diffMs < 0) {
|
||||||
|
@ -133,6 +133,25 @@ export default function Board() {
|
||||||
</div>
|
</div>
|
||||||
</DashboardCard>
|
</DashboardCard>
|
||||||
</Col>
|
</Col>
|
||||||
|
{/* 删除状态卡片 */}
|
||||||
|
{/* <Col xs={24} sm={12} md={6}>
|
||||||
|
<DashboardCard
|
||||||
|
title={
|
||||||
|
<div className="flex items-center">
|
||||||
|
<CheckCircleOutlined style={{ marginRight: 8, fontSize: 16 }} />
|
||||||
|
已清理文件数
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
className="h-full"
|
||||||
|
>
|
||||||
|
<div className="flex flex-col h-full justify-between py-2">
|
||||||
|
<Statistic value={isDeletedLoading ? 0 : `${deletedData.resourceCount}`} />
|
||||||
|
<div className="text-gray-500 text-sm mt-2">
|
||||||
|
已经清理文件大小: {isDeletedLoading? 0 : `${(deletedData.totalSize / 1024 / 1024 / 1024).toFixed(2)}GB`}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</DashboardCard>
|
||||||
|
</Col> */}
|
||||||
</Row>
|
</Row>
|
||||||
</>
|
</>
|
||||||
}
|
}
|
Loading…
Reference in New Issue