<template>
<div class="timeRange">
<div class="calendar">
<table>
<thead>
<tr>
<th rowspan="6" class="weekRow"><b>周/时间</b></th>
<th colspan="24"><b>00:00 - 12:00</b></th>
<th colspan="24"><b>12:00 - 24:00</b></th>
</tr>
<tr>
<td colspan="2" v-for="index in 24" :key="index">{{ index - 1 }}</td>
</tr>
</thead>
<tbody @mousemove.prevent="handleMouseMove">
<tr v-for="(item, index) in weekDate" :key="index">
<td>{{ item }}</td>
<td class="calendar-atom-time" v-for="i in 48" :key="index + '-' + i"
:class="{ 'active': selectCells[`${index}_${i}`] }" @mousedown.prevent="handleMouseDown(index, i, $event)"
@mouseup.prevent="handleMouseUp(index, i)">
</td>
</tr>
<div id="box" v-show="moveStartEvent"></div>
</tbody>
</table>
<div class="table-core">
<div class="clearfix">
<span class="pull-left tip-text">可拖动鼠标选择时间段</span>
<button class="clearBtn" @click="handleClear">清除所有</button>
</div>
<ul>
<li v-for="(item, index) in selectDate" :key="index" v-if="item.data && item.data.length">
<label>{{ item.label }}</label>
<span v-for="o in item.data" :key="o">{{ o[0] }}~{{ o[1] }}</span>
</li>
</ul>
</div>
</div>
</div>
</template>
<script>
export default {
name: 'timeRange',
data () {
return {
// 表列
weekDate: ['一', '二', '三', '四', '五', '六', '日'],
// 所选格子
selectCells: {},
// 所选时间数据(做提交时使用)
selectDate: {},
// 记录鼠标位置
moveStartEvent: false,
moveStartColumn: 0, // 列
moveStarRow: 0, // 行
moveStartX: 0,
moveStartY: 0
}
},
created () {
},
mounted () {
},
methods: {
// 初始
init (data) {
if (data && data instanceof Object) {
this.selectCells = data
} else {
this.selectCells = {}
}
this.getSelectDate()
},
// 按下
handleMouseDown (column, row, e) {
this.moveStartEvent = true
this.moveStartColumn = column
this.moveStarRow = row
this.moveStartX = e.layerX
this.moveStartY = e.layerY
},
// 松开
handleMouseUp (column, row) {
if (this.moveStartEvent) {
this.moveStartEvent = false
const X = row - this.moveStarRow
const Y = column - this.moveStartColumn
const checked = !this.selectCells[`${column}_${row}`]
if (X > -1 && Y > -1) {
const obj = this.clone(this.selectCells)
for (let i = this.moveStartColumn; i <= column; i++) {
for (let j = this.moveStarRow; j <= row; j++) {
var key = `${i}_${j}`
if (checked) {
obj[key] = checked
} else if (obj[key]) {
delete obj[key]
}
}
}
this.selectCells = obj
this.$forceUpdate()
this.getSelectDate()
}
}
this.moveStartDay = 0
this.moveStarTime = 0
},
// 滑动中
handleMouseMove (e) {
if (this.moveStartEvent) {
const dom = this.$el.querySelector('#box')
const X = e.layerX - this.moveStartX
const Y = e.layerY - this.moveStartY
if (X >= 0 && Y >= 0) {
dom.style.left = this.moveStartX + 'px'
dom.style.top = this.moveStartY + 'px'
dom.style.width = X + 'px'
dom.style.height = Y + 'px'
}
}
},
// 组合时间数据
getSelectDate () {
const arr = []
this.weekDate.forEach((item, index) => {
arr.push({
label: item,
data: []
})
for (var i = 1; i <= 48; i++) {
var o = this.selectCells[`${index}_${i}`]
if (o) {
var endTime = i / 2
var startTime = endTime - 0.5
if (startTime < 10) {
startTime = '0' + startTime
}
if (endTime < 10) {
endTime = '0' + endTime
}
startTime += ''
endTime += ''
if (startTime.indexOf('.5') > -1) {
startTime = startTime.replace('.5', ':30')
} else {
endTime = endTime.replace('.5', ':30')
}
if (startTime.indexOf(':30') < 0) {
startTime += ':00'
} else {
endTime += ':00'
}
arr[index].data.push([startTime, endTime])
}
}
})
arr.forEach(item => {
for (var i = 0; i < item.data.length; i++) {
var o = item.data
if (o[i + 1] && o[i][1] === o[i + 1][0]) {
o[i + 1][0] = o[i][0]
item.data.splice(i, 1)
i--
}
}
})
this.selectDate = arr
},
// 清除选择
handleClear () {
this.selectCells = {}
this.getSelectDate()
this.$forceUpdate()
},
// 获取数据
getData () {
return this.selectDate
}
}
}
</script>
<style lang="less" scoped>
.timeRange {
user-select: none;
position: relative;
padding: 10px 0;
.calendar {
display: inline-block;
}
table {
width: 100%;
border-radius: 4px;
border-spacing: 0;
table-layout: fixed;
border-collapse: collapse;
thead {
th,
td {
height: 30px;
}
th {
padding: 5px 0;
}
.weekRow {
width: 100px;
min-width: 100px;
padding: 20px 0
}
}
td,
th {
outline: 0;
border: 1px solid #E3E3E3;
font-size: 12px;
text-align: center;
min-width: 11px;
line-height: 1.6em;
min-width: 24px;
}
tbody {
position: relative;
overflow: hidden;
td {
height: 20px !important;
}
}
td.active {
background: #F60457;
}
}
.table-core {
line-height: 2.4em;
border: 1px solid #E3E3E3;
border-top: 0;
overflow: hidden;
padding: 10px;
.clearfix {
color: #8A8A8A;
text-align: left;
height: 22px;
line-height: 22px;
margin: 8px 0;
display: flex;
font-size: 12px;
.clearBtn {
cursor: pointer;
color: #5775F9;
font-size: 14px;
margin-left: auto;
}
}
ul {
li {
line-height: 22px;
margin-bottom: 5px;
label {
display: inline-block;
min-width: 60px;
color: #8A8A8A;
text-align: left;
}
span {
font-size: 12px;
&::after {
content: "、"
}
&:last-child::after {
display: none;
}
}
}
}
}
#box {
background: rgba(241, 1, 85, 0.4);
pointer-events: none;
position: absolute;
top: 0;
left: 0;
}
}
</style>