This commit is contained in:
ln1778 2024-09-06 16:17:51 +08:00
parent fb6bba617a
commit ba97fbca46
5 changed files with 511 additions and 55 deletions

View File

@ -9,7 +9,8 @@
"lib": "vue-cli-service build --target lib --dest lib packages/index.js"
},
"dependencies": {
"core-js": "^3.8.3"
"core-js": "^3.8.3",
"vuedraggable": "^2.24.3"
},
"devDependencies": {
"@vue/cli-plugin-babel": "~5.0.0",
@ -20,9 +21,9 @@
"element-ui": "^2.15.14",
"sass": "^1.32.7",
"sass-loader": "^12.0.0",
"vue-template-compiler": "^2.6.14",
"vue": "^2.6.14",
"vue-router": "^3.5.1",
"vue-template-compiler": "^2.6.14",
"vuex": "^3.6.2"
},
"browserslist": [

View File

@ -1,18 +1,66 @@
<template>
<div class="uploadbox">
<div class="uploadimgbox" :style="{height:width+'px'}">
<div v-for="img,index in fileList" :key="index" :style="{width:width+'px'}" class="imgitem" @dragstart="onDragstart" @dragenter="onDragenter" @dragover="onDragover" @dragend="onDragend">
<img :src="img.url" class="img"/>
<div class="uploadimgbox" :style="{height:width+'px'}" v-if="listType=='picture-card'">
<div v-for="img,index in imageList" :key="index" :style="{width:width+'px'}" :draggable="dragmove" class="imgitem" :class="dragmove&&dragmoveclass" @dragstart="onDragstart" @dragenter="onDragenter" @dragover="onDragover" @dragend="onDragend" @dragleave="onMouseup" >
<slot name="file" :file="img">
<img :src="img.url" class="img" v-if="img.type.indexOf('image')>-1"/>
<div v-else class="filetext">
<div class="filetitletext">文件</div>
<div>{{img.name}}</div>
</div>
<div class="uploadimgmask" v-if="clear||isPrew" >
<i class="el-icon-search" v-if="isPrew" @click="handlePictureCardPreview(img)"></i>
<i class="el-icon-search" v-if="isPrew&&img.type.indexOf('image')>-1" @click="handlePictureCardPreview(img)"></i>
<i class="el-icon-delete" v-if="clear" @click="handleRemove(img.raw,index)"></i>
</div>
</slot>
</div>
<div class="uploadcontain" :style="{width:width+'px'}">
<label for="uploadinput" class="uploadlabel"> <i class="el-icon-plus"></i></label>
<input key="" type="file" style="display:none;" :multiple="$attrs.multiple" id="uploadinput" @change="onUpdate"/>
<div class="uploadcontain" :style="{height:width+'px',aspectRatio:isDrap?4/3:1/1}"
:draggable="isDrap"
@dragover.prevent
@dragenter.prevent
@drop="onUploadDrap"
v-if="limit>imageList.length">
<label for="uploadinput" class="uploadlabel" @click="onInputClick">
<slot>
<i class="el-icon-plus"></i>
<span class="draptiptext">{{isDrap?'拖拽上传':'上传'}}</span>
</slot>
</label>
</div>
</div>
<div class="uploadtextbox" v-if="listType=='text'||listType=='picture'">
<div class="uploadtextcontain"
:draggable="isDrap"
@dragover.prevent
@dragenter.prevent
@drop="onUploadDrap"
>
<label for="uploadinput" class="uploadlabel" @click="onInputClick" >
<slot>
<el-button type="primary" size="small"><i class="el-icon-plus"></i> {{isDrap?'拖拽上传':'上传'}}</el-button>
</slot>
</label>
</div>
<slot name="tip">
</slot>
<ul class="uploadtextlist" :class="'upload-list--'+listType">
<li v-for="img,index in imageList" :key="index" class="uploadtextitem" >
<slot name="file" :file="img">
<img v-if="listType=='picture'" :src="img.url" class="ag-upload-list__item-thumbnail" />
<a class="ag-upload-list__item-name" @click="handlePictureCardPreview(img)"><i class="el-icon-document ag-icon-document"></i>{{img.name}}
</a>
</slot>
<el-popconfirm
:title="`确定移除${img.name}吗?`"
@confirm="handleRemove(img.raw,index)"
>
<i class="el-icon-close ag-icon-close" slot="reference"></i>
</el-popconfirm>
</li>
</ul>
</div>
<input type="file" style="display:none;" :multiple="limit>1" :accept="$attrs.accept" id="uploadinput" @change="onUpdate" ref="fileinputref"/>
<el-dialog :visible.sync="dialogVisible">
<img width="100%" :src="dialogImageUrl" alt="">
</el-dialog>
@ -20,7 +68,6 @@
</template>
<script>
export default {
name: "agUpdate",
props:{
@ -35,68 +82,252 @@
width:{
type:Number,
default:80
},
dragmove:{
type:Boolean,
default:false
},
isDrap:{
type:Boolean,
default:false
},
limit:{
type:Number,
default:1
},
fileList:{
type:Array,
default(){
return [];
}
},
listType:{
type:String,
default:'picture-card'
}
},
mounted() {
if(this.fileList.length>0){
let list=[];
this.fileList.map((h)=>{
if(typeof(h)=='object'){
list.push(h);
}else{
let imgurl=h.split("/");
let filename=imgurl[imgurl.length-1];
let extarr=h.split(".");
let extname=extarr[extarr.length-1];
if(['jpg','jpeg','png','gif','svg'].indexOf(extname)>-1){
list.push({
name:filename,
url:h,
type:'image/'+extname.toLowerCase(),
raw:null
});
}else{
list.push({
name:filename,
url:h,
type:'other/'+extname.toLowerCase(),
raw:null
});
}
}
});
this.imageList=list;
}
},
watch:{
fileList(val){
if(val.length>0){
let list=[];
val.map((h)=>{
if(typeof(h)=='object'){
list.push(h);
}else{
let imgurl=h.split("/");
let filename=imgurl[imgurl.length-1];
let extarr=h.split(".");
let extname=extarr[extarr.length-1];
if(['jpg','jpeg','png','gif','svg'].indexOf(extname)>-1){
list.push({
name:filename,
url:h,
type:'image/'+extname.toLowerCase(),
raw:null
});
}else{
list.push({
name:filename,
url:h,
type:'other/'+extname.toLowerCase(),
raw:null
});
}
}
});
this.imageList=list;
}
}
},
data() {
return {
dialogImageUrl: '',
dialogVisible: false,
fileList:[]
imageList:[],
sourceNode:null,
partNode:null,
selectTop:false,
drag:false,
dragmoveclass:'imghover'
};
},
mounted() {
},
methods: {
handleRemove(file,index) {
this.fileList=this.fileList.filter((item,inkey)=>{
this.imageList=this.imageList.filter((item,inkey)=>{
return inkey !== index;
});
this.$emit('onRemove',file,this.fileList);
this.$emit('onRemove',file,this.imageList);
},
handlePictureCardPreview(file) {
this.dialogImageUrl = file.url;
console.log(this.dialogImageUrl,'this.dialogImageUrl');
this.dialogVisible = true;
},
onUpdate(e){
if(this.limit<=this.imageList.length){
return;
}
try{
let uplist=[];
let files=[...e.target.files];
let files=[...e.target.files].slice(0,this.limit-this.imageList.length);
const find=files.find((f,i)=>{
if(this.$attrs.accept){
let acceptarr=this.$attrs.accept.split(",");
if(!acceptarr.includes(f.type)){
if(this.$listeners.onError){
this.$emit('onError',`其中第${i+1}张图片类型错误`);
}
return true;
}
}
if(this.$attrs.maxSize){
if(f.size>this.$attrs.maxSize){
if(this.$listeners.onError){
this.$emit('onError',`其中第${i+1}张图片大小不能超过${this.$attrs.maxSize/1024/1024}M"`);
}
return true;
}
}
});
if(find){
return;
}
files.map((item,index) => {
let filerender=new FileReader();
filerender.onload=function(e){
uplist.push({
name:item.name,
url:e.target.result,
type:item.type,
size:item.size,
raw:item
});
if(files.length==uplist.length){
this.fileList.push(...uplist);
this.$emit('onUpload',uplist,this.fileList);
this.imageList.push(...uplist);
this.$emit('onUpload',uplist,this.imageList);
}
}.bind(this);
filerender.readAsDataURL(item);
});
}catch(e){
if(this.$listeners.onError){
this.$emit('onError',e);
}
}
},
onDragstart(e){
e.preventDefault();
console.log(e,"eee");
this.sourceNode=e.target;
this.partNode=e.target.parentNode;
e.target.classList.add("tabsbg");
setTimeout(()=>{
e.target.classList.remove("tabsbg");
e.target.classList.add("moving");
},1);
},
onDragenter(e){
e.preventDefault();
console.log(e,"eee");
if(!this.dragmove){
return;
}
if(this.partNode===e.target||e.target===this.sourceNode){
return
}
const childrens=[...this.partNode.children];
let thistarget=childrens.find((f)=>f==e.target);
if(!thistarget){
thistarget=e.target.parentNode;
}
if(!thistarget){
return
}
const sourceIndex=childrens.indexOf(this.sourceNode);
const targetIndex=childrens.indexOf(thistarget);
if(sourceIndex<targetIndex){
this.partNode.insertBefore(this.sourceNode,thistarget.nextElementSibling);
}else{
this.partNode.insertBefore(this.sourceNode,thistarget);
}
},
onDragover(e){
e.preventDefault();
console.log(e,"eee");
},
onMouseup(e){
e.preventDefault();
if(!this.dragmove){
return;
}
if(this.partNode===e.target||e.target===this.sourceNode){
return
}
this.sourceNode.classList.remove("moving");
},
onDragend(e){
e.preventDefault();
console.log(e,"eee");
if(!this.dragmove){
return;
}
e.target.classList.remove("moving");
e.target.classList.remove("tabsbg");
this.sourceNode.classList.remove("moving");
if(this.partNode===e.target||e.target===this.sourceNode){
return
}
const childrens=[...this.partNode.children];
const sourceIndex=childrens.indexOf(this.sourceNode);
const item = this.imageList.splice(sourceIndex, 1)[0];
this.imageList.splice(sourceIndex, 0, item);
this.sourceNode=null;
this.partNode=null;
},
onUploadDrap(e){
e.preventDefault(); //
e.stopPropagation(); //
if(this.drap){
return;
}
const files = event.dataTransfer.files;
this.onUpdate({target:{files: files}});
},
onInputClick(e){
e.preventDefault(); //
e.stopPropagation(); //
this.$refs.fileinputref.click();
}
},
};
</script>
@ -115,10 +346,18 @@
color:#97a8be;
display: block;
width:100%;
cursor: pointer;
height:100%;
display: flex;
align-items: center;
justify-content: center;
flex-direction: column;
.draptiptext{
font-size:13px;
color:#666;
text-align: center;
margin-top: 5px;
}
}
}
.uploadimgbox{
@ -135,6 +374,23 @@
border-radius: 4px;
overflow: hidden;
aspect-ratio: 1/1;
transition: all .3s;
&.imghover:hover{
cursor: move;
}
&.tabsbg{
border-radius:6px 6px 0 0;
background:#fff;
overflow:hidden;
}
&.opcacityzero{
opacity: 0;
}
&.moving{
opacity: 0;
visibility: hidden;
}
img{
display: block;
aspect-ratio: 1/1;
@ -151,6 +407,7 @@
align-items: center;
justify-content: center;
gap:6px;
z-index: 1;
i{
font-size: 20px;
color:#fff;
@ -163,8 +420,186 @@
}
}
}
.filetext{
font-size:12px;
display: flex;
justify-content: center;
flex-direction: column;
padding:5px;
box-sizing: border-box;
overflow: hidden;
height:100%;
white-space: nowrap; /* 文本不换行 */
overflow: hidden; /* 隐藏溢出的内容 */
text-overflow: ellipsis;
text-align: center;
.filetitletext{
font-size:15px;
}
}
}
.uploadtextbox{
.uploadtextcontain{
.uploadtextcontaindefaultbtn{
display:flex;
align-items:center;
gap:5px;
background: #fff;
width:fit-content;
padding:5px 12px;
box-sizing: border-box;
border-radius:4px;
font-size:13px;
}
}
.uploadtextlist{
display: block;
list-style-type: disc;
margin-inline-start: 0px;
margin-inline-end: 0px;
padding-inline-start: 40px;
unicode-bidi: isolate;
margin: 0;
padding: 0;
list-style: none;
.upload-list--text{
&:first-child{
margin-top: 10px;
}
position: relative;
list-style: none;
transition: all .5s cubic-bezier(.55,0,.1,1);
font-size: 14px;
color: #606266;
line-height:1;
margin-top: 5px;
position: relative;
display: flex;
align-items: center;
justify-content: space-between;
box-sizing: border-box;
cursor: pointer;
border-radius: 4px;
width: 100%;
&:hover{
background-color: #f5f7fa;
.ag-icon-close{
display:inline-block;
}
}
.ag-upload-list__item-name{
text-decoration: none;
color: #606266;
display: block;
margin-right: 40px;
overflow: hidden;
padding-left: 4px;
text-overflow: ellipsis;
transition: color .3s;
white-space: nowrap;
font-size: 14px;
line-height: 1.8;
.ag-icon-document{
height: 100%;
margin-right: 7px;
color: #909399;
line-height: inherit;
&:hover{
color: #409eff;
cursor: pointer;
}
}
}
.el-icon-close{
position: relative;
right: 5px;
cursor: pointer;
opacity: .75;
color: #606266;
display:none;
}
}
}
.upload-list--picture{
margin: 0;
padding: 0;
list-style: none;
.uploadtextitem{
overflow: hidden;
position: relative;
z-index: 0;
background-color: #fff;
border: 1px solid #c0ccda;
border-radius: 6px;
box-sizing: border-box;
margin-top: 10px;
padding: 10px 10px 10px 90px;
height: 92px;
gap:10px;
display: flex;
align-items: center;
cursor: pointer;
&:hover{
.ag-icon-close{
display:inline-block;
}
}
.ag-upload-list__item-thumbnail{
vertical-align: middle;
display: inline-block;
width: 70px;
height: 70px;
float: left;
position: relative;
z-index: 1;
margin-left: -80px;
background: #fff;
}
.ag-upload-list__item-name{
flex:1;
color: #606266;
display: block;
margin-right: 40px;
overflow: hidden;
padding-left: 4px;
text-overflow: ellipsis;
transition: color .3s;
white-space: nowrap;
line-height: 70px;
margin-top: 0;
text-decoration: none;
.ag-icon-document{
display:none;
}
&:hover{
color: #409eff;
cursor: pointer;
}
}
.ag-icon-close{
position: absolute;
font-family: element-icons !important;
font-style: normal;
font-weight: 400;
font-variant: normal;
text-transform: none;
line-height: 1;
vertical-align: baseline;
display: none;
-webkit-font-smoothing: antialiased;
line-height: 1;
top: 5px;
right: 5px;
cursor: pointer;
opacity: .75;
color: #606266;
}
}
}
}
::v-deep {
.el-table {
width: 100%;

View File

@ -47,8 +47,9 @@
<div>{{row.date}} </div>
</template>
</agTable>
<agUpdate @onUpload="onUpload" multiple >
<agUpdate @onUpload="onUpload" multiple isDrap :limit="5" @onError="onError" listType="picture" :maxSize="1024*1024" :fileList="['https://git.aiguoai.com/assets/img/logo.svg']">
<el-button type="primary" size="small">点击上传</el-button>
<div slot="tip">只能上传jpg/png文件且不超过500kb</div>
</agUpdate>
<!-- <el-input
size="small"
@ -78,10 +79,13 @@ import agCascadeOptional from "../packages/agCascadeOptional/src/index.vue";
import agMultifunctionSearch from "../packages/agMultifunctionSearch/src/index.vue";
import agQuery from "../packages/agQuery/src/index.vue";
import agTable from "../packages/agTable/src/index.vue";
import vuedraggable from 'vuedraggable';
import agElemUI from "../packages/index.js";
Vue.use(ElementUI);
Vue.use(agElemUI);
// Vue.use(vuedraggable);
Vue.component('vuedraggable', window.vuedraggable)
export default {
@ -94,7 +98,8 @@ export default {
agCascadeOptional,
agMultifunctionSearch,
agQuery,
agTable
agTable,
vuedraggable
},
data() {
var validatePass = (rule, value, callback) => {
@ -371,7 +376,10 @@ export default {
},
methods: {
onUpload(files,filelist){
console.log("onblur",files,filelist);
console.log("onUpload",files,filelist);
},
onError(err){
console.log("onError",err);
},
onblur(val,elem){
console.log("onblur",val,elem,this);

View File

@ -4,12 +4,12 @@ import Vue from 'vue';
import App from './App.vue';
import router from './router';
import store from './store';
import vuedraggable from 'vuedraggable';
import agElemUI from "../packages/index.js";
console.log('main.js', process.env);
Vue.use(ElementUI);
Vue.use(agElemUI);
Vue.use(vuedraggable);

View File

@ -5130,6 +5130,11 @@ sockjs@^0.3.24:
uuid "^8.3.2"
websocket-driver "^0.7.4"
sortablejs@1.10.2:
version "1.10.2"
resolved "http://112.124.55.31:4873/sortablejs/-/sortablejs-1.10.2.tgz#6e40364d913f98b85a14f6678f92b5c1221f5290"
integrity sha512-YkPGufevysvfwn5rfdlGyrGjt7/CRHwvRPogD/lC+TnvcN29jDpCifKP+rBqf+LRldfXSTh+0CGLcSg0VIxq3A==
"source-map-js@>=0.6.2 <2.0.0", source-map-js@^1.2.0:
version "1.2.0"
resolved "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.0.tgz#16b809c162517b5b8c3e7dcd315a2a5c2612b2af"
@ -5576,6 +5581,13 @@ vue@^2.6.14:
"@vue/compiler-sfc" "2.7.16"
csstype "^3.1.0"
vuedraggable@^2.24.3:
version "2.24.3"
resolved "http://112.124.55.31:4873/vuedraggable/-/vuedraggable-2.24.3.tgz#43c93849b746a24ce503e123d5b259c701ba0d19"
integrity sha512-6/HDXi92GzB+Hcs9fC6PAAozK1RLt1ewPTLjK0anTYguXLAeySDmcnqE8IC0xa7shvSzRjQXq3/+dsZ7ETGF3g==
dependencies:
sortablejs "1.10.2"
vuex@^3.6.2:
version "3.6.2"
resolved "https://registry.npmjs.org/vuex/-/vuex-3.6.2.tgz#236bc086a870c3ae79946f107f16de59d5895e71"