Skip to content

Commit 79d456a

Browse files
committed
feat: 新增导出到剪切板
1 parent e27fc10 commit 79d456a

2 files changed

Lines changed: 83 additions & 11 deletions

File tree

src/components/popovers/ExportPopover.vue

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
<template>
22
<div class="popover">
3+
<div class="export-item" @click="handleCopyText">导出到剪切板</div>
34
<div class="export-item" @click="handleExportText">导出为 TEXT</div>
45
<div class="export-item" @click="handleExportHtml">导出为 HTML</div>
56
<div class="export-item" @click="handleExportDoc">导出为 DOC</div>
@@ -14,10 +15,26 @@ import { useExport } from '@/composables/useExporter';
1415
import { useProjectManager } from '@/composables/useProjectManager';
1516
const projectManager = useProjectManager();
1617
17-
const { exportAsText, exportAsHtml, exportAsDoc, exportAsDocx } = useExport();
18+
const {
19+
exportAsText,
20+
exportAsHtml,
21+
exportAsDoc,
22+
exportAsDocx,
23+
copyTextToClipboard,
24+
} = useExport();
25+
async function handleCopyText() {
26+
try {
27+
await copyTextToClipboard();
28+
alert('已复制导出内容到剪切板');
29+
} catch (error) {
30+
console.error(error);
31+
alert(error instanceof Error ? error.message : '复制导出时发生错误');
32+
}
33+
}
34+
1835
async function handleExportText() {
1936
try {
20-
exportAsText();
37+
await exportAsText();
2138
} catch (error) {
2239
console.error(error);
2340
alert(error instanceof Error ? error.message : '导出TXT时发生错误');

src/composables/useExporter.ts

Lines changed: 64 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -8,22 +8,25 @@ import {
88
htmlAdapter,
99
docAdapter,
1010
} from '@/io/export/adapters/exportAdapters';
11-
import type { ExportFormat } from '@/types/export';
11+
import type { ExportFormat, ExportRow } from '@/types/export';
1212

1313
export function useExport() {
1414
const logStore = useLogStore();
1515
const styleStore = useStyleStore();
1616
const exportStore = useExportStore();
1717

18-
function buildRows() {
18+
function buildRows(): ExportRow[] {
1919
const { documents } = logStore;
2020
const { viewSettings, activeRules } = styleStore;
2121

2222
return flattenLogToRows(documents, viewSettings, activeRules);
2323
}
2424

2525
async function exportWithAdapter(
26-
adapter: (rows: any, format: ExportFormat) => any,
26+
adapter: (
27+
rows: ExportRow[],
28+
format: ExportFormat,
29+
) => string | Blob | Promise<string | Blob>,
2730
format: ExportFormat,
2831
fileExtension: string,
2932
mimeType: string,
@@ -39,26 +42,51 @@ export function useExport() {
3942

4043
// ===== 对外接口 =====
4144

42-
const exportAsText = (format: ExportFormat = exportStore.activeFormat) => {
43-
exportWithAdapter(
45+
const buildTextContent = (
46+
format: ExportFormat = exportStore.activeFormat,
47+
): string => {
48+
const rows = buildRows();
49+
return textAdapter(rows, format);
50+
};
51+
52+
const exportAsText = async (
53+
format: ExportFormat = exportStore.activeFormat,
54+
) => {
55+
await exportWithAdapter(
4456
textAdapter,
4557
format,
4658
format.fileExtension || '.txt',
4759
'text/plain;charset=utf-8',
4860
);
4961
};
5062

51-
const exportAsHtml = (format: ExportFormat = exportStore.activeFormat) => {
52-
exportWithAdapter(
63+
const copyTextToClipboard = async (
64+
format: ExportFormat = exportStore.activeFormat,
65+
) => {
66+
const content = buildTextContent(format);
67+
await writeTextToClipboard(content);
68+
};
69+
70+
const exportAsHtml = async (
71+
format: ExportFormat = exportStore.activeFormat,
72+
) => {
73+
await exportWithAdapter(
5374
htmlAdapter,
5475
format,
5576
'.html',
5677
'text/html;charset=utf-8',
5778
);
5879
};
5980

60-
const exportAsDoc = (format: ExportFormat = exportStore.activeFormat) => {
61-
exportWithAdapter(docAdapter, format, '.doc', 'application/msword');
81+
const exportAsDoc = async (
82+
format: ExportFormat = exportStore.activeFormat,
83+
) => {
84+
await exportWithAdapter(
85+
docAdapter,
86+
format,
87+
'.doc',
88+
'application/msword',
89+
);
6290
};
6391

6492
const exportAsDocx = async (
@@ -79,9 +107,36 @@ export function useExport() {
79107
exportAsHtml,
80108
exportAsDoc,
81109
exportAsDocx,
110+
copyTextToClipboard,
82111
};
83112
}
84113

114+
async function writeTextToClipboard(content: string) {
115+
if (navigator.clipboard?.writeText) {
116+
await navigator.clipboard.writeText(content);
117+
return;
118+
}
119+
120+
const textarea = document.createElement('textarea');
121+
textarea.value = content;
122+
textarea.setAttribute('readonly', '');
123+
textarea.style.position = 'fixed';
124+
textarea.style.left = '-9999px';
125+
textarea.style.top = '0';
126+
127+
document.body.appendChild(textarea);
128+
textarea.select();
129+
130+
try {
131+
const copied = document.execCommand('copy');
132+
if (!copied) {
133+
throw new Error('复制失败');
134+
}
135+
} finally {
136+
document.body.removeChild(textarea);
137+
}
138+
}
139+
85140
function downloadFile(
86141
content: string | Blob,
87142
filename: string,

0 commit comments

Comments
 (0)