演示视频
使用HTML5拖放特性实现一个任务管理小功能
实现功能
- 可以自己定义新增和配置任务面板
- 可以在任务面板中添加多个任务
- 不同面板中的任务可以拖放到其他面板中,并且拖放完成后自动请求后台修改接口
总体上我目前只需要上面的这些功能,方便自己在开发过程中清晰的知道自己需要做什么,以及完成了什么。
实现过程
整体使用的是原生HTML5中的拖放特性来实现的。废话不多说,直接上代码
<template>
<div class="index">
<div class="taskBox" @mouseup="handleMouseUp">
<el-button v-if="taskTypeList.length == 0" @click="showPane = true; taskType = {}" type="primary" plain
icon="Plus">增加面板</el-button>
<div class="taskItem" v-for="item in taskTypeList" :key="item.id" @dragover="allowDrop">
<div class="taskItemHead" :style="'background-color:' + item.taskHeaderColor">
<div class="taskItemHeadLeft">{{ item.taskHeaderName }}</div>
<div class="taskItemHeadRight">
<el-button @click="delTaskType(item.id)" size="small" icon="Delete" circle></el-button>
<el-button @click="showPane = true; taskType = {}" size="small" icon="Plus" circle>
</el-button>
</div>
</div>
<div class="taskItemContent" @drop="drop" :data-tasktypeid="item.id" :id="'taskType'+item.id">
<div :id="'task'+task.id" draggable="true" @dragend="dragEnd" v-for="task in item.taskList" :key="task" class="card"
:style="'background-color:' + item.taskHeaderColor + '33'" :data-taskId="task.id" :data-tasktypeid="item.id">
<div class="cardHeader">
<div>{{ task.taskTitle }}</div>
<el-button @click="delTask(task.id)" round plain type="danger" size="small" icon="Delete">删除
</el-button>
</div>
<div class="cardContent">
{{ task.taskContent }}
</div>
<div class="cardFooter">
{{ task.createTime }}
</div>
</div>
<el-button @click="preAddTask(item.id)" icon="Plus" plain type="primary"
style="width:calc(100% - 20px); margin:10px;">添加任务</el-button>
</div>
</div>
</div>
<el-dialog title="面板信息" v-model="showPane">
<el-form :model="taskType" label-width="120px">
<el-form-item label="面板名称">
<el-input placeholder="输入面板名称" v-model="taskType.taskHeaderName"></el-input>
</el-form-item>
<el-form-item label="面板头部颜色">
<el-input placeholder="面板头部颜色" v-model="taskType.taskHeaderColor"></el-input>
</el-form-item>
<el-form-item>
<el-button type="info">取消</el-button>
<el-button @click="addTaskType" type="primary">确定</el-button>
</el-form-item>
</el-form>
</el-dialog>
<el-dialog title="任务信息" v-model="showTask">
<el-form :model="task">
<el-form-item label="任务标题">
<el-input placeholder="输入任务标题" v-model="task.taskTitle"></el-input>
</el-form-item>
<el-form-item label="任务内容">
<el-input type="textarea" placeholder="输入任务标题" v-model="task.taskContent"></el-input>
</el-form-item>
<el-form-item>
<el-button type="info">取消</el-button>
<el-button @click="addTask" type="primary">提交</el-button>
</el-form-item>
</el-form>
</el-dialog>
</div>
</template>
<script>
import { addTaskType, taskTypeList, delTaskType, addTask, setTask, delTask } from '../js/api.js'
import { ElMessage, ElMessageBox } from 'element-plus'
import draggable from "vuedraggable"
export default {
components: {
draggable
},
data() {
return {
showPane: false,
showTask: false,
taskType: {},
taskTypeList: [],
task: {},
list: [],
tempTaskTypeId: null,
}
},
methods: {
addTaskType() {
addTaskType(this.taskType).then(res => {
ElMessage({ type: res.status ? 'success' : 'error', message: res.msg })
this.showPane = false;
this.getTaskTypeList();
})
},
getTaskTypeList() {
taskTypeList().then(res => {
this.taskTypeList = res.data;
})
},
delTaskType(id) {
ElMessageBox.confirm('该操作将删除该面板以及里面的所有任务,是否继续?', '提示', { confirmButtonText: '确定', cancelButtonText: '取消' }).then(() => {
delTaskType([id]).then(res => {
ElMessage({ type: res.status ? 'success' : 'error', message: res.msg });
this.getTaskTypeList();
})
})
},
delTask(id) {
ElMessageBox.confirm('该操作将删除该任务,是否继续?', '提示', { confirmButtonText: '确定', cancelButtonText: '取消' }).then(() => {
delTask([id]).then(res => {
ElMessage({ type: res.status ? 'success' : 'error', message: res.msg });
this.getTaskTypeList();
})
})
},
preAddTask(taskTypeId) {
this.task.taskTypeId = taskTypeId;
this.showTask = true;
},
addTask() {
addTask(this.task).then(res => {
ElMessage({ type: res.status ? 'success' : 'error', message: res.msg });
this.showTask = false;
this.getTaskTypeList();
})
},
allowDrop(event){
event.preventDefault();
},
drop(event){
console.log('097907097097',document.getElementById(event.target.id).dataset)
this.tempTaskTypeId = document.getElementById(event.target.id).dataset.tasktypeid;
console.log(event.target.id)
event.preventDefault();
// var data=event.dataTransfer.getData("Text");
// event.target.appendChild(document.getElementById(data));
},
dragEnd(event){
let taskId = document.getElementById(event.target.id).dataset.taskid;
console.log(taskId)
let oldTask = null;
for(let i=0; i<this.taskTypeList.length; i++){
let tempTaskList = this.taskTypeList[i].taskList;
for(let j=0; j<tempTaskList.length; j++){
if(taskId==tempTaskList[j].id){
oldTask = tempTaskList[j];
break;
}
}
}
oldTask.taskTypeId = this.tempTaskTypeId;
setTask(oldTask).then(res=>{
ElMessage({ type: res.status ? 'success' : 'error', message: res.msg });
this.getTaskTypeList();
})
console.log(oldTask);
}
},
mounted() {
this.getTaskTypeList();
}
}
</script>
<style lang="scss">
.index {
height: calc(100vh - 50px);
display: flex;
flex-direction: column;
justify-content: center;
}
.taskBox {
display: flex;
justify-content: center;
}
.taskItem {
width: 300px;
height: calc(100vh - 200px);
border: 1px solid gainsboro;
border-radius: 5px;
margin: 0 10px;
box-shadow: 2px 3px 10px gainsboro;
}
.taskItemHead {
width: 100%;
height: 40px;
font-weight: bold;
display: flex;
align-items: center;
font-size: 13px;
color: white;
justify-content: space-between;
}
.taskItemHeadLeft {
padding-left: 10px;
display: flex;
justify-content: center;
}
.taskItemHeadRight {
display: flex;
align-items: center;
padding-right: 10px;
cursor: pointer;
}
.taskItemContent {
height: calc(100vh - 240px);
overflow-y: auto;
}
.card {
margin: 10px;
cursor: pointer;
box-shadow: 2px 3px 10px gainsboro;
text-align: left;
padding: 5px;
border-radius: 4px;
}
.cardHeader {
display: flex;
justify-content: space-between;
align-items: center;
font-weight: bold;
font-size: 16px;
}
.cardContent {
padding: 10px 0;
}
.cardFooter {
padding-top: 5px;
font-size: 14px;
}
</style>
上面是实现此功能的所有代码,当然其中的请求接口需要自己实现,后台的具体代码就不往出贴了,这里只贴出用到的表结构,相信大家很容易实现上面那些接口
任务类型表(也就是面板表)
任务表