giime 0.6.2 → 0.6.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.css +59 -58
- package/es/api/materialApi/cross/getAdFileExist.d.ts +1 -0
- package/es/api/materialApi/cross/getAdFileExist.mjs.map +1 -1
- package/es/components/src/base/chart/Chart.vue.d.ts +2 -2
- package/es/components/src/base/chart/index.d.ts +2 -2
- package/es/components/src/base/empty/Empty.vue.d.ts +1 -1
- package/es/components/src/base/empty/index.d.ts +3 -3
- package/es/components/src/business/loginDialog/LoginDialog.vue2.mjs +7 -8
- package/es/components/src/business/loginDialog/LoginDialog.vue2.mjs.map +1 -1
- package/es/components/src/business/uploadMaterial/UploadMaterial.vue.d.ts +4 -4
- package/es/components/src/business/uploadMaterial/index.d.ts +4 -4
- package/es/components/src/business/uploadMaterial/uploadMaterial.d.ts +2 -5
- package/es/components/src/business/uploadMaterial/uploadMaterial.mjs.map +1 -1
- package/es/components/src/composite/fileComponent/FileComponent.vue.d.ts +1 -1
- package/es/components/src/composite/fileComponent/index.d.ts +1 -1
- package/es/components/src/composite/importDialog/ImportDialog.vue.d.ts +9 -2
- package/es/components/src/composite/importDialog/ImportDialog.vue2.mjs +5 -4
- package/es/components/src/composite/importDialog/ImportDialog.vue2.mjs.map +1 -1
- package/es/components/src/composite/importDialog/index.d.ts +193 -49
- package/es/components/src/composite/previewFile/PreviewFile.vue.d.ts +1 -1
- package/es/components/src/composite/previewFile/index.d.ts +1 -1
- package/es/components/src/composite/uploadFile/UploadFile.vue.d.ts +5 -5
- package/es/components/src/composite/uploadFile/UploadFile.vue.mjs +1 -1
- package/es/components/src/composite/uploadFile/UploadFile.vue2.mjs +156 -145
- package/es/components/src/composite/uploadFile/UploadFile.vue2.mjs.map +1 -1
- package/es/components/src/composite/uploadFile/index.d.ts +12 -12
- package/es/giime/index.mjs +2 -1
- package/es/giime/index.mjs.map +1 -1
- package/es/giime/version.d.ts +1 -1
- package/es/giime/version.mjs +1 -1
- package/es/giime/version.mjs.map +1 -1
- package/es/hooks/base/usePasteFile/index.d.ts +89 -0
- package/es/hooks/base/usePasteFile/index.mjs +109 -0
- package/es/hooks/base/usePasteFile/index.mjs.map +1 -0
- package/es/hooks/store/useOrgUserList/index.d.ts +3 -3
- package/es/hooks/store/useOrgUserList/index.mjs +3 -3
- package/es/hooks/store/useOrgUserList/index.mjs.map +1 -1
- package/es/index.css +59 -58
- package/es/utils/index.d.ts +1 -0
- package/es/utils/index.mjs +2 -1
- package/es/utils/index.mjs.map +1 -1
- package/es/utils/src/alioss/aliossPutHook.d.ts +116 -41
- package/es/utils/src/alioss/aliossPutHook.mjs +165 -97
- package/es/utils/src/alioss/aliossPutHook.mjs.map +1 -1
- package/es/utils/src/file.d.ts +7 -0
- package/es/utils/src/file.mjs +39 -1
- package/es/utils/src/file.mjs.map +1 -1
- package/es/utils/src/pasteFile/index.d.ts +33 -0
- package/es/utils/src/pasteFile/index.mjs +142 -0
- package/es/utils/src/pasteFile/index.mjs.map +1 -0
- package/lib/api/materialApi/cross/getAdFileExist.d.ts +1 -0
- package/lib/api/materialApi/cross/getAdFileExist.js.map +1 -1
- package/lib/components/src/base/chart/Chart.vue.d.ts +2 -2
- package/lib/components/src/base/chart/index.d.ts +2 -2
- package/lib/components/src/base/empty/Empty.vue.d.ts +1 -1
- package/lib/components/src/base/empty/index.d.ts +3 -3
- package/lib/components/src/business/loginDialog/LoginDialog.vue2.js +7 -8
- package/lib/components/src/business/loginDialog/LoginDialog.vue2.js.map +1 -1
- package/lib/components/src/business/uploadMaterial/UploadMaterial.vue.d.ts +4 -4
- package/lib/components/src/business/uploadMaterial/index.d.ts +4 -4
- package/lib/components/src/business/uploadMaterial/uploadMaterial.d.ts +2 -5
- package/lib/components/src/business/uploadMaterial/uploadMaterial.js.map +1 -1
- package/lib/components/src/composite/fileComponent/FileComponent.vue.d.ts +1 -1
- package/lib/components/src/composite/fileComponent/index.d.ts +1 -1
- package/lib/components/src/composite/importDialog/ImportDialog.vue.d.ts +9 -2
- package/lib/components/src/composite/importDialog/ImportDialog.vue2.js +4 -3
- package/lib/components/src/composite/importDialog/ImportDialog.vue2.js.map +1 -1
- package/lib/components/src/composite/importDialog/index.d.ts +193 -49
- package/lib/components/src/composite/previewFile/PreviewFile.vue.d.ts +1 -1
- package/lib/components/src/composite/previewFile/index.d.ts +1 -1
- package/lib/components/src/composite/uploadFile/UploadFile.vue.d.ts +5 -5
- package/lib/components/src/composite/uploadFile/UploadFile.vue.js +1 -1
- package/lib/components/src/composite/uploadFile/UploadFile.vue2.js +160 -149
- package/lib/components/src/composite/uploadFile/UploadFile.vue2.js.map +1 -1
- package/lib/components/src/composite/uploadFile/index.d.ts +12 -12
- package/lib/giime/index.js +334 -328
- package/lib/giime/index.js.map +1 -1
- package/lib/giime/version.d.ts +1 -1
- package/lib/giime/version.js +1 -1
- package/lib/giime/version.js.map +1 -1
- package/lib/hooks/base/usePasteFile/index.d.ts +89 -0
- package/lib/hooks/base/usePasteFile/index.js +111 -0
- package/lib/hooks/base/usePasteFile/index.js.map +1 -0
- package/lib/hooks/store/useOrgUserList/index.d.ts +3 -3
- package/lib/hooks/store/useOrgUserList/index.js +3 -3
- package/lib/hooks/store/useOrgUserList/index.js.map +1 -1
- package/lib/index.css +59 -58
- package/lib/utils/index.d.ts +1 -0
- package/lib/utils/index.js +6 -0
- package/lib/utils/index.js.map +1 -1
- package/lib/utils/src/alioss/aliossPutHook.d.ts +116 -41
- package/lib/utils/src/alioss/aliossPutHook.js +165 -97
- package/lib/utils/src/alioss/aliossPutHook.js.map +1 -1
- package/lib/utils/src/file.d.ts +7 -0
- package/lib/utils/src/file.js +40 -0
- package/lib/utils/src/file.js.map +1 -1
- package/lib/utils/src/pasteFile/index.d.ts +33 -0
- package/lib/utils/src/pasteFile/index.js +146 -0
- package/lib/utils/src/pasteFile/index.js.map +1 -0
- package/package.json +1 -1
package/lib/utils/src/file.js
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
+
var jsMd5 = require('js-md5');
|
|
4
|
+
|
|
3
5
|
async function urlToBlob(url) {
|
|
4
6
|
const response = await fetch(url);
|
|
5
7
|
return response.blob();
|
|
@@ -51,14 +53,52 @@ function base64ToBlob(base64, options) {
|
|
|
51
53
|
function fileToUrl(file) {
|
|
52
54
|
return URL.createObjectURL(file);
|
|
53
55
|
}
|
|
56
|
+
function fileValidType(file, validTypes) {
|
|
57
|
+
const fileType = file.type || "";
|
|
58
|
+
const fileExtension = file.name.slice(Math.max(0, file.name.lastIndexOf(".")));
|
|
59
|
+
const acceptTypes = validTypes.split(",").map((type) => type.trim());
|
|
60
|
+
return acceptTypes.some((type) => {
|
|
61
|
+
if (type.startsWith(".")) {
|
|
62
|
+
return fileExtension.toLowerCase() === type.toLowerCase();
|
|
63
|
+
} else if (type.includes("/*")) {
|
|
64
|
+
const [mainType] = type.split("/");
|
|
65
|
+
return fileType.startsWith(`${mainType}/`);
|
|
66
|
+
} else {
|
|
67
|
+
return fileType === type;
|
|
68
|
+
}
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
const fileMd5 = (file) => {
|
|
72
|
+
return new Promise((resolve, reject) => {
|
|
73
|
+
const reader = new FileReader();
|
|
74
|
+
reader.onload = (e) => {
|
|
75
|
+
try {
|
|
76
|
+
const binary = e.target.result;
|
|
77
|
+
if (binary) {
|
|
78
|
+
resolve(jsMd5.md5(binary));
|
|
79
|
+
} else {
|
|
80
|
+
reject(new Error("\u8BFB\u53D6\u6587\u4EF6\u5185\u5BB9\u5931\u8D25"));
|
|
81
|
+
}
|
|
82
|
+
} catch (error) {
|
|
83
|
+
reject(new Error(`\u8BA1\u7B97MD5\u5931\u8D25: ${error instanceof Error ? error.message : String(error)}`));
|
|
84
|
+
}
|
|
85
|
+
};
|
|
86
|
+
reader.onerror = () => {
|
|
87
|
+
reject(new Error("\u8BFB\u53D6\u6587\u4EF6\u5931\u8D25"));
|
|
88
|
+
};
|
|
89
|
+
reader.readAsArrayBuffer(file);
|
|
90
|
+
});
|
|
91
|
+
};
|
|
54
92
|
|
|
55
93
|
exports.base64ToBlob = base64ToBlob;
|
|
56
94
|
exports.base64ToFile = base64ToFile;
|
|
57
95
|
exports.blobToBase64 = blobToBase64;
|
|
58
96
|
exports.blobToFile = blobToFile;
|
|
97
|
+
exports.fileMd5 = fileMd5;
|
|
59
98
|
exports.fileToBase64 = fileToBase64;
|
|
60
99
|
exports.fileToBlob = fileToBlob;
|
|
61
100
|
exports.fileToUrl = fileToUrl;
|
|
101
|
+
exports.fileValidType = fileValidType;
|
|
62
102
|
exports.urlToBlob = urlToBlob;
|
|
63
103
|
exports.urlToFile = urlToFile;
|
|
64
104
|
//# sourceMappingURL=file.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"file.js","sources":["../../../../../packages/utils/src/file.ts"],"sourcesContent":["
|
|
1
|
+
{"version":3,"file":"file.js","sources":["../../../../../packages/utils/src/file.ts"],"sourcesContent":["import { md5 } from 'js-md5';\r\n\r\nexport interface FileConversionOptions {\r\n mimeType?: string;\r\n}\r\n/**\r\n * 将 URL 转换为 Blob\r\n * @param url\r\n * @returns\r\n */\r\nexport async function urlToBlob(url: string): Promise<Blob> {\r\n const response = await fetch(url);\r\n return response.blob();\r\n}\r\n\r\n/**\r\n * 将 URL 转换为 File\r\n * @param url\r\n * @param filename\r\n * @param options\r\n * @returns\r\n */\r\nexport async function urlToFile(url: string, filename: string, options?: FileConversionOptions): Promise<File> {\r\n const blob = await urlToBlob(url);\r\n return new File([blob], filename, { type: options?.mimeType ?? blob.type });\r\n}\r\n\r\n/**\r\n * 将 Base64 字符串转换为 File\r\n * @param base64\r\n * @param filename\r\n * @param options\r\n * @returns\r\n */\r\nexport function base64ToFile(base64: string, filename: string, options?: FileConversionOptions): File {\r\n const bolb = base64ToBlob(base64, { mimeType: options?.mimeType });\r\n return blobToFile(bolb, filename);\r\n}\r\n\r\n/**\r\n * 将 File 转换为 Base64 字符串\r\n * @param file\r\n * @returns\r\n */\r\nexport function fileToBase64(file: File): Promise<string> {\r\n return new Promise((resolve, reject) => {\r\n const reader = new FileReader();\r\n reader.onloadend = () => resolve(reader.result as string);\r\n reader.onerror = reject;\r\n reader.readAsDataURL(file);\r\n });\r\n}\r\n\r\n/**\r\n * 将 Blob 转换为 Base64 字符串\r\n * @param blob\r\n * @returns\r\n */\r\nexport function blobToBase64(blob: Blob): Promise<string> {\r\n return new Promise((resolve, reject) => {\r\n const reader = new FileReader();\r\n reader.onloadend = () => resolve(reader.result as string);\r\n reader.onerror = reject;\r\n reader.readAsDataURL(blob);\r\n });\r\n}\r\n\r\n/**\r\n * 将 File 转换为 Blob\r\n * @param file\r\n * @param options\r\n * @returns\r\n */\r\nexport function fileToBlob(file: File, options?: FileConversionOptions): Blob {\r\n return new Blob([file], { type: options?.mimeType ?? file.type });\r\n}\r\n\r\n/**\r\n * 将 Blob 转换为 File\r\n * @param blob\r\n * @param filename\r\n * @param options\r\n * @returns\r\n */\r\nexport function blobToFile(blob: Blob, filename: string, options?: FileConversionOptions): File {\r\n return new File([blob], filename, { type: options?.mimeType ?? blob.type });\r\n}\r\n\r\n/**\r\n * 将 Base64 字符串转换为 Blob\r\n * @param base64\r\n * @param options\r\n * @returns\r\n */\r\nexport function base64ToBlob(base64: string, options?: FileConversionOptions): Blob {\r\n const matches = base64.match(/^data:(.+);base64,(.*)$/);\r\n\r\n if (!matches || matches.length !== 3) {\r\n throw new Error('Invalid Base64 string');\r\n }\r\n\r\n const mimeType = options?.mimeType ?? matches[1];\r\n const byteString = atob(matches[2]);\r\n const arrayBuffer = new ArrayBuffer(byteString.length);\r\n const intArray = new Uint8Array(arrayBuffer);\r\n\r\n for (let i = 0; i < byteString.length; i++) {\r\n intArray[i] = byteString.charCodeAt(i);\r\n }\r\n\r\n return new Blob([intArray], { type: mimeType });\r\n}\r\n/**\r\n * 文件转本地url\r\n * @param file\r\n * @returns\r\n */\r\nexport function fileToUrl(file: File | Blob) {\r\n return URL.createObjectURL(file);\r\n}\r\n\r\n// 导出一个函数,用于检查文件类型是否合法\r\nexport function fileValidType(file: File, validTypes: string) {\r\n // 获取文件的 MIME 类型\r\n const fileType = file.type || '';\r\n // 获取文件的扩展名\r\n const fileExtension = file.name.slice(Math.max(0, file.name.lastIndexOf('.')));\r\n // 将合法的文件类型字符串分割成数组\r\n const acceptTypes = validTypes.split(',').map(type => type.trim());\r\n // 遍历合法的文件类型数组,检查文件类型是否合法\r\n return acceptTypes.some(type => {\r\n // 如果文件类型以 . 开头,则检查文件扩展名\r\n if (type.startsWith('.')) {\r\n // 检查文件扩展名是否与合法的文件类型匹配\r\n return fileExtension.toLowerCase() === type.toLowerCase();\r\n // 如果文件类型包含 /*,则检查 MIME 类型组,如 image/*\r\n } else if (type.includes('/*')) {\r\n // 检查 MIME 类型组,如 image/*\r\n const [mainType] = type.split('/');\r\n return fileType.startsWith(`${mainType}/`);\r\n } else {\r\n // 检查具体 MIME 类型\r\n return fileType === type;\r\n }\r\n });\r\n}\r\n\r\n/**\r\n * 计算文件的MD5哈希值\r\n * @param file 要计算哈希值的文件\r\n * @returns 文件的MD5哈希值\r\n */\r\nexport const fileMd5 = (file: File): Promise<string> => {\r\n return new Promise<string>((resolve, reject) => {\r\n const reader = new FileReader();\r\n\r\n reader.onload = e => {\r\n try {\r\n const binary = (e.target as FileReader).result;\r\n if (binary) {\r\n resolve(md5(binary));\r\n } else {\r\n reject(new Error('读取文件内容失败'));\r\n }\r\n } catch (error) {\r\n reject(new Error(`计算MD5失败: ${error instanceof Error ? error.message : String(error)}`));\r\n }\r\n };\r\n\r\n reader.onerror = () => {\r\n reject(new Error('读取文件失败'));\r\n };\r\n\r\n reader.readAsArrayBuffer(file);\r\n });\r\n};\r\n"],"names":["md5"],"mappings":"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"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 粘贴文件处理相关错误类型
|
|
3
|
+
*/
|
|
4
|
+
export declare class PasteFileError extends Error {
|
|
5
|
+
originalError?: unknown;
|
|
6
|
+
constructor(message: string, originalError?: unknown);
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* 生成唯一的文件名
|
|
10
|
+
* @param name 原始文件名(可选)
|
|
11
|
+
* @param ext 文件扩展名(可选)
|
|
12
|
+
* @param prefix 文件名前缀(可选),默认为 'clipboard'
|
|
13
|
+
* @returns 生成的文件名
|
|
14
|
+
*/
|
|
15
|
+
export declare const generateFileName: (name?: string, ext?: string, prefix?: string) => string;
|
|
16
|
+
/**
|
|
17
|
+
* 处理粘贴事件,返回粘贴的文件数组
|
|
18
|
+
* @param e 剪贴板事件对象
|
|
19
|
+
* @returns Promise<File[]> 文件对象数组
|
|
20
|
+
*
|
|
21
|
+
* @example
|
|
22
|
+
* ```ts
|
|
23
|
+
* // 在事件处理函数中使用
|
|
24
|
+
* document.addEventListener('paste', async (e) => {
|
|
25
|
+
* const files = await handlePasteEvent(e);
|
|
26
|
+
* if (files.length > 0) {
|
|
27
|
+
* console.log('粘贴的文件:', files);
|
|
28
|
+
* // 处理文件...
|
|
29
|
+
* }
|
|
30
|
+
* });
|
|
31
|
+
* ```
|
|
32
|
+
*/
|
|
33
|
+
export declare const handlePasteEvent: (e: ClipboardEvent) => Promise<File[]>;
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
class PasteFileError extends Error {
|
|
4
|
+
constructor(message, originalError) {
|
|
5
|
+
super(message);
|
|
6
|
+
this.originalError = originalError;
|
|
7
|
+
this.name = "PasteFileError";
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
const generateFileName = (name, ext, prefix = "clipboard") => {
|
|
11
|
+
const timestamp = Date.now();
|
|
12
|
+
const random = Math.floor(Math.random() * 1e4);
|
|
13
|
+
if (name) {
|
|
14
|
+
const hasExtension = /\.[^.]+$/i.test(name);
|
|
15
|
+
if (hasExtension) {
|
|
16
|
+
return `${prefix}_${timestamp}_${random}_${name.split(".")[0]}${name.match(/\.[^.]+$/i)?.[0] || ""}`;
|
|
17
|
+
}
|
|
18
|
+
return `${name}${ext || ".png"}`;
|
|
19
|
+
}
|
|
20
|
+
return `${prefix}_${timestamp}_${random}${ext || ".png"}`;
|
|
21
|
+
};
|
|
22
|
+
const extractImagesFromHtml = (html) => {
|
|
23
|
+
const urls = [];
|
|
24
|
+
const imgRegex = /<img[^>]+src="([^">]+)"/gi;
|
|
25
|
+
let match;
|
|
26
|
+
while ((match = imgRegex.exec(html)) !== null) {
|
|
27
|
+
if (match[1]) {
|
|
28
|
+
urls.push(match[1]);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
return urls;
|
|
32
|
+
};
|
|
33
|
+
const fetchImageAsFile = async (url) => {
|
|
34
|
+
try {
|
|
35
|
+
const response = await fetch(url);
|
|
36
|
+
if (!response.ok) {
|
|
37
|
+
throw new Error(`\u83B7\u53D6\u56FE\u7247\u5931\u8D25: ${response.status} ${response.statusText}`);
|
|
38
|
+
}
|
|
39
|
+
const blob = await response.blob();
|
|
40
|
+
let fileName = url.split("/").pop() || "";
|
|
41
|
+
fileName = fileName.split("?")[0];
|
|
42
|
+
if (!fileName || fileName.length < 3) {
|
|
43
|
+
fileName = generateFileName(void 0, `.${blob.type.split("/")[1] || "png"}`, "image");
|
|
44
|
+
} else {
|
|
45
|
+
fileName = generateFileName(fileName, `.${blob.type.split("/")[1] || fileName.split(".").pop() || "png"}`, "image");
|
|
46
|
+
}
|
|
47
|
+
return new File([blob], fileName, { type: blob.type });
|
|
48
|
+
} catch (error) {
|
|
49
|
+
console.error("\u83B7\u53D6\u56FE\u7247\u6587\u4EF6\u5931\u8D25:", error);
|
|
50
|
+
return null;
|
|
51
|
+
}
|
|
52
|
+
};
|
|
53
|
+
const handleFileItem = (item) => {
|
|
54
|
+
const file = item.getAsFile();
|
|
55
|
+
if (!file) {
|
|
56
|
+
return null;
|
|
57
|
+
}
|
|
58
|
+
const { name, type } = file;
|
|
59
|
+
const ext = name.match(/\.[^.]+?$/i)?.[0] || `.${type.split("/")[1] || "bin"}`;
|
|
60
|
+
const newName = generateFileName(name, ext);
|
|
61
|
+
return new File([file], newName, { type });
|
|
62
|
+
};
|
|
63
|
+
const handleHtmlItem = async (item) => {
|
|
64
|
+
try {
|
|
65
|
+
const html = await new Promise((resolve, reject) => {
|
|
66
|
+
try {
|
|
67
|
+
item.getAsString(resolve);
|
|
68
|
+
} catch (error) {
|
|
69
|
+
reject(new PasteFileError("\u83B7\u53D6HTML\u5185\u5BB9\u5931\u8D25", error));
|
|
70
|
+
}
|
|
71
|
+
});
|
|
72
|
+
const imageUrls = extractImagesFromHtml(html);
|
|
73
|
+
if (imageUrls.length === 0) {
|
|
74
|
+
return [];
|
|
75
|
+
}
|
|
76
|
+
const filePromises = imageUrls.map((url) => fetchImageAsFile(url));
|
|
77
|
+
const files = await Promise.all(filePromises);
|
|
78
|
+
return files.filter((file) => file !== null);
|
|
79
|
+
} catch (error) {
|
|
80
|
+
console.error("\u5904\u7406HTML\u56FE\u7247\u5F15\u7528\u5931\u8D25:", error);
|
|
81
|
+
return [];
|
|
82
|
+
}
|
|
83
|
+
};
|
|
84
|
+
const handleTextItem = async (item) => {
|
|
85
|
+
try {
|
|
86
|
+
const text = await new Promise((resolve, reject) => {
|
|
87
|
+
try {
|
|
88
|
+
item.getAsString(resolve);
|
|
89
|
+
} catch (error) {
|
|
90
|
+
reject(new PasteFileError("\u83B7\u53D6\u6587\u672C\u5185\u5BB9\u5931\u8D25", error));
|
|
91
|
+
}
|
|
92
|
+
});
|
|
93
|
+
const urlRegex = /^(https?:\/\/.*\.(jpeg|jpg|gif|png|webp|bmp|svg))$/i;
|
|
94
|
+
if (urlRegex.test(text.trim())) {
|
|
95
|
+
const file = await fetchImageAsFile(text.trim());
|
|
96
|
+
return file ? [file] : [];
|
|
97
|
+
}
|
|
98
|
+
return [];
|
|
99
|
+
} catch (error) {
|
|
100
|
+
console.error("\u5904\u7406\u6587\u672C\u5185\u5BB9\u5931\u8D25:", error);
|
|
101
|
+
return [];
|
|
102
|
+
}
|
|
103
|
+
};
|
|
104
|
+
const handlePasteEvent = async (e) => {
|
|
105
|
+
try {
|
|
106
|
+
const files = [];
|
|
107
|
+
const items = e.clipboardData?.items;
|
|
108
|
+
if (!items || items.length === 0) {
|
|
109
|
+
return files;
|
|
110
|
+
}
|
|
111
|
+
const filePromises = [];
|
|
112
|
+
for (const item of items) {
|
|
113
|
+
if (item.kind === "file") {
|
|
114
|
+
const file = handleFileItem(item);
|
|
115
|
+
if (file) {
|
|
116
|
+
files.push(file);
|
|
117
|
+
}
|
|
118
|
+
} else if (item.type === "text/html") {
|
|
119
|
+
filePromises.push(handleHtmlItem(item));
|
|
120
|
+
} else if (item.type === "text/plain") {
|
|
121
|
+
filePromises.push(handleTextItem(item));
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
if (filePromises.length > 0) {
|
|
125
|
+
const results = await Promise.all(filePromises);
|
|
126
|
+
for (const result of results) {
|
|
127
|
+
if (result) {
|
|
128
|
+
if (Array.isArray(result)) {
|
|
129
|
+
files.push(...result);
|
|
130
|
+
} else {
|
|
131
|
+
files.push(result);
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
return files;
|
|
137
|
+
} catch (error) {
|
|
138
|
+
console.error("\u7C98\u8D34\u6587\u4EF6\u5904\u7406\u5931\u8D25:", error);
|
|
139
|
+
throw new PasteFileError("\u7C98\u8D34\u6587\u4EF6\u5904\u7406\u5931\u8D25", error);
|
|
140
|
+
}
|
|
141
|
+
};
|
|
142
|
+
|
|
143
|
+
exports.PasteFileError = PasteFileError;
|
|
144
|
+
exports.generateFileName = generateFileName;
|
|
145
|
+
exports.handlePasteEvent = handlePasteEvent;
|
|
146
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sources":["../../../../../../packages/utils/src/pasteFile/index.ts"],"sourcesContent":["/**\r\n * 粘贴文件处理相关错误类型\r\n */\r\nexport class PasteFileError extends Error {\r\n constructor(\r\n message: string,\r\n public originalError?: unknown,\r\n ) {\r\n super(message);\r\n this.name = 'PasteFileError';\r\n }\r\n}\r\n\r\n/**\r\n * 生成唯一的文件名\r\n * @param name 原始文件名(可选)\r\n * @param ext 文件扩展名(可选)\r\n * @param prefix 文件名前缀(可选),默认为 'clipboard'\r\n * @returns 生成的文件名\r\n */\r\nexport const generateFileName = (name?: string, ext?: string, prefix = 'clipboard'): string => {\r\n // 获取当前时间戳和随机数,用于确保文件名唯一\r\n const timestamp = Date.now();\r\n const random = Math.floor(Math.random() * 10000);\r\n\r\n // 如果提供了原始文件名\r\n if (name) {\r\n // 检查文件名是否已包含扩展名\r\n const hasExtension = /\\.[^.]+$/i.test(name);\r\n\r\n // 如果文件名已包含扩展名,直接使用;否则添加扩展名\r\n if (hasExtension) {\r\n return `${prefix}_${timestamp}_${random}_${name.split('.')[0]}${name.match(/\\.[^.]+$/i)?.[0] || ''}`;\r\n }\r\n\r\n // 如果提供了扩展名,使用提供的扩展名;否则默认使用.png\r\n return `${name}${ext || '.png'}`;\r\n }\r\n\r\n // 如果没有提供原始文件名,生成一个默认文件名\r\n return `${prefix}_${timestamp}_${random}${ext || '.png'}`;\r\n};\r\n\r\n/**\r\n * 从HTML中提取图片URL\r\n * @param html HTML字符串\r\n * @returns 图片URL数组\r\n */\r\nconst extractImagesFromHtml = (html: string): string[] => {\r\n const urls: string[] = [];\r\n const imgRegex = /<img[^>]+src=\"([^\">]+)\"/gi;\r\n let match;\r\n\r\n // 提取所有图片URL\r\n while ((match = imgRegex.exec(html)) !== null) {\r\n if (match[1]) {\r\n urls.push(match[1]);\r\n }\r\n }\r\n\r\n return urls;\r\n};\r\n\r\n/**\r\n * 从URL获取图片文件\r\n * @param url 图片URL\r\n * @returns 文件对象\r\n */\r\nconst fetchImageAsFile = async (url: string): Promise<File | null> => {\r\n try {\r\n // 获取图片数据\r\n const response = await fetch(url);\r\n\r\n if (!response.ok) {\r\n throw new Error(`获取图片失败: ${response.status} ${response.statusText}`);\r\n }\r\n\r\n // 获取图片数据\r\n const blob = await response.blob();\r\n\r\n // 从URL中提取文件名\r\n let fileName = url.split('/').pop() || '';\r\n // 如果文件名包含查询参数,去除查询参数\r\n fileName = fileName.split('?')[0];\r\n\r\n // 如果无法从URL中提取有效文件名,生成一个默认文件名\r\n if (!fileName || fileName.length < 3) {\r\n fileName = generateFileName(undefined, `.${blob.type.split('/')[1] || 'png'}`, 'image');\r\n } else {\r\n // 确保文件名有正确的扩展名\r\n fileName = generateFileName(fileName, `.${blob.type.split('/')[1] || fileName.split('.').pop() || 'png'}`, 'image');\r\n }\r\n\r\n // 创建文件对象\r\n return new File([blob], fileName, { type: blob.type });\r\n } catch (error) {\r\n console.error('获取图片文件失败:', error);\r\n return null;\r\n }\r\n};\r\n\r\n/**\r\n * 处理剪贴板中的文件类型项\r\n * @param item 剪贴板数据项\r\n * @returns 文件对象或null\r\n */\r\nconst handleFileItem = (item: DataTransferItem): File | null => {\r\n const file = item.getAsFile();\r\n\r\n if (!file) {\r\n return null;\r\n }\r\n\r\n // 获取文件名和类型\r\n const { name, type } = file;\r\n\r\n // 获取文件扩展名\r\n const ext = name.match(/\\.[^.]+?$/i)?.[0] || `.${type.split('/')[1] || 'bin'}`;\r\n\r\n // 生成新文件名\r\n const newName = generateFileName(name, ext);\r\n\r\n // 创建新文件\r\n return new File([file], newName, { type });\r\n};\r\n\r\n/**\r\n * 处理剪贴板中的HTML类型项\r\n * @param item 剪贴板数据项\r\n * @returns Promise<File[]> 文件对象数组\r\n */\r\nconst handleHtmlItem = async (item: DataTransferItem): Promise<File[]> => {\r\n try {\r\n // 获取HTML字符串\r\n const html = await new Promise<string>((resolve, reject) => {\r\n try {\r\n item.getAsString(resolve);\r\n } catch (error) {\r\n reject(new PasteFileError('获取HTML内容失败', error));\r\n }\r\n });\r\n\r\n // 提取图片URL\r\n const imageUrls = extractImagesFromHtml(html);\r\n\r\n if (imageUrls.length === 0) {\r\n return [];\r\n }\r\n\r\n // 获取所有图片文件\r\n const filePromises = imageUrls.map(url => fetchImageAsFile(url));\r\n const files = await Promise.all(filePromises);\r\n\r\n // 过滤掉null值\r\n return files.filter((file): file is File => file !== null);\r\n } catch (error) {\r\n console.error('处理HTML图片引用失败:', error);\r\n return [];\r\n }\r\n};\r\n\r\n/**\r\n * 处理剪贴板中的文本类型项(检查是否包含图片URL)\r\n * @param item 剪贴板数据项\r\n * @returns Promise<File[]> 文件对象数组\r\n */\r\nconst handleTextItem = async (item: DataTransferItem): Promise<File[]> => {\r\n try {\r\n // 获取文本内容\r\n const text = await new Promise<string>((resolve, reject) => {\r\n try {\r\n item.getAsString(resolve);\r\n } catch (error) {\r\n reject(new PasteFileError('获取文本内容失败', error));\r\n }\r\n });\r\n\r\n // 检查文本是否是URL\r\n const urlRegex = /^(https?:\\/\\/.*\\.(jpeg|jpg|gif|png|webp|bmp|svg))$/i;\r\n if (urlRegex.test(text.trim())) {\r\n const file = await fetchImageAsFile(text.trim());\r\n return file ? [file] : [];\r\n }\r\n\r\n return [];\r\n } catch (error) {\r\n console.error('处理文本内容失败:', error);\r\n return [];\r\n }\r\n};\r\n\r\n/**\r\n * 处理粘贴事件,返回粘贴的文件数组\r\n * @param e 剪贴板事件对象\r\n * @returns Promise<File[]> 文件对象数组\r\n *\r\n * @example\r\n * ```ts\r\n * // 在事件处理函数中使用\r\n * document.addEventListener('paste', async (e) => {\r\n * const files = await handlePasteEvent(e);\r\n * if (files.length > 0) {\r\n * console.log('粘贴的文件:', files);\r\n * // 处理文件...\r\n * }\r\n * });\r\n * ```\r\n */\r\nexport const handlePasteEvent = async (e: ClipboardEvent): Promise<File[]> => {\r\n try {\r\n // 创建一个空文件数组\r\n const files: File[] = [];\r\n\r\n // 获取剪贴板中的数据项\r\n const items = e.clipboardData?.items;\r\n\r\n // 如果没有数据项,返回空文件数组\r\n if (!items || items.length === 0) {\r\n return files;\r\n }\r\n\r\n // 处理所有数据项\r\n const filePromises: Promise<File | File[] | null>[] = [];\r\n\r\n for (const item of items) {\r\n // 根据数据项类型进行处理\r\n if (item.kind === 'file') {\r\n // 处理文件类型\r\n const file = handleFileItem(item);\r\n if (file) {\r\n files.push(file);\r\n }\r\n } else if (item.type === 'text/html') {\r\n // 处理HTML类型(可能包含图片引用)\r\n filePromises.push(handleHtmlItem(item));\r\n } else if (item.type === 'text/plain') {\r\n // 处理文本类型(可能是图片URL)\r\n filePromises.push(handleTextItem(item));\r\n }\r\n }\r\n\r\n // 等待所有异步处理完成\r\n if (filePromises.length > 0) {\r\n const results = await Promise.all(filePromises);\r\n\r\n // 将结果添加到文件数组中\r\n for (const result of results) {\r\n if (result) {\r\n if (Array.isArray(result)) {\r\n files.push(...result);\r\n } else {\r\n files.push(result);\r\n }\r\n }\r\n }\r\n }\r\n\r\n return files;\r\n } catch (error) {\r\n console.error('粘贴文件处理失败:', error);\r\n throw new PasteFileError('粘贴文件处理失败', error);\r\n }\r\n};\r\n"],"names":[],"mappings":"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"}
|