feat(douyu): 二维码弹窗增加复制二维码/复制链接按钮
- 新增 QrActions 组件:复制二维码图片、复制二维码链接(含 execCommand 降级) - 精英宝典绑定/电竞手册/支付三个弹窗统一功能按钮在上、操作按钮在下
This commit is contained in:
@@ -0,0 +1,86 @@
|
||||
import { useState } from 'react';
|
||||
import type { RefObject } from 'react';
|
||||
import { Button, Space } from 'antd';
|
||||
import { CopyOutlined, LinkOutlined } from '@ant-design/icons';
|
||||
import { copyImageToClipboard } from '../utils/exchangeImage';
|
||||
import { getErrorMessage } from '../utils/error';
|
||||
import { message } from '../utils/antdMessage';
|
||||
|
||||
interface Props {
|
||||
wrapRef: RefObject<HTMLDivElement | null>;
|
||||
url?: string;
|
||||
disabled?: boolean;
|
||||
}
|
||||
|
||||
function copyTextToClipboard(text: string): Promise<void> {
|
||||
if (navigator.clipboard?.writeText) {
|
||||
return navigator.clipboard.writeText(text);
|
||||
}
|
||||
// fallback:利用 textarea + execCommand,兼容 http 远程访问
|
||||
return new Promise((resolve, reject) => {
|
||||
const ta = document.createElement('textarea');
|
||||
ta.value = text;
|
||||
ta.style.position = 'fixed';
|
||||
ta.style.left = '-9999px';
|
||||
document.body.appendChild(ta);
|
||||
ta.select();
|
||||
try {
|
||||
const ok = document.execCommand('copy');
|
||||
document.body.removeChild(ta);
|
||||
if (ok) {
|
||||
resolve();
|
||||
} else {
|
||||
reject(new Error('execCommand copy failed'));
|
||||
}
|
||||
} catch (e) {
|
||||
document.body.removeChild(ta);
|
||||
reject(e);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
export default function QrActions({ wrapRef, url, disabled }: Props) {
|
||||
const [copyingImage, setCopyingImage] = useState(false);
|
||||
const [copyingLink, setCopyingLink] = useState(false);
|
||||
|
||||
const copyImage = async () => {
|
||||
const canvas = wrapRef.current?.querySelector('canvas');
|
||||
if (!canvas) return;
|
||||
setCopyingImage(true);
|
||||
try {
|
||||
const blob = await new Promise<Blob>((resolve, reject) => {
|
||||
canvas.toBlob((b) => (b ? resolve(b) : reject(new Error('二维码图片导出失败'))), 'image/png');
|
||||
});
|
||||
await copyImageToClipboard(blob);
|
||||
message.success('二维码已复制到剪贴板');
|
||||
} catch (error) {
|
||||
message.error(getErrorMessage(error));
|
||||
} finally {
|
||||
setCopyingImage(false);
|
||||
}
|
||||
};
|
||||
|
||||
const copyLink = async () => {
|
||||
if (!url) return;
|
||||
setCopyingLink(true);
|
||||
try {
|
||||
await copyTextToClipboard(url);
|
||||
message.success('二维码链接已复制');
|
||||
} catch (error) {
|
||||
message.error(getErrorMessage(error));
|
||||
} finally {
|
||||
setCopyingLink(false);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<Space size={8}>
|
||||
<Button size="small" icon={<CopyOutlined />} loading={copyingImage} disabled={disabled} onClick={copyImage}>
|
||||
复制二维码
|
||||
</Button>
|
||||
<Button size="small" icon={<LinkOutlined />} loading={copyingLink} disabled={disabled || !url} onClick={copyLink}>
|
||||
复制链接
|
||||
</Button>
|
||||
</Space>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user