vxe-pc-ui
Version:
A vue based PC component library
1,455 lines (1,454 loc) • 57 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
var _vue = require("vue");
var _xeUtils = _interopRequireDefault(require("xe-utils"));
var _ui = require("../../ui");
var _vn = require("../..//ui/src/vn");
var _log = require("../../ui/src/log");
var _dom = require("../../ui/src/dom");
var _util = require("./util");
var _button = _interopRequireDefault(require("../../button/src/button"));
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
var _default = exports.default = (0, _vue.defineComponent)({
name: 'VxeUpload',
props: {
modelValue: [Array, String, Object],
showList: {
type: Boolean,
default: () => (0, _ui.getConfig)().upload.showList
},
moreConfig: Object,
readonly: {
type: Boolean,
default: null
},
disabled: {
type: Boolean,
default: null
},
mode: {
type: String,
default: () => (0, _ui.getConfig)().upload.mode
},
imageTypes: {
type: Array,
default: () => _xeUtils.default.clone((0, _ui.getConfig)().upload.imageTypes, true)
},
imageConfig: {
type: Object,
default: () => _xeUtils.default.clone((0, _ui.getConfig)().upload.imageConfig, true)
},
/**
* 已废弃,被 image-config 替换
* @deprecated
*/
imageStyle: {
type: Object,
default: () => _xeUtils.default.clone((0, _ui.getConfig)().upload.imageStyle, true)
},
fileTypes: {
type: Array,
default: () => _xeUtils.default.clone((0, _ui.getConfig)().upload.fileTypes, true)
},
dragSort: Boolean,
dragToUpload: {
type: Boolean,
default: () => _xeUtils.default.clone((0, _ui.getConfig)().upload.dragToUpload, true)
},
pasteToUpload: {
type: Boolean,
default: () => _xeUtils.default.clone((0, _ui.getConfig)().upload.pasteToUpload, true)
},
keyField: String,
singleMode: Boolean,
urlMode: Boolean,
multiple: Boolean,
limitSize: {
type: [String, Number],
default: () => (0, _ui.getConfig)().upload.limitSize
},
showLimitSize: {
type: Boolean,
default: () => (0, _ui.getConfig)().upload.showLimitSize
},
limitSizeText: {
type: [String, Number, Function],
default: () => (0, _ui.getConfig)().upload.limitSizeText
},
limitCount: {
type: [String, Number],
default: () => (0, _ui.getConfig)().upload.limitCount
},
showLimitCount: {
type: Boolean,
default: () => (0, _ui.getConfig)().upload.showLimitCount
},
limitCountText: {
type: [String, Number, Function],
default: () => (0, _ui.getConfig)().upload.limitCountText
},
nameField: {
type: String,
default: () => (0, _ui.getConfig)().upload.nameField
},
typeField: {
type: String,
default: () => (0, _ui.getConfig)().upload.typeField
},
urlField: {
type: String,
default: () => (0, _ui.getConfig)().upload.urlField
},
sizeField: {
type: String,
default: () => (0, _ui.getConfig)().upload.sizeField
},
showErrorStatus: {
type: Boolean,
default: () => (0, _ui.getConfig)().upload.showErrorStatus
},
showProgress: {
type: Boolean,
default: () => (0, _ui.getConfig)().upload.showProgress
},
progressText: {
type: [String, Number, Function],
default: () => (0, _ui.getConfig)().upload.progressText
},
autoHiddenButton: {
type: Boolean,
default: () => (0, _ui.getConfig)().upload.autoHiddenButton
},
showUploadButton: {
type: Boolean,
default: () => (0, _ui.getConfig)().upload.showUploadButton
},
buttonText: {
type: [String, Number, Function],
default: () => (0, _ui.getConfig)().upload.buttonText
},
buttonIcon: {
type: String,
default: () => (0, _ui.getConfig)().upload.buttonIcon
},
showButtonText: {
type: Boolean,
default: () => (0, _ui.getConfig)().upload.showButtonText
},
showButtonIcon: {
type: Boolean,
default: () => (0, _ui.getConfig)().upload.showButtonIcon
},
showRemoveButton: {
type: Boolean,
default: () => (0, _ui.getConfig)().upload.showRemoveButton
},
showDownloadButton: {
type: Boolean,
default: () => (0, _ui.getConfig)().upload.showDownloadButton
},
showPreview: {
type: Boolean,
default: () => (0, _ui.getConfig)().upload.showPreview
},
showTip: {
type: Boolean,
default: () => null
},
tipText: [String, Number, Function],
hintText: String,
previewMethod: Function,
uploadMethod: Function,
beforeRemoveMethod: Function,
removeMethod: Function,
beforeDownloadMethod: Function,
downloadMethod: Function,
getUrlMethod: Function,
getThumbnailUrlMethod: Function,
size: {
type: String,
default: () => (0, _ui.getConfig)().upload.size || (0, _ui.getConfig)().size
}
},
emits: ['update:modelValue', 'add', 'remove', 'remove-fail', 'download', 'download-fail', 'upload-success', 'upload-error', 'sort-dragend'],
setup(props, context) {
const {
emit,
slots
} = context;
const $xeForm = (0, _vue.inject)('$xeForm', null);
const formItemInfo = (0, _vue.inject)('xeFormItemInfo', null);
const $xeTable = (0, _vue.inject)('$xeTable', null);
const xID = _xeUtils.default.uniqueId();
const {
computeSize
} = (0, _ui.useSize)(props);
const refElem = (0, _vue.ref)();
const refPopupElem = (0, _vue.ref)();
const refDragLineElem = (0, _vue.ref)();
const refModalDragLineElem = (0, _vue.ref)();
const reactData = (0, _vue.reactive)({
isDragUploadStatus: false,
showMorePopup: false,
isActivated: false,
fileList: [],
fileCacheMaps: {},
isDragMove: false,
dragIndex: -1,
dragTipText: ''
});
const internalData = {
imagePreviewTypes: ['jpg', 'jpeg', 'png', 'gif'],
prevDragIndex: -1
// prevDragPos: ''
};
const refMaps = {
refElem
};
const computeFormReadonly = (0, _vue.computed)(() => {
const {
readonly
} = props;
if (readonly === null) {
if ($xeForm) {
return $xeForm.props.readonly;
}
return false;
}
return readonly;
});
const computeIsDisabled = (0, _vue.computed)(() => {
const {
disabled
} = props;
if (disabled === null) {
if ($xeForm) {
return $xeForm.props.disabled;
}
return false;
}
return disabled;
});
const computeKeyField = (0, _vue.computed)(() => {
return props.keyField || '_X_KEY';
});
const computeIsImage = (0, _vue.computed)(() => {
return props.mode === 'image';
});
const computeNameProp = (0, _vue.computed)(() => {
return props.nameField || 'name';
});
const computeTypeProp = (0, _vue.computed)(() => {
return props.typeField || 'type';
});
const computeUrlProp = (0, _vue.computed)(() => {
return props.urlField || 'url';
});
const computeSizeProp = (0, _vue.computed)(() => {
return props.sizeField || 'size';
});
const computeLimitMaxSize = (0, _vue.computed)(() => {
return _xeUtils.default.toNumber(props.limitSize) * 1024 * 1024;
});
const computeLimitMaxCount = (0, _vue.computed)(() => {
return props.multiple ? _xeUtils.default.toNumber(props.limitCount) : 1;
});
const computeOverCount = (0, _vue.computed)(() => {
const {
multiple
} = props;
const {
fileList
} = reactData;
const limitMaxCount = computeLimitMaxCount.value;
if (multiple) {
if (limitMaxCount) {
return fileList.length >= limitMaxCount;
}
return true;
}
return fileList.length >= 1;
});
const computeLimitSizeUnit = (0, _vue.computed)(() => {
const limitSize = _xeUtils.default.toNumber(props.limitSize);
if (limitSize) {
if (limitSize > 1048576) {
return `${limitSize / 1048576}T`;
}
if (limitSize > 1024) {
return `${limitSize / 1024}G`;
}
return `${limitSize}M`;
}
return '';
});
const computedShowTipText = (0, _vue.computed)(() => {
const {
showTip,
tipText
} = props;
if (_xeUtils.default.isBoolean(showTip)) {
return showTip;
}
const defShowTip = (0, _ui.getConfig)().upload.showTip;
if (_xeUtils.default.isBoolean(defShowTip)) {
return defShowTip;
}
if (tipText) {
return true;
}
return false;
});
const computedDefTipText = (0, _vue.computed)(() => {
const {
limitSize,
fileTypes,
multiple,
limitCount
} = props;
const tipText = props.tipText || props.hintText;
const isImage = computeIsImage.value;
const limitSizeUnit = computeLimitSizeUnit.value;
if (_xeUtils.default.isString(tipText)) {
return tipText;
}
if (_xeUtils.default.isFunction(tipText)) {
return `${tipText({})}`;
}
const defTips = [];
if (isImage) {
if (multiple && limitCount) {
defTips.push((0, _ui.getI18n)('vxe.upload.imgCountHint', [limitCount]));
}
if (limitSize && limitSizeUnit) {
defTips.push((0, _ui.getI18n)('vxe.upload.imgSizeHint', [limitSizeUnit]));
}
} else {
if (fileTypes && fileTypes.length) {
defTips.push((0, _ui.getI18n)('vxe.upload.fileTypeHint', [fileTypes.join('/')]));
}
if (limitSize && limitSizeUnit) {
defTips.push((0, _ui.getI18n)('vxe.upload.fileSizeHint', [limitSizeUnit]));
}
if (multiple && limitCount) {
defTips.push((0, _ui.getI18n)('vxe.upload.fileCountHint', [limitCount]));
}
}
return defTips.join((0, _ui.getI18n)('vxe.base.comma'));
});
const computeImageOpts = (0, _vue.computed)(() => {
return Object.assign({}, props.imageConfig || props.imageStyle);
});
const computeImgStyle = (0, _vue.computed)(() => {
const imageOpts = computeImageOpts.value;
const {
width,
height
} = imageOpts;
const stys = {};
if (width) {
stys.width = (0, _dom.toCssUnit)(width);
}
if (height) {
stys.height = (0, _dom.toCssUnit)(height);
}
return stys;
});
const computeMoreOpts = (0, _vue.computed)(() => {
return Object.assign({
showMoreButton: true
}, props.moreConfig);
});
const computeMaps = {};
const $xeUpload = {
xID,
props,
context,
reactData,
internalData,
getRefMaps: () => refMaps,
getComputeMaps: () => computeMaps
};
const getUniqueKey = () => {
return _xeUtils.default.uniqueId();
};
const getFieldKey = item => {
const keyField = computeKeyField.value;
return item[keyField];
};
const updateFileList = () => {
const {
modelValue,
multiple
} = props;
const formReadonly = computeFormReadonly.value;
const keyField = computeKeyField.value;
const nameProp = computeNameProp.value;
const typeProp = computeTypeProp.value;
const urlProp = computeUrlProp.value;
const sizeProp = computeSizeProp.value;
const fileList = modelValue ? (modelValue ? _xeUtils.default.isArray(modelValue) ? modelValue : [modelValue] : []).map(item => {
if (!item || _xeUtils.default.isString(item)) {
const url = `${item || ''}`;
const urlObj = _xeUtils.default.parseUrl(item);
const name = (urlObj ? urlObj.searchQuery[nameProp] : '') || parseFileName(url);
return {
[nameProp]: name,
[typeProp]: (urlObj ? urlObj.searchQuery[typeProp] : '') || parseFileType(name),
[urlProp]: url,
[sizeProp]: _xeUtils.default.toNumber(urlObj ? urlObj.searchQuery[sizeProp] : 0) || 0,
[keyField]: getUniqueKey()
};
}
const name = item[nameProp] || '';
item[nameProp] = name;
item[typeProp] = item[typeProp] || parseFileType(name);
item[urlProp] = item[urlProp] || '';
item[sizeProp] = item[sizeProp] || 0;
item[keyField] = item[keyField] || getUniqueKey();
return item;
}) : [];
reactData.fileList = formReadonly || multiple ? fileList : fileList.slice(0, 1);
};
const parseFileName = url => {
return decodeURIComponent(`${url || ''}`).split('/').pop() || '';
};
const parseFileType = name => {
// 这里不用split('.').pop()因为没有后缀时会返回自身
const index = name.lastIndexOf('.');
if (index > 0) {
return name.substring(index + 1).toLowerCase();
}
return '';
};
const dispatchEvent = (type, params, evnt) => {
emit(type, (0, _ui.createEvent)(evnt, {
$upload: $xeUpload
}, params));
};
const handleChange = value => {
const {
singleMode,
urlMode
} = props;
const urlProp = computeUrlProp.value;
const nameProp = computeNameProp.value;
let restList = value ? value.slice(0) : [];
if (urlMode) {
restList = restList.map(item => {
const url = item[urlProp];
if (url) {
const urlObj = _xeUtils.default.parseUrl(url);
if (!urlObj.searchQuery[nameProp]) {
return `${url}${url.indexOf('?') === -1 ? '?' : '&'}${nameProp}=${encodeURIComponent(item[nameProp] || '')}`;
}
}
return url;
});
}
emit('update:modelValue', singleMode ? restList[0] || null : restList);
};
const getThumbnailFileUrl = item => {
const getThumbnailUrlFn = props.getThumbnailUrlMethod || (0, _ui.getConfig)().upload.getThumbnailUrlMethod;
if (getThumbnailUrlFn) {
return getThumbnailUrlFn({
$upload: $xeUpload,
option: item
});
}
return getFileUrl(item);
};
const getFileUrl = item => {
const getUrlFn = props.getUrlMethod || (0, _ui.getConfig)().upload.getUrlMethod;
const urlProp = computeUrlProp.value;
return getUrlFn ? getUrlFn({
$upload: $xeUpload,
option: item
}) : item[urlProp];
};
const handleDefaultFilePreview = item => {
const {
imageTypes,
showDownloadButton
} = props;
const typeProp = computeTypeProp.value;
const beforeDownloadFn = props.beforeDownloadMethod || (0, _ui.getConfig)().upload.beforeDownloadMethod;
const {
imagePreviewTypes
} = internalData;
// 如果是预览图片
if (imagePreviewTypes.concat(imageTypes || []).some(type => `${type}`.toLowerCase() === `${item[typeProp]}`.toLowerCase())) {
if (_ui.VxeUI.previewImage) {
_ui.VxeUI.previewImage({
urlList: [getFileUrl(item)],
showDownloadButton,
beforeDownloadMethod: beforeDownloadFn ? () => {
return beforeDownloadFn({
$upload: $xeUpload,
option: item
});
} : undefined
});
}
}
};
const handlePreviewFileEvent = (evnt, item) => {
const previewFn = props.previewMethod || (0, _ui.getConfig)().upload.previewMethod;
if (props.showPreview) {
if (previewFn) {
previewFn({
$upload: $xeUpload,
option: item
});
} else {
handleDefaultFilePreview(item);
}
}
};
const handlePreviewImageEvent = (evnt, item, index) => {
const {
showDownloadButton
} = props;
const {
fileList
} = reactData;
const beforeDownloadFn = props.beforeDownloadMethod || (0, _ui.getConfig)().upload.beforeDownloadMethod;
if (props.showPreview) {
if (_ui.VxeUI.previewImage) {
_ui.VxeUI.previewImage({
urlList: fileList.map(item => getFileUrl(item)),
activeIndex: index,
showDownloadButton,
beforeDownloadMethod: beforeDownloadFn ? ({
index
}) => {
return beforeDownloadFn({
$upload: $xeUpload,
option: fileList[index]
});
} : undefined
});
}
}
};
const handleUploadResult = (item, file) => {
const {
showErrorStatus
} = props;
const fileKey = getFieldKey(item);
const uploadFn = props.uploadMethod || (0, _ui.getConfig)().upload.uploadMethod;
if (uploadFn) {
return Promise.resolve(uploadFn({
$upload: $xeUpload,
file,
option: item,
updateProgress(percentNum) {
const {
fileCacheMaps
} = reactData;
const cacheItem = fileCacheMaps[getFieldKey(item)];
if (cacheItem) {
cacheItem.percent = Math.max(0, Math.min(99, _xeUtils.default.toNumber(percentNum)));
}
}
})).then(res => {
const {
fileCacheMaps
} = reactData;
const cacheItem = fileCacheMaps[fileKey];
if (cacheItem) {
cacheItem.percent = 100;
}
Object.assign(item, res);
dispatchEvent('upload-success', {
option: item,
data: res
}, null);
}).catch(res => {
const {
fileCacheMaps
} = reactData;
const cacheItem = fileCacheMaps[fileKey];
if (cacheItem) {
cacheItem.status = 'error';
}
if (showErrorStatus) {
Object.assign(item, res);
} else {
reactData.fileList = reactData.fileList.filter(obj => getFieldKey(obj) !== fileKey);
}
dispatchEvent('upload-error', {
option: item,
data: res
}, null);
}).finally(() => {
const {
fileCacheMaps
} = reactData;
const cacheItem = fileCacheMaps[fileKey];
if (cacheItem) {
cacheItem.loading = false;
}
});
} else {
const {
fileCacheMaps
} = reactData;
const cacheItem = fileCacheMaps[fileKey];
if (cacheItem) {
cacheItem.loading = false;
}
}
return Promise.resolve();
};
const handleReUpload = item => {
const {
uploadMethod,
urlMode
} = props;
const {
fileCacheMaps
} = reactData;
const fileKey = getFieldKey(item);
const cacheItem = fileCacheMaps[fileKey];
const uploadFn = uploadMethod || (0, _ui.getConfig)().upload.uploadMethod;
if (uploadFn && cacheItem) {
const file = cacheItem.file;
cacheItem.loading = true;
cacheItem.status = '';
cacheItem.percent = 0;
handleUploadResult(item, file).then(() => {
if (urlMode) {
handleChange(reactData.fileList);
}
});
}
};
const uploadFile = (files, evnt) => {
const {
multiple,
urlMode,
showLimitSize,
limitSizeText,
showLimitCount,
limitCountText
} = props;
const {
fileList
} = reactData;
const uploadFn = props.uploadMethod || (0, _ui.getConfig)().upload.uploadMethod;
const keyField = computeKeyField.value;
const nameProp = computeNameProp.value;
const typeProp = computeTypeProp.value;
const urlProp = computeUrlProp.value;
const sizeProp = computeSizeProp.value;
const limitMaxSize = computeLimitMaxSize.value;
const limitMaxCount = computeLimitMaxCount.value;
const limitSizeUnit = computeLimitSizeUnit.value;
let selectFiles = files;
if (multiple && limitMaxCount) {
// 校验文件数量
if (showLimitCount && fileList.length >= limitMaxCount) {
if (_ui.VxeUI.modal) {
_ui.VxeUI.modal.notification({
title: (0, _ui.getI18n)('vxe.modal.errTitle'),
status: 'error',
content: limitCountText ? `${_xeUtils.default.isFunction(limitCountText) ? limitCountText({
maxCount: limitMaxCount
}) : limitCountText}` : (0, _ui.getI18n)('vxe.upload.overCountErr', [limitMaxCount])
});
}
return;
}
const overNum = selectFiles.length - (limitMaxCount - fileList.length);
if (showLimitCount && overNum > 0) {
const overExtraList = selectFiles.slice(limitMaxCount - fileList.length);
if (limitCountText) {
_ui.VxeUI.modal.notification({
title: (0, _ui.getI18n)('vxe.modal.errTitle'),
status: 'error',
content: `${_xeUtils.default.isFunction(limitCountText) ? limitCountText({
maxCount: limitMaxCount
}) : limitCountText}`
});
} else if (_ui.VxeUI.modal) {
_ui.VxeUI.modal.notification({
title: (0, _ui.getI18n)('vxe.modal.errTitle'),
status: 'error',
width: null,
slots: {
default() {
return (0, _vue.h)('div', {
class: 'vxe-upload--file-message-over-error'
}, [(0, _vue.h)('div', {}, (0, _ui.getI18n)('vxe.upload.overCountExtraErr', [limitMaxCount, overNum])), (0, _vue.h)('div', {
class: 'vxe-upload--file-message-over-extra'
}, overExtraList.map((file, index) => {
return (0, _vue.h)('div', {
key: index,
class: 'vxe-upload--file-message-over-extra-item'
}, file.name);
}))]);
}
}
});
}
}
selectFiles = selectFiles.slice(0, limitMaxCount - fileList.length);
}
// 校验文件大小
if (showLimitSize && limitMaxSize) {
for (let i = 0; i < files.length; i++) {
const file = files[0];
if (file.size > limitMaxSize) {
if (_ui.VxeUI.modal) {
_ui.VxeUI.modal.notification({
title: (0, _ui.getI18n)('vxe.modal.errTitle'),
status: 'error',
content: limitSizeText ? `${_xeUtils.default.isFunction(limitSizeText) ? limitSizeText({
maxSize: limitMaxSize
}) : limitSizeText}` : (0, _ui.getI18n)('vxe.upload.overSizeErr', [limitSizeUnit])
});
}
return;
}
}
}
const cacheMaps = Object.assign({}, reactData.fileCacheMaps);
const newFileList = multiple ? fileList : [];
const uploadPromiseRests = [];
selectFiles.forEach(file => {
const {
name
} = file;
const fileKey = getUniqueKey();
const fileObj = {
[nameProp]: name,
[typeProp]: parseFileType(name),
[sizeProp]: file.size,
[urlProp]: URL.createObjectURL(file),
[keyField]: fileKey
};
if (uploadFn) {
cacheMaps[fileKey] = {
file: file,
loading: true,
status: '',
percent: 0
};
}
const item = (0, _vue.reactive)(fileObj);
if (uploadFn) {
uploadPromiseRests.push(handleUploadResult(item, file));
}
newFileList.push(item);
dispatchEvent('add', {
option: item
}, evnt);
});
reactData.fileList = newFileList;
reactData.fileCacheMaps = cacheMaps;
Promise.all(urlMode ? uploadPromiseRests : []).then(() => {
handleChange(newFileList);
// 自动更新校验状态
if ($xeForm && formItemInfo) {
$xeForm.triggerItemEvent(evnt, formItemInfo.itemConfig.field, newFileList);
}
});
};
const handleChoose = evnt => {
const {
multiple,
imageTypes,
fileTypes
} = props;
const isDisabled = computeIsDisabled.value;
const isImage = computeIsImage.value;
if (isDisabled) {
return Promise.resolve({
status: false,
files: [],
file: null
});
}
return (0, _util.readLocalFile)({
multiple,
types: isImage ? imageTypes : fileTypes
}).then(params => {
uploadFile(params.files, evnt);
return params;
});
};
const clickEvent = evnt => {
handleChoose(evnt).catch(() => {
// 错误文件类型
});
};
const handleRemoveEvent = (evnt, item, index) => {
const {
fileList
} = reactData;
fileList.splice(index, 1);
handleChange(fileList);
// 自动更新校验状态
if ($xeForm && formItemInfo) {
$xeForm.triggerItemEvent(evnt, formItemInfo.itemConfig.field, fileList);
}
dispatchEvent('remove', {
option: item
}, evnt);
};
const removeFileEvent = (evnt, item, index) => {
const beforeRemoveFn = props.beforeRemoveMethod || (0, _ui.getConfig)().upload.beforeRemoveMethod;
const removeFn = props.removeMethod || (0, _ui.getConfig)().upload.removeMethod;
Promise.resolve(beforeRemoveFn ? beforeRemoveFn({
$upload: $xeUpload,
option: item
}) : true).then(status => {
if (status) {
if (removeFn) {
Promise.resolve(removeFn({
$upload: $xeUpload,
option: item
})).then(() => {
handleRemoveEvent(evnt, item, index);
}).catch(e => e);
} else {
handleRemoveEvent(evnt, item, index);
}
} else {
dispatchEvent('remove-fail', {
option: item
}, evnt);
}
});
};
const handleDownloadEvent = (evnt, item) => {
dispatchEvent('download', {
option: item
}, evnt);
};
const downloadFileEvent = (evnt, item) => {
const beforeDownloadFn = props.beforeDownloadMethod || (0, _ui.getConfig)().upload.beforeDownloadMethod;
const downloadFn = props.downloadMethod || (0, _ui.getConfig)().upload.downloadMethod;
Promise.resolve(beforeDownloadFn ? beforeDownloadFn({
$upload: $xeUpload,
option: item
}) : true).then(status => {
if (status) {
if (downloadFn) {
Promise.resolve(downloadFn({
$upload: $xeUpload,
option: item
})).then(() => {
handleDownloadEvent(evnt, item);
}).catch(e => e);
} else {
handleDownloadEvent(evnt, item);
}
} else {
dispatchEvent('download-fail', {
option: item
}, evnt);
}
});
};
const handleUploadDragleaveEvent = evnt => {
const targetElem = evnt.currentTarget;
const {
clientX,
clientY
} = evnt;
if (targetElem) {
const {
x: targetX,
y: targetY,
height: targetHeight,
width: targetWidth
} = targetElem.getBoundingClientRect();
if (clientX < targetX || clientX > targetX + targetWidth || clientY < targetY || clientY > targetY + targetHeight) {
reactData.isDragUploadStatus = false;
}
}
};
const handleUploadDragoverEvent = evnt => {
const dataTransfer = evnt.dataTransfer;
if (dataTransfer) {
const {
items
} = dataTransfer;
if (items && items.length) {
evnt.preventDefault();
reactData.isDragUploadStatus = true;
}
}
};
const uploadTransferFileEvent = (evnt, files) => {
const {
imageTypes
} = props;
const {
imagePreviewTypes
} = internalData;
const isImage = computeIsImage.value;
if (isImage) {
const pasteImgTypes = imagePreviewTypes.concat(imageTypes && imageTypes.length ? imageTypes : []);
files = files.filter(file => {
const fileType = `${file.type.split('/')[1] || ''}`.toLowerCase();
if (pasteImgTypes.some(type => `${type}`.toLowerCase() === fileType)) {
return true;
}
return false;
});
}
// 如果全部不满足条件
if (!files.length) {
if (_ui.VxeUI.modal) {
_ui.VxeUI.modal.notification({
title: (0, _ui.getI18n)('vxe.modal.errTitle'),
status: 'error',
content: (0, _ui.getI18n)('vxe.upload.uploadTypeErr')
});
}
return;
}
uploadFile(files, evnt);
};
const handleUploadDropEvent = evnt => {
const dataTransfer = evnt.dataTransfer;
if (dataTransfer) {
const {
items
} = dataTransfer;
if (items && items.length) {
evnt.preventDefault();
const files = handleTransferFiles(items);
if (files.length) {
uploadTransferFileEvent(evnt, files);
}
}
}
reactData.isDragUploadStatus = false;
};
const handleTransferFiles = items => {
const files = [];
_xeUtils.default.arrayEach(items, item => {
const file = item.getAsFile();
if (file) {
files.push(file);
}
});
return files;
};
const handleMoreEvent = () => {
const formReadonly = computeFormReadonly.value;
const isImage = computeIsImage.value;
if (_ui.VxeUI.modal) {
_ui.VxeUI.modal.open({
title: formReadonly ? (0, _ui.getI18n)('vxe.upload.morePopup.readTitle') : (0, _ui.getI18n)(`vxe.upload.morePopup.${isImage ? 'imageTitle' : 'fileTitle'}`),
width: 660,
height: 500,
escClosable: true,
showMaximize: true,
resize: true,
maskClosable: true,
slots: {
default() {
const {
showErrorStatus,
dragToUpload,
dragSort
} = props;
const {
isActivated,
isDragMove,
isDragUploadStatus,
dragIndex
} = reactData;
const {
fileList
} = reactData;
const isDisabled = computeIsDisabled.value;
const ons = {};
if (dragToUpload && dragIndex === -1) {
ons.onDragover = handleUploadDragoverEvent;
ons.onDragleave = handleUploadDragleaveEvent;
ons.onDrop = handleUploadDropEvent;
}
return (0, _vue.h)('div', Object.assign({
ref: refPopupElem,
class: ['vxe-upload--more-popup', {
'is--readonly': formReadonly,
'is--disabled': isDisabled,
'is--active': isActivated,
'show--error': showErrorStatus,
'is--drag': isDragUploadStatus
}]
}, ons), [isImage ? dragSort ? (0, _vue.h)(_vue.TransitionGroup, {
name: `vxe-upload--drag-list${isDragMove ? '' : '-disabled'}`,
tag: 'div',
class: 'vxe-upload--image-more-list'
}, {
default: () => renderImageItemList(fileList, true).concat(renderImageAction(true))
}) : (0, _vue.h)('div', {
class: 'vxe-upload--image-more-list'
}, renderImageItemList(fileList, true).concat(renderImageAction(true))) : (0, _vue.h)('div', {
class: 'vxe-upload--file-more-list'
}, [renderFileAction(true), dragSort ? (0, _vue.h)(_vue.TransitionGroup, {
name: `vxe-upload--drag-list${isDragMove ? '' : '-disabled'}`,
tag: 'div',
class: 'vxe-upload--file-list'
}, {
default: () => renderFileItemList(fileList, false)
}) : (0, _vue.h)('div', {
class: 'vxe-upload--file-list'
}, renderFileItemList(fileList, true))]), dragSort ? (0, _vue.h)('div', {
ref: refModalDragLineElem,
class: 'vxe-upload--drag-line'
}) : (0, _ui.renderEmptyElement)($xeUpload), isDragUploadStatus ? (0, _vue.h)('div', {
class: 'vxe-upload--drag-placeholder'
}, (0, _ui.getI18n)('vxe.upload.dragPlaceholder')) : (0, _ui.renderEmptyElement)($xeUpload)]);
}
},
onShow() {
reactData.showMorePopup = true;
},
onHide() {
reactData.showMorePopup = false;
}
});
}
};
const showDropTip = (evnt, dragEl, dragPos) => {
const {
showMorePopup
} = reactData;
const el = refElem.value;
const popupEl = refPopupElem.value;
const wrapperEl = showMorePopup ? popupEl : el;
if (!wrapperEl) {
return;
}
const wrapperRect = wrapperEl.getBoundingClientRect();
const ddLineEl = refDragLineElem.value;
const mdLineEl = refModalDragLineElem.value;
const currDLineEl = showMorePopup ? mdLineEl : ddLineEl;
if (currDLineEl) {
const dragRect = dragEl.getBoundingClientRect();
currDLineEl.style.display = 'block';
currDLineEl.style.top = `${Math.max(1, dragRect.y - wrapperRect.y)}px`;
currDLineEl.style.left = `${Math.max(1, dragRect.x - wrapperRect.x)}px`;
currDLineEl.style.height = `${dragRect.height}px`;
currDLineEl.style.width = `${dragRect.width - 1}px`;
currDLineEl.setAttribute('drag-pos', dragPos);
}
};
const hideDropTip = () => {
const ddLineEl = refDragLineElem.value;
const mdLineEl = refModalDragLineElem.value;
if (ddLineEl) {
ddLineEl.style.display = '';
}
if (mdLineEl) {
mdLineEl.style.display = '';
}
};
// 拖拽
const handleDragSortDragstartEvent = evnt => {
evnt.stopPropagation();
if (evnt.dataTransfer) {
evnt.dataTransfer.setDragImage((0, _dom.getTpImg)(), 0, 0);
}
const dragEl = evnt.currentTarget;
const parentEl = dragEl.parentElement;
const dragIndex = _xeUtils.default.findIndexOf(Array.from(parentEl.children), item => dragEl === item);
reactData.isDragMove = true;
reactData.dragIndex = dragIndex;
setTimeout(() => {
reactData.isDragMove = false;
}, 500);
};
const handleDragSortDragoverEvent = evnt => {
evnt.stopPropagation();
evnt.preventDefault();
const {
dragIndex
} = reactData;
if (dragIndex === -1) {
return;
}
const isImage = computeIsImage.value;
const dragEl = evnt.currentTarget;
const parentEl = dragEl.parentElement;
const currIndex = _xeUtils.default.findIndexOf(Array.from(parentEl.children), item => dragEl === item);
let dragPos = '';
if (isImage) {
const offsetX = evnt.clientX - dragEl.getBoundingClientRect().x;
dragPos = offsetX < dragEl.clientWidth / 2 ? 'left' : 'right';
} else {
const offsetY = evnt.clientY - dragEl.getBoundingClientRect().y;
dragPos = offsetY < dragEl.clientHeight / 2 ? 'top' : 'bottom';
}
if (dragIndex === currIndex) {
showDropTip(evnt, dragEl, dragPos);
return;
}
showDropTip(evnt, dragEl, dragPos);
internalData.prevDragIndex = currIndex;
internalData.prevDragPos = dragPos;
};
const handleDragSortDragendEvent = evnt => {
const {
fileList,
dragIndex
} = reactData;
const {
prevDragIndex,
prevDragPos
} = internalData;
const oldIndex = dragIndex;
const targetIndex = prevDragIndex;
const dragOffsetIndex = prevDragPos === 'bottom' || prevDragPos === 'right' ? 1 : 0;
const oldItem = fileList[oldIndex];
const newItem = fileList[targetIndex];
if (oldItem && newItem) {
fileList.splice(oldIndex, 1);
const ptfIndex = _xeUtils.default.findIndexOf(fileList, item => newItem === item);
const nIndex = ptfIndex + dragOffsetIndex;
fileList.splice(nIndex, 0, oldItem);
dispatchEvent('sort-dragend', {
oldItem: oldItem,
newItem: newItem,
dragPos: prevDragPos,
offsetIndex: dragOffsetIndex,
_index: {
newIndex: nIndex,
oldIndex: oldIndex
}
}, evnt);
}
hideDropTip();
reactData.dragIndex = -1;
};
const handleItemMousedownEvent = evnt => {
if ($xeTable) {
evnt.stopPropagation();
}
reactData.isActivated = true;
};
const handleGlobalPasteEvent = evnt => {
const {
pasteToUpload
} = props;
const {
isActivated
} = reactData;
if (!isActivated || !pasteToUpload) {
return;
}
const clipboardData = evnt.clipboardData || evnt.originalEvent.clipboardData;
if (!clipboardData) {
return;
}
const {
items
} = clipboardData;
if (!items) {
return;
}
const files = handleTransferFiles(items);
if (files.length) {
evnt.preventDefault();
uploadTransferFileEvent(evnt, files);
}
};
const handleGlobalMousedownEvent = evnt => {
const el = refElem.value;
const popupEl = refPopupElem.value;
let isActivated = (0, _dom.getEventTargetNode)(evnt, el).flag;
if (!isActivated && popupEl) {
const parentEl = popupEl.parentElement || popupEl;
const modalEl = parentEl ? parentEl.parentElement : parentEl;
isActivated = (0, _dom.getEventTargetNode)(evnt, modalEl).flag;
}
reactData.isActivated = isActivated;
};
const handleGlobalBlurEvent = () => {
reactData.isActivated = false;
};
const uploadMethods = {
dispatchEvent,
choose() {
return handleChoose(null);
}
};
const uploadPrivateMethods = {};
Object.assign($xeUpload, uploadMethods, uploadPrivateMethods);
const renderFileItemList = (currList, isMoreView) => {
const {
showRemoveButton,
showDownloadButton,
showProgress,
progressText,
showPreview,
showErrorStatus,
dragSort
} = props;
const {
fileCacheMaps
} = reactData;
const isDisabled = computeIsDisabled.value;
const formReadonly = computeFormReadonly.value;
const nameProp = computeNameProp.value;
const typeProp = computeTypeProp.value;
const cornerSlot = slots.corner;
const ons = {};
if (dragSort && currList.length > 1) {
ons.onDragstart = handleDragSortDragstartEvent;
ons.onDragover = handleDragSortDragoverEvent;
ons.onDragend = handleDragSortDragendEvent;
}
return currList.map((item, index) => {
const fileKey = getFieldKey(item);
const cacheItem = fileCacheMaps[fileKey];
const isLoading = cacheItem && cacheItem.loading;
const isError = cacheItem && cacheItem.status === 'error';
return (0, _vue.h)('div', Object.assign({
key: dragSort ? fileKey : index,
class: ['vxe-upload--file-item', {
'is--preview': showPreview,
'is--loading': isLoading,
'is--error': isError
}],
fileid: fileKey,
draggable: dragSort ? true : null
}, ons), [(0, _vue.h)('div', {
class: 'vxe-upload--file-item-icon'
}, [(0, _vue.h)('i', {
class: (0, _ui.getIcon)()[`UPLOAD_FILE_TYPE_${`${item[typeProp]}`.toLocaleUpperCase()}`] || (0, _ui.getIcon)().UPLOAD_FILE_TYPE_DEFAULT
})]), (0, _vue.h)('div', {
class: 'vxe-upload--file-item-name',
onClick(evnt) {
if (!isLoading && !isError) {
handlePreviewFileEvent(evnt, item);
}
}
}, `${item[nameProp] || ''}`), isLoading ? (0, _vue.h)('div', {
class: 'vxe-upload--file-item-loading-icon'
}, [(0, _vue.h)('i', {
class: (0, _ui.getIcon)().UPLOAD_LOADING
})]) : (0, _vue.createCommentVNode)(), showProgress && isLoading && cacheItem ? (0, _vue.h)('div', {
class: 'vxe-upload--file-item-loading-text'
}, progressText ? _xeUtils.default.toFormatString(`${_xeUtils.default.isFunction(progressText) ? progressText({}) : progressText}`, {
percent: cacheItem.percent
}) : (0, _ui.getI18n)('vxe.upload.uploadProgress', [cacheItem.percent])) : (0, _vue.createCommentVNode)(), showErrorStatus && isError ? (0, _vue.h)('div', {
class: 'vxe-upload--image-item-error'
}, [(0, _vue.h)(_button.default, {
icon: (0, _ui.getIcon)().UPLOAD_IMAGE_RE_UPLOAD,
mode: 'text',
status: 'primary',
content: (0, _ui.getI18n)('vxe.upload.reUpload'),
onClick() {
handleReUpload(item);
}
})]) : (0, _vue.createCommentVNode)(), (0, _vue.h)('div', {
class: 'vxe-upload--file-item-btn-wrapper'
}, [cornerSlot ? (0, _vue.h)('div', {
class: 'vxe-upload--file-item-corner'
}, (0, _vn.getSlotVNs)(cornerSlot({
option: item,
isMoreView,
readonly: formReadonly
}))) : (0, _vue.createCommentVNode)(), showDownloadButton && !isLoading ? (0, _vue.h)('div', {
class: 'vxe-upload--file-item-download-btn',
onClick(evnt) {
downloadFileEvent(evnt, item);
}
}, [(0, _vue.h)('i', {
class: (0, _ui.getIcon)().UPLOAD_FILE_DOWNLOAD
})]) : (0, _vue.createCommentVNode)(), showRemoveButton && !formReadonly && !isDisabled && !isLoading ? (0, _vue.h)('div', {
class: 'vxe-upload--file-item-remove-btn',
onClick(evnt) {
removeFileEvent(evnt, item, index);
}
}, [(0, _vue.h)('i', {
class: (0, _ui.getIcon)().UPLOAD_FILE_REMOVE
})]) : (0, _vue.createCommentVNode)()])]);
});
};
const renderFileAction = isMoreView => {
const {
showUploadButton,
buttonText,
buttonIcon,
showButtonText,
showButtonIcon,
autoHiddenButton
} = props;
const isDisabled = computeIsDisabled.value;
const formReadonly = computeFormReadonly.value;
const showTipText = computedShowTipText.value;
const defTipText = computedDefTipText.value;
const overCount = computeOverCount.value;
const defaultSlot = slots.default;
const tipSlot = slots.tip || slots.hint;
if (formReadonly || !showUploadButton) {
return (0, _vue.createCommentVNode)();
}
return (0, _vue.h)('div', {
class: 'vxe-upload--file-action'
}, [autoHiddenButton && overCount ? (0, _vue.createCommentVNode)() : (0, _vue.h)('div', {
class: 'vxe-upload--file-action-btn',
onClick: clickEvent
}, defaultSlot ? (0, _vn.getSlotVNs)(defaultSlot({
$upload: $xeUpload
})) : [(0, _vue.h)(_button.default, {
class: 'vxe-upload--file-action-button',
content: isMoreView || showButtonText ? buttonText ? `${_xeUtils.default.isFunction(buttonText) ? buttonText({}) : buttonText}` : (0, _ui.getI18n)('vxe.upload.fileBtnText') : '',
icon: showButtonIcon ? buttonIcon || (0, _ui.getIcon)().UPLOAD_FILE_ADD : '',
disabled: isDisabled
})]), showTipText && (defTipText || tipSlot) ? (0, _vue.h)('div', {
class: 'vxe-upload--file-action-tip'
}, tipSlot ? (0, _vn.getSlotVNs)(tipSlot({
$upload: $xeUpload
})) : `${defTipText}`) : (0, _vue.createCommentVNode)()]);
};
const renderAllMode = () => {
const {
showList,
moreConfig,
dragSort
} = props;
const {
fileList,
isDragMove
} = reactData;
const moreOpts = computeMoreOpts.value;
const {
maxCount,
showMoreButton,
layout
} = moreOpts;
const isHorizontal = layout === 'horizontal';
let currList = fileList;
let overMaxNum = 0;
if (maxCount && fileList.length > maxCount) {
overMaxNum = fileList.length - maxCount;
currList = fileList.slice(0, maxCount);
}
return (0, _vue.h)('div', {
key: 'all',
class: 'vxe-upload--file-wrapper'
}, showList ? [showMoreButton && moreConfig && isHorizontal ? (0, _vue.createCommentVNode)() : renderFileAction(true), currList.length || showMoreButton && isHorizontal ? (0, _vue.h)('div', {
class: ['vxe-upload--file-list-wrapper', {
'is--horizontal': isHorizontal
}]
}, [currList.length ? dragSort ? (0, _vue.h)(_vue.TransitionGroup, {
name: `vxe-upload--drag-list${isDragMove ? '' : '-disabled'}`,
tag: 'div',
class: 'vxe-upload--file-list'
}, {
default: () => renderFileItemList(currList, false)
}) : (0, _vue.h)('div', {
class: 'vxe-upload--file-list'
}, renderFileItemList(currList, false)) : (0, _vue.createCommentVNode)(), showMoreButton && overMaxNum ? (0, _vue.h)('div', {
class: 'vxe-upload--file-over-more'
}, [(0, _vue.h)(_button.default, {
mode: 'text',
content: (0, _ui.getI18n)('vxe.upload.moreBtnText', [fileList.length]),
status: 'primary',
onClick: handleMoreEvent
})]) : (0, _vue.createCommentVNode)(), showMoreButton && moreConfig && isHorizontal ? renderFileAction(false) : (0, _vue.createCommentVNode)()]) : (0, _vue.createCommentVNode)()] : [renderFileAction(false)]);
};
const renderImageItemList = (currList, isMoreView) => {
const {
showRemoveButton,
showProgress,
progressText,
showPreview,
showErrorStatus,
dragSort
} = props;
const {
fileCacheMaps
} = reactData;
const isDisabled = computeIsDisabled.value;
const formReadonly = computeFormReadonly.value;
const imageOpts = computeImageOpts.value;
const imgStyle = computeImgStyle.value;
const cornerSlot = slots.corner;
const ons = {
onMousedown: handleItemMousedownEvent
};
if (dragSort && currList.length > 1) {
ons.onDragstart = handleDragSortDragstartEvent;
ons.onDragover = handleDragSortDragoverEvent;
ons.onDragend = handleDragSortDragendEvent;
}
return currList.map((item, index) => {
const fileKey = getFieldKey(item);
const cacheItem = fileCacheMaps[fileKey];
const isLoading = cacheItem && cacheItem.loading;
const isError = cacheItem && cacheItem.status === 'error';
return (0, _vue.h)('div', Object.assign({
key: dragSort ? fileKey : index,
class: ['vxe-upload--image-item', {
'is--preview': showPreview,
'is--circle': imageOpts.circle,
'is--loading': isLoading,
'is--error': isError
}],
fileid: fileKey,
draggable: dragSort ? true : null
}, ons), [(0, _vue.h)('div', {
class: 'vxe-upload--image-item-box',
style: isMoreView ? null : imgStyle,
title: (0, _ui.getI18n)('vxe.upload.viewItemTitle'),
onClick(evnt) {
if (!isLoading && !isError) {
handlePreviewImageEvent(evnt, item, index);
}
}
}, [isLoading && cacheItem ? (0, _vue.h)('div', {
class: 'vxe-upload--image-item-loading'
}, [(0, _vue.h)('div', {
class: 'vxe-upload--image-item-loading-icon'
}, [(0, _vue.h)('i', {
class: (0, _ui.getIcon)().UPLOAD_LOADING
})]), showProgress ? (0, _vue.h)('div', {
class: 'vxe-upload--image-item-loading-text'
}, progressText ? _xeUtils.default.toFormatString(`${_xeUtils.default.isFunction(progressText) ? progressText({}) : progressText}`, {
percent: cacheItem.percent
}) : (0, _ui.getI18n)('vxe.upload.uploadProgress', [cacheItem.percent])) : (0, _vue.createCommentVNode)()]) : (0, _vue.createCommentVNode)(), !isLoading ? isError && showErrorStatus ? (0, _vue.h)('div', {
class: 'vxe-upload--image-item-error'
}, [(0, _vue.h)(_button.default, {
icon: (0, _ui.getIcon)().UPLOAD_IMAGE_RE_UPLOAD,
mode: 'text',
status: 'primary',
content: (0, _ui.getI18n)('vxe.upload.reUpload'),
onClick() {
handleReUpload(item);
}
})]) : (0, _vue.h)('div', {
class: 'vxe-upload--image-item-img-wrapper'
}, [(0, _vue.h)('img', {
class: 'vxe-upload--image-item-img',
src: getThumbnailFileUrl(item)
})]) : (0, _vue.createCommentVNode)(), (0, _vue.h)('div', {
class: 'vxe-upload--image-item-btn-wrapper',
onClick(evnt) {
evnt.stopPropagation();
}
}, [cornerSlot ? (0, _vue.h)('div', {
class: 'vxe-upload--file-item-corner'
}, (0, _vn.getSlotVNs)(cornerSlot({
option: item,
isMoreView,
readonly: formReadonly
}))) : (0, _vue.createCommentVNode)(), showRemoveButton && !formReadonly && !isDisabled && !isLoading ? (0, _vue.h)('div', {
class: 'vxe-upload--image-item-remove-btn',
onClick(evnt) {
evnt.stopPropagation();
re