![QQ202488-155336-HD[00h00m00s-00h00m10s].gif](https://p9-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/9273010b500e40c99c70c8058b5984b7~tplv-73owjymdk6-jj-mark-v1:0:0:0:0:5o6Y6YeR5oqA5pyv56S-5Yy6IEAgTmVwbmVw:q75.awebp?rk3s=f64ab15b&x-expires=1770883089&x-signature=tl5H68T6f8RLoRftzqDS4yjoJvU%3D)
<template>
<el-scrollbar
class="gantt-box"
wrap-style="max-height:346px"
view-class="rel"
>
<div class="calendar-header flex-wrap">
<div
class="calendar-head-date flex-shark"
:class="{ 'today-date': item.isToday }"
:style="{ width: unitWidth + 'px' }"
v-for="item in showDate"
:key="item.formatDate"
>
<div class="calendar-weekday">{{ item.time.format('dd') }}</div>
<div class="calendar-date">{{ item.time.format('DD') }}</div>
</div>
</div>
<div class="mission-box" :style="handleMissionBoxStyle()">
<div
class="mission-single-line flex-wrap"
v-for="(group, index) in showMissionList"
:key="index"
>
<div
v-for="(item, i) in group"
:key="item.id"
class="mission-item flex-center-wrap flex-shark flex-justify-between"
:style="handleMissionStyle(item, i)"
>
<div class="text-ess-1">
{{ item.name }}-{{ item.real_start || item.start }}到{{
item.real_end || item.end
}}
</div>
<div class="ml16">{{ item.duration }}天</div>
</div>
</div>
</div>
</el-scrollbar>
</template>
<script>
export default {
name: 'ganttCalendar',
components: {},
mixins: {},
props: {
missionList: {
type: Array,
default: () => []
}
},
data() {
return {
showDate: [],
showMissionList: [],
unitWidth: 86,
typeList: [
{
id: 1,
name: '活动计划',
background: '#ECF5FF'
},
{
id: 2,
name: '团队计划',
background: '#E1F3D8'
},
{
id: 3,
name: '其它计划',
background: '#E8ECFF'
}
]
}
},
computed: {},
filters: {},
methods: {
init() {
this.setShowDate()
this.handleShowMission()
},
setShowDate(time) {
time = new dayjs(time || undefined)
let startTime = time.subtract(13, 'd')
let endTime = time.add(14, 'd')
let showDate = []
while (startTime.isBefore(endTime)) {
let info = {
time: startTime,
date: dayjs(startTime.format('YYYY-MM-DD')),
formatDate: startTime.format('YYYY-MM-DD'),
isToday: startTime.isSame(time, 'd')
}
showDate.push(info)
startTime = startTime.add(1, 'd')
}
this.showDate = showDate
console.log('showdate', this.showDate)
},
handleShowMission() {
let missionList = this.missionList.sort((a, b) => {
return dayjs(a.start).valueOf() - dayjs(b.start).valueOf()
})
missionList = missionList.map(item => {
item.startDate = dayjs(dayjs(item.start).format('YYYY-MM-DD'))
item.endDate = dayjs(dayjs(item.end).format('YYYY-MM-DD 23:59:59'))
item.duration = item.endDate.diff(item.startDate, 'd') + 1
if (item.startDate.isBefore(this.showDate[0].date)) {
item.real_start = item.start
item.start = this.showDate[0].formatDate
item.startDate = this.showDate[0].date
}
if (
item.endDate.isAfter(this.showDate[this.showDate.length - 1].date)
) {
item.real_end = item.end
item.end = this.showDate[this.showDate.length - 1].formatDate
item.endDate = this.showDate[this.showDate.length - 1].date
}
return item
})
let showMissionList = []
let temp = []
missionList.forEach(item => {
if (
item.startDate.isAfter(
this.showDate[this.showDate.length - 1].date
) ||
item.endDate.isBefore(this.showDate[0].date)
) {
return
}
item.show_day = item.endDate.diff(item.startDate, 'd') + 1
let unOverlap = temp.findIndex(t => {
return item.startDate.isAfter(t)
})
if (unOverlap === -1) {
item.distance = item.startDate.diff(this.showDate[0].date, 'd')
showMissionList.push([item])
temp.push(item.endDate)
} else {
item.distance = item.startDate.diff(temp[unOverlap], 'd')
showMissionList[unOverlap].push(item)
temp[unOverlap] = item.endDate
}
})
this.showMissionList = showMissionList
console.log('showMissionList', this.showMissionList)
},
handleMissionStyle(item, index) {
return {
width: item.show_day * this.unitWidth - 1 + 'px',
background: this.typeList.find(t => t.id === item.type).background,
'margin-left':
item.real_start && !index
? 0
: Math.max(1, item.distance * this.unitWidth + (index ? 1 : 0)) +
'px'
}
},
handleMissionBoxStyle() {
return {
width: this.showDate.length * this.unitWidth + 'px',
'background-image': `linear-gradient(to left, #DCDFE6 1px, transparent 1px), linear-gradient(to left, #409EFF 1px, transparent 1px)`,
'background-size': `${this.unitWidth}px 100%, 50% 100%`
}
}
},
watch: {},
created() {
this.missionList = [
{
id: 1,
name: '任务1',
start: '2024-08-01 12:00:00',
end: '2024-08-10 12:00:00',
type: 1
},
{
id: 3,
name: '任务3',
start: '2024-08-12 12:00:00',
end: '2024-08-20 12:00:00',
type: 1
},
{
id: 4,
name: '任务4',
start: '2024-08-18 12:00:00',
end: '2024-08-25 12:00:00',
type: 2
},
{
id: 5,
name: '任务5',
start: '2024-07-20 12:00:00',
end: '2024-07-25 12:00:00',
type: 2
},
{
id: 6,
name: '任务6',
start: '2024-07-25 12:00:00',
end: '2024-07-30 12:00:00',
type: 1
},
{
id: 7,
name: '任务7',
start: '2024-07-30 12:00:00',
end: '2024-08-02 12:00:00',
type: 2
},
{
id: 8,
name: '任务8',
start: '2024-08-02 12:00:00',
end: '2024-08-06 12:00:00',
type: 1
},
{
id: 9,
name: '任务9',
start: '2024-08-06 12:00:00',
end: '2024-08-11 12:00:00',
type: 2
},
{
id: 10,
name: '任务10',
start: '2024-08-11 12:00:00',
end: '2024-08-15 12:00:00',
type: 1
},
{
id: 11,
name: '任务11',
start: '2024-08-15 12:00:00',
end: '2024-08-19 12:00:00',
type: 3
},
{
id: 12,
name: '任务12',
start: '2024-08-19 12:00:00',
end: '2024-08-23 12:00:00',
type: 3
},
{
id: 13,
name: '任务13',
start: '2024-08-23 12:00:00',
end: '2024-08-27 12:00:00',
type: 2
},
{
id: 14,
name: '任务14',
start: '2024-08-27 12:00:00',
end: '2024-08-31 12:00:00',
type: 1
},
{
id: 15,
name: '任务15',
start: '2024-08-31 12:00:00',
end: '2024-09-04 12:00:00',
type: 2
},
{
id: 16,
name: '任务16',
start: '2024-09-04 12:00:00',
end: '2024-09-08 12:00:00',
type: 1
},
{
id: 17,
name: '任务17',
start: '2024-08-01 12:00:00',
end: '2024-08-02 12:00:00',
type: 1
},
{
id: 18,
name: '任务18',
start: '2024-08-01 12:00:00',
end: '2024-08-02 12:00:00',
type: 2
},
{
id: 19,
name: '任务19',
start: '2024-08-01 12:00:00',
end: '2024-08-02 12:00:00',
type: 1
},
{
id: 20,
name: '任务20',
start: '2024-08-01 12:00:00',
end: '2024-08-02 12:00:00',
type: 2
},
{
id: 21,
name: '任务21',
start: '2024-08-01 12:00:00',
end: '2024-08-02 12:00:00',
type: 1
},
{
id: 22,
name: '任务22',
start: '2024-08-01 12:00:00',
end: '2024-08-02 12:00:00',
type: 3
},
{
id: 23,
name: '任务23',
start: '2024-08-01 12:00:00',
end: '2024-08-02 12:00:00',
type: 1
},
{
id: 24,
name: '任务24',
start: '2024-08-01 12:00:00',
end: '2024-08-02 12:00:00',
type: 2
},
{
id: 25,
name: '任务25',
start: '2024-08-01 12:00:00',
end: '2024-08-02 12:00:00',
type: 1
},
{
id: 26,
name: '任务26',
start: '2024-08-01 12:00:00',
end: '2024-08-02 12:00:00',
type: 2
}
]
this.init()
},
mounted() {}
}
</script>
<style lang="scss" scoped>
.gantt-box {
border-radius: 4px;
border: 1px solid #dcdfe6;
}
.calendar-header {
position: sticky;
top: 0;
width: fit-content;
text-align: center;
background: #fff;
border-bottom: 1px solid #dcdfe6;
.calendar-head-date {
padding: 4px 0;
}
.calendar-weekday {
font-weight: 400;
font-size: 12px;
color: #909399;
line-height: 17px;
}
.calendar-date {
font-weight: 600;
font-size: 14px;
color: #606266;
line-height: 20px;
}
.today-date {
position: relative;
background: #ecf5ff;
}
.today-date::after {
content: '';
position: absolute;
left: 50%;
transform: translate(-62%, 90%);
display: block;
height: 5px;
width: 5px;
border: 1px solid #409eff;
background: #fff;
border-radius: 50%;
}
}
.mission-box {
padding: 12px 0;
.mission-single-line {
// 也许以后用得上,比如被展示日期截断的任务不要那一侧的圆角
.border-radius-left {
border-radius: 4px 0 0 4px;
}
.border-radius-right {
border-radius: 0 4px 4px 0;
}
.mission-item {
padding: 0 8px;
height: 20px;
line-height: 20px;
border-radius: 4px;
white-space: nowrap;
font-weight: 400;
font-size: 12px;
color: #606266;
}
}
.mission-single-line + .mission-single-line {
margin-top: 8px;
}
}
</style>