collect-system/apps/web/src/app/admin/sharecode/sharecodegenerator.tsx

198 lines
6.7 KiB
TypeScript
Executable File
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import React, { useEffect, useState } from 'react';
import { Button, DatePicker, Form, message, Select } from 'antd';
import { CopyOutlined } from '@ant-design/icons';
import { useQueryClient } from '@tanstack/react-query';
import { getQueryKey } from '@trpc/react-query';
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 {
fileId: string;
onSuccess?: (code: string) => void;
fileName?: string;
}
export function copyToClipboard(text) {
if (navigator.clipboard) {
return navigator.clipboard.writeText(text);
} else {
const textarea = document.createElement('textarea');
textarea.value = text;
document.body.appendChild(textarea);
textarea.select();
document.execCommand('copy');
document.body.removeChild(textarea);
return Promise.resolve();
}
}
export const ShareCodeGenerator: React.FC<ShareCodeGeneratorProps> = ({
fileId,
fileName,
}) => {
const [loading, setLoading] = useState(false);
const [shareCode, setShareCode] = useState<string>('');
const [expiresAt, setExpiresAt] = useState<string | null>(null);
const [canUseTimes, setCanUseTimes] = useState<number>(null);
const queryClient = useQueryClient();
const queryKey = getQueryKey(api.shareCode);
const [isGenerate, setIsGenerate] = useState(false);
const [currentFileId, setCurrentFileId] = useState<string>('');
const [form] = Form.useForm();
const { saveCodeRecord } = useQuickFileContext();
const generateShareCode = api.shareCode.generateShareCodeByFileId.useMutation({
onSuccess: (data) => {
queryClient.invalidateQueries({ queryKey });
},
});
useEffect(() => {
if (fileId !== currentFileId || !fileId) {
setIsGenerate(false);
}
setCurrentFileId(fileId);
}, [fileId])
const generateCode = async () => {
if (!fileId) {
message.error('请先上传文件');
return;
}
setLoading(true);
console.log('开始生成分享码fileId:', fileId, 'fileName:', fileName);
try {
const data: ShareCodeResponse = await generateShareCode.mutateAsync({
fileId,
expiresAt: form.getFieldsValue()?.expiresAt ? form.getFieldsValue().expiresAt.tz('Asia/Shanghai').toDate() : dayjs().add(1, 'day').tz('Asia/Shanghai').toDate(),
canUseTimes: form.getFieldsValue()?.canUseTimes ? form.getFieldsValue().canUseTimes : 10,
});
console.log('data', data)
setShareCode(data.code);
setIsGenerate(true);
setExpiresAt(dayjs(data.expiresAt).format('YYYY-MM-DD HH:mm:ss'));
setCanUseTimes(data.canUseTimes);
saveCodeRecord(data,'shareCodeGeneratorRecords');
message.success('分享码生成成功'+data.code);
} catch (error) {
console.error('生成分享码错误:', error);
message.error('生成分享码失败: ' + (error instanceof Error ? error.message : '未知错误'));
} finally {
setLoading(false);
}
};
const handleCopy = (code) => {
copyToClipboard(code)
.then(() => console.log('复制成功'))
.catch(() => console.error('复制失败'));
};
useEffect(() => {
const date = dayjs().add(1, 'day').tz('Asia/Shanghai');
form.setFieldsValue({
expiresAt: date,
canUseTimes: 10
});
}, [form]);
useEffect(() => {
if (fileId) {
generateCode()
}
}, [fileId])
return (
<div style={{ padding: '20px', backgroundColor: '#f8f9fa', borderRadius: '8px' }}>
<div style={{ marginBottom: '3px' }}>
<small style={{ color: '#666' }}>ID: {fileId ? fileId : '暂未上传文件'}</small>
</div>
{!isGenerate ? (
<>
<Form form={form}>
<div className='w-4/5 h-16 flex flex-row justify-between items-center'>
<small style={{ color: '#666' }}>
{"分享码的有效期"}
</small>
<Form.Item name="expiresAt" className='mt-5'>
<DatePicker
showTime
disabledDate={(current) => current && current < dayjs().startOf('day')}
disabledTime={(current) => {
if (current && current.isSame(dayjs(), 'day')) {
return {
disabledHours: () => [...Array(dayjs().hour() + 1).keys()],
disabledMinutes: (selectedHour) => {
if (selectedHour === dayjs().hour()) {
return [...Array(dayjs().minute() + 1).keys()];
}
return [];
}
};
}
return {};
}}
/>
</Form.Item>
<small style={{ color: '#666' }}>
{"分享码的使用次数"}
</small>
<Form.Item name="canUseTimes" className='mt-5'>
<Select
style={{ width: 120 }}
//onChange={handleChange}
options={[
{ value: 10, label: '10' },
{ value: 20, label: '20' },
{ value: 30, label: '30' },
{ value: 40, label: '40' },
{ value: 50, label: '50' },
]}
/>
</Form.Item>
</div>
</Form>
</>
) : (
<div style={{ textAlign: 'center' }}>
<div style={{
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
gap: '12px',
margin: '16px 0'
}}>
<span style={{
fontSize: '24px',
fontWeight: 'bold',
letterSpacing: '2px',
color: '#1890ff',
padding: '8px 16px',
backgroundColor: '#e6f7ff',
borderRadius: '4px'
}}>
{shareCode}
</span>
<Button
icon={<CopyOutlined />}
onClick={() => {
handleCopy(shareCode)
//navigator.clipboard.writeText(shareCode);
message.success('分享码已复制');
}}
/>
</div>
{isGenerate && expiresAt ? (
<div style={{ color: '#666' }}>
: {expiresAt} 使: {canUseTimes}
</div>
) : (
<div style={{ color: 'red' }}>
</div>
)}
</div>
)}
</div>
);
};