<template>
<div style="-moz-user-select:none;-webkit-user-select:none;user-select:none;overflow-x:auto;overflow-y:hide">
<div class="plans" :style="{width:width}">
<div class="plan-row-header">
<!-- <div class="plan-week plan-header" @click.prevent="refresh()" style="cursor:pointer;"><i
class="el-icon-close" title="点击还原"></i> 重置</div> -->
<div class="plan-week plan-header" v-if="editStatus == false" @click.prevent="selectall()" style="cursor:pointer;"><i
class="el-icon-check" title="点击全选"></i> 全选</div>
<div class="plan-week plan-header" v-if="editStatus == false" @click.prevent="unselectall()" style="cursor:pointer;"><i
class="el-icon-close" title="点击清空"></i> 清空</div>
<div class="plan-week plan-header" v-if="editStatus == true" style="cursor:pointer;"><i
class="el-icon-check" title="点击全选"></i> 全选</div>
<div class="plan-week plan-header" v-if="editStatus == true" style="cursor:pointer;"><i
class="el-icon-close" title="点击清空"></i> 清空</div>
</div>
<div v-for="(day, index) in zhouList" class="plan-row" :index="index" :key="index">
<div class="plan-week">
<el-checkbox :disabled="editStatus" v-model="day.checked" @change="checkType(day)">{{
day.name
}}</el-checkbox>
<!-- 星期{{day.name}} -->
</div>
<div class="plan-hours">
<div v-for="hour in 24" :key="hour"
:class="{'plan-title-num': true,'plan-title-num-left': hour <=1 ,'plan-title-num-right': hour >= 10 }">
{{ ((hour%2) == 0 || hour == 1 ) ? (hour == 1 ? 0:hour):''}}</div>
<div v-for="hour in 24" :key="'kd'+hour"
:class="{'plan-title-line': true,'plan-title-line-left': hour <=1 }">|</div>
<div :index="index" class="plan-day" @mousedown.prevent="dayClick($event,index)">
<span v-for="(d, i) in (durations[index] || [])" :key="i">
<el-popover placement="top" :title="title" width="250" trigger="click">
<div style="width:224px;margin:auto;">
<el-input style="width:46px;" :disabled="editStatus" size="mini" placeholder="时"
v-model="dstarthh" min="0" max="23"></el-input> :
<el-input style="width:46px;" :disabled="editStatus" size="mini" placeholder="分"
v-model="dstartmm" min="0" max="59"></el-input> -
<el-input style="width:46px;" :disabled="editStatus" size="mini" placeholder="时"
v-model="dendhh" min="0" max="23"></el-input> :
<el-input style="width:46px;" :disabled="editStatus" size="mini" placeholder="分"
v-model="dendmm" min="0" max="59"></el-input>
</div>
<div style="text-align: center; margin: 0">
<el-button size="mini" v-if="editStatus==false" type="text"
@click="removeDuration(index,i)">删除</el-button>
<el-button size="mini" v-if="editStatus==false" type="text"
@click="saveDuration(index,i)">保存</el-button>
</div>
<div v-if="editStatus" slot="reference"
@mousedown.prevent="durationClick($event,d,index)" class="plan-duration"
:style="'width:'+ durationWidth(d,index)+'%;left:'+durationLeft(d,index,i)+'%;'">
</div>
<div v-else-if="editStatus==false" slot="reference" @mousemove.prevent="durationmove($event,index,i)"
@mousedown.prevent="durationClick($event,d,index)" :id="'duration'+index+''+i"
:dayindex="index" :durationindex="i" :start="d['s'+(index+1)]"
:end="d['e'+(index+1)]" class="plan-duration"
:style="'width:'+ durationWidth(d,index)+'%;left:'+durationLeft(d,index,i)+'%;'">
</div>
</el-popover>
</span>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
export default {
props: {
serial: {
type: String,
default: ''
},
code: {
type: String,
default: ''
},
// title
title: {
type: String,
default: ''
},
// 宽度
width: {
type: String,
default: ''
},
// 查看或 新增编辑
editStatus: {
type: Boolean,
default: false
}
},
data() {
return {
zhouList: [
{
checked: false,
name: "星期一",
weekType: 1,
},
{
checked: false,
name: "星期二",
weekType: 2,
},
{
checked: false,
name: "星期三",
weekType: 3,
},
{
checked: false,
name: "星期四",
weekType: 4,
},
{
checked: false,
name: "星期五",
weekType: 5,
},
{
checked: false,
name: "星期六",
weekType: 6,
},
{
checked: false,
name: "星期日",
weekType: 7,
},
],
days: ["一", "二", "三", "四", "五", "六", "日"],
checks: [],
ho: 24,
isclick: false,
recordPlan: "",
isDown: false,
divIndex: 0,
currentDayWidth: 0,
isDown: false,
visible: false,
currentDuration: null,
isDownLeft: false,
isDownLeft: false,
value1: "",
durations: [[], [], [], [], [], [], []],
originDurations: [],
dayindex: 0,
overIndex: -1,
durationDatas: [],
prex: 0,
durationindex: 0,
startNum: 0,
dstarthh: "",
dstartmm: "",
dendhh: "",
dendmm: "",
moveprex: 0,
recordPlan: "",
mouseup: null,
mousemove: null,
movePosNum: 0,
nextStartNum: 0,
}
},
created() { },
watch: {},
mounted() {
this.mouseup = (e) => {
this.isDown = false;
this.isDownLeft = false;
this.isDownRight = false;
this.moveprex = 0;
this.movePosNum = 0;
this.prex = 0;
this.nextStartNum = 0;
this.checkPlanData(false);
this.log("mouse up")
}
this.mousemove = (e) => {
if (!this.isDown && !this.isDownLeft && !this.isDownRight) {
return false
}
if (this.isDown) {
var x = this.getPosX(e);
this.moveprex = x;
var pos = Math.floor((x / 656) * 1440 / 60) + ":" + Math.floor((x / 656) * 1440 % 60);
//校准成30的倍数
var posNum = this.timeToNum(pos);
posNum = posNum + (30 - posNum % 30);
if (posNum > 1440) {
posNum = 1440;
}
if (posNum <= this.movePosNum) {
return
}
this.movePosNum = posNum;
if (x == this.prex) {
return
}
if (x > this.prex) {
var start_time = this.numToTime(this.startNum);
var end_time = this.numToTime(posNum);
var start_key = "s" + (this.dayindex + 1);
var end_key = "e" + (this.dayindex + 1);
if (this.startNum == posNum || start_time == end_time) {
this.log("right move ignore isDown:" + this.isDown + ",prex=" + this.prex + ",x=" + x + "datalenth=" + this.durationDatas.length + ",durationindex=" + this.durationindex + ",posNum=" + posNum)
return
}
//判断有没有和其它交界
if ((this.durationindex + 1) < this.durationDatas.length) {
this.nextStartNum = this.timeToNum(this.durationDatas[this.durationindex + 1][start_key]);
if (posNum > this.nextStartNum) {
this.log("right move ignore 交界 isDown:" + this.isDown + ",prex=" + this.prex + "',x=" + x + ",datalenth=" + this.durationDatas.length + ",durationindex=" + this.durationindex + ",posNum=" + posNum + ",nextStart=" + this.durationDatas[this.durationindex + 1]["s" + (this.dayindex + 1)])
return
}
}
if (this.nextStartNum != 0 && posNum > this.nextStartNum) {
posNum = this.nextStartNum;
this.movePosNum = posNum;
end_time = this.numToTime(posNum);
}
this.durationDatas[this.durationindex][start_key] = start_time;
this.durationDatas[this.durationindex][end_key] = end_time;
this.log("right move log isDown:" + this.isDown + ",prex=" + this.prex + ",x=" + x + ",datalenth=" + this.durationDatas.length + ",durationindex=" + this.durationindex + ",posNum=" + posNum)
this.$set(this.durations, this.dayindex, this.durationDatas);
}
}
}
if (this.editStatus == false) {
document.addEventListener('mouseup', this.mouseup);
document.addEventListener('mousemove', this.mousemove);
}
{"startTime":"17:00","endTime":"21:30","weekType":1},{"startTime":"09:00","endTime":"15:00","weekType":2},{"startTime":"19:30","endTime":"22:00","weekType":2}]')
},
beforeDestroy() {
if (this.editStatus == false) {
document.removeEventListener('mouseup', this.mouseup);
document.removeEventListener('mousemove', this.mousemove);
}
},
methods: {
checkType(day){
if(day.checked == false){
this.durations[day.weekType-1] = [];
}
},
init(recordPlan) {
let recordPlanJx = JSON.parse(recordPlan);
if (recordPlanJx.length != 0) {
let FhData = [[], [], [], [], [], [], []]
for (let i = 0; i < recordPlanJx.length; i++) {
if (recordPlanJx[i].weekType == 1) {
FhData[0].push({ s1: recordPlanJx[i].startTime, e1: recordPlanJx[i].endTime })
}
if (recordPlanJx[i].weekType == 2) {
FhData[1].push({ s2: recordPlanJx[i].startTime, e2: recordPlanJx[i].endTime })
}
if (recordPlanJx[i].weekType == 3) {
FhData[2].push({ s3: recordPlanJx[i].startTime, e3: recordPlanJx[i].endTime })
}
if (recordPlanJx[i].weekType == 4) {
FhData[3].push({ s4: recordPlanJx[i].startTime, e4: recordPlanJx[i].endTime })
}
if (recordPlanJx[i].weekType == 5) {
FhData[4].push({ s5: recordPlanJx[i].startTime, e5: recordPlanJx[i].endTime })
}
if (recordPlanJx[i].weekType == 6) {
FhData[5].push({ s6: recordPlanJx[i].startTime, e6: recordPlanJx[i].endTime })
}
if (recordPlanJx[i].weekType == 7) {
FhData[6].push({ s7: recordPlanJx[i].startTime, e7: recordPlanJx[i].endTime })
}
this.zhouList[recordPlanJx[i].weekType -1].checked = true;
}
this.durations = FhData
} else {
this.durations = [[], [], [], [], [], [], []];
}
this.originDurations = [];
for (var i = 0; i < 7; i++) {
var el = [];
if (this.durations[i]) {
el = this.durations[i];
} else {
this.durations[i] = el;
}
this.originDurations[i] = el;
}
},
isModify() {
if (this.originDurations.length == 0) {
return false;
}
for (var i = 0; i < this.durations.length; i++) {
if (this.originDurations[i] != this.durations[i]) {
return true;
}
}
return false;
},
log(content) {
return
console.log(content)
},
durationmove(e, dayindex, durationindex) {
if (this.isDown && durationindex == this.durationindex && dayindex == this.dayindex) {
var x = this.getPosX(e);
var end_num = this.timeToNum(Math.floor(((this.prex + x) / 656) * 1440 / 60) + ":" + Math.floor(((this.prex + x) / 656) * 1440 % 60));
end_num = end_num + (30 - end_num % 30);
if (x == 0) {
end_num = this.startNum;
}
if (end_num > 1440) {
end_num = 1440;
}
this.log("duration move log moveprex=" + this.moveprex + ",prex=" + this.prex + ",x=" + x + ",startNum=" + this.startNum + ",end_num=" + end_num);
if (end_num >= this.startNum) {
if (this.nextStartNum != 0 && end_num > this.nextStartNum) {
end_num = this.nextStartNum;
}
this.movePosNum = end_num;
this.durations[dayindex][durationindex]["e" + (dayindex + 1)] = this.numToTime(end_num);
}
}
},
removeDuration(dayindex, durationindex) {
var newdaydurations = [];
for (var i = 0; i < this.durations[dayindex].length; i++) {
if (i == durationindex) {
continue
}
newdaydurations.push(this.durations[dayindex][i]);
}
if(newdaydurations.length == 0){
this.zhouList[dayindex].checked = false;
}
this.$set(this.durations, dayindex, newdaydurations);
$(".plan-row-header").click();
},
saveDuration(dayindex, durationindex) {
if (this.dstarthh.length == 1) {
this.dstarthh = "0" + this.dstarthh;
}
if (this.dstartmm.length == 1) {
this.dstartmm = "0" + this.dstartmm;
}
if (this.dendhh.length == 1) {
this.dendhh = "0" + this.dendhh;
}
if (this.dendmm.length == 1) {
this.dendmm = "0" + this.dendmm;
}
var start_time = this.dstarthh + ":" + this.dstartmm;
var end_time = this.dendhh + ":" + this.dendmm;
var newdaydurations = [];
var len = this.durations[dayindex].length;
for (var i = 0; i < len; i++) {
if (i == durationindex) {
if (this.timeToNum(start_time) > this.timeToNum(end_time)) {
this.$message({
type: 'warning',
message: '结束时间不能小于开始时间'
});
return
}
if (this.timeToNum(end_time) > 1440) {
this.$message({
type: 'warning',
message: '结束时间不能大于24点'
});
return
}
if (this.timeToNum(start_time) < 0) {
this.$message({
type: 'warning',
message: '开始时间不能小于0点'
});
return
}
if (i > 0) {
var pd = this.durations[dayindex][i - 1];
if (this.timeToNum(start_time) < this.timeToNum(pd["e" + (dayindex + 1)])) {
this.$message({
type: 'warning',
message: '开始时间须大于上一段结束时间'
});
return
}
}
if (i + 1 < len) {
var pd = this.durations[dayindex][i + 1];
if (this.timeToNum(end_time) > this.timeToNum(pd["s" + (dayindex + 1)])) {
this.$message({
type: 'warning',
message: '结束时间须小于下一段开始时间'
});
return
}
}
var ndata = {};
ndata["s" + (dayindex + 1)] = start_time;
ndata["e" + (dayindex + 1)] = end_time;
newdaydurations.push(ndata);
} else {
newdaydurations.push(this.durations[dayindex][i]);
}
}
this.$set(this.durations, dayindex, newdaydurations);
$(".plan-row-header").click();
},
durationClick(e, d, dayindex) {
this.dstarthh = d["s" + (dayindex + 1)].split(":")[0];
this.dstartmm = d["s" + (dayindex + 1)].split(":")[1];
this.dendhh = d["e" + (dayindex + 1)].split(":")[0];
this.dendmm = d["e" + (dayindex + 1)].split(":")[1];
if (e && e.stopPropagation) {
e.stopPropagation();
} else {
window.event.cancelBubble = true;
}
},
dayClick(event,hour) {
if (this.durations.length != 7) {
this.$message({
type: 'warning',
message: '初始化中,请稍后...'
});
return
}
this.isDown = true
var x = this.getPosX(event);
this.prex = x;
this.dayindex = parseInt($(event.currentTarget).attr("index"));
var durationDatas = [];
var start = Math.floor((x / 656) * 1440 / 60) + ":" + Math.floor(((x / 656) * 1440 % 60))
//校准成30的倍数
var snum = this.timeToNum(start);
if (snum % 30 > 15) {
this.startNum = snum + (30 - snum % 30);
} else {
this.startNum = snum - snum % 30;
}
var newData = {}
newData["s" + (this.dayindex + 1)] = this.numToTime(this.startNum);
newData["e" + (this.dayindex + 1)] = this.numToTime(this.startNum);
var hasPush = false;
for (var i = 0; i < this.durations[this.dayindex].length; i++) {
var el = this.durations[this.dayindex][i];
if (this.startNum < this.timeToNum(el["s" + (this.dayindex + 1)]) && !hasPush) {
hasPush = true;
this.durationindex = i;
durationDatas.push(newData)
}
durationDatas.push(el)
}
if (durationDatas.length == 0 || !hasPush) {
durationDatas.push(newData)
this.durationindex = durationDatas.length - 1;
}
this.durationDatas = durationDatas;
this.zhouList[hour].checked = true;
this.log("day click log x=" + x + ",dayindex=" + this.dayindex + ",predatalength=" + (this.durations[this.dayindex] || []).length + ",time=" + newData["s" + (this.dayindex + 1)] + "dataarr=" + this.durations[this.dayindex]);
},
getPosX(event) {
var x, y;
var event = event || window.event;
if (event.offsetX || event.offsetY) {
x = event.offsetX;
y = event.offsetY;
} else if (event.layerX || event.layerY) {
x = event.layerX;
y = event.layerY;
}
x = parseInt(x);
if (x < 0) {
x = 0;
} else if (x > 656) {
x = 656;
}
return x;
},
timeToNum(t) {
var time = t && t.split(":");
var h = parseInt(time[0]);
var m = parseInt(time[1]);
var sum = h * 60 + m;
return sum
},
numToTime(sum) {
var h = Math.floor(sum / 60) < 10 ? '0' + Math.floor(sum / 60) : Math.floor(sum / 60);
var m = sum % 60 < 10 ? '0' + (sum % 60) : sum % 60;
var t = h + ":" + m;
return t;
},
durationLeft(d, dayindex, durationindex) {
var preWidth = 0;
for (var i = 0; i < durationindex; i++) {
preWidth += this.durationWidth(this.durations[dayindex][i], dayindex);
}
if (preWidth < 0) {
preWidth = 0;
}
var s = this.timeToNum(d["s" + (dayindex + 1)]);
var ret = (s / 1440) * 100 - preWidth;
return ret
},
durationWidth(d, dayindex) {
var s = this.timeToNum(d["e" + (dayindex + 1)]) - this.timeToNum(d["s" + (dayindex + 1)]);
return (s / 1440) * 100
},
refresh() {
this.$confirm(
'<div class="tips" style="color:#333;font-weight:600;font-size:16px;margin-bottom:20px;">恢复初始配置,当前的编辑会丢失,是否继续?</div>',
"温馨提示",
{
confirmButtonText: "确定",
cancelButtonText: "取消",
showCancelButton: true,
// customClass: "del-model",
cancelButtonClass: "cancelOk",
confirmButtonClass: "letOk2",
dangerouslyUseHTMLString: true,
center: true,
}
)
.then(() => {
this.reset();
})
.catch(() => { });
},
getChecks() {
var plans = this.checks.join("")
return plans
},
reset() {
for (let i = 0; i < this.zhouList.length; i++) {
this.zhouList[i].checked = false
}
for (var i = 0; i < 7; i++) {
var el = this.originDurations[i] || [];
this.$set(this.durations, i, el);
}
},
checkPlanData(join) {
var durationDatas = [];
for (var i = 0; i < 7; i++) {
var els = [];
if (this.durations[i]) {
for (var j = 0; j < this.durations[i].length; j++) {
var s_key = "s" + (i + 1);
var e_key = "e" + (i + 1);
var s_num = this.timeToNum(this.durations[i][j][s_key]);
if (s_num < 0 || s_num > 1440) {
continue
}
var e_num = this.timeToNum(this.durations[i][j][e_key]);
if (e_num < 0 || e_num > 1440) {
continue
}
if (s_num >= e_num) {
continue
}
var _duration = {}
if (els.length > 0) {
var pre = els[els.length - 1];
var e_num_pre = this.timeToNum(pre[e_key]);
if (s_num < e_num_pre) {
s_num = e_num_pre;
}
if (join) {
if (s_num == e_num_pre) {
els[els.length - 1][e_key] = this.numToTime(e_num);
continue
}
}
}
_duration[s_key] = this.numToTime(s_num);
_duration[e_key] = this.numToTime(e_num);
els.push(_duration);
}
}
durationDatas.push(els)
}
this.durations = durationDatas;
},
getplan() {
this.checkPlanData(true);
let rtData = [];
if (this.zhouList[0].checked == true) {
if (this.durations[0].length != 0) {
for (let i = 0; i < this.durations[0].length; i++) {
rtData.push({ startTime: this.durations[0][i].s1, endTime: this.durations[0][i].e1, weekType: 1 })
}
}
}
if (this.zhouList[1].checked == true) {
if (this.durations[1].length != 0) {
for (let i = 0; i < this.durations[1].length; i++) {
rtData.push({ startTime: this.durations[1][i].s2, endTime: this.durations[1][i].e2, weekType: 2 })
}
}
}
if (this.zhouList[2].checked == true) {
if (this.durations[2].length != 0) {
for (let i = 0; i < this.durations[2].length; i++) {
rtData.push({ startTime: this.durations[2][i].s3, endTime: this.durations[2][i].e3, weekType: 3 })
}
}
}
if (this.zhouList[3].checked == true) {
if (this.durations[3].length != 0) {
for (let i = 0; i < this.durations[3].length; i++) {
rtData.push({ startTime: this.durations[3][i].s4, endTime: this.durations[3][i].e4, weekType: 4 })
}
}
}
if (this.zhouList[4].checked == true) {
if (this.durations[4].length != 0) {
for (let i = 0; i < this.durations[4].length; i++) {
rtData.push({ startTime: this.durations[4][i].s5, endTime: this.durations[4][i].e5, weekType: 5 })
}
}
}
if (this.zhouList[5].checked == true) {
if (this.durations[5].length != 0) {
for (let i = 0; i < this.durations[5].length; i++) {
rtData.push({ startTime: this.durations[5][i].s6, endTime: this.durations[5][i].e6, weekType: 6 })
}
}
}
if (this.zhouList[6].checked == true) {
if (this.durations[6].length != 0) {
for (let i = 0; i < this.durations[6].length; i++) {
// this.durations[6][i].startTime = this.durations[6][i].s7;
// this.durations[6][i].endTime = this.durations[6][i].e7;
// this.durations[6][i].weekType = 7;
rtData.push({ startTime: this.durations[6][i].s7, endTime: this.durations[6][i].e7, weekType: 7 })
}
}
}
console.log(rtData)
var plan = JSON.stringify(rtData);
return plan;
},
selectall() {
for (let i = 0; i < this.zhouList.length; i++) {
this.zhouList[i].checked = true
}
for (var i = 0; i < 7; i++) {
var el = [];
var n = {};
n["s" + (i + 1)] = "00:00";
n["e" + (i + 1)] = "24:00";
el.push(n);
this.$set(this.durations, i, el);
}
},
unselectall() {
for (let i = 0; i < this.zhouList.length; i++) {
this.zhouList[i].checked = false
}
for (var i = 0; i < 7; i++) {
var el = [];
this.$set(this.durations, i, el);
}
}
},
}
</script>
<style lang="less" scoped>
/* @import url(~assets/styles/variables.less); */
.plans {
font-size: 12px;
text-align: center;
border: 0;
float: left;
background-color: #f8fbfe;
padding: 15px 30px 30px 20px;
}
.plan-week {
width: 10%;
height: 100%;
float: left;
background-color: #f8fbfe;
color: #646363;
line-height: 88px;
border: 0;
}
.plan-week:hover {
background-color: #f8fbfe;
}
.plan-hours {
margin-left: 2%;
width: 88%;
height: 100%;
float: left;
background-color: #f8fbfe;
}
.plan-title-num {
font-weight: bold;
height: 25% !important;
color: #7f7e7e;
background-color: #f8fbfe;
line-height: 20px !important;
width: 4.166%;
float: left;
font-size: 12px;
border-color: #eee;
border-style: none none none none;
text-align: right;
}
.plan-title-num-right {
margin-left: 2px;
margin-right: -2px;
}
.plan-title-num-left {
text-align: left !important;
margin-left: -10px;
padding-left: 5px;
margin-right: 10px;
}
.plan-title-line {
font-weight: bold;
height: 15% !important;
color: #dddddd;
background-color: #f8fbfe;
line-height: 14px !important;
width: 4.167%;
float: left;
font-size: 12px;
border-style: none none none none;
text-align: right;
}
.plan-title-line-left {
border-style: none none none solid !important;
border-color: #dddddd;
border-left-width: 1px;
margin-left: -0.4%;
}
.plan-day {
width: 100%;
height: 60%;
float: left;
background-color: white;
color: #eee;
line-height: 40px;
border: solid;
border-width: 1px;
border-color: #dddddd;
margin-left: -0.5%;
}
.plan-header {
font-weight: bold;
height: 24px !important;
color: #646363;
background-color: #f8fbfe !important;
line-height: 24px !important;
}
.plan-header:hover {
background-color: #f8fbfe;
}
.plan-row-header {
height: 24px;
width: 100%;
}
.plan-row {
height: 60px;
width: 100%;
border-top: 1px;
border-style: none;
border-color: #eee;
}
.plan-duration {
display: block;
height: 100%;
background-color: #347fff;
border-color: black;
border-style: none none none none;
font-size: 10px;
cursor: pointer;
float: left;
position: relative;
}
.plan-duration:hover {
background-color: #80acf7;
}
</style>
![](https://i-blog.csdnimg.cn/blog_migrate/d4adaad35b7cfc2494938c4ec408c61d.png)