时间轴组件:
<template>
<div class="timeline-container">
<h5>套餐详情</h5>
<div style="display: inline-block">
<!-- 事件轴 -->
<div class="scaleline-container">
<div class="year-container" v-for="(item,indexYear) in lineData.length" :key="indexYear">
<!-- {
{
`${
minYear + indexYear}年`}} -->
<div class="m-container">
<div class="month-container" v-for="(item,index) in loopYear(item)" :key="index">
<div class="name">{
{
`${
minYear + indexYear}年${
index +1}月`}}</div>
<div class="name1">
<div v-for="(item,index) in item" class="line" :key="index"></div>
</div>
</div>
</div>
</div>
</div>
<!-- 边缘线 -->
<div class="margin-container">
<div class="no-active" :style="{width: '30%'}"></div>
<div class="active" :style="{width: '70%'}"></div>
</div>
<!-- 今天 -->
<div class="today-container">
<div class="before" :style="{width: today+'%'}"></div>
<div class="triangle"></div>
<div class="text">{
{
'今天'}}</div>
</div>
<!-- 套餐 -->
<div class="package-container" v-for="(item,index) in packageList" :key="index">
<div class="prefix-container" :style="{width: item.before+'%'}"></div>
<div class="content-container">
<span class="title">
<span>{
{
`总数: ${
item.channelNum}`}}</span>
<span>{
{
`(${
item.startTime} ${
item.endTime})`}}</span>
</span>
</div>
<div class="suffix-container" :style="{width: item.after+'%'}"></div>
</div>
</div>
</div>
</template>
<script>
import moment from 'moment';
const DAY31 = [30,28,30,29,31,29,31,31,29,31,29,31];
const DAY30 = [30,27,30,30,31,30,31,31,30,31,30,31];
const COMPONENT_NAME = 'timeLine';
export default {
name: COMPONENT_NAME,
props: {
packageDetail: {
type: Array,
default: () => ([
{
channelNum: 999999,
endTime: 1678530041000,
packageType: 3,
startTime: 1617287134582,
status: 0
},
{
channelNum: 50,
endTime: 1657849440428,
packageType: 3,
startTime: 1655257440428,
status: 2
},
{
channelNum: 8,
endTime: 4102329600000,
packageType: 1,
startTime: 1655256659902,
status: 0
},{
channelNum: 50,
endTime: 1657849440428,
packageType: 3,
startTime: 1655257440428,
status: 2
},
{
channelNum: 8,
endTime: 4102329600000,
packageType: 1,
startTime: 1655256659902,
status: 0
},{
channelNum: 50,
endTime: 1657849440428,
packageType: 3,
startTime: 1655257440428,
status: 2
},
{
channelNum: 8,
endTime: 4102329600000,
packageType: 1,
startTime: 1655256659902,
status: 0
},
{
channelNum: 50,
endTime: 1657849440428,
packageType: 3,
startTime: 1655257440428,
status: 2
},
{
channelNum: 8,
endTime: 4102329600000,
packageType: 1,
startTime: 1655256659902,
status: 0
}
])
},
},
data() {
return {
// 套餐
packageList: [],
// 最大日期
maxDate: '',
maxYear: 0,
maxMonth: 0,
maxDay: 0,
// 最小日期
minDate: '',
minYear: 0,
minMonth: 0,
minDay: 0,
// 画多少年?
manyYear: 0,
// 刻度线数据
lineData: [],
// 总长
total: 0,
// 今天
today: new Date().getTime()
};
},
computed: {
},
watch: {
},
created() {
this.handleData();
this.handleScaleLine()
},
methods: {
handleData() {
let max = this.packageDetail[0]['endTime'];
let min = this.packageDetail[0]['startTime'];
this.packageDetail.forEach( item => {
if(item['endTime'] > max ) {
max = item['endTime']
}
if(item['startTime'] < min) {
min = item['startTime']
}
this.packageList.push({
channelNum: item.channelNum,
endTime: moment(item['endTime']).format('YYYY-MM-DD HH:mm'),
packageType: item.packageType,
startTime: moment(item['startTime']).format('YYYY-MM-DD HH:mm'),
status: item.status
});
})
this.maxDate = moment(max).format('YYYYMMDD')
this.maxYear = Number(this.maxDate.slice(0,4))
this.maxMonth = Number(this.maxDate.slice(4,6))
this.maxDay = Number(this.maxDate.slice(6,8))
this.minDate = moment(min).format('YYYYMMDD')
this.minYear = Number(this.minDate.slice(0,4))
this.minMonth = Number(this.minDate.slice(4,6))
this.minDay = Number(this.minDate.slice(6,8))
this.total = new Date(`${
this.maxYear}-12-31`).getTime() - new Date(`${
this.minYear}-01-01`).getTime()
this.today = ((new Date().getTime() - new Date(`${
this.minYear}-01-01`)) / this.total) * 100
this.manyYear = (this.maxYear - this.minYear) + 1
this.handlePackage()
},
// 润平年?
howYear(year) {
if (year % 4 == 0 && year % 100 != 0 || year % 400 == 0) {
return true // 闰年
}
return false // 平年
},
// 刻度线
handleScaleLine() {
for (let index = 0; index < this.manyYear; index++) {
this.lineData.push(this.howYear(this.minYear+index))
}
},
// 循环那一年的月
loopYear(flag) {
return flag ? DAY31: DAY30
},
// 给每个套餐加比例
handlePackage() {
this.packageList.forEach(item => {
item.before = ((new Date(item.startTime.slice(0,10)).getTime() - new Date(`${
this.minYear}-01-01`).getTime()) / this.total ) * 100
item.after = ((new Date(`${
this.maxYear}-12-31`).getTime() - new Date(item.endTime.slice(0,10)).getTime() ) / this.total ) * 100
})
}
}
};
</script>
<style scoped lang="less">
.timeline-container {
width: 800px;
height: 200px;
border: 1px solid #000;
overflow: auto;
h5 {
margin: 0;
opacity: 0.7;
font-family: MicrosoftYaHeiUI;
font-size: 14px;
color: #000000;
letter-spacing: 0;
line-height: 20px;
font-weight: 400;
}
.scaleline-container {
display: inline-block !important;
height: 28px;
white-space: nowrap;
.year-container {
display: inline-block !important;
height: 28px;
.m-container {
display: inline-block !important;
height: 28px;
}
.month-container {
height: 28px;
display: inline-block !important;
// background-color: antiquewhite;
border-left: 0.67px solid rgba(151,151,151,1);
margin-left: 3.5px;
&:first-child {
margin-left: 0;
}
.name {
font-family: PingFangSC-Regular;
font-size: 12px;
color: rgba(0,0,0,.3);
text-align: center;
// background-color: aqua;
}
.name1 {
height: 12px;
font-family: PingFangSC-Regular;
font-size: 12px;
color: rgba(0,0,0,.3);
// background-color: red;
}
.line {
display: inline-block;
height: 100%;
width: 1px;
margin-left: 3.5px;
background-color: rgba(151,151,151,0.3);
}
}
&:last-child {
.month-container:last-child {
border-right: 0.67px solid rgba(151,151,151,1);
.line:last-child {
display: none;
}
}
}
}
}
.margin-container {
margin-top: -5px;
height: 10px;
display: flex;
.no-active {
background: #CACACA;
}
.active {
background: #9CBDE6;
}
}
.today-container {
height: 16px;
display: flex;
.before {
// background: #f60;
}
.triangle {
margin-left: -6px;
width: 12px;
height: 12px;
box-sizing: border-box;
border-top: 6px solid transparent;
border-left: 6px solid transparent;
border-right: 6px solid transparent;
border-bottom: 6px solid rgb(0, 0, 0);
}
.text {
margin-left: 4px;
font-family: PingFangSC-Regular;
font-size: 12px;
color: #000000;
letter-spacing: 0;
font-weight: 400;
}
}
.package-container {
height: 24px;
margin-top: 9px;
display: flex;
font-family: PingFangSC-Regular;
font-size: 12px;
color: #FFFFFF;
letter-spacing: 0;
font-weight: 400;
&:first-child {
margin-top: 19px;
}
.content-container {
flex: 1;
width: 2px;
line-height: 24px;
padding-left: 6px;
white-space: nowrap;
overflow: hidden;
text-overflow:ellipsis;
background: #455EEC;
.title {
span:last-child {
margin-left: 8px;
}
}
}
}
}
</style>