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

View File

@ -2,7 +2,7 @@
<div class="common-img-update">
<div v-if="type !== 'callback'" class="imgcomp-upload-list" v-for="item in uploadList">
<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">
<Icon type="ios-eye-outline" @click.native="handleView(item)"></Icon>
<Icon type="ios-trash-outline" @click.native="handleRemove(item)"></Icon>
@ -13,7 +13,7 @@
</template>
</div>
<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>
</div>
<div class="add-box-upload">
@ -77,314 +77,361 @@
</template>
<script>
export default {
name: 'ImgUpload',
props: {
value: {
},
num: {
},
width: {
},
height: {
},
whcut: {
},
type: {
},
http: {
type: Boolean,
default: false
},
otherParams: {
type: Object,
default: () => {
return {};
import {languageList} from "../language";
export default {
name: 'ImgUpload',
props: {
value: {},
num: {},
width: {},
height: {},
whcut: {},
type: {},
http: {
type: Boolean,
default: false
},
otherParams: {
type: Object,
default: () => {
return {};
}
},
uploadIng: {
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 {
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
});
},
watch: {
value(val) {
if (typeof val === 'string') {
this.$emit('input', this.initItems(val));
return;
}
},
mounted () {
if (val === this.$refs.upload.fileList) {
return;
}
this.$refs.upload.fileList = this.initItems(val);
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: {
value (val) {
if (typeof val === 'string') {
this.$emit('input', this.initItems(val));
return;
}
if (val === this.$refs.upload.fileList) {
return;
}
this.$refs.upload.fileList = this.initItems(val);
this.uploadList = this.$refs.upload.fileList;
},
browseVisible() {
this.httpType = '';
this.httpValue = '';
browseVisible() {
this.httpType = '';
this.httpValue = '';
}
},
computed: {
uploadHeaders() {
return {
fd: $A.getSessionStorageString("userWsFd"),
token: this.userToken,
}
},
computed: {
uploadHeaders() {
return {
fd: $A.getSessionStorageString("userWsFd"),
token: this.userToken,
}
},
uploadParams() {
let params = {
width: this.width,
height: this.height,
whcut: this.whcut,
};
if (Object.keys(this.otherParams).length > 0) {
return Object.assign(params, this.otherParams);
} else {
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;
uploadParams() {
let params = {
width: this.width,
height: this.height,
whcut: this.whcut,
};
if (Object.keys(this.otherParams).length > 0) {
return Object.assign(params, this.otherParams);
} else {
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;
},
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>

View File

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

View File

@ -45,6 +45,9 @@
left: 0;
right: 0;
background: rgba(0, 0, 0, .6);
flex-direction: row;
align-items: center;
justify-content: center;
}
.imgcomp-upload-list-cover i {
@ -74,7 +77,7 @@
}
.imgcomp-upload-list:hover .imgcomp-upload-list-cover {
display: block;
display: flex;
}
.img-upload-foot {
@ -111,10 +114,11 @@
vertical-align: top;
.add-box-icon {
i {
vertical-align: middle;
padding-bottom: 2px;
}
display: flex;
align-items: center;
justify-content: center;
width: 100%;
height: 100%;
}
.add-box-upload {
@ -132,8 +136,12 @@
height: 22px;
line-height: 22px;
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;
border: 0;
border-radius: 0;
@ -260,3 +268,17 @@
background-color: rgba(255, 255, 255, 0.9);
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-wrapper";
@import "file-content";
@import "general-operation";
@import "meeting-manager";
@import "project-archived";
@import "project-dialog";
@ -20,7 +21,6 @@
@import "task-deleted";
@import "task-detail";
@import "task-menu";
@import "task-operation";
@import "task-priority";
@import "task-move";
@import "team-management";

View File

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