Files
im-uniapp/components/Gantt/uniapp/GanttCanvas.vue
2025-07-16 14:23:42 +08:00

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>