Skip to content

Commit

Permalink
Merge pull request #553 from beansmile/feat-drag-upload
Browse files Browse the repository at this point in the history
feat: 支持拖拽上传
  • Loading branch information
ColinLQ authored Oct 27, 2023
2 parents e9b90cf + 8ce52a3 commit 4980432
Show file tree
Hide file tree
Showing 11 changed files with 227 additions and 3 deletions.
119 changes: 119 additions & 0 deletions src/plugin/components/dropbox.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
<template>
<div
class="admin-dropbox"
:class="{ active, disabled }"
@dragenter.stop.prevent="handleDropEnter"
@dragover.stop.prevent="handleDropEnter"
@dragleave.stop.prevent="handleDropLeave"
@drop.stop.prevent="handleDropFile"
@click.stop="handleClick"
v-loading="loading"
>
<i class="el-icon-upload" />
<div class="upload-text">{{ $t('bean.dragAndDropUpload') }}</div>
<slot />

<input
:accept="accept"
type="file"
style="position: fixed; left: -200%; width: 0; height: 0;"
ref="input"
:multiple="limit > 1"
@change="handleFileInputChange"
@click.stop
/>
</div>
</template>

<script>
import { Vue, Component, Prop } from 'vue-property-decorator';
@Component
export default class DropBox extends Vue {
@Prop(String) accept;
@Prop(Boolean) disabled;
@Prop(Boolean) loading;
@Prop({ type: Number, default: 0 }) size; // 单位M 0表示不限制
@Prop({ type: Number, default: 1 }) limit;
active = false;
checkFileType(file, accept) {
if (!accept || accept === '*') {
return true;
}
const valid = accept.replace(/\s/g, '').split(',').filter(accept => {
if (accept.startsWith('.')) {
return (file.name || '').toLowerCase().endsWith(accept.toLowerCase());
}
return new RegExp(accept.replace('*', '.*')).test(file.type);
}).length > 0;
return valid;
}
handleDropEnter() {
this.active = true;
}
handleDropLeave() {
this.active = false;
}
validateFile(file, { validateType = true, validateSize = true } = {}) {
if (validateType) {
const fileTypeValid = this.checkFileType(file, this.accept);
if (!fileTypeValid) {
return `${file.name} - ${this.$t('bean.fileTypeisInvalid')}`;
}
}
if (validateSize && this.size > 0) {
if (file.size > this.size * 1024 * 1024) {
return `${file.name} - ${this.$t('bean.maximumFileSize', { size: `${this.size}M` })}`;
}
}
return null;
}
handleFiles(files, { validateType = true, validateSize = true } = {}) {
if (files.length) {
if (files.length > this.limit) {
this.$emit('error', this.$t('bean.maximumUploadFileCount', { count: this.limit }));
return;
}
if (this.limit === 1) {
const errMsg = this.validateFile(files[0], { validateType, validateSize });
if (errMsg) {
this.$emit('error', errMsg);
return;
}
this.$emit('change', files);
} else {
const validFiles = files.filter(item => !this.validateFile(item, { validateType, validateSize }));
if (validFiles.length !== files.length) {
this.$emit('error', this.$t('bean.filteredUploadFileTip'));
}
if (validFiles.length) {
this.$emit('change', validFiles);
}
}
}
}
handleDropFile(e) {
this.handleDropLeave();
this.handleFiles([...e.dataTransfer.files]);
}
handleFileInputChange(e) {
const files = e.target.files;
this.handleFiles([...files], { validateType: false });
// 相同文件change事件不会触发
e.target.value = '';
}
handleClick() {
this.$refs.input.click();
}
}
</script>
3 changes: 3 additions & 0 deletions src/plugin/components/form/upload.vue
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
<div class="admin-form-upload">
<template v-if="useResourceUploader">
<ResourceUploader
:drag="drag"
:disabled="disabled || uploadLimit < 1"
:limit="uploadLimit"
:cropper="cropper"
Expand All @@ -23,6 +24,7 @@

<Uploader
v-else
:drag="drag"
:disabled="disabled || uploadLimit < 1"
:limit="uploadLimit"
:cropper="cropper"
Expand Down Expand Up @@ -81,6 +83,7 @@ export default class AdminFormUpload extends Vue {
@Prop({ type: String }) uploadButtonText;
@Prop({ type: [Array, String], default: 'image' }) type; // 资源类型
@Prop(Boolean) disableResourceUploader;
@Prop(Boolean) drag;
disalogVisible = false;
Expand Down
34 changes: 33 additions & 1 deletion src/plugin/components/upload/index.vue
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,27 @@
:accept="accept"
@change="handleFileChange"
/>
<DropBox
v-if="drag && limit === 1"
:accept="accept"
:disabled="loading"
:size="size"
@error="handleDropboxError"
@change="handleDropboxChange"
>
<div v-if="loading">
<small>
<template v-if="checksumPending">
{{ $t('bean.checksumPending') }}
</template>
<template v-else>
({{ uploadProgressPct }}%)
</template>
</small>
</div>
</DropBox>
<el-button
v-else
type="primary"
icon="el-icon-upload"
@click="handleUploadBtnClick"
Expand All @@ -27,6 +47,7 @@
</el-button>
<MultipleUpload
v-if="renderMultipleUploadDialog && limit > 1"
:drag="drag"
v-model="showMultipleUploadDialog"
v-bind="{ limit, cropper, accept, size, ...$attrs }"
@success="$emit('success', $event)"
Expand All @@ -48,11 +69,13 @@ import { Vue, Component, Prop, Emit } from 'vue-property-decorator';
import MultipleUpload from './multiple-upload';
import ImageCropper from './image-cropper';
import { uploadFile, isImageFile, imageFileNeedCrop, checkFileSize, getImageInfo } from '../../utils';
import DropBox from '../dropbox.vue';
@Component({
components: {
MultipleUpload,
ImageCropper
ImageCropper,
DropBox,
}
})
export default class AdminUpload extends Vue {
Expand All @@ -62,6 +85,7 @@ export default class AdminUpload extends Vue {
@Prop({ type: String, default: 'image/*' }) accept;
@Prop({ type: Number, default: 3 }) size; // 单位M
@Prop({ type: String }) uploadButtonText;
@Prop(Boolean) drag;
FILE_INPUT_REF_NAME = 'fileInput';
Expand Down Expand Up @@ -147,5 +171,13 @@ export default class AdminUpload extends Vue {
}
this.handleUpload(file);
}
handleDropboxError(errMsg) {
this.$message.error(errMsg);
}
handleDropboxChange(files) {
this.handleUpload(files[0]);
}
}
</script>
24 changes: 22 additions & 2 deletions src/plugin/components/upload/multiple-upload.vue
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,16 @@
@closed="$emit('closed')"
>
<div class="admin-multiple-upload">
<DropBox
v-if="drag"
:accept="accept"
:disabled="loading || (tableData.length >= limit)"
:size="size"
:limit="limit - tableData.length"
@error="handleDropboxError"
@change="handleDropboxChange"
/>

<AdminForm
v-if="formColumns.length"
v-model="uploadForm"
Expand Down Expand Up @@ -44,7 +54,7 @@
>

<el-row class="btn-group">
<el-button type="primary" icon="el-icon-plus" :disabled="loading || (tableData.length >= limit)" @click="handleUploadBtnClick">{{ $t('bean.actionChooseFile') }}</el-button>
<el-button v-if="!drag" type="primary" icon="el-icon-plus" :disabled="loading || (tableData.length >= limit)" @click="handleUploadBtnClick">{{ $t('bean.actionChooseFile') }}</el-button>
<el-button v-if="directory" type="primary" icon="el-icon-plus" :disabled="loading || (tableData.length >= limit)" @click="handleUploadDirectoryBtnClick">{{ $t('bean.actionChooseDirectory') }}</el-button>
<el-button type="warning" @click="handleUploadAll" :loading="loading" :disabled="loading || (!needUploadData.length)">{{ $t('bean.actionUploadAll') }}</el-button>
<el-button type="danger" @click="handleDeleteAll" :disabled="loading || (!tableData.length)">{{ $t('bean.actionRemoveAll') }}</el-button>
Expand Down Expand Up @@ -77,12 +87,14 @@ import { checkFileSize, uploadFile } from '../../utils';
import _ from 'lodash';
import ImageCropperAction from './image-cropper-action';
import { screenService } from '../../services';
import DropBox from '../dropbox.vue';
@Component({
components: {
AdminTable,
FormSelect,
AdminForm
AdminForm,
DropBox,
}
})
export default class MultipleUploadDialog extends Vue {
Expand All @@ -93,6 +105,7 @@ export default class MultipleUploadDialog extends Vue {
@Prop({ type: Number, default: 3 }) size; // 单位M
@Prop(String) hint; // 提示
@Prop(Boolean) directory;
@Prop(Boolean) drag;
FILE_INPUT_REF_NAME = 'fileInput';
DIRECTORY_INPUT_REF_NAME = 'fileDirectory';
Expand Down Expand Up @@ -326,5 +339,12 @@ export default class MultipleUploadDialog extends Vue {
return this.tableData.map(item => item.result)
}
handleDropboxError(errMsg) {
this.$message.info(errMsg);
}
handleDropboxChange(files) {
this.tableData.push(...files.map(file => ({ file })));
}
}
</script>
2 changes: 2 additions & 0 deletions src/plugin/components/upload/resource-uploader.vue
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
<div class="box-header">
<Uploader
v-bind="$attrs"
:drag="drag"
:limit="50"
@success="handleUploadSuccess"
/>
Expand Down Expand Up @@ -88,6 +89,7 @@
@Model('change', { type: Boolean }) value;
@Prop({ type: [Array, String], default: 'image' }) type;
@Prop({ type: Number, default: 1 }) limit;
@Prop(Boolean) drag;
loading = false;
data = [];
Expand Down
2 changes: 2 additions & 0 deletions src/plugin/locale/en.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ export default {
imageResized: 'Resized',
maximumFileSize: 'Maximum file size: {size}',
maximumUploadFileCount: 'Up to {count} files can be uploaded',
fileTypeisInvalid: 'Wrong file format',
dragAndDropUpload: 'Drag your files here, or click Upload',
filteredUploadFileTip: 'Filtered files that do not meet the requirements',
chooseBlobTagTip: 'Select or create the tag. Tag to apply to all images to be uploaded',
fileFormat: 'File format',
Expand Down
2 changes: 2 additions & 0 deletions src/plugin/locale/zh-CN.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ export default {
imageResized: '已裁剪',
maximumFileSize: '文件大小最大: {size}',
maximumUploadFileCount: '最多可上传{count}个文件',
fileTypeisInvalid: '文件格式不对',
dragAndDropUpload: '将文件拖到此处,或点击上传',
filteredUploadFileTip: '已过滤不符合要求的文件',
chooseBlobTagTip: '选择标签 标签将作用于即将上传的所有图片',
fileFormat: '文件格式',
Expand Down
2 changes: 2 additions & 0 deletions src/plugin/locale/zh-HK.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ export default {
imageResized: '已裁剪',
maximumFileSize: '文件大小最大: {size}',
maximumUploadFileCount: '最多可上傳{count}個文件',
fileTypeisInvalid: '文件格式不對',
dragAndDropUpload: '將文件拖曳到此處,或點擊上傳',
filteredUploadFileTip: '已過濾不符合要求的文件',
chooseBlobTagTip: '選擇標籤 標籤將作用於即將上傳的所有圖片',
fileFormat: '文件格式',
Expand Down
36 changes: 36 additions & 0 deletions src/plugin/styles/dropbox.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
.admin-dropbox {
background-color: #fff;
border: 2px dashed #d9d9d9;
border-radius: 6px;
box-sizing: border-box;
width: 360px;
height: 180px;
text-align: center;
cursor: pointer;
overflow: hidden;

&.disabled {
pointer-events: none;
opacity: .3;
}

&:not(.disabled) {
&.active,
&:hover {
border-color: $--color-primary;
}
}

.el-icon-upload {
font-size: 67px;
color: #c0c4cc;
margin: 40px 0 16px;
line-height: 50px;
}

.upload-text {
color: #606266;
font-size: $--font-size-base;
text-align: center;
}
}
1 change: 1 addition & 0 deletions src/plugin/styles/theme.scss
Original file line number Diff line number Diff line change
Expand Up @@ -38,3 +38,4 @@ $--font-path: '~element-ui/lib/theme-chalk/fonts';
@import './page-creator.scss';
@import './rich-text.scss';
@import './markdown.scss';
@import './dropbox.scss';
5 changes: 5 additions & 0 deletions src/plugin/styles/upload.scss
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,11 @@
.tags-selector {
margin-top: 20px;
}

.admin-dropbox {
width: 100%;
margin-bottom: 20px;
}
}


Expand Down

0 comments on commit 4980432

Please sign in to comment.