perf: 优化图片选择器

This commit is contained in:
kuaifan 2024-11-12 20:30:54 +08:00
parent 6e0a575da9
commit 02d6dcd592
6 changed files with 395 additions and 321 deletions

View File

@ -2,15 +2,15 @@
<EDropdown <EDropdown
ref="dropdown" ref="dropdown"
trigger="click" trigger="click"
class="task-operation-dropdown" class="general-operation-dropdown"
placement="bottom" placement="bottom"
size="small" size="small"
:style="styles" :style="styles"
@command="onCommand" @command="onCommand"
@visible-change="visibleChange"> @visible-change="visibleChange">
<div ref="icon" class="task-operation-icon"></div> <div ref="icon" class="general-operation-icon"></div>
<EDropdownMenu ref="dropdownMenu" slot="dropdown" class="task-operation-more-dropdown"> <EDropdownMenu ref="dropdownMenu" slot="dropdown" class="general-operation-more-dropdown menu-dropdown">
<li class="task-operation-more-warp small"> <li class="general-operation-more-warp small">
<ul> <ul>
<EDropdownItem <EDropdownItem
v-for="(item, key) in list" v-for="(item, key) in list"
@ -73,8 +73,8 @@ export default {
this.scrollHide = typeof data.scrollHide === "boolean" ? data.scrollHide : false; this.scrollHide = typeof data.scrollHide === "boolean" ? data.scrollHide : false;
// //
this.$refs.icon.focus(); this.$refs.icon.focus();
this.updatePopper();
this.show(); this.show();
this.updatePopper();
this.setupEventListeners(data.event) this.setupEventListeners(data.event)
} else { } else {
this.hide() this.hide()
@ -103,7 +103,9 @@ export default {
}, },
updatePopper() { updatePopper() {
this.$nextTick(this.$refs.dropdownMenu.updatePopper) setTimeout(() => {
this.$refs.dropdownMenu.updatePopper();
}, 0);
}, },
setupEventListeners(event) { setupEventListeners(event) {

View File

@ -2,7 +2,7 @@
<div class="common-img-update"> <div class="common-img-update">
<div v-if="type !== 'callback'" class="imgcomp-upload-list" v-for="item in uploadList"> <div v-if="type !== 'callback'" class="imgcomp-upload-list" v-for="item in uploadList">
<template v-if="item.status === 'finished'"> <template v-if="item.status === 'finished'">
<div class="imgcomp-upload-img" v-bind:style="{ 'background-image': 'url(' + backgroundImage(item.thumb) + ')' }"></div> <div @click="handleTouch($event, item)" class="imgcomp-upload-img" v-bind:style="{ 'background-image': 'url(' + backgroundImage(item.thumb) + ')' }"></div>
<div class="imgcomp-upload-list-cover"> <div class="imgcomp-upload-list-cover">
<Icon type="ios-eye-outline" @click.native="handleView(item)"></Icon> <Icon type="ios-eye-outline" @click.native="handleView(item)"></Icon>
<Icon type="ios-trash-outline" @click.native="handleRemove(item)"></Icon> <Icon type="ios-trash-outline" @click.native="handleRemove(item)"></Icon>
@ -13,7 +13,7 @@
</template> </template>
</div> </div>
<div class="add-box" v-bind:class="{ 'callback-add-box': type === 'callback' }"> <div class="add-box" v-bind:class="{ 'callback-add-box': type === 'callback' }">
<div class="add-box-icon"> <div @click="handleTouch($event, null)" class="add-box-icon">
<Icon type="md-add" size="32"></Icon> <Icon type="md-add" size="32"></Icon>
</div> </div>
<div class="add-box-upload"> <div class="add-box-upload">
@ -77,314 +77,361 @@
</template> </template>
<script> <script>
export default { import {languageList} from "../language";
name: 'ImgUpload',
props: { export default {
value: { name: 'ImgUpload',
}, props: {
num: { value: {},
}, num: {},
width: { width: {},
}, height: {},
height: { whcut: {},
}, type: {},
whcut: { http: {
}, type: Boolean,
type: { default: false
}, },
http: { otherParams: {
type: Boolean, type: Object,
default: false default: () => {
}, return {};
otherParams: { }
type: Object, },
default: () => { uploadIng: {
return {}; type: Number,
default: 0
}
},
data() {
return {
actionUrl: $A.apiUrl('system/imgupload'),
multiple: this.num > 1,
visible: false,
browseVisible: false,
isLoading: false,
browseList: [],
browseListNext: [],
imgVisible: '',
defaultList: this.initItems(this.value),
uploadList: [],
maxNum: Math.min(Math.max($A.runNum(this.num), 1), 99),
httpValue: '',
httpType: '',
maxSize: 2048
}
},
mounted() {
this.uploadList = this.$refs.upload.fileList;
this.$emit('input', this.uploadList);
//
let browseBox = $A(this.$refs.browselistbox);
browseBox.scroll(() => {
let nHight = browseBox[0].scrollHeight;
let nTop = browseBox[0].scrollTop;
let boxHight = browseBox.height();
if (nTop + boxHight >= nHight) {
//
if (this.browseListNext.length > 0) {
let tmpNext = this.browseListNext;
this.browseListNext = [];
this.browsePictureFor(tmpNext);
} }
},
uploadIng: {
type: Number,
default: 0
} }
}, });
data () { },
return { watch: {
actionUrl: $A.apiUrl('system/imgupload'), value(val) {
multiple: this.num > 1, if (typeof val === 'string') {
visible: false, this.$emit('input', this.initItems(val));
browseVisible: false, return;
isLoading: false,
browseList: [],
browseListNext: [],
imgVisible: '',
defaultList: this.initItems(this.value),
uploadList: [],
maxNum: Math.min(Math.max($A.runNum(this.num), 1), 99),
httpValue: '',
httpType: '',
maxSize: 2048
} }
}, if (val === this.$refs.upload.fileList) {
mounted () { return;
}
this.$refs.upload.fileList = this.initItems(val);
this.uploadList = this.$refs.upload.fileList; this.uploadList = this.$refs.upload.fileList;
this.$emit('input', this.uploadList);
//
let browseBox = $A(this.$refs.browselistbox);
browseBox.scroll(()=>{
let nHight = browseBox[0].scrollHeight;
let nTop = browseBox[0].scrollTop;
let boxHight = browseBox.height();
if(nTop + boxHight >= nHight) {
//
if (this.browseListNext.length > 0) {
let tmpNext = this.browseListNext;
this.browseListNext = [];
this.browsePictureFor(tmpNext);
}
}
});
}, },
watch: { browseVisible() {
value (val) { this.httpType = '';
if (typeof val === 'string') { this.httpValue = '';
this.$emit('input', this.initItems(val)); }
return; },
} computed: {
if (val === this.$refs.upload.fileList) { uploadHeaders() {
return; return {
} fd: $A.getSessionStorageString("userWsFd"),
this.$refs.upload.fileList = this.initItems(val); token: this.userToken,
this.uploadList = this.$refs.upload.fileList;
},
browseVisible() {
this.httpType = '';
this.httpValue = '';
} }
}, },
computed: {
uploadHeaders() {
return {
fd: $A.getSessionStorageString("userWsFd"),
token: this.userToken,
}
},
uploadParams() { uploadParams() {
let params = { let params = {
width: this.width, width: this.width,
height: this.height, height: this.height,
whcut: this.whcut, whcut: this.whcut,
}; };
if (Object.keys(this.otherParams).length > 0) { if (Object.keys(this.otherParams).length > 0) {
return Object.assign(params, this.otherParams); return Object.assign(params, this.otherParams);
} else { } else {
return params; return params;
}
}
},
methods: {
handleCallback(file) {
if (this.type === 'callback') {
if (file === true) {
this.$emit('on-callback', this.uploadList);
this.$refs.upload.fileList = [];
this.uploadList = this.$refs.upload.fileList;
}else if (typeof file === "object") {
this.$emit('on-callback', [file]);
}
}
this.browseVisible = false;
},
initItems(items) {
//
if (typeof items === 'string') {
items = [{'url': items}];
}
let list = [];
$A.each(items, (index, item)=>{
if (typeof item === 'string') item = {'url': item};
if (item.url) {
item.active = true;
item.status = 'finished';
if (typeof item.path === 'undefined') item.path = item.url;
if (typeof item.thumb === 'undefined') item.thumb = item.url;
list.push(item);
}
});
return list;
},
handleView (item) {
//
this.$store.dispatch("previewImage", item.url)
// this.visible = true;
// this.imgVisible = item.url;
},
handleRemove (item) {
//
let fileList = this.$refs.upload.fileList;
this.$refs.upload.fileList.splice(fileList.indexOf(item), 1);
this.$emit('input', this.$refs.upload.fileList);
},
handleProgress(event, file) {
//
if (file._uploadIng === undefined) {
file._uploadIng = true;
this.$emit('update:uploadIng', this.uploadIng + 1);
}
},
handleSuccess (res, file) {
//
this.$emit('update:uploadIng', this.uploadIng - 1);
if (res.ret === 1) {
file.url = res.data.url;
file.path = res.data.path;
file.thumb = res.data.thumb;
this.handleCallback(file);
}else{
$A.noticeWarning({
title: this.$L('上传失败'),
desc: this.$L('文件 ' + file.name + ' 上传失败 ' + res.msg),
});
this.$refs.upload.fileList.pop();
}
this.$emit('input', this.$refs.upload.fileList);
},
handleError() {
//
this.$emit('update:uploadIng', this.uploadIng - 1);
},
handleFormatError (file) {
//
$A.noticeWarning({
title: this.$L('文件格式不正确'),
desc: this.$L('文件 ' + file.name + ' 格式不正确,请上传 jpg、jpeg、webp、gif、png 格式的图片。')
});
},
handleMaxSize (file) {
//
$A.noticeWarning({
title: this.$L('超出文件大小限制'),
desc: this.$L('文件 ' + file.name + ' 太大,不能超过:' + $A.bytesToSize(this.maxSize * 1024))
});
},
handleBeforeUpload () {
//
let check = this.uploadList.length < this.maxNum;
if (!check && this.uploadList.length == 1) {
this.handleRemove(this.uploadList[0]);
check = this.uploadList.length < this.maxNum;
}
if (!check) {
$A.noticeWarning(this.$L('最多只能上传 ' + this.maxNum + ' 张图片。'));
}
return check;
},
handleClick() {
//
if (this.handleBeforeUpload()) {
this.$refs.upload.handleClick()
}
},
handleManual(file) {
//file
if (this.handleBeforeUpload()) {
this.$refs.upload.upload(file);
}
},
browsePicture(path) {
//
this.browseVisible = true;
this.browseList = [];
this.browseListNext = [];
this.isLoading = true;
this.$store.dispatch("call", {
url: 'system/imgview',
data: {path: path ? path : ''},
}).then(({data}) => {
let dirs = data['dirs'];
for (let i = 0; i < dirs.length; i++) {
this.browseList.push(dirs[i]);
}
this.browsePictureFor(data['files']);
}).catch(({msg}) => {
this.browseVisible = false;
$A.noticeWarning(msg);
}).finally(_ => {
this.isLoading = false;
});
},
browsePictureFor(files) {
for (let o = 0; o < files.length; o++) {
for (let j = 0; j < this.uploadList.length; j++) {
if (this.uploadList[j]['url'] === files[o]['url']
|| this.uploadList[j]['url'] === files[o]['path']) {
files[o]['active'] = true;
break;
}
}
if (o < 100) {
this.browseList.push(files[o]);
}else{
this.browseListNext.push(files[o]);
}
}
},
browseItem(item) {
//
if (item.type === 'dir') {
//
this.browsePicture(item.path);
}else if (item.type === 'file') {
//
if (item.active) {
let fileList = this.$refs.upload.fileList;
this.$refs.upload.fileList.splice(fileList.indexOf(item), 1);
item.active = false;
}else{
if (this.maxNum === 1) {
for (let i = 0; i < this.browseList.length; i++) {
this.browseList[i].active = false;
}
this.$refs.upload.fileList = [];
this.uploadList = this.$refs.upload.fileList;
}
let check = this.uploadList.length < this.maxNum;
if (!check) {
$A.noticeWarning(this.$L('最多只能选择 ' + this.maxNum + ' 张图片。'));
return;
}
item.active = true;
item.status = 'finished';
this.$refs.upload.fileList.push(item);
this.uploadList = this.$refs.upload.fileList;
}
this.$emit('input', this.$refs.upload.fileList);
}
},
browseStyle(thumb) {
if (!/https*:\/\//.test(thumb) && !/^\//.test(thumb)) {
thumb = $A.mainUrl(thumb);
}
return {
'background-image': `url("${thumb}")`
}
},
backgroundImage(url) {
if ($A.strExists(url, "?", false)) {
return $A.mainUrl(url) + "&__thumb=true";
}else{
return $A.mainUrl(url) + "?__thumb=true";
}
},
httpEnter() {
this.$emit('input', this.initItems(this.httpValue));
this.browseVisible = false;
} }
} }
},
methods: {
handleCallback(file) {
if (this.type === 'callback') {
if (file === true) {
this.$emit('on-callback', this.uploadList);
this.$refs.upload.fileList = [];
this.uploadList = this.$refs.upload.fileList;
} else if (typeof file === "object") {
this.$emit('on-callback', [file]);
}
}
this.browseVisible = false;
},
initItems(items) {
//
if (typeof items === 'string') {
items = [{'url': items}];
}
let list = [];
$A.each(items, (index, item) => {
if (typeof item === 'string') item = {'url': item};
if (item.url) {
item.active = true;
item.status = 'finished';
if (typeof item.path === 'undefined') item.path = item.url;
if (typeof item.thumb === 'undefined') item.thumb = item.url;
list.push(item);
}
});
return list;
},
handleTouch(event, item) {
if (!this.windowTouch) {
return;
}
const list = [];
if (item === null) {
const subfix = this.type === 'callback' ? '图片' : '';
list.push(...[
{
label: '浏览' + subfix,
value: 'browse'
},
{
label: '上传' + subfix,
value: 'upload'
}
])
} else {
list.push(...[
{
label: '查看',
value: 'view'
},
{
label: '删除',
value: 'trash'
}
])
}
this.$store.state.menuOperation = {
event,
list,
scrollHide: true,
onUpdate: async (act) => {
switch (act) {
case 'browse':
this.browsePicture();
break;
case 'upload':
this.$refs.upload?.handleClick()
break;
case 'view':
this.handleView(item);
break;
case 'trash':
this.handleRemove(item);
break;
}
}
}
},
handleView(item) {
//
this.$store.dispatch("previewImage", item.url)
// this.visible = true;
// this.imgVisible = item.url;
},
handleRemove(item) {
//
let fileList = this.$refs.upload.fileList;
this.$refs.upload.fileList.splice(fileList.indexOf(item), 1);
this.$emit('input', this.$refs.upload.fileList);
},
handleProgress(event, file) {
//
if (file._uploadIng === undefined) {
file._uploadIng = true;
this.$emit('update:uploadIng', this.uploadIng + 1);
}
},
handleSuccess(res, file) {
//
this.$emit('update:uploadIng', this.uploadIng - 1);
if (res.ret === 1) {
file.url = res.data.url;
file.path = res.data.path;
file.thumb = res.data.thumb;
this.handleCallback(file);
} else {
$A.noticeWarning({
title: this.$L('上传失败'),
desc: this.$L('文件 ' + file.name + ' 上传失败 ' + res.msg),
});
this.$refs.upload.fileList.pop();
}
this.$emit('input', this.$refs.upload.fileList);
},
handleError() {
//
this.$emit('update:uploadIng', this.uploadIng - 1);
},
handleFormatError(file) {
//
$A.noticeWarning({
title: this.$L('文件格式不正确'),
desc: this.$L('文件 ' + file.name + ' 格式不正确,请上传 jpg、jpeg、webp、gif、png 格式的图片。')
});
},
handleMaxSize(file) {
//
$A.noticeWarning({
title: this.$L('超出文件大小限制'),
desc: this.$L('文件 ' + file.name + ' 太大,不能超过:' + $A.bytesToSize(this.maxSize * 1024))
});
},
handleBeforeUpload() {
//
let check = this.uploadList.length < this.maxNum;
if (!check && this.uploadList.length == 1) {
this.handleRemove(this.uploadList[0]);
check = this.uploadList.length < this.maxNum;
}
if (!check) {
$A.noticeWarning(this.$L('最多只能上传 ' + this.maxNum + ' 张图片。'));
}
return check;
},
handleClick() {
//
if (this.handleBeforeUpload()) {
this.$refs.upload.handleClick()
}
},
handleManual(file) {
//file
if (this.handleBeforeUpload()) {
this.$refs.upload.upload(file);
}
},
browsePicture(path) {
//
this.browseVisible = true;
this.browseList = [];
this.browseListNext = [];
this.isLoading = true;
this.$store.dispatch("call", {
url: 'system/imgview',
data: {path: path ? path : ''},
}).then(({data}) => {
let dirs = data['dirs'];
for (let i = 0; i < dirs.length; i++) {
this.browseList.push(dirs[i]);
}
this.browsePictureFor(data['files']);
}).catch(({msg}) => {
this.browseVisible = false;
$A.noticeWarning(msg);
}).finally(_ => {
this.isLoading = false;
});
},
browsePictureFor(files) {
for (let o = 0; o < files.length; o++) {
for (let j = 0; j < this.uploadList.length; j++) {
if (this.uploadList[j]['url'] === files[o]['url']
|| this.uploadList[j]['url'] === files[o]['path']) {
files[o]['active'] = true;
break;
}
}
if (o < 100) {
this.browseList.push(files[o]);
} else {
this.browseListNext.push(files[o]);
}
}
},
browseItem(item) {
//
if (item.type === 'dir') {
//
this.browsePicture(item.path);
} else if (item.type === 'file') {
//
if (item.active) {
let fileList = this.$refs.upload.fileList;
this.$refs.upload.fileList.splice(fileList.indexOf(item), 1);
item.active = false;
} else {
if (this.maxNum === 1) {
for (let i = 0; i < this.browseList.length; i++) {
this.browseList[i].active = false;
}
this.$refs.upload.fileList = [];
this.uploadList = this.$refs.upload.fileList;
}
let check = this.uploadList.length < this.maxNum;
if (!check) {
$A.noticeWarning(this.$L('最多只能选择 ' + this.maxNum + ' 张图片。'));
return;
}
item.active = true;
item.status = 'finished';
this.$refs.upload.fileList.push(item);
this.uploadList = this.$refs.upload.fileList;
}
this.$emit('input', this.$refs.upload.fileList);
}
},
browseStyle(thumb) {
if (!/https*:\/\//.test(thumb) && !/^\//.test(thumb)) {
thumb = $A.mainUrl(thumb);
}
return {
'background-image': `url("${thumb}")`
}
},
backgroundImage(url) {
if ($A.strExists(url, "?", false)) {
return $A.mainUrl(url) + "&__thumb=true";
} else {
return $A.mainUrl(url) + "?__thumb=true";
}
},
httpEnter() {
this.$emit('input', this.initItems(this.httpValue));
this.browseVisible = false;
}
} }
}
</script> </script>

View File

@ -6,13 +6,13 @@
:disabled="disabled" :disabled="disabled"
:size="size" :size="size"
:style="styles" :style="styles"
class="task-operation-dropdown" class="general-operation-dropdown"
placement="bottom" placement="bottom"
@command="dropTask" @command="dropTask"
@visible-change="visibleChange"> @visible-change="visibleChange">
<div ref="icon" class="task-operation-icon"></div> <div ref="icon" class="general-operation-icon"></div>
<EDropdownMenu ref="dropdownMenu" slot="dropdown" class="task-operation-more-dropdown"> <EDropdownMenu ref="dropdownMenu" slot="dropdown" class="general-operation-more-dropdown">
<li class="task-operation-more-warp" :class="size"> <li class="general-operation-more-warp" :class="size">
<ul> <ul>
<EDropdownItem v-if="!flow" class="load-flow" disabled> <EDropdownItem v-if="!flow" class="load-flow" disabled>
<div class="load-flow-warp"> <div class="load-flow-warp">

View File

@ -45,6 +45,9 @@
left: 0; left: 0;
right: 0; right: 0;
background: rgba(0, 0, 0, .6); background: rgba(0, 0, 0, .6);
flex-direction: row;
align-items: center;
justify-content: center;
} }
.imgcomp-upload-list-cover i { .imgcomp-upload-list-cover i {
@ -74,7 +77,7 @@
} }
.imgcomp-upload-list:hover .imgcomp-upload-list-cover { .imgcomp-upload-list:hover .imgcomp-upload-list-cover {
display: block; display: flex;
} }
.img-upload-foot { .img-upload-foot {
@ -111,10 +114,11 @@
vertical-align: top; vertical-align: top;
.add-box-icon { .add-box-icon {
i { display: flex;
vertical-align: middle; align-items: center;
padding-bottom: 2px; justify-content: center;
} width: 100%;
height: 100%;
} }
.add-box-upload { .add-box-upload {
@ -132,8 +136,12 @@
height: 22px; height: 22px;
line-height: 22px; line-height: 22px;
cursor: pointer; cursor: pointer;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
.ivu-upload-drag, .ivu-upload-drag:hover { .ivu-upload-drag,
.ivu-upload-drag:hover {
background: transparent; background: transparent;
border: 0; border: 0;
border-radius: 0; border-radius: 0;
@ -260,3 +268,17 @@
background-color: rgba(255, 255, 255, 0.9); background-color: rgba(255, 255, 255, 0.9);
z-index: 1; z-index: 1;
} }
// 移动端不显示
body.window-touch {
.imgcomp-upload-list:hover .imgcomp-upload-list-cover {
display: none;
}
.add-box:hover {
border-color: #dddee1;
.add-box-upload {
display: none;
}
}
}

View File

@ -4,6 +4,7 @@
@import "dialog-select"; @import "dialog-select";
@import "dialog-wrapper"; @import "dialog-wrapper";
@import "file-content"; @import "file-content";
@import "general-operation";
@import "meeting-manager"; @import "meeting-manager";
@import "project-archived"; @import "project-archived";
@import "project-dialog"; @import "project-dialog";
@ -20,7 +21,6 @@
@import "task-deleted"; @import "task-deleted";
@import "task-detail"; @import "task-detail";
@import "task-menu"; @import "task-menu";
@import "task-operation";
@import "task-priority"; @import "task-priority";
@import "task-move"; @import "task-move";
@import "team-management"; @import "team-management";

View File

@ -1,4 +1,4 @@
.task-operation-dropdown { .general-operation-dropdown {
position: absolute; position: absolute;
top: 0; top: 0;
left: 0; left: 0;
@ -18,9 +18,9 @@
} }
} }
.task-operation-more-dropdown { .general-operation-more-dropdown {
> li { > li {
&.task-operation-more-warp { &.general-operation-more-warp {
list-style: none; list-style: none;
> ul { > ul {
@ -89,16 +89,19 @@
border-color: rgba($flow-status-start-color, 0.1); border-color: rgba($flow-status-start-color, 0.1);
color: $flow-status-start-color; color: $flow-status-start-color;
} }
&.progress { &.progress {
background-color: rgba($flow-status-progress-color, 0.1); background-color: rgba($flow-status-progress-color, 0.1);
border-color: rgba($flow-status-progress-color, 0.1); border-color: rgba($flow-status-progress-color, 0.1);
color: $flow-status-progress-color; color: $flow-status-progress-color;
} }
&.test { &.test {
background-color: rgba($flow-status-test-color, 0.1); background-color: rgba($flow-status-test-color, 0.1);
border-color: rgba($flow-status-test-color, 0.1); border-color: rgba($flow-status-test-color, 0.1);
color: $flow-status-test-color; color: $flow-status-test-color;
} }
&.end { &.end {
background-color: rgba($flow-status-end-color, 0.1); background-color: rgba($flow-status-end-color, 0.1);
border-color: rgba($flow-status-end-color, 0.1); border-color: rgba($flow-status-end-color, 0.1);