From 34dde48aafb5bc7b250eafb491c17f22d518eb04 Mon Sep 17 00:00:00 2001 From: Rao <1227431568@qq.com> Date: Wed, 9 Apr 2025 17:01:21 +0800 Subject: [PATCH] rht --- .../models/share-code/share-code.service.ts | 45 +++++-- .../admin/code-manage/CodeManageContext.tsx | 17 +-- .../code-manage/components/ShareCodeList.tsx | 21 +--- .../components/ShareCodeListCard.tsx | 43 +++++-- apps/web/src/app/admin/quick-file/page.tsx | 101 ++++++---------- .../app/admin/quick-file/quickFileContext.tsx | 111 +++++++++++++++++ .../admin/sharecode/components/CodeRecord.tsx | 88 ++++++++++++++ .../admin/sharecode/sharecodegenerator.tsx | 13 +- .../admin/sharecode/sharecodevalidator.tsx | 112 +++++++++--------- apps/web/src/routes/index.tsx | 7 +- 10 files changed, 375 insertions(+), 183 deletions(-) create mode 100644 apps/web/src/app/admin/quick-file/quickFileContext.tsx create mode 100644 apps/web/src/app/admin/sharecode/components/CodeRecord.tsx 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 33535a5..810c82a 100755 --- a/apps/server/src/models/share-code/share-code.service.ts +++ b/apps/server/src/models/share-code/share-code.service.ts @@ -9,6 +9,7 @@ import dayjs from 'dayjs'; import utc from 'dayjs/plugin/utc'; import timezone from 'dayjs/plugin/timezone'; import { BaseService } from '../base/base.service'; +import { url } from 'inspector'; dayjs.extend(utc); dayjs.extend(timezone); export interface ShareCode { @@ -25,12 +26,19 @@ export interface GenerateShareCodeResponse { code: string; expiresAt: Date; canUseTimes: number; + fileName?: string; + resource: { + id: string; + type: string; + url: string; + meta: ResourceMeta + } } interface ResourceMeta { filename: string; filetype: string; - filesize: string; + size: string; } @Injectable() @@ -44,7 +52,7 @@ export class ShareCodeService extends BaseService { constructor(private readonly resourceService: ResourceService) { super(db, ObjectType.SHARE_CODE, false); - } + } async generateShareCode( fileId: string, @@ -61,7 +69,7 @@ export class ShareCodeService extends BaseService { if (!resource) { throw new NotFoundException('文件不存在'); } - const { filename } = resource.meta as any as ResourceMeta + const { filename, filetype, size } = resource.meta as any as ResourceMeta // 生成分享码 const code = this.generateCode(); // 查找是否已有分享码记录 @@ -78,7 +86,7 @@ export class ShareCodeService extends BaseService { expiresAt, canUseTimes, isUsed: false, - fileName: filename|| "downloaded_file", + fileName: filename || "downloaded_file", }, }); } else { @@ -99,6 +107,17 @@ export class ShareCodeService extends BaseService { code, expiresAt, canUseTimes, + fileName: filename || "downloaded_file", + resource: { + id: resource.id, + type: resource.type, + url: resource.url, + meta: { + filename, + filetype, + size, + } + } }; } catch (error) { this.logger.error('Failed to generate share code', error); @@ -274,7 +293,7 @@ export class ShareCodeService extends BaseService { where: { fileId: shareCode.fileId }, }); this.logger.log('获取到的资源信息:', resource); - const { filename } = resource.meta as any as ResourceMeta + const { filename,filetype,size } = resource.meta as any as ResourceMeta const fileUrl = resource?.url if (!resource) { throw new NotFoundException('文件不存在'); @@ -282,12 +301,19 @@ export class ShareCodeService extends BaseService { // 直接返回正确的数据结构 const response = { - fileId: shareCode.fileId, - fileName: filename || 'downloaded_file', + id:shareCode.id, code: shareCode.code, + fileName: filename || 'downloaded_file', expiresAt: shareCode.expiresAt, - url: fileUrl, canUseTimes: shareCode.canUseTimes - 1, + resource:{ + id:resource.id, + type:resource.type, + url:resource.url, + meta:{ + filename,filetype,size + } + } }; this.logger.log('返回给前端的数据:', response); // 添加日志 @@ -316,11 +342,10 @@ export class ShareCodeService extends BaseService { totalPages: number; }> { try { - console.log('args:', args.where.OR); // 使用include直接关联查询Resource const { items, totalPages } = await super.findManyWithPagination({ ...args, - select:{ + select: { id: true, code: true, fileId: true, diff --git a/apps/web/src/app/admin/code-manage/CodeManageContext.tsx b/apps/web/src/app/admin/code-manage/CodeManageContext.tsx index 260a924..2ebadcb 100644 --- a/apps/web/src/app/admin/code-manage/CodeManageContext.tsx +++ b/apps/web/src/app/admin/code-manage/CodeManageContext.tsx @@ -3,6 +3,7 @@ import { api } from "@nice/client"; import { createContext, useContext, useState } from "react"; import { useQueryClient } from "@tanstack/react-query"; import { getQueryKey } from "@trpc/react-query"; +import { ShareCodeResponse } from "../quick-file/quickFileContext"; interface CodeManageContextType { editForm: FormInstance; @@ -22,21 +23,7 @@ interface CodeManageContextType { } interface ShareCodeWithResource { - items: { - id: string; - code: string; - fileName: string; - fileSize: number; - expiresAt: string; - createdAt: string; - canUseTimes: number; - resource: { - id: string; - type: string; - url: string; - meta: any; - } - }[], + items: ShareCodeResponse[], totalPages: number } diff --git a/apps/web/src/app/admin/code-manage/components/ShareCodeList.tsx b/apps/web/src/app/admin/code-manage/components/ShareCodeList.tsx index 50d315b..6f92693 100644 --- a/apps/web/src/app/admin/code-manage/components/ShareCodeList.tsx +++ b/apps/web/src/app/admin/code-manage/components/ShareCodeList.tsx @@ -4,29 +4,14 @@ import dayjs from 'dayjs'; import utc from 'dayjs/plugin/utc'; import timezone from 'dayjs/plugin/timezone'; import ShareCodeListCard from './ShareCodeListCard'; +import { ShareCodeResponse } from '../../quick-file/quickFileContext'; dayjs.extend(utc); dayjs.extend(timezone); -export interface ShareCodeItem { - id: string; - code: string; - expiresAt: string; - fileName: string; - canUseTimes: number; - resource: { - id: string; - type: string; - url: string; - meta: { - size: number; - filename: string; - }; - } -} interface ShareCodeListProps { - data: ShareCodeItem[]; + data: ShareCodeResponse[]; loading?: boolean; onEdit?: (id: string,expiresAt:Date,canUseTimes:number,code:string) => void; onDelete?: (id: string) => void; @@ -46,7 +31,7 @@ const ShareCodeList: React.FC = ({ loading={loading} renderItem={(item) => ( - + )} /> diff --git a/apps/web/src/app/admin/code-manage/components/ShareCodeListCard.tsx b/apps/web/src/app/admin/code-manage/components/ShareCodeListCard.tsx index bddad1c..59c9d84 100644 --- a/apps/web/src/app/admin/code-manage/components/ShareCodeListCard.tsx +++ b/apps/web/src/app/admin/code-manage/components/ShareCodeListCard.tsx @@ -1,14 +1,21 @@ -import { DeleteOutlined, EditOutlined } from "@ant-design/icons"; +import { DeleteOutlined, DownloadOutlined, EditOutlined } from "@ant-design/icons"; import { Button, Card, Typography } from "antd"; import dayjs from "dayjs"; -import { ShareCodeItem } from "./ShareCodeList"; import { useEffect } from "react"; +import { ShareCodeResponse } from "../../quick-file/quickFileContext"; -export default function ShareCodeListCard({ item, onEdit, onDelete }: { item: ShareCodeItem, onEdit: (id: string,expiresAt:Date,canUseTimes:number,code:string) => void, onDelete: (id: string) => void }) { +export default function ShareCodeListCard({ item, onEdit, onDelete, styles, onDownload }: + { + item: ShareCodeResponse, + styles?: string, + onDelete: (id: string) => void, + onEdit?: (id: string, expiresAt: Date, canUseTimes: number, code: string) => void, + onDownload?: (id: string) => void + }) { useEffect(() => { console.log('item:', item); }, [item]); - return
+ return
} - onClick={() => onEdit?.(item.id,dayjs(item.expiresAt).toDate(),item.canUseTimes,item.code)} - className="text-blue-500 hover:text-blue-700" - />, + onEdit && ( + + + {records.length > 0 ? ( +
+ {records.map(item => ( + + ))} +
+ ) : ( + + )} +
+ + ); +} \ No newline at end of file diff --git a/apps/web/src/app/admin/sharecode/sharecodegenerator.tsx b/apps/web/src/app/admin/sharecode/sharecodegenerator.tsx index 8dd6892..65a214d 100755 --- a/apps/web/src/app/admin/sharecode/sharecodegenerator.tsx +++ b/apps/web/src/app/admin/sharecode/sharecodegenerator.tsx @@ -7,6 +7,7 @@ import { api } from '@nice/client'; import dayjs from 'dayjs'; import utc from 'dayjs/plugin/utc'; import timezone from 'dayjs/plugin/timezone'; +import { ShareCodeResponse, useQuickFileContext } from '../quick-file/quickFileContext'; dayjs.extend(utc); dayjs.extend(timezone); interface ShareCodeGeneratorProps { @@ -14,11 +15,7 @@ interface ShareCodeGeneratorProps { onSuccess?: (code: string) => void; fileName?: string; } -interface ShareCodeResponse { - code?: string; - expiresAt?: Date; - canUseTimes?: number; -} + export function copyToClipboard(text) { if (navigator.clipboard) { @@ -35,7 +32,6 @@ export function copyToClipboard(text) { } export const ShareCodeGenerator: React.FC = ({ fileId, - onSuccess, fileName, }) => { const [loading, setLoading] = useState(false); @@ -47,6 +43,7 @@ export const ShareCodeGenerator: React.FC = ({ const [isGenerate, setIsGenerate] = useState(false); const [currentFileId, setCurrentFileId] = useState(''); const [form] = Form.useForm(); + const { saveCodeRecord } = useQuickFileContext(); const generateShareCode = api.shareCode.generateShareCodeByFileId.useMutation({ onSuccess: (data) => { queryClient.invalidateQueries({ queryKey }); @@ -74,10 +71,10 @@ export const ShareCodeGenerator: React.FC = ({ console.log('data', data) setShareCode(data.code); setIsGenerate(true); - onSuccess?.(data.code); setExpiresAt(dayjs(data.expiresAt).format('YYYY-MM-DD HH:mm:ss')); setCanUseTimes(data.canUseTimes); - //message.success('分享码生成成功'); + saveCodeRecord(data,'shareCodeGeneratorRecords'); + message.success('分享码生成成功'+data.code); } catch (error) { console.error('生成分享码错误:', error); message.error('生成分享码失败: ' + (error instanceof Error ? error.message : '未知错误')); diff --git a/apps/web/src/app/admin/sharecode/sharecodevalidator.tsx b/apps/web/src/app/admin/sharecode/sharecodevalidator.tsx index ca160ac..7c11c57 100755 --- a/apps/web/src/app/admin/sharecode/sharecodevalidator.tsx +++ b/apps/web/src/app/admin/sharecode/sharecodevalidator.tsx @@ -1,50 +1,42 @@ import React, { useCallback, useEffect, useState } from 'react'; -import { Input, Button, message } from 'antd'; +import { Input, Button, message, Spin } from 'antd'; import styles from './ShareCodeValidator.module.css'; import { api } from '@nice/client'; import dayjs from 'dayjs'; -interface ShareCodeValidatorProps { - onValidSuccess: (fileId: string, fileName: string) => void; -} import utc from 'dayjs/plugin/utc'; import timezone from 'dayjs/plugin/timezone'; import { env } from '@web/src/env'; import { copyToClipboard } from './sharecodegenerator'; +import { ShareCodeResponse, useQuickFileContext } from '../quick-file/quickFileContext'; dayjs.extend(utc); dayjs.extend(timezone); -export const ShareCodeValidator: React.FC = ({ - onValidSuccess, -}) => { - const [code, setCode] = useState(''); - const { data: result, isLoading, refetch } = api.shareCode.getFileByShareCode.useQuery( - { code: code.trim() }, - { - enabled: false - } - ) +export const ShareCodeValidator: React.FC = ({ }) => { + const { saveCodeRecord,handleValidSuccess,isGetingFileId,downloadCode,setDownloadCode,refetchShareCodeWithResource,isLoading,downloadResult } = useQuickFileContext(); + const validateCode = useCallback(async () => { - if (!code.trim()) { + if (!downloadCode?.trim()) { message.warning('请输入正确的分享码'); return; } try { - const { data: latestResult } = await refetch(); + const { data: latestResult } = await refetchShareCodeWithResource(); console.log('验证分享码返回数据:', latestResult); - onValidSuccess(latestResult.url, latestResult.fileName); + saveCodeRecord(latestResult as any as ShareCodeResponse,'shareCodeDownloadRecords') + handleValidSuccess(latestResult.resource.url, latestResult.fileName); } catch (error) { console.error('验证分享码失败:', error); message.error('分享码无效或已过期'); } - }, [refetch, code, onValidSuccess]); + }, [refetchShareCodeWithResource, downloadCode, handleValidSuccess]); const getDownloadUrl = useCallback(async () => { try { - const { data: latestResult } = await refetch(); + const { data: latestResult } = await refetchShareCodeWithResource(); console.log('验证分享码返回数据:', latestResult); - const downloadUrl = `http://${env.SERVER_IP}:${env.FILE_PORT}/uploads/${latestResult.url}`; + const downloadUrl = `http://${env.SERVER_IP}:${env.FILE_PORT}/uploads/${latestResult.resource.url}`; copyToClipboard(downloadUrl) .then(() => { - message.success(`${latestResult.fileName}的下载链接已复制`,6) + message.success(`${latestResult.fileName}的下载链接已复制`, 6) }) .catch(() => { message.error('复制失败') @@ -53,44 +45,52 @@ export const ShareCodeValidator: React.FC = ({ console.error('验证分享码失败:', error); message.error('分享码无效或已过期'); } - }, [refetch, code, onValidSuccess]); + }, [refetchShareCodeWithResource, downloadCode, handleValidSuccess]); return ( <> -
- setCode(e.target.value.toUpperCase())} - placeholder="请输入分享码" - maxLength={8} - onPressEnter={validateCode} - /> - - -
{ - !isLoading && result && ( -
- {`分享码:${result?.code ? result.code : ''}`} - {`文件名:${result?.fileName ? result.fileName : ''}`} - {`过期时间:${result?.expiresAt ? dayjs(result.expiresAt).format('YYYY-MM-DD HH:mm:ss') : ''}`} - {`剩余使用次数:${result?.canUseTimes ? result.canUseTimes : ''}`} -
- ) + isGetingFileId ? + () : + ( + <> +
+ setDownloadCode(e.target.value.toUpperCase())} + placeholder="请输入分享码" + maxLength={8} + onPressEnter={validateCode} + /> + + +
+ { + !isLoading && downloadResult && ( +
+ {`分享码:${downloadResult?.code ? downloadResult.code : ''}`} + {`文件名:${downloadResult?.fileName ? downloadResult.fileName : ''}`} + {`过期时间:${downloadResult?.expiresAt ? dayjs(downloadResult.expiresAt).format('YYYY-MM-DD HH:mm:ss') : ''}`} + {`剩余使用次数:${downloadResult?.canUseTimes ? downloadResult.canUseTimes : ''}`} +
+ ) + } + + ) } ); diff --git a/apps/web/src/routes/index.tsx b/apps/web/src/routes/index.tsx index dfd76bb..83176a4 100755 --- a/apps/web/src/routes/index.tsx +++ b/apps/web/src/routes/index.tsx @@ -11,6 +11,7 @@ import WithAuth from "../components/utils/with-auth"; import { CodeManageProvider } from "../app/admin/code-manage/CodeManageContext"; import CodeManageLayout from "../app/admin/code-manage/CodeManageLayout"; import QuickUploadPage from "../app/admin/quick-file/page"; +import { QuickFileProvider } from "../app/admin/quick-file/quickFileContext"; interface CustomIndexRouteObject extends IndexRouteObject { name?: string; breadcrumb?: string; @@ -34,7 +35,11 @@ export type CustomRouteObject = export const routes: CustomRouteObject[] = [ { path: "/", - element: , + element: <> + + + + , errorElement: , }, {