79 lines
1.7 KiB
Vue
79 lines
1.7 KiB
Vue
<template>
|
|
<view class="gantt-canvas">
|
|
<view v-for="task in tasks" :key="task.id"
|
|
class="gantt-task-bar"
|
|
:style="{
|
|
top: layoutMap[task.id] && layoutMap[task.id].top + 'px',
|
|
left: layoutMap[task.id] && layoutMap[task.id].left + 'px',
|
|
width: layoutMap[task.id] && layoutMap[task.id].width + 'px',
|
|
height: layoutMap[task.id] && layoutMap[task.id].height + 'px',
|
|
background: layoutMap[task.id] && layoutMap[task.id].color
|
|
}"
|
|
@tap.stop="onTaskClick(task)"
|
|
>
|
|
<slot name="task-bar" :task="task" :layout="layoutMap[task.id]">
|
|
<!-- 默认渲染 -->
|
|
<text class="task-name">{{ task.name }}</text>
|
|
</slot>
|
|
</view>
|
|
</view>
|
|
</template>
|
|
<script>
|
|
export default {
|
|
name: 'GanttCanvas',
|
|
props: {
|
|
tasks: {
|
|
type: Array,
|
|
required: true
|
|
},
|
|
layout: {
|
|
type: Array,
|
|
required: true
|
|
}
|
|
},
|
|
data() {
|
|
return {
|
|
layoutMap: {}
|
|
}
|
|
},
|
|
watch: {
|
|
layout: {
|
|
immediate: true,
|
|
handler(val) {
|
|
const map = {}
|
|
val.forEach(item => { map[item.id] = item })
|
|
this.layoutMap = map
|
|
}
|
|
}
|
|
},
|
|
methods: {
|
|
onTaskClick(task) {
|
|
this.$emit('task-click', task)
|
|
}
|
|
}
|
|
}
|
|
</script>
|
|
<style scoped>
|
|
.gantt-canvas {
|
|
position: relative;
|
|
min-height: 400px;
|
|
background: #fff;
|
|
}
|
|
.gantt-task-bar {
|
|
position: absolute;
|
|
border-radius: 4px;
|
|
box-shadow: 0 1px 2px rgba(0,0,0,0.04);
|
|
display: flex;
|
|
align-items: center;
|
|
padding-left: 8px;
|
|
font-size: 13px;
|
|
color: #fff;
|
|
cursor: pointer;
|
|
transition: box-shadow 0.2s;
|
|
}
|
|
.task-name {
|
|
white-space: nowrap;
|
|
overflow: hidden;
|
|
text-overflow: ellipsis;
|
|
}
|
|
</style> |