|
|
|
<template>
|
|
|
|
<view>
|
|
|
|
<scroll-view scroll-y="true">
|
|
|
|
<view v-if="!changeEvent">
|
|
|
|
<view :id="'cu-' + index" :key="item.id" class="cu-item flex-col" v-for="(item, index) in itemList">
|
|
|
|
<ProjectItem
|
|
|
|
class="w-full"
|
|
|
|
:index="index"
|
|
|
|
:item="item"
|
|
|
|
:menuList="menuList"
|
|
|
|
@chooseAction="chooseAction"
|
|
|
|
@openSubProject="openSubProject"
|
|
|
|
/>
|
|
|
|
</view>
|
|
|
|
</view>
|
|
|
|
<view v-else>
|
|
|
|
<view
|
|
|
|
:id="'cu-' + index"
|
|
|
|
:key="index"
|
|
|
|
:style="{ 'background-color': item.color }"
|
|
|
|
@touchend="stops($event, index)"
|
|
|
|
@touchmove.stop.prevent="move"
|
|
|
|
@touchstart="start($event, index)"
|
|
|
|
class="cu-item flex-col"
|
|
|
|
v-for="(item, index) in itemList"
|
|
|
|
>
|
|
|
|
<view class="border-100 bg-blue-500" v-if="item.showTopBorder"></view>
|
|
|
|
<!-- 内容区 -->
|
|
|
|
<!-- 父项目 -->
|
|
|
|
<view class="w-full">
|
|
|
|
<view class="flex items-center justify-between p-3">
|
|
|
|
<u-icon class="mover" name="https://www.tall.wiki/staticrec/drag.svg" size="48"></u-icon>
|
|
|
|
|
|
|
|
<view class="flex-1 px-3">
|
|
|
|
<view class="flex items-center mb-1">
|
|
|
|
<view class="mr-2">{{ item.name }}</view>
|
|
|
|
<!-- 状态 TODO:-->
|
|
|
|
<view class="px-2 text-xs text-green-400 bg-green-100 rounded-full">进行中</view>
|
|
|
|
</view>
|
|
|
|
|
|
|
|
<view class="flex items-center text-xs text-gray-400">
|
|
|
|
<view class="pr-2">{{ $moment(+item.startTime).format('MM-DD HH:mm') }}</view>
|
|
|
|
至
|
|
|
|
<view class="pl-2">{{ $moment(+item.endTime).format('MM-DD HH:mm') }}</view>
|
|
|
|
</view>
|
|
|
|
</view>
|
|
|
|
|
|
|
|
<!-- 箭头 -->
|
|
|
|
<view v-if="item.sonProjectList && item.sonProjectList.length">
|
|
|
|
<u-icon
|
|
|
|
@click="openSubProject(item.sonProjectList.length, index)"
|
|
|
|
class="text-gray-400"
|
|
|
|
name="arrow-up"
|
|
|
|
size="14px"
|
|
|
|
v-if="item.show"
|
|
|
|
></u-icon>
|
|
|
|
<u-icon
|
|
|
|
@click="openSubProject(item.sonProjectList.length, index)"
|
|
|
|
class="text-gray-400"
|
|
|
|
name="arrow-down"
|
|
|
|
size="14px"
|
|
|
|
v-else
|
|
|
|
></u-icon>
|
|
|
|
</view>
|
|
|
|
<u-icon class="text-gray-400" name="arrow-right" size="14px" v-else></u-icon>
|
|
|
|
</view>
|
|
|
|
<!-- 父项目 end -->
|
|
|
|
<!-- 子项目 -->
|
|
|
|
<view class="ml-8" v-if="item.show">
|
|
|
|
<view
|
|
|
|
:id="'cu-' + index + '-' + subIndex"
|
|
|
|
:key="subIndex"
|
|
|
|
@touchend.stop.prevent="stops($event, index + '-' + subIndex, item.sonProjectList.length)"
|
|
|
|
@touchmove.stop.prevent="move($event, item.sonProjectList.length)"
|
|
|
|
@touchstart.stop.prevent="start($event, index + '-' + subIndex)"
|
|
|
|
class="cu-item flex-col"
|
|
|
|
v-for="(subItem, subIndex) in item.sonProjectList"
|
|
|
|
>
|
|
|
|
<view class="flex items-center justify-between p-3 w-full">
|
|
|
|
<u-icon class="mover" name="https://www.tall.wiki/staticrec/drag.svg" size="48"></u-icon>
|
|
|
|
|
|
|
|
<view class="flex-1 px-3">
|
|
|
|
<view class="flex items-center">
|
|
|
|
<view class="mr-2">{{ subItem.name }}</view>
|
|
|
|
<!-- 状态 -->
|
|
|
|
<view
|
|
|
|
:class="
|
|
|
|
subItem.status === 0
|
|
|
|
? 'text-blue-400 bg-blue-100'
|
|
|
|
: subItem.status === 1
|
|
|
|
? 'text-green-400 bg-green-100'
|
|
|
|
: subItem.status === 2
|
|
|
|
? 'text-red-400 bg-red-100'
|
|
|
|
: 'text-gray-400 bg-gray-100'
|
|
|
|
"
|
|
|
|
class="px-2 text-xs text-gray-400 bg-gray-100 rounded-full"
|
|
|
|
>
|
|
|
|
{{ subItem.status === 0 ? '未开始' : subItem.status === 1 ? '进行中' : subItem.status === 2 ? '暂停' : '已完成' }}
|
|
|
|
</view>
|
|
|
|
</view>
|
|
|
|
</view>
|
|
|
|
|
|
|
|
<!-- 箭头 -->
|
|
|
|
<u-icon class="text-gray-400" name="arrow-right" size="14px"></u-icon>
|
|
|
|
</view>
|
|
|
|
</view>
|
|
|
|
</view>
|
|
|
|
</view>
|
|
|
|
<!-- 内容区 end -->
|
|
|
|
<view class="border-100 bg-blue-500" v-if="item.showBorder"></view>
|
|
|
|
<view class="border-80 bg-blue-500" v-if="item.showSubBorder"></view>
|
|
|
|
</view>
|
|
|
|
</view>
|
|
|
|
</scroll-view>
|
|
|
|
<!-- 移动悬浮 begin -->
|
|
|
|
<view v-if="showMoveImage">
|
|
|
|
<view :style="{ left: moveLeft + 'px', top: moveTop + 'px' }" class="cu-item absolute">
|
|
|
|
<ProjectItem class="w-full" :item="moveItem" />
|
|
|
|
</view>
|
|
|
|
</view>
|
|
|
|
<!-- 移动悬浮 end -->
|
|
|
|
</view>
|
|
|
|
</template>
|
|
|
|
|
|
|
|
<script>
|
|
|
|
import ProjectItem from '../Projects/ProjectItem.vue';
|
|
|
|
import { mapState, mapGetters, mapMutations } from 'vuex';
|
|
|
|
|
|
|
|
export default {
|
|
|
|
components: { ProjectItem },
|
|
|
|
name: 'exchange',
|
|
|
|
model: { prop: 'showPop', event: 'change' },
|
|
|
|
|
|
|
|
data() {
|
|
|
|
return {
|
|
|
|
itemTop: 0,
|
|
|
|
itemLeft: 0,
|
|
|
|
itemHeight: 0, // 移动元素的高度
|
|
|
|
subItemHeight: 0, // 移动子元素的高度
|
|
|
|
itemWidth: 0, // 移动元素的宽度
|
|
|
|
showMoveImage: false,
|
|
|
|
moveItem: '',
|
|
|
|
moveLeft: 0,
|
|
|
|
moveTop: 0,
|
|
|
|
deltaLeft: 0,
|
|
|
|
deltaTop: 0,
|
|
|
|
beginleft: 0,
|
|
|
|
begintop: 0,
|
|
|
|
itemList: [],
|
|
|
|
setSubItem: false,
|
|
|
|
changeEvent: false,
|
|
|
|
|
|
|
|
showMenu: false,
|
|
|
|
tips: {
|
|
|
|
text: '',
|
|
|
|
color: '#909399',
|
|
|
|
fontSize: 28,
|
|
|
|
},
|
|
|
|
menuList: [{ text: '复制' }, { text: '编辑' }, { text: '删除' }, { text: '置顶' }, { text: '排序' }],
|
|
|
|
// show: false,
|
|
|
|
border: 'border border-blue-500 shadow rounded-md',
|
|
|
|
showBorder: false,
|
|
|
|
showItemIndex: undefined,
|
|
|
|
};
|
|
|
|
},
|
|
|
|
|
|
|
|
computed: {
|
|
|
|
...mapGetters('user', ['userId']),
|
|
|
|
...mapState('project', ['projects']),
|
|
|
|
|
|
|
|
eventName() {
|
|
|
|
if (this.changeEvent) {
|
|
|
|
return 'move.stop.prevent';
|
|
|
|
} else {
|
|
|
|
return 'move';
|
|
|
|
}
|
|
|
|
},
|
|
|
|
},
|
|
|
|
|
|
|
|
mounted() {
|
|
|
|
this.$nextTick(function () {
|
|
|
|
this.itemList = this.projects;
|
|
|
|
this.itemList.forEach(item => {
|
|
|
|
item.showBorder = false;
|
|
|
|
item.showSubBorder = false;
|
|
|
|
item.showTopBorder = false;
|
|
|
|
});
|
|
|
|
});
|
|
|
|
},
|
|
|
|
|
|
|
|
watch: {
|
|
|
|
projects(val) {
|
|
|
|
this.itemList = val;
|
|
|
|
this.itemList.forEach(item => {
|
|
|
|
item.showBorder = false;
|
|
|
|
item.showSubBorder = false;
|
|
|
|
item.showTopBorder = false;
|
|
|
|
});
|
|
|
|
},
|
|
|
|
},
|
|
|
|
|
|
|
|
methods: {
|
|
|
|
...mapMutations('project', ['setProjectItemShow']),
|
|
|
|
// 展开子项目
|
|
|
|
openSubProject(length, index) {
|
|
|
|
this.setProjectItemShow({ index, show: this.itemList[index].show ? false : true });
|
|
|
|
if (length && index) {
|
|
|
|
this.$emit('changeHeight', length, index);
|
|
|
|
}
|
|
|
|
this.showItemIndex = index;
|
|
|
|
},
|
|
|
|
|
|
|
|
// 获取项目列表距离顶部的距离
|
|
|
|
getDate() {
|
|
|
|
const query = uni.createSelectorQuery().in(this);
|
|
|
|
query
|
|
|
|
.select(`#cu-0`)
|
|
|
|
.boundingClientRect(data => {
|
|
|
|
console.log('data: ', data);
|
|
|
|
this.begintop = data.top;
|
|
|
|
this.beginleft = data.left;
|
|
|
|
})
|
|
|
|
.exec();
|
|
|
|
},
|
|
|
|
|
|
|
|
// 操作
|
|
|
|
chooseAction(index) {
|
|
|
|
if (this.menuList[index].text === '排序') {
|
|
|
|
this.changeEvent = true;
|
|
|
|
this.$t.ui.showToast('请移动进行排序');
|
|
|
|
}
|
|
|
|
|
|
|
|
if (this.showItemIndex !== undefined) {
|
|
|
|
this.setProjectItemShow({ index: this.showItemIndex, show: true });
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
|
|
|
isNumber(val) {
|
|
|
|
return val === +val;
|
|
|
|
},
|
|
|
|
|
|
|
|
start(e, index) {
|
|
|
|
console.log('开始', e);
|
|
|
|
setTimeout(() => {
|
|
|
|
this.getDate();
|
|
|
|
}, 300);
|
|
|
|
|
|
|
|
if (this.isNumber(index)) {
|
|
|
|
this.setSubItem = false;
|
|
|
|
const query = uni.createSelectorQuery().in(this);
|
|
|
|
query
|
|
|
|
.select(`#cu-${index}`)
|
|
|
|
.boundingClientRect(data => {
|
|
|
|
this.moveTop = data.top;
|
|
|
|
this.moveLeft = data.left;
|
|
|
|
this.moveItem = this.itemList[index];
|
|
|
|
this.itemWidth = data.width;
|
|
|
|
this.itemHeight = data.height;
|
|
|
|
})
|
|
|
|
.exec();
|
|
|
|
} else {
|
|
|
|
let arr = index.split('-');
|
|
|
|
this.setSubItem = true;
|
|
|
|
const query = uni.createSelectorQuery().in(this);
|
|
|
|
query
|
|
|
|
.select(`#cu-${arr[0] - 0}`)
|
|
|
|
.boundingClientRect(data => {
|
|
|
|
this.itemHeight = data.height;
|
|
|
|
})
|
|
|
|
.exec();
|
|
|
|
|
|
|
|
query
|
|
|
|
.select(`#cu-${index}`)
|
|
|
|
.boundingClientRect(data => {
|
|
|
|
this.moveTop = data.top;
|
|
|
|
this.moveLeft = data.left;
|
|
|
|
this.moveItem = this.itemList[arr[0] - 0].sonProjectList[arr[1] - 0];
|
|
|
|
this.itemWidth = data.width;
|
|
|
|
this.subItemHeight = data.height;
|
|
|
|
})
|
|
|
|
.exec();
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
|
|
|
move(e, length) {
|
|
|
|
console.log('移动');
|
|
|
|
this.showMoveImage = true; //悬浮开始
|
|
|
|
const touch = e.touches[0];
|
|
|
|
if (this.deltaLeft == 0) {
|
|
|
|
// 获得本身的移动
|
|
|
|
this.deltaLeft = touch.pageX - this.moveLeft;
|
|
|
|
this.deltaTop = touch.pageY - this.moveTop;
|
|
|
|
}
|
|
|
|
this.moveLeft = touch.pageX - this.deltaLeft;
|
|
|
|
this.moveTop = touch.pageY - this.deltaTop;
|
|
|
|
|
|
|
|
let lastIndex = (lastIndex = this.findOverIndex(touch.pageY, length));
|
|
|
|
// 显示下划线
|
|
|
|
for (let i = 0; i < this.itemList.length; i++) {
|
|
|
|
if (this.moveLeft > 35) {
|
|
|
|
this.itemList[i].showBorder = false;
|
|
|
|
this.itemList[i].showTopBorder = false;
|
|
|
|
if (i === lastIndex) {
|
|
|
|
this.itemList[i].showSubBorder = true;
|
|
|
|
} else {
|
|
|
|
this.itemList[i].showSubBorder = false;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (lastIndex === -1) {
|
|
|
|
this.itemList[0].showTopBorder = true;
|
|
|
|
this.itemList[i].showSubBorder = false;
|
|
|
|
this.itemList[i].showBorder = false;
|
|
|
|
} else {
|
|
|
|
this.itemList[i].showSubBorder = false;
|
|
|
|
this.itemList[i].showTopBorder = false;
|
|
|
|
if (i === lastIndex) {
|
|
|
|
this.itemList[i].showBorder = true;
|
|
|
|
} else {
|
|
|
|
this.itemList[i].showBorder = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
|
|
|
stops(e, index, length) {
|
|
|
|
console.log('结束');
|
|
|
|
const touch = e.mp.changedTouches[0];
|
|
|
|
let lastIndex = (lastIndex = this.findOverIndex(touch.pageY, length));
|
|
|
|
|
|
|
|
// 交换两个值
|
|
|
|
for (let i = 0; i < this.itemList.length; i++) {
|
|
|
|
// 插入顶部
|
|
|
|
if (this.itemList[i].showTopBorder) {
|
|
|
|
if (this.isNumber(index)) {
|
|
|
|
let Value = this.itemList[index];
|
|
|
|
this.itemList.unshift(Value);
|
|
|
|
this.itemList.splice(index + 1, 1);
|
|
|
|
} else {
|
|
|
|
let arr = index.split('-');
|
|
|
|
let Value = this.itemList[arr[0] - 0].sonProjectList[arr[1] - 0];
|
|
|
|
this.itemList.unshift(Value);
|
|
|
|
this.itemList[arr[0] - 0].sonProjectList.splice([arr[1] - 0], 1);
|
|
|
|
const options = {
|
|
|
|
id: Value.id,
|
|
|
|
parentId: 0,
|
|
|
|
};
|
|
|
|
this.$emit('change', options);
|
|
|
|
}
|
|
|
|
// 清空
|
|
|
|
this.clearSet(i);
|
|
|
|
this.$emit('change', this.itemList);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
// 插入一级项目
|
|
|
|
if (this.itemList[i].showBorder) {
|
|
|
|
if (this.isNumber(index)) {
|
|
|
|
let Value = this.itemList[index];
|
|
|
|
this.itemList.splice(i + 1, 0, Value);
|
|
|
|
if (i < index) {
|
|
|
|
this.itemList.splice(index + 1, 1);
|
|
|
|
} else {
|
|
|
|
this.itemList.splice(index, 1);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
let arr = index.split('-');
|
|
|
|
let Value = this.itemList[arr[0] - 0].sonProjectList[arr[1] - 0];
|
|
|
|
this.itemList.splice(i + 1, 0, Value);
|
|
|
|
this.itemList[arr[0] - 0].sonProjectList.splice([arr[1] - 0], 1);
|
|
|
|
const options = {
|
|
|
|
id: Value.id,
|
|
|
|
parentId: 0,
|
|
|
|
};
|
|
|
|
this.$emit('change', options);
|
|
|
|
}
|
|
|
|
// 清空
|
|
|
|
this.clearSet(i);
|
|
|
|
this.$emit('change', this.itemList);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
// 插入二级项目
|
|
|
|
if (this.itemList[i].showSubBorder) {
|
|
|
|
if (this.isNumber(index)) {
|
|
|
|
let Value = this.itemList[index];
|
|
|
|
if (this.itemList[lastIndex - 1].sonProjectList && this.itemList[lastIndex - 1].sonProjectList.length) {
|
|
|
|
this.itemList[lastIndex - 1].sonProjectList.push(Value);
|
|
|
|
} else {
|
|
|
|
this.itemList[lastIndex].sonProjectList = [Value];
|
|
|
|
}
|
|
|
|
this.itemList.splice(index, 1);
|
|
|
|
// 清空
|
|
|
|
this.clearSet(i);
|
|
|
|
const options = {
|
|
|
|
id: Value.id,
|
|
|
|
parentId: this.itemList[lastIndex - 1].id,
|
|
|
|
};
|
|
|
|
this.$emit('change', options);
|
|
|
|
} else {
|
|
|
|
let arr = index.split('-');
|
|
|
|
let Value = this.itemList[arr[0] - 0].sonProjectList[arr[1] - 0];
|
|
|
|
if (this.itemList[lastIndex].sonProjectList && this.itemList[lastIndex].sonProjectList.length) {
|
|
|
|
this.itemList[lastIndex].sonProjectList.push(Value);
|
|
|
|
} else {
|
|
|
|
this.itemList[lastIndex].sonProjectList = [Value];
|
|
|
|
}
|
|
|
|
this.itemList[arr[0] - 0].sonProjectList.splice([arr[1] - 0], 1);
|
|
|
|
// 清空
|
|
|
|
this.clearSet(i);
|
|
|
|
const options = {
|
|
|
|
id: Value.id,
|
|
|
|
parentId: this.itemList[lastIndex].id,
|
|
|
|
};
|
|
|
|
this.$emit('change', options);
|
|
|
|
|
|
|
|
const options1 = {
|
|
|
|
id: Value.id,
|
|
|
|
parentId: 0,
|
|
|
|
};
|
|
|
|
this.$emit('change', options1);
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
|
|
|
// 还原初始数据
|
|
|
|
clearSet(i) {
|
|
|
|
this.itemList[i].showBorder = false;
|
|
|
|
this.itemList[i].showSubBorder = false;
|
|
|
|
this.itemList[i].showTopBorder = false;
|
|
|
|
this.deltaLeft == 0;
|
|
|
|
this.showMoveImage = false;
|
|
|
|
this.setSubItem = false;
|
|
|
|
this.changeEvent = false;
|
|
|
|
this.showItemIndex = undefined;
|
|
|
|
},
|
|
|
|
|
|
|
|
// 找到停下的元素的下标
|
|
|
|
findOverIndex(posY) {
|
|
|
|
// 如果有子项目展开着
|
|
|
|
let leng = this.itemList.length * this.itemHeight; // 最后一个元素距离顶部的距离
|
|
|
|
if (posY < this.begintop) {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
for (var i = 0; i < this.itemList.length; i++) {
|
|
|
|
let begin = this.itemHeight * i + this.begintop;
|
|
|
|
let end = this.itemHeight * i + this.begintop + this.itemHeight;
|
|
|
|
if (begin <= posY && end >= posY) {
|
|
|
|
return i;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (posY > leng) {
|
|
|
|
// 交换最后一个
|
|
|
|
return this.itemList.length - 1;
|
|
|
|
} else if (posY < this.begintop) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
},
|
|
|
|
},
|
|
|
|
};
|
|
|
|
</script>
|
|
|
|
|
|
|
|
<style lang="scss" scoped>
|
|
|
|
.cu-item {
|
|
|
|
width: 100%;
|
|
|
|
display: flex;
|
|
|
|
align-items: center;
|
|
|
|
font-size: 14px;
|
|
|
|
}
|
|
|
|
|
|
|
|
.border-100 {
|
|
|
|
width: 92%;
|
|
|
|
height: 4rpx;
|
|
|
|
}
|
|
|
|
.border-80 {
|
|
|
|
width: 84%;
|
|
|
|
height: 2px;
|
|
|
|
margin-left: 30px;
|
|
|
|
}
|
|
|
|
</style>
|