|
|
@@ -15,7 +15,7 @@
|
|
|
<div class="l-flex__auto l-flex--col">
|
|
|
<div class="l-flex__none c-device-detail__name u-ellipsis">{{ deivceName }}</div>
|
|
|
<template v-if="programProxy">
|
|
|
- <div class="l-flex__none c-device-detail__program">
|
|
|
+ <div class="l-flex__none c-device-detail__program u-ellipsis">
|
|
|
<span
|
|
|
class="u-pointer"
|
|
|
@click="onView"
|
|
|
@@ -27,7 +27,7 @@
|
|
|
</div>
|
|
|
<div
|
|
|
v-loading="deviceOptions.loading"
|
|
|
- class="l-flex__auto l-flex--col c-timeline"
|
|
|
+ class="l-flex__fill l-flex--col c-timeline"
|
|
|
>
|
|
|
<div class="l-flex__none l-flex--row has-bottom-padding">
|
|
|
<div class="l-flex__auto c-sibling-item" />
|
|
|
@@ -69,46 +69,56 @@
|
|
|
搜索
|
|
|
</button>
|
|
|
</div>
|
|
|
- <div class="l-flex__none l-flex--col u-relative">
|
|
|
- <div class="l-flex c-timeline__row header">
|
|
|
- <div class="l-flex__none c-timeline__col c-timeline__left">设备</div>
|
|
|
- <div class="l-flex__auto l-flex--row c-timeline__col">
|
|
|
- <i
|
|
|
- class="l-flex__none c-timeline__arrow el-icon-arrow-left u-pointer"
|
|
|
- :class="{ display: canPrevious }"
|
|
|
- @click="offsetTime(-1)"
|
|
|
- />
|
|
|
- <div class="l-flex__auto l-flex--row c-timeline__time">
|
|
|
- <div
|
|
|
- v-for="time in times"
|
|
|
- :key="time"
|
|
|
- class="l-flex__none"
|
|
|
- >
|
|
|
- {{ time }}
|
|
|
- </div>
|
|
|
+ <div class="l-flex__none l-flex c-timeline__row header">
|
|
|
+ <div class="l-flex__none c-timeline__left">
|
|
|
+ <span class="o-priority priority3">高</span>
|
|
|
+ <span class="o-priority priority2">中</span>
|
|
|
+ <span class="o-priority priority1">低</span>
|
|
|
+ </div>
|
|
|
+ <div class="l-flex__auto l-flex--row c-timeline__right">
|
|
|
+ <i
|
|
|
+ class="l-flex__none c-timeline__arrow left el-icon-arrow-left u-pointer"
|
|
|
+ :class="{ display: canPrevious }"
|
|
|
+ @click="offsetTime(-1)"
|
|
|
+ />
|
|
|
+ <div class="l-flex__auto l-flex--row c-timeline__time">
|
|
|
+ <div
|
|
|
+ v-for="time in times"
|
|
|
+ :key="time"
|
|
|
+ class="l-flex__none"
|
|
|
+ >
|
|
|
+ {{ time }}
|
|
|
</div>
|
|
|
- <i
|
|
|
- class="l-flex__none c-timeline__arrow display el-icon-arrow-right u-pointer"
|
|
|
- @click="offsetTime(1)"
|
|
|
- />
|
|
|
</div>
|
|
|
+ <i
|
|
|
+ class="l-flex__none c-timeline__arrow right display el-icon-arrow-right u-pointer"
|
|
|
+ @click="offsetTime(1)"
|
|
|
+ />
|
|
|
</div>
|
|
|
- <div
|
|
|
- v-for="item in deviceOptions.list"
|
|
|
- :key="item.id"
|
|
|
- class="l-flex c-timeline__row"
|
|
|
- :class="{ selected: item.id === deviceId }"
|
|
|
- @click="chooseProgramProxy(item)"
|
|
|
- >
|
|
|
- <div class="l-flex__none c-timeline__col c-timeline__left u-pointer">
|
|
|
- <div class="u-ellipsis">{{ item.name }}</div>
|
|
|
- </div>
|
|
|
- <div class="l-flex__auto l-flex--row c-timeline__col u-relative">
|
|
|
- <template v-if="item.options.loading">
|
|
|
- <i class="el-icon-loading has-padding--h" />加载中...
|
|
|
- </template>
|
|
|
- <template v-else-if="item.options.error">
|
|
|
- <div class="has-padding--h">
|
|
|
+ </div>
|
|
|
+ <div class="l-flex--col c-timeline__main u-relative">
|
|
|
+ <div class="l-flex__auto u-overflow-y--auto">
|
|
|
+ <div
|
|
|
+ v-for="item in deviceOptions.list"
|
|
|
+ :key="item.id"
|
|
|
+ class="l-flex c-timeline__row"
|
|
|
+ :class="{ selected: item.id === deviceId }"
|
|
|
+ @click="chooseProgramProxy(item)"
|
|
|
+ >
|
|
|
+ <div class="l-flex__none c-timeline__left u-relative u-pointer">
|
|
|
+ <div class="u-ellipsis">{{ item.name }}</div>
|
|
|
+ </div>
|
|
|
+ <div class="l-flex__auto l-flex--col c-timeline__right">
|
|
|
+ <div
|
|
|
+ v-if="item.options.loading"
|
|
|
+ class="l-flex--row c-timeline__programs"
|
|
|
+ >
|
|
|
+ <i class="el-icon-loading has-padding--h" />加载中...
|
|
|
+ </div>
|
|
|
+ <div
|
|
|
+ v-else-if="item.options.error"
|
|
|
+ class="l-flex--row c-timeline__programs has-padding--h"
|
|
|
+ >
|
|
|
<el-link
|
|
|
class="u-pointer"
|
|
|
type="warning"
|
|
|
@@ -117,39 +127,45 @@
|
|
|
出错了,点击重试
|
|
|
</el-link>
|
|
|
</div>
|
|
|
- </template>
|
|
|
- <template v-else-if="item.options.list.length">
|
|
|
+ <template v-else-if="item.options.list.length">
|
|
|
+ <div
|
|
|
+ v-for="(programs, index) in item.options.list"
|
|
|
+ :key="index"
|
|
|
+ class="c-timeline__programs l-flex--row u-relative"
|
|
|
+ >
|
|
|
+ <div
|
|
|
+ v-for="program in programs"
|
|
|
+ :key="program.key"
|
|
|
+ class="l-flex__none l-flex--row c-program u-pointer"
|
|
|
+ :class="[{ 'selected': program.event.selected }, `priority${program.event.priority}`]"
|
|
|
+ :style="program.style"
|
|
|
+ @click.stop="chooseProgramProxy(item, program)"
|
|
|
+ >
|
|
|
+ <i
|
|
|
+ class="l-flex__none c-program__img o-program"
|
|
|
+ :style="program.event.style"
|
|
|
+ />
|
|
|
+ <div class="l-flex__auto">
|
|
|
+ <auto-text
|
|
|
+ class="c-program__time"
|
|
|
+ :text="program.time"
|
|
|
+ :tag="program.style.width"
|
|
|
+ />
|
|
|
+ <auto-text
|
|
|
+ class="c-program__name"
|
|
|
+ :text="program.event.target.name"
|
|
|
+ :tag="program.style.width"
|
|
|
+ />
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </template>
|
|
|
<div
|
|
|
- v-for="(program, index) in item.options.list"
|
|
|
- :key="index"
|
|
|
- class="l-flex__none l-flex--row c-program u-pointer"
|
|
|
- :class="{ 'selected': program.event && program.event.selected }"
|
|
|
- :style="program.style"
|
|
|
- @click.stop="chooseProgramProxy(item, program)"
|
|
|
+ v-else
|
|
|
+ class="l-flex--row c-timeline__programs has-padding--h"
|
|
|
>
|
|
|
- <i
|
|
|
- class="l-flex__none c-program__img o-program"
|
|
|
- :style="program.event.style"
|
|
|
- />
|
|
|
- <div class="l-flex__auto">
|
|
|
- <auto-text
|
|
|
- class="c-program__time"
|
|
|
- :text="program.time"
|
|
|
- :tag="program.style.width"
|
|
|
- />
|
|
|
- <auto-text
|
|
|
- class="c-program__name"
|
|
|
- :text="program.event.target.name"
|
|
|
- :tag="program.style.width"
|
|
|
- />
|
|
|
- </div>
|
|
|
+ 当前时段暂无节目
|
|
|
</div>
|
|
|
- </template>
|
|
|
- <div
|
|
|
- v-else
|
|
|
- class="has-padding--h"
|
|
|
- >
|
|
|
- 当前时段暂无节目
|
|
|
</div>
|
|
|
</div>
|
|
|
</div>
|
|
|
@@ -207,7 +223,8 @@ import {
|
|
|
getNearestHitDate,
|
|
|
getStartDate,
|
|
|
getFinishDate,
|
|
|
- pickMin
|
|
|
+ pickMin,
|
|
|
+ pickMax
|
|
|
} from '@/utils/event'
|
|
|
import { EventCache } from '@/utils/cache'
|
|
|
import {
|
|
|
@@ -346,12 +363,7 @@ export default {
|
|
|
options.loading = false
|
|
|
}).then(events => {
|
|
|
const now = Date.now()
|
|
|
- options.events = events.map(this.transformEvent).filter(({ until }) => !until || now < new Date(until)).sort((a, b) => {
|
|
|
- if (b.priority === a.priority) {
|
|
|
- return toDate(a.start) - toDate(b.start)
|
|
|
- }
|
|
|
- return b.priority - a.priority
|
|
|
- })
|
|
|
+ options.events = this.transformEvents(events.map(this.transformEvent).filter(({ until }) => !until || now < new Date(until)))
|
|
|
this.calcEvents(options)
|
|
|
}, () => {
|
|
|
options.error = true
|
|
|
@@ -375,6 +387,19 @@ export default {
|
|
|
}
|
|
|
}
|
|
|
},
|
|
|
+ transformEvents (events) {
|
|
|
+ const map = {}
|
|
|
+ for (let i = 0; i < events.length; i++) {
|
|
|
+ const event = events[i]
|
|
|
+ if (!map[event.priority]) {
|
|
|
+ map[event.priority] = []
|
|
|
+ }
|
|
|
+ map[event.priority].push(event)
|
|
|
+ }
|
|
|
+ return Object.keys(map)
|
|
|
+ .sort((a, b) => a > b ? -1 : 1)
|
|
|
+ .map(key => map[key].sort((a, b) => toDate(a.start) - toDate(b.start)))
|
|
|
+ },
|
|
|
getTime (event) {
|
|
|
const { freq, start, until, byDay, startTime, endTime } = event
|
|
|
switch (freq) {
|
|
|
@@ -391,7 +416,7 @@ export default {
|
|
|
return date < min || date > max
|
|
|
},
|
|
|
initTimes (date) {
|
|
|
- date = toDate(date)
|
|
|
+ date = pickMax(toDate(date), new Date())
|
|
|
this.current = toZeroPoint(date)
|
|
|
this.startHour = Math.min(20, date.getHours())
|
|
|
this.refreshTimes(this.startHour)
|
|
|
@@ -416,7 +441,7 @@ export default {
|
|
|
this.style = null
|
|
|
} else {
|
|
|
this.style = {
|
|
|
- width: `${Math.min(100, (now - this.$startDateTime) / 144000)}%`
|
|
|
+ left: `${Math.min(100, (now - this.$startDateTime) / 144000)}%`
|
|
|
}
|
|
|
}
|
|
|
},
|
|
|
@@ -428,10 +453,14 @@ export default {
|
|
|
offsetTime (offset) {
|
|
|
const next = this.startHour + offset
|
|
|
if (offset < 0) {
|
|
|
- const timestamp = this.$startDateTime.getTime() + next * 3600000
|
|
|
- if (timestamp >= Date.now()) {
|
|
|
+ const timestamp = this.current.getTime() + next * 3600000
|
|
|
+ const now = new Date()
|
|
|
+ now.setMinutes(0)
|
|
|
+ now.setSeconds(0)
|
|
|
+ now.setMilliseconds(0)
|
|
|
+ if (timestamp >= now) {
|
|
|
if (next < 0) {
|
|
|
- this.initTimes(new Date(timestamp), true)
|
|
|
+ this.initTimes(timestamp)
|
|
|
} else {
|
|
|
this.refreshTimes(this.startHour = next)
|
|
|
}
|
|
|
@@ -447,12 +476,8 @@ export default {
|
|
|
onTimeChange (val) {
|
|
|
this.initTimes(val)
|
|
|
},
|
|
|
- calcEvents (options) {
|
|
|
- if (options.loading || options.error) {
|
|
|
- return
|
|
|
- }
|
|
|
+ calcSamePriorityEvents (events) {
|
|
|
const total = 144000
|
|
|
- const events = options.events
|
|
|
const arr = []
|
|
|
for (let i = 0; i < events.length; i++) {
|
|
|
const event = events[i]
|
|
|
@@ -466,6 +491,7 @@ export default {
|
|
|
const startDate = getStartDate(event, hit)
|
|
|
const endDate = getFinishDate(event, hit)
|
|
|
arr.push({
|
|
|
+ key: event.target.id,
|
|
|
event,
|
|
|
time: `${toDateStr(startDate)} ${toTimeStr(startDate)} - ${toDateStr(endDate)} ${toTimeStr(endDate)}`,
|
|
|
style: {
|
|
|
@@ -476,9 +502,18 @@ export default {
|
|
|
})
|
|
|
event.invoke?.()
|
|
|
event.img?.()
|
|
|
+ if (endDate >= this.$endDateTime) {
|
|
|
+ break
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
- options.list = arr
|
|
|
+ return arr
|
|
|
+ },
|
|
|
+ calcEvents (options) {
|
|
|
+ if (options.loading || options.error) {
|
|
|
+ return
|
|
|
+ }
|
|
|
+ options.list = options.events.map(this.calcSamePriorityEvents).filter(events => events.length)
|
|
|
},
|
|
|
chooseProgramProxy (device, programProxy) {
|
|
|
this.device = device
|
|
|
@@ -550,27 +585,31 @@ export default {
|
|
|
.c-timeline {
|
|
|
min-height: 400px;
|
|
|
|
|
|
- &__row {
|
|
|
- height: 56px;
|
|
|
+ &__main {
|
|
|
+ flex: 0 1 auto;
|
|
|
+ min-height: 0;
|
|
|
+ border: 1px solid $border;
|
|
|
+ }
|
|
|
|
|
|
+ &__row {
|
|
|
& + & {
|
|
|
- margin-top: 1px;
|
|
|
+ border-top: 1px solid $border;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- &__row.header &__col {
|
|
|
- color: $black;
|
|
|
- background-color: #f4f7fb;
|
|
|
- user-select: none;
|
|
|
+ &__row.header {
|
|
|
+ .c-timeline__left {
|
|
|
+ border-right: none;
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
- &__row.header &__left {
|
|
|
- justify-content: center;
|
|
|
- padding: 0;
|
|
|
- font-weight: bold;
|
|
|
+ &__row.header &__right {
|
|
|
+ color: $black;
|
|
|
+ user-select: none;
|
|
|
+ background-color: transparent;
|
|
|
}
|
|
|
|
|
|
- &__row.selected &__col {
|
|
|
+ &__row.selected &__left {
|
|
|
color: #fff;
|
|
|
background-color: #9fbfe8;
|
|
|
}
|
|
|
@@ -585,32 +624,53 @@ export default {
|
|
|
background-color: $blue;
|
|
|
}
|
|
|
|
|
|
- &__col {
|
|
|
- position: relative;
|
|
|
- color: $info--dark;
|
|
|
- font-size: 14px;
|
|
|
- line-height: 1;
|
|
|
- background-color: #edf0f6;
|
|
|
- overflow: hidden;
|
|
|
- }
|
|
|
-
|
|
|
&__left {
|
|
|
display: inline-flex;
|
|
|
align-items: center;
|
|
|
width: 210px;
|
|
|
padding: 0 10px 0 20px;
|
|
|
margin-right: 1px;
|
|
|
+ color: $black;
|
|
|
font-size: 16px;
|
|
|
+ background-color: #fafbfc;
|
|
|
+ border-right: 1px solid $border;
|
|
|
+ }
|
|
|
+
|
|
|
+ &__right {
|
|
|
+ position: relative;
|
|
|
+ color: $info--dark;
|
|
|
+ font-size: 14px;
|
|
|
+ line-height: 1;
|
|
|
+ overflow: hidden;
|
|
|
+ }
|
|
|
+
|
|
|
+ &__programs {
|
|
|
+ box-sizing: content-box;
|
|
|
+ height: 48px;
|
|
|
+
|
|
|
+ & + & {
|
|
|
+ border-top: 1px dashed $border;
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
&__arrow {
|
|
|
visibility: hidden;
|
|
|
+ position: absolute;
|
|
|
+ top: 50%;
|
|
|
padding: 6px;
|
|
|
- margin: 0 16px;
|
|
|
color: #fff;
|
|
|
font-size: 12px;
|
|
|
border-radius: 4px;
|
|
|
background-color: $blue;
|
|
|
+ transform: translateY(-50%);
|
|
|
+
|
|
|
+ &.left {
|
|
|
+ left: 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ &.right {
|
|
|
+ right: 0;
|
|
|
+ }
|
|
|
|
|
|
&.display {
|
|
|
visibility: visible;
|
|
|
@@ -618,15 +678,16 @@ export default {
|
|
|
}
|
|
|
|
|
|
&__time {
|
|
|
- justify-content: space-between;
|
|
|
+ justify-content: space-around;
|
|
|
+ padding: 10px 0;
|
|
|
color: $black;
|
|
|
- font-size: 16px;
|
|
|
+ font-size: 14px;
|
|
|
}
|
|
|
|
|
|
&__line {
|
|
|
position: absolute;
|
|
|
- top: 0;
|
|
|
- left: 211px;
|
|
|
+ top: -12px;
|
|
|
+ left: 210px;
|
|
|
right: 0;
|
|
|
bottom: 0;
|
|
|
pointer-events: none;
|
|
|
@@ -637,13 +698,9 @@ export default {
|
|
|
top: 0;
|
|
|
left: 0;
|
|
|
bottom: 0;
|
|
|
- color: #e51414;
|
|
|
+ color: #ff0000;
|
|
|
border-right: 1px solid currentColor;
|
|
|
- background-image: linear-gradient(
|
|
|
- -90deg,
|
|
|
- rgba(#ff8a8a, 0.33) 0%,
|
|
|
- rgba(#fff, 0) 100%
|
|
|
- );
|
|
|
+ z-index: 999;
|
|
|
|
|
|
&::after {
|
|
|
content: "";
|
|
|
@@ -662,15 +719,12 @@ export default {
|
|
|
position: absolute;
|
|
|
top: 0;
|
|
|
bottom: 0;
|
|
|
- padding: 0 4px;
|
|
|
- color: #fff;
|
|
|
- font-size: 14px;
|
|
|
- background-color: rgba($blue, 0.4);
|
|
|
+ font-size: 12px;
|
|
|
overflow: hidden;
|
|
|
|
|
|
&:hover {
|
|
|
- color: $black;
|
|
|
- background-color: $blue--light;
|
|
|
+ color: #fff;
|
|
|
+ background-color: rgba($blue, 0.4);
|
|
|
}
|
|
|
|
|
|
&.selected {
|
|
|
@@ -682,7 +736,7 @@ export default {
|
|
|
&__img {
|
|
|
width: 84px;
|
|
|
height: 48px;
|
|
|
- margin-right: $spacing;
|
|
|
+ margin-right: 8px;
|
|
|
border-radius: 4px;
|
|
|
}
|
|
|
|
|
|
@@ -691,6 +745,32 @@ export default {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+.o-priority {
|
|
|
+ display: inline-block;
|
|
|
+ padding: 4px;
|
|
|
+ font-size: 12px;
|
|
|
+ border-radius: 4px;
|
|
|
+
|
|
|
+ & + & {
|
|
|
+ margin-left: 4px;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+.priority1 {
|
|
|
+ color: #8e929c;
|
|
|
+ background-color: #edf0f6;
|
|
|
+}
|
|
|
+
|
|
|
+.priority2 {
|
|
|
+ color: #7642fd;
|
|
|
+ background-color: #eae2fe;
|
|
|
+}
|
|
|
+
|
|
|
+.priority3 {
|
|
|
+ color: #ff2222;
|
|
|
+ background-color: #ffecec;
|
|
|
+}
|
|
|
+
|
|
|
.o-program {
|
|
|
background: url("~@/assets/program_bg.png") 0 0 / 100% 100% no-repeat;
|
|
|
}
|