feat(SubmitterWindow): add screenshot paste shortcut and refactor upload logic

新增截图粘贴上传功能,重构了截图上传的处理逻辑,将公共上传逻辑提取为importScreenshots方法,同时支持通过Ctrl+V粘贴截图直接上传,优化了截图文件的筛选和上传流程
This commit is contained in:
2026-07-17 21:17:40 +08:00
parent 37217cd6fb
commit 5a01d95e0f
+41 -20
View File
@@ -214,7 +214,14 @@
class="block text-sm font-medium text-slate-700 dark:text-slate-300 mb-2" class="block text-sm font-medium text-slate-700 dark:text-slate-300 mb-2"
>截图最多5张</label >截图最多5张</label
> >
<div class="grid grid-cols-5 gap-3"> <p class="mb-2 text-xs text-slate-500 dark:text-slate-400">
可直接 Ctrl+V 粘贴截图
</p>
<div
tabindex="0"
class="grid grid-cols-5 gap-3 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500"
@paste="handleScreenshotPaste"
>
<div <div
v-for="(screenshot, index) in formData.screenshots" v-for="(screenshot, index) in formData.screenshots"
:key="index" :key="index"
@@ -1429,30 +1436,44 @@ const addScreenshot = () => {
screenshotInput.value?.click(); screenshotInput.value?.click();
}; };
const importScreenshots = (files: File[]) => {
for (const file of files) {
if (formData.screenshots.length >= 5) break;
const reader = new FileReader();
reader.onload = () => {
if (
formData.screenshots.length < 5 &&
typeof reader.result === "string"
) {
formData.screenshots.push(reader.result);
}
};
reader.readAsDataURL(file);
}
};
const handleScreenshotSelect = (event: Event) => { const handleScreenshotSelect = (event: Event) => {
const target = event.target as HTMLInputElement; const target = event.target as HTMLInputElement;
const files = target.files; const files = Array.from(target.files ?? []).filter((file) =>
if (files) { /\.(png|jpe?g)$/i.test(file.name),
for (let i = 0; i < files.length && formData.screenshots.length < 5; i++) { );
const file = files[i]; importScreenshots(files);
if (
file.name.endsWith(".png") ||
file.name.endsWith(".jpg") ||
file.name.endsWith(".jpeg")
) {
const reader = new FileReader();
reader.onload = (e) => {
if (formData.screenshots.length < 5) {
formData.screenshots.push(e.target?.result as string);
}
};
reader.readAsDataURL(file);
}
}
}
target.value = ""; target.value = "";
}; };
const handleScreenshotPaste = (event: ClipboardEvent) => {
const files = Array.from(event.clipboardData?.items ?? [])
.filter((item) => item.type.startsWith("image/"))
.map((item) => item.getAsFile())
.filter((file): file is File => file !== null);
if (files.length > 0) {
event.preventDefault();
importScreenshots(files);
}
};
const removeScreenshot = (index: number) => { const removeScreenshot = (index: number) => {
formData.screenshots.splice(index, 1); formData.screenshots.splice(index, 1);
}; };