|
|
@@ -13,14 +13,23 @@
|
|
|
v-show="false"
|
|
|
type="file"
|
|
|
ref="qFile"
|
|
|
- v-model="uploadFile"
|
|
|
+ v-model="inputFiles"
|
|
|
@update:model-value="handleFileChange"
|
|
|
multiple
|
|
|
accept=".srt,.ass,.ssa,.sbv,.webvtt"
|
|
|
/>
|
|
|
|
|
|
- <q-dialog v-model="show">
|
|
|
- <q-card style="min-width: 900px">
|
|
|
+ <q-dialog v-model="show" @before-show="handleBeforeShow">
|
|
|
+ <q-card
|
|
|
+ class="relative-position"
|
|
|
+ style="min-width: 900px"
|
|
|
+ @dragover="handleDragenter"
|
|
|
+ @drop="handleDrop"
|
|
|
+ @dragleave="handleDragleave"
|
|
|
+ >
|
|
|
+ <div class="drag-mask row items-center justify-center text-white text-h5" v-if="isDragover">
|
|
|
+ 放置字幕文件到此处
|
|
|
+ </div>
|
|
|
<q-card-section>
|
|
|
<div class="text-body1">批量上传</div>
|
|
|
</q-card-section>
|
|
|
@@ -28,31 +37,48 @@
|
|
|
<q-separator />
|
|
|
|
|
|
<q-card-section style="min-height: 500px">
|
|
|
- <q-list separator>
|
|
|
- <q-item v-for="item in uploadFile" :key="item.name">
|
|
|
- <q-item-section>{{ item.name }}</q-item-section>
|
|
|
- <q-item-section side>
|
|
|
- <q-select
|
|
|
- v-model="mapForm[item.name]"
|
|
|
- :options="items"
|
|
|
- dense
|
|
|
- filled
|
|
|
- style="width: 200px"
|
|
|
- label="选择对应的集数"
|
|
|
- clearable
|
|
|
- >
|
|
|
- <template v-slot:selected>
|
|
|
- <span v-if="mapForm[item.name]"> 第{{ mapForm[item.name].episode }}集 </span>
|
|
|
- </template>
|
|
|
- <template v-slot:option="scope">
|
|
|
- <q-item v-bind="scope.itemProps" clickable v-ripple>
|
|
|
- <q-item-section>第{{ scope.opt.episode }}集</q-item-section>
|
|
|
- </q-item>
|
|
|
- </template>
|
|
|
- </q-select>
|
|
|
- </q-item-section>
|
|
|
- </q-item>
|
|
|
- </q-list>
|
|
|
+ <div
|
|
|
+ v-if="uploadFiles.length === 0"
|
|
|
+ class="upload-area column justify-center items-center q-gutter-sm"
|
|
|
+ style="height: 500px"
|
|
|
+ >
|
|
|
+ <div>拖拽文件上传</div>
|
|
|
+ <div>或者</div>
|
|
|
+ <q-btn color="primary" label="选择文件" dense flat @click="() => qFile.$el.click()" />
|
|
|
+ </div>
|
|
|
+ <template v-else>
|
|
|
+ <q-btn color="primary" label="添加字幕文件" @click="() => qFile.$el.click()" class="q-mb-sm" />
|
|
|
+ <q-list separator>
|
|
|
+ <q-item v-for="item in uploadFiles" :key="item.name">
|
|
|
+ <q-item-section>{{ item.name }}</q-item-section>
|
|
|
+ <q-item-section side>
|
|
|
+ <q-select
|
|
|
+ :disable="submitting"
|
|
|
+ v-model="mapForm[item.name]"
|
|
|
+ :options="items"
|
|
|
+ dense
|
|
|
+ filled
|
|
|
+ style="width: 200px"
|
|
|
+ label="选择对应的集数"
|
|
|
+ clearable
|
|
|
+ >
|
|
|
+ <template v-slot:selected>
|
|
|
+ <span v-if="mapForm[item.name]"> 第{{ mapForm[item.name].episode }}集 </span>
|
|
|
+ </template>
|
|
|
+ <template v-slot:option="scope">
|
|
|
+ <q-item v-bind="scope.itemProps" clickable v-ripple>
|
|
|
+ <q-item-section>第{{ scope.opt.episode }}集</q-item-section>
|
|
|
+ </q-item>
|
|
|
+ </template>
|
|
|
+ </q-select>
|
|
|
+ </q-item-section>
|
|
|
+
|
|
|
+ <q-item-section side>
|
|
|
+ <q-btn color="negative" flat icon="close" dense title="删除" rounded @click="handleRemoveFile(item)" />
|
|
|
+ </q-item-section>
|
|
|
+ </q-item>
|
|
|
+ </q-list>
|
|
|
+ </template>
|
|
|
</q-card-section>
|
|
|
|
|
|
<q-separator />
|
|
|
@@ -85,14 +111,17 @@ const props = defineProps({
|
|
|
},
|
|
|
});
|
|
|
|
|
|
-const uploadFile = ref(null);
|
|
|
+const inputFiles = ref(null);
|
|
|
const qFile = ref(null);
|
|
|
const show = ref(false);
|
|
|
const submitting = ref(false);
|
|
|
const mapForm = reactive({});
|
|
|
+const isDragover = ref(false);
|
|
|
+const uploadFiles = ref([]);
|
|
|
|
|
|
const handleUploadClick = () => {
|
|
|
- qFile.value.$el.click();
|
|
|
+ show.value = true;
|
|
|
+ // qFile.value.$el.click();
|
|
|
};
|
|
|
|
|
|
const upload = async () => {
|
|
|
@@ -105,12 +134,15 @@ const upload = async () => {
|
|
|
formData.append('video_f_path', item.video_f_path);
|
|
|
formData.append(
|
|
|
'file',
|
|
|
- [].find.call(uploadFile.value, (file) => file.name === name)
|
|
|
+ uploadFiles.value.find((file) => file.name === name)
|
|
|
);
|
|
|
// eslint-disable-next-line no-await-in-loop
|
|
|
await LibraryApi.uploadSubtitle(formData);
|
|
|
// eslint-disable-next-line no-await-in-loop
|
|
|
await getSubtitleUploadList();
|
|
|
+ // sleep 1s
|
|
|
+ // eslint-disable-next-line no-await-in-loop,no-promise-executor-return
|
|
|
+ await new Promise((resolve) => setTimeout(resolve, 1000));
|
|
|
eventBus.emit('subtitle-uploaded');
|
|
|
}
|
|
|
}
|
|
|
@@ -121,18 +153,74 @@ const upload = async () => {
|
|
|
show.value = false;
|
|
|
};
|
|
|
|
|
|
-const handleFileChange = (val) => {
|
|
|
- if (val.length > 0) {
|
|
|
- show.value = true;
|
|
|
- [].forEach.call(val, (e) => {
|
|
|
- const episode = getEpisode(e.name);
|
|
|
- const item = props.items.find((i) => i.episode === episode);
|
|
|
- if (item) {
|
|
|
- mapForm[e.name] = item;
|
|
|
- } else {
|
|
|
- mapForm[e.name] = null;
|
|
|
- }
|
|
|
- });
|
|
|
+const addMapForm = (file) => {
|
|
|
+ const episode = getEpisode(file.name);
|
|
|
+ const item = props.items.find((i) => i.episode === episode);
|
|
|
+ if (item) {
|
|
|
+ mapForm[file.name] = item;
|
|
|
+ } else {
|
|
|
+ mapForm[file.name] = null;
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+const handleNewFileAdded = (file) => {
|
|
|
+ if (/\.srt|\.ass|\.ssa|\.sbv|\.webvtt/.test(file.name)) {
|
|
|
+ if (!uploadFiles.value.some((f) => f.name === file.name)) {
|
|
|
+ uploadFiles.value.push(file);
|
|
|
+ addMapForm(file);
|
|
|
+ }
|
|
|
}
|
|
|
};
|
|
|
+
|
|
|
+const handleFileChange = (val) => {
|
|
|
+ [].forEach.call(val, (file) => {
|
|
|
+ handleNewFileAdded(file);
|
|
|
+ });
|
|
|
+};
|
|
|
+
|
|
|
+const handleDragenter = (e) => {
|
|
|
+ e.preventDefault();
|
|
|
+ isDragover.value = true;
|
|
|
+};
|
|
|
+
|
|
|
+const handleDragleave = (e) => {
|
|
|
+ e.preventDefault();
|
|
|
+};
|
|
|
+
|
|
|
+const handleDrop = (e) => {
|
|
|
+ e.preventDefault();
|
|
|
+ const { files } = e.dataTransfer;
|
|
|
+ [].forEach.call(files, (file) => {
|
|
|
+ handleNewFileAdded(file);
|
|
|
+ });
|
|
|
+ handleFileChange(files);
|
|
|
+ isDragover.value = false;
|
|
|
+};
|
|
|
+
|
|
|
+const handleRemoveFile = (file) => {
|
|
|
+ uploadFiles.value = uploadFiles.value.filter((f) => f.name !== file.name);
|
|
|
+ delete mapForm[file.name];
|
|
|
+};
|
|
|
+
|
|
|
+const handleBeforeShow = () => {
|
|
|
+ uploadFiles.value = [];
|
|
|
+ Object.keys(mapForm).forEach((key) => {
|
|
|
+ delete mapForm[key];
|
|
|
+ });
|
|
|
+};
|
|
|
</script>
|
|
|
+
|
|
|
+<style lang="scss">
|
|
|
+.drag-mask {
|
|
|
+ position: absolute;
|
|
|
+ width: 100%;
|
|
|
+ height: 100%;
|
|
|
+ z-index: 999;
|
|
|
+ background-color: rgba(0, 0, 0, 0.5);
|
|
|
+}
|
|
|
+
|
|
|
+.upload-area {
|
|
|
+ border: 2px dashed #ccc;
|
|
|
+ border-radius: 4px;
|
|
|
+}
|
|
|
+</style>
|