修改复制的问题
This commit is contained in:
@@ -1,6 +1,7 @@
|
|||||||
import React, { useEffect, useMemo, useState } from 'react';
|
import React, { useEffect, useMemo, useState } from 'react';
|
||||||
import { Alert, Button, Empty, Image, Space, Typography, message } from 'antd';
|
import { Alert, Button, Empty, Image, Space, Typography, message } from 'antd';
|
||||||
import { CopyOutlined, LinkOutlined } from '@ant-design/icons';
|
import { CopyOutlined, LinkOutlined } from '@ant-design/icons';
|
||||||
|
import { copyToClipboard } from '../../../utils/clipboard';
|
||||||
|
|
||||||
const RAW_API_BASE = import.meta.env.VITE_API_BASE || 'http://localhost:8000';
|
const RAW_API_BASE = import.meta.env.VITE_API_BASE || 'http://localhost:8000';
|
||||||
const RESOURCE_BASE = RAW_API_BASE.replace(/\/api\/?$/i, '').replace(/\/$/, '');
|
const RESOURCE_BASE = RAW_API_BASE.replace(/\/api\/?$/i, '').replace(/\/$/, '');
|
||||||
@@ -37,12 +38,8 @@ const MediaPreview: React.FC<MediaPreviewProps> = ({
|
|||||||
|
|
||||||
const copyUrl = async () => {
|
const copyUrl = async () => {
|
||||||
if (!resolvedUrl) return;
|
if (!resolvedUrl) return;
|
||||||
try {
|
const ok = await copyToClipboard(resolvedUrl);
|
||||||
await navigator.clipboard.writeText(resolvedUrl);
|
message.success(ok ? '资源地址已复制' : '复制失败,请手动复制');
|
||||||
message.success('资源地址已复制');
|
|
||||||
} catch {
|
|
||||||
message.error('复制失败,请手动复制');
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const tools = resolvedUrl ? (
|
const tools = resolvedUrl ? (
|
||||||
|
|||||||
@@ -0,0 +1,23 @@
|
|||||||
|
/** 安全复制文本到剪贴板,兼容非 HTTPS 环境 */
|
||||||
|
export async function copyToClipboard(text: string): Promise<boolean> {
|
||||||
|
try {
|
||||||
|
if (navigator.clipboard && typeof navigator.clipboard.writeText === 'function') {
|
||||||
|
await navigator.clipboard.writeText(text);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
// 降级方案:使用 textarea + execCommand
|
||||||
|
const textarea = document.createElement('textarea');
|
||||||
|
textarea.value = text;
|
||||||
|
textarea.style.position = 'fixed';
|
||||||
|
textarea.style.left = '-9999px';
|
||||||
|
textarea.style.top = '0';
|
||||||
|
document.body.appendChild(textarea);
|
||||||
|
textarea.focus();
|
||||||
|
textarea.select();
|
||||||
|
const succeeded = document.execCommand('copy');
|
||||||
|
document.body.removeChild(textarea);
|
||||||
|
return succeeded;
|
||||||
|
} catch {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
import React, { useEffect, useRef, useState } from "react";
|
import React, { useEffect, useRef, useState } from "react";
|
||||||
|
import { copyToClipboard } from "../utils/clipboard";
|
||||||
import { createPortal } from "react-dom";
|
import { createPortal } from "react-dom";
|
||||||
import {
|
import {
|
||||||
Button,
|
Button,
|
||||||
@@ -2741,10 +2742,7 @@ const GeneratePage: React.FC = () => {
|
|||||||
type="text"
|
type="text"
|
||||||
size="small"
|
size="small"
|
||||||
icon={<CopyOutlined />}
|
icon={<CopyOutlined />}
|
||||||
onClick={() => {
|
onClick={async () => { const ok = await copyToClipboard(editedPrompt); message.success(ok ? '已复制' : '复制失败'); }}
|
||||||
navigator.clipboard.writeText(editedPrompt);
|
|
||||||
message.success("已复制");
|
|
||||||
}}
|
|
||||||
style={{ color: "#94a3b8" }}
|
style={{ color: "#94a3b8" }}
|
||||||
/>
|
/>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
@@ -2886,10 +2884,7 @@ const GeneratePage: React.FC = () => {
|
|||||||
type="text"
|
type="text"
|
||||||
size="small"
|
size="small"
|
||||||
icon={<CopyOutlined />}
|
icon={<CopyOutlined />}
|
||||||
onClick={() => {
|
onClick={async () => { const ok = await copyToClipboard(editedPrompt); message.success(ok ? '已复制' : '复制失败'); }}
|
||||||
navigator.clipboard.writeText(editedPrompt);
|
|
||||||
message.success("已复制");
|
|
||||||
}}
|
|
||||||
style={{ color: "#94a3b8" }}
|
style={{ color: "#94a3b8" }}
|
||||||
/>
|
/>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
@@ -3683,10 +3678,7 @@ const GeneratePage: React.FC = () => {
|
|||||||
type="text"
|
type="text"
|
||||||
size="small"
|
size="small"
|
||||||
icon={<CopyOutlined />}
|
icon={<CopyOutlined />}
|
||||||
onClick={() => {
|
onClick={async () => { const ok = await copyToClipboard(prompt); message.success(ok ? '已复制' : '复制失败'); }}
|
||||||
navigator.clipboard.writeText(prompt);
|
|
||||||
message.success("已复制");
|
|
||||||
}}
|
|
||||||
style={{ color: "#94a3b8" }}
|
style={{ color: "#94a3b8" }}
|
||||||
/>
|
/>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
|
|||||||
@@ -33,6 +33,7 @@ import { useNavigate } from 'react-router-dom';
|
|||||||
import { useAppStore } from '../store/useAppStore';
|
import { useAppStore } from '../store/useAppStore';
|
||||||
import type { GenerationStatus, AspectRatio, Resolution } from '../types';
|
import type { GenerationStatus, AspectRatio, Resolution } from '../types';
|
||||||
import { formatDate } from '../utils/formatDate';
|
import { formatDate } from '../utils/formatDate';
|
||||||
|
import { copyToClipboard } from '../utils/clipboard';
|
||||||
|
|
||||||
const statusConfig: Record<GenerationStatus, { color: string; text: string; icon: React.ReactNode }> = {
|
const statusConfig: Record<GenerationStatus, { color: string; text: string; icon: React.ReactNode }> = {
|
||||||
optimizing: { color: 'processing', text: '优化中', icon: <LoadingOutlined spin /> },
|
optimizing: { color: 'processing', text: '优化中', icon: <LoadingOutlined spin /> },
|
||||||
@@ -300,7 +301,7 @@ const RecordsPage: React.FC = () => {
|
|||||||
<Space size={4}>
|
<Space size={4}>
|
||||||
<Tooltip title="复制">
|
<Tooltip title="复制">
|
||||||
<Button type="text" size="small" icon={<CopyOutlined />}
|
<Button type="text" size="small" icon={<CopyOutlined />}
|
||||||
onClick={() => { navigator.clipboard.writeText(prompt); message.success('已复制'); }}
|
onClick={async () => { const ok = await copyToClipboard(prompt); message.success(ok ? '已复制' : '复制失败'); }}
|
||||||
style={{ color: '#94a3b8' }} />
|
style={{ color: '#94a3b8' }} />
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
{record.status === 'prompt_optimized' && (
|
{record.status === 'prompt_optimized' && (
|
||||||
|
|||||||
@@ -0,0 +1,23 @@
|
|||||||
|
/** 安全复制文本到剪贴板,兼容非 HTTPS 环境 */
|
||||||
|
export async function copyToClipboard(text: string): Promise<boolean> {
|
||||||
|
try {
|
||||||
|
if (navigator.clipboard && typeof navigator.clipboard.writeText === 'function') {
|
||||||
|
await navigator.clipboard.writeText(text);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
// 降级方案:使用 textarea + execCommand
|
||||||
|
const textarea = document.createElement('textarea');
|
||||||
|
textarea.value = text;
|
||||||
|
textarea.style.position = 'fixed';
|
||||||
|
textarea.style.left = '-9999px';
|
||||||
|
textarea.style.top = '0';
|
||||||
|
document.body.appendChild(textarea);
|
||||||
|
textarea.focus();
|
||||||
|
textarea.select();
|
||||||
|
const succeeded = document.execCommand('copy');
|
||||||
|
document.body.removeChild(textarea);
|
||||||
|
return succeeded;
|
||||||
|
} catch {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user