Explorar el Código

财务公开图片

rongxin_prod
zhao hace 1 año
padre
commit
a3613503b3
Se han modificado 3 ficheros con 492 adiciones y 19 borrados
  1. +326
    -0
      src/components/DnD.vue
  2. +83
    -10
      src/views/sunVillage_info/list_finance_add.vue
  3. +83
    -9
      src/views/sunVillage_info/list_finance_edit.vue

+ 326
- 0
src/components/DnD.vue Ver fichero

@@ -0,0 +1,326 @@
<template>
<!-- 拖拽组件 DnD DragAndDrop -->
<!-- 针对移动端draggable不生效的解决方案 父级元素定位必须为 position: relative; -->
<!-- 属性
valueKey: 取值属性键名, 默认 value
showMask: 是否显示遮罩层, 默认 false
-->
<!-- 标签参数
touchdraggable: 是否启用拖动, 默认 false
touchdroppable: 是否允许放置, 默认 false
touchdraggroup: 拖拽分组, 默认 空(不限制), 只有同种分组的允许相互拖拽
-->
<!-- 事件
touchdragstart: 开始拖动, 参数(element: 拖动的元素)
touchdrop: 结束放置, 参数(src_element: 被拖动的元素, dst_element: 放置的元素, src_data: 被拖动元素的数据, dst_data: 放置元素的数据)
touchdropstart: 开始放置, 参数(src_element: 被拖动的元素, dst_element: 放置的元素, src_data: 被拖动元素的数据, dst_data: 放置元素的数据)
touchdragcancel: 中止拖动, 参数(element: 拖动的元素)
touchdragmotion: 拖动中(坐标改变), 参数(element: 拖动的元素)
-->
<!-- 插槽
default: 内部元素
mask: 遮罩层内部元素
-->
<!-- 事例
<DnD class="preview-cover van-ellipsis" @touchdragstart="drag" @touchdrop="drop" :value="file.index" touchdraggable touchdroppable show-mask="1" value-key="value">
<template #mask>遮罩层内部元素</template>
<div>内部元素</div>
</DnD>
-->
<div class="root"
@touchstart.stop="Drag($event)"
@touchend.stop="Drop($event)"
@touchcandel.stop="Cancel($event)"
@touchmove.stop="Motion($event)"
>
<slot name="default"></slot>
<div class="mask" v-if="maskVisible" :style="{top: `${maskY}px`, left: `${maskX}px`, 'background-color': maskColor, 'border-color': maskColor}">
<slot name="mask"></slot>
</div>
</div>

</template>

<script>

const STATE_NONE = 0; // 空闲状态
const STATE_START = 1; // 点击后等待完成长按状态
const STATE_DRAGGING = 2; // 长按状态完成, 进入拖拽状态

const HOLD_TIME_LIMIT = 200; // 从点击开始到可以允许拖拽间的最小时间间隔(模拟按住), 以区别于纯点击事件
const HOLD_POSITION_RANGE = 10/*px*/; // 从点击开始到可以允许拖拽间的最小时间间隔(模拟按住), 手指坐标距离开始点击坐标的范围限制, 以区别于手指纯滑动事件

const DRAGGABLE_NAME = 'touchdraggable'; // 允许拖动参数
const DROPPABLE_NAME = 'touchdroppable'; // 允许放置参数
const DRAGGROUP_NAME = 'touchdraggroup'; // 拖拽组名参数

const MASK_COLOR = 'rgba(0, 0, 0, 1)'; // 无放置目标时颜色
const MASK_DROP_COLOR = 'rgba(144,238,144, 1)'; // 有放置目标时颜色
const MASK_FORBID_COLOR = 'rgba(255,69,0, 1)'; // 禁止放置目标时颜色(放置到自身)

export default {
name: "DnD",
props: ['valueKey', 'showMask', ],
data() {
return {
data: null, // 拖动时存储的数据
state: STATE_NONE, // 当前拖拽状态
startX: -1, // 开始点击坐标(client)
startY: -1,
timerHandler: null, // 模拟按住的定时器
startTime: -1, // 开始点击时间
currentX: -1, // 当前触摸坐标(client)
currentY: -1,
element: null, // 被拖动的元素
dropElement: null, // 当前可放置的元素

startGlobalX: -1, // 开始点击坐标(page)
startGlobalY: -1,
maskX: 0, // 遮罩left = pageX - startGlobalX
maskY: 0, // 遮罩top = pageY - startGlobalY
maskColor: MASK_COLOR, // 遮罩提示颜色
};
},
methods: {
Drag(event) {
if(!this.HasAttr(this.GetEventElement(event), DRAGGABLE_NAME))
return;
if(this.state !== STATE_NONE)
{
console.error('Drag', 'Only support single finger!');
return;
}
this.UpdateMask(event);
this.element = this.GetEventElement(event);
[this.startX, this.startY] = this.GetEventPosition(event);
this.currentX = this.startX;
this.currentY = this.startY;
this.StartHold();
},
Drop(event) {
if(!this.HasAttr(this.GetEventElement(event), DROPPABLE_NAME))
return;
if(this.state !== STATE_DRAGGING)
{
this.Reset();
return;
}
[this.currentX, this.currentY] = this.GetEventPosition(event);
this.dropElement = this.GetCurrentPositionDropElement(event);
this.UpdateMask(event, this.HasCurrentPositionDropElement(event));
if(this.dropElement)
{
this.Log('touchdrop', this.data, this.GetValue(this.dropElement));
this.$emit('touchdrop', this.element, this.dropElement, this.data, this.GetValue(this.dropElement));
}
else
{
this.Log('touchcancel -> touchend');
this.$emit('touchdragcancel', this.element);
}
this.Reset();
this.state = STATE_NONE;
},
Motion(event) {
if(this.state === STATE_NONE)
{
this.Reset();
return;
}
[this.currentX, this.currentY] = this.GetEventPosition(event);
let dropElement = this.GetCurrentPositionDropElement(event);
this.UpdateMask(event, this.HasCurrentPositionDropElement(event));
if(dropElement && this.dropElement !== dropElement)
{
this.Log('touchdropstart', this.dropElement, dropElement);
this.$emit('touchdropstart', this.element, dropElement, this.data, this.GetValue(dropElement));
}
this.dropElement = dropElement;
this.$emit('touchdragmotion', this.element);
},
Cancel(event) {
if(this.state === STATE_DRAGGING)
{
this.Log('touchcancel -> touchcancel');
this.$emit('touchdragcancel', this.element);
}
this.Reset();
},
GetEventElement(event) {
return event.target;
},
GetEventPosition(event) {
let x = event.changedTouches[0].clientX;
let y = event.changedTouches[0].clientY;
//this.Log('GetEventPosition', x, y);
return [x, y];
},
GetEventViewportPosition(event) {
let x = event.changedTouches[0].pageX;
let y = event.changedTouches[0].pageY;
//this.Log('GetEventViewportPosition', x, y);
return [x, y];
},
GetElementByPosition(event, x, y) {
let arr = document.elementsFromPoint(x, y);
if(!arr)
return null;
let res = null;
let srcEle = this.GetEventElement(event);
for(let e of arr)
{
if(this.IsDroppable(srcEle, e))
{
res = e;
break;
}
}
//this.Log('GetElementByPosition', res, x, y);
return res;
},
IsDroppable(srcElement, elememt) {
let a = this.HasAttr(elememt, DROPPABLE_NAME);
if(!a)
return false;
let e1 = srcElement.getAttribute(DRAGGROUP_NAME);
let e2 = elememt.getAttribute(DRAGGROUP_NAME);
return e1 == e2;
},
Log(what, data) {
//console.log(...arguments);
//this.DEBUG();
},
StopHold() {
if(null !== this.timerHandler)
{
clearTimeout(this.timerHandler);
this.timerHandler = null;
}
},
StartHold() {
this.StopHold();
this.state = STATE_START;
this.startTime = Date.now();
this.timerHandler = setTimeout(this.WaitHold, HOLD_TIME_LIMIT);
},
WaitHold() {
this.timerHandler = null;
if(this.state !== STATE_START)
{
this.Log('state cancel');
this.Reset();
return;
}
if(!this.CheckPosition())
{
this.Log('CheckPosition cancel');
this.Reset();
return;
}
this.state = STATE_DRAGGING;
this.Log('touchdragstart', this.value);
this.data = this.GetValue(this.element);
this.$emit('touchdragstart', this.element);
},
Reset() {
this.StopHold();
this.state = STATE_NONE;
this.startTime = -1;
this.startX = this.startY = -1;
this.currentX = this.currentY = -1;
this.data = null;
this.element = null;
this.startGlobalX = this.startGlobalY = -1;
this.maskX = this.maskY = 0;
this.maskColor = MASK_COLOR;
this.dropElement = null;
},
CheckPosition() {
if(this.startX < 0 || this.startY < 0)
return false;
if(this.currentX < 0 || this.currentY < 0)
return false;
let deltaX = this.currentX - this.startX;
let deltaY = this.currentY - this.startY;
return deltaX * deltaX + deltaY * deltaY <= HOLD_POSITION_RANGE * HOLD_POSITION_RANGE;
},
DEBUG() {
console.log(
`state: ${this.state}
start: [${this.startX}, ${this.startY}]
startTime: ${this.startTime}
timerHandler: ${this.timerHandler}
data: ${this.data}
current: [${this.currentX}, ${this.currentY}]
`);
},
HasAttr(element, name) {
let a = element.getAttribute(name);
return a !== null && a !== undefined;
},
GetValue(element) {
return element.getAttribute(this._valueKey)
},
UpdateMask(event, element) {
let [x, y] = this.GetEventViewportPosition(event);
if(this.startGlobalX < 0)
{
this.startGlobalX = x;
}
if(this.startGlobalY < 0)
{
this.startGlobalY = y;
}
this.maskX = x - this.startGlobalX;
this.maskY = y - this.startGlobalY;
this.maskColor = element > 0 ? MASK_DROP_COLOR : (element < 0 ? MASK_COLOR : MASK_FORBID_COLOR);
},
GetCurrentPositionDropElement(event) {
let element = this.GetElementByPosition(event, this.currentX, this.currentY);
if(element && element !== this.GetEventElement(event))
return element;
return null;
},
HasCurrentPositionDropElement(event) {
let element = this.GetElementByPosition(event, this.currentX, this.currentY);
if(!element)
return -1;
if(element === this.GetEventElement(event))
return 0;
return 1;
},
},
computed: {
_valueKey() {
return this.valueKey || 'value';
},
maskVisible() {
return !!this.showMask && this.state === STATE_DRAGGING;
},
},
}
</script>

<style scoped>
.root {
position: absolute;
bottom: 0;
top: 0;
left: 0;
right: 0;
background: rgba(0, 0, 0, 0);
overflow: visible;
}
.mask {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0, 0, 0, 1);
z-index: 99;
opacity: 0.6;
border-width: 4px;
border-style: solid;
}
</style>

+ 83
- 10
src/views/sunVillage_info/list_finance_add.vue Ver fichero

@@ -50,7 +50,17 @@
</template>
</van-field>
<!-- @delete="deleteFile1"-->
<van-uploader v-model="fileList" multiple :after-read="afterRead" @delete="deleteFile1" style="margin-top: 10PX" />
<van-uploader v-model="fileList" multiple :after-read="afterRead" @delete="deleteFile1" style="margin-top: 10PX">
<template #preview-cover="file">
<DnD class="van-ellipsis" @touchdragstart="drag" @touchdrop="drop" :value="file.index" touchdraggable touchdroppable show-mask="1">
<template #mask>
<div class="preview-cover">
<img :src="file.url || file.content" class="van-image__img" style="object-fit: cover;"/>
</div>
</template>
</DnD>
</template>
</van-uploader>

<div style="border-top: 1px solid #ededed;margin-top: 10PX;">
<van-field readonly input-align="right" :border="false" >
@@ -94,8 +104,10 @@
import { commonUpload , openAdd } from "@/api/sunVillage_info/fixedAssets";
import Cookies from "js-cookie";
import request from '@/utils/request'
import DnD from "@/components/DnD";
export default {
name: "certificateList",
components: {DnD},
data() {
return {
showBuildTime:false,
@@ -140,7 +152,11 @@
console.log(this.openPic)
var that = this;
that.form.openFile = that.openFile2.join(',')
that.form.openPic = that.openPic2.join(',')
//that.form.openPic = that.openPic2.join(',')
that.form.openPic = that.fileList
.filter((x) => x.url && x.url.startsWith('/api'))
.map((x) => x.url.substr(4))
.join(',');
openAdd(that.form).then((r1) => {
if (r1.code == 200){
that.$notify({ type: 'success', message: '新增成功' });
@@ -172,20 +188,42 @@
});
// 此时可以自行将文件上传至服务器
if (file instanceof Array){//判断是否为数组,单张图片为array,多张为数组,数组返回true否则为false
file.map(res=>{
this.openPic.push(res.file);
let params1 = new FormData();
params1.append("file", res.file);
commonUpload(params1).then((r1) => {
this.openPic2.push(r1.fileName);
if(false) // 顺序上传
{
let SequenceUpload = (list, index) => {
if(index >= list.length)
return;
let res = list[index];
this.openPic.push(res.file);
let params1 = new FormData();
params1.append("file", res.file);
commonUpload(params1).then((r1) => {
this.openPic2.push(r1.fileName);
res.url = '/api' + r1.fileName;
SequenceUpload(list, index + 1);
})
};
SequenceUpload(file, 0);
}
else
{
file.map(res=>{
this.openPic.push(res.file);
let params1 = new FormData();
params1.append("file", res.file);
commonUpload(params1).then((r1) => {
this.openPic2.push(r1.fileName);
res.url = '/api' + r1.fileName;
})
})
})
}
}else{
this.openPic.push(file);
let params1 = new FormData();
params1.append("file", file.file);
commonUpload(params1).then((r1) => {
this.openPic2.push(r1.fileName);
file.url = '/api' + r1.fileName;
})
}
},
@@ -205,7 +243,30 @@
}
this.openFileList.push({name:file.file.name,type:type})
this.openFile.push(file.file);
}
},
drag(src_element) {
//console.log("drag", event);
},
drop(src_element, dst_element, srcData, dstData) {
//console.log("drop", event);
let srcIndex = parseInt(srcData);
let index = parseInt(dstData);
//console.log(srcIndex, index,this.fileList);
if(srcIndex !== index)
{
let src = this.fileList[srcIndex];
if(srcIndex > index)
{
this.fileList.splice(srcIndex, 1);
this.fileList.splice(index, 0, src);
}
else
{
this.fileList.splice(srcIndex, 1);
this.fileList.splice(index, 0, src);
}
}
},
},
}
</script>
@@ -325,5 +386,17 @@
/deep/ .van-field__error-message{
display: none;
}
.preview-cover {
position: absolute;
bottom: 0;
top: 0;
left: 0;
right: 0;
background: rgba(0, 0, 0, 0);
}

/deep/ .van-uploader__preview-image {
overflow: visible;
}
}
</style>

+ 83
- 9
src/views/sunVillage_info/list_finance_edit.vue Ver fichero

@@ -50,7 +50,17 @@
</template>
</van-field>
<!-- @delete="deleteFile1"-->
<van-uploader v-model="openPic" multiple :after-read="afterRead" @delete="deleteFile1" style="margin-top: 10PX" />
<van-uploader v-model="openPic" multiple :after-read="afterRead" @delete="deleteFile1" style="margin-top: 10PX" >
<template #preview-cover="file">
<DnD class="van-ellipsis" @touchdragstart="drag" @touchdrop="drop" :value="file.index" touchdraggable touchdroppable show-mask="1">
<template #mask>
<div class="preview-cover">
<img :src="file.url || file.content" class="van-image__img" style="object-fit: cover;"/>
</div>
</template>
</DnD>
</template>
</van-uploader>

<div style="border-top: 1px solid #ededed;margin-top: 10PX;">
<van-field readonly input-align="right" :border="false" >
@@ -94,8 +104,11 @@
import { commonUpload , openEdit , financePublicDetail } from "@/api/sunVillage_info/fixedAssets";
import Cookies from "js-cookie";
import request from '@/utils/request'
import DnD from "@/components/DnD";

export default {
name: "certificateList",
components: {DnD},
data() {
return {
showBuildTime:false,
@@ -167,7 +180,11 @@
onSubmit(){
var that = this;
that.form.openFile = that.openFile2.join(',')
that.form.openPic = that.openPic2.join(',')
//that.form.openPic = that.openPic2.join(',')
that.form.openPic = that.openPic
.filter((x) => x.url && x.url.startsWith('/api'))
.map((x) => x.url.substr(4))
.join(',');
openEdit(that.form).then((r1) => {
if (r1.code == 200){
that.$notify({ type: 'success', message: '修改成功' });
@@ -197,18 +214,40 @@
duration: 0,
});
if (file instanceof Array){//判断是否为数组,单张图片为array,多张为数组,数组返回true否则为false
file.map(res=>{
let params1 = new FormData();
params1.append("file", res.file);
commonUpload(params1).then((r1) => {
this.openPic2.push(r1.fileName);
if(false) // 顺序上传
{
let SequenceUpload = (list, index) => {
if(index >= list.length)
return;
let res = list[index];
this.openPic.push(res.file);
let params1 = new FormData();
params1.append("file", res.file);
commonUpload(params1).then((r1) => {
this.openPic2.push(r1.fileName);
res.url = '/api' + r1.fileName;
SequenceUpload(list, index + 1);
})
};
SequenceUpload(file, 0);
}
else
{
file.map(res => {
let params1 = new FormData();
params1.append("file", res.file);
commonUpload(params1).then((r1) => {
this.openPic2.push(r1.fileName);
res.url = '/api' + r1.fileName;
})
})
})
}
}else{
let params1 = new FormData();
params1.append("file", file.file);
commonUpload(params1).then((r1) => {
this.openPic2.push(r1.fileName);
file.url = '/api' + r1.fileName;
})
}
},
@@ -228,7 +267,30 @@
}
this.openFile.push({name:file.file.name,type:type})
this.openFileList.push(file.file);
}
},
drag(src_element) {
//console.log("drag", event);
},
drop(src_element, dst_element, srcData, dstData) {
//console.log("drop", event);
let srcIndex = parseInt(srcData);
let index = parseInt(dstData);
//console.log(srcIndex, index,this.openPic);
if(srcIndex !== index)
{
let src = this.openPic[srcIndex];
if(srcIndex > index)
{
this.openPic.splice(srcIndex, 1);
this.openPic.splice(index, 0, src);
}
else
{
this.openPic.splice(srcIndex, 1);
this.openPic.splice(index, 0, src);
}
}
},
},
}
</script>
@@ -348,5 +410,17 @@
/deep/ .van-field__error-message{
display: none;
}
.preview-cover {
position: absolute;
bottom: 0;
top: 0;
left: 0;
right: 0;
background: rgba(0, 0, 0, 0);
}

/deep/ .van-uploader__preview-image {
overflow: visible;
}
}
</style>

Cargando…
Cancelar
Guardar