|
|
@@ -1,6 +1,7 @@
|
|
|
<template>
|
|
|
<div
|
|
|
class="o-device u-pointer"
|
|
|
+ :data-id="device.id"
|
|
|
@click="onClick"
|
|
|
>
|
|
|
<div class="l-flex__none l-flex--row c-sibling-item--v o-device__header u-font-size u-bold">
|
|
|
@@ -46,13 +47,13 @@
|
|
|
<div class="l-flex__none l-flex--row c-sibling-item--v">
|
|
|
<div class="u-relative">
|
|
|
<span class="u-font-size--md u-bold">{{ current.startTime }}</span>
|
|
|
- <span class="o-device__ymd u-color--info light u-font-size--xs">{{ current.startDate }}</span>
|
|
|
+ <span class="o-device__ymd u-color--black light u-font-size--xs">{{ current.startDate }}</span>
|
|
|
</div>
|
|
|
<template v-if="current.endDate">
|
|
|
<span class="o-device__line" />
|
|
|
<div class="u-relative">
|
|
|
<span class="u-font-size--md u-bold">{{ current.endTime }}</span>
|
|
|
- <span class="o-device__ymd u-color--info light u-font-size--xs">{{ current.endDate }}</span>
|
|
|
+ <span class="o-device__ymd u-color--black light u-font-size--xs">{{ current.endDate }}</span>
|
|
|
</div>
|
|
|
</template>
|
|
|
</div>
|
|
|
@@ -71,7 +72,7 @@
|
|
|
{{ lastOnline }}
|
|
|
</span>
|
|
|
</div>
|
|
|
- <div class="l-flex__none l-flex--row c-sibling-item--v o-device__next u-color--info light u-font-size--xs u-text--center">
|
|
|
+ <div class="l-flex__none l-flex--row c-sibling-item--v o-device__next u-color--black light u-font-size--xs u-text--center">
|
|
|
<auto-text
|
|
|
v-if="next"
|
|
|
class="l-flex__fill"
|
|
|
@@ -89,14 +90,14 @@
|
|
|
</template>
|
|
|
|
|
|
<script>
|
|
|
-import { getTimeline } from '@/api/device'
|
|
|
-import { EventPriorityInfo } from '@/constant'
|
|
|
import {
|
|
|
- listen,
|
|
|
- unlisten
|
|
|
-} from '@/utils/mqtt'
|
|
|
+ EventPriority,
|
|
|
+ EventPriorityInfo
|
|
|
+} from '@/constant'
|
|
|
+import { getTimelineByRange } from '@/api/device'
|
|
|
import { ScreenshotCache } from '@/utils/cache'
|
|
|
import {
|
|
|
+ ONE_DAY,
|
|
|
isHit,
|
|
|
getNearestHitDate,
|
|
|
getFinishDate,
|
|
|
@@ -111,6 +112,14 @@ export default {
|
|
|
device: {
|
|
|
type: Object,
|
|
|
required: true
|
|
|
+ },
|
|
|
+ observer: {
|
|
|
+ type: Function,
|
|
|
+ required: true
|
|
|
+ },
|
|
|
+ flag: {
|
|
|
+ type: Number,
|
|
|
+ required: true
|
|
|
}
|
|
|
},
|
|
|
data () {
|
|
|
@@ -150,26 +159,76 @@ export default {
|
|
|
return this.next ? `下一场:${this.next.startDate} ${this.next.startTime} ${this.next.name}` : ''
|
|
|
}
|
|
|
},
|
|
|
+ watch: {
|
|
|
+ flag () {
|
|
|
+ this.checkStatus()
|
|
|
+ }
|
|
|
+ },
|
|
|
created () {
|
|
|
+ this.$timer = -1
|
|
|
+ this.$refreshTimer = -1
|
|
|
+ },
|
|
|
+ mounted () {
|
|
|
if (this.isOnline) {
|
|
|
- this.getTimeline()
|
|
|
- listen(this.onMessage)
|
|
|
- ScreenshotCache.watch(this.device, this.onScreenshotUpdate)
|
|
|
+ this.observer(this.$el)
|
|
|
} else {
|
|
|
ScreenshotCache.remove(this.device.id)
|
|
|
}
|
|
|
},
|
|
|
beforeDestroy () {
|
|
|
- if (this.isOnline) {
|
|
|
- unlisten(this.onMessage)
|
|
|
+ if (this.$firstView) {
|
|
|
ScreenshotCache.unwatch(this.device.id)
|
|
|
+ clearTimeout(this.$refreshTimer)
|
|
|
clearTimeout(this.$timer)
|
|
|
this.$timer = -1
|
|
|
}
|
|
|
},
|
|
|
methods: {
|
|
|
+ intoView () {
|
|
|
+ if (!this.isOnline) {
|
|
|
+ return
|
|
|
+ }
|
|
|
+ if (!this.$firstView) {
|
|
|
+ ScreenshotCache.watch(this.device, this.onScreenshotUpdate)
|
|
|
+ this.$firstView = true
|
|
|
+ }
|
|
|
+ console.log(this.device.name, 'intoView')
|
|
|
+ this.$timer = null
|
|
|
+ if (!this.loadingTimeline) {
|
|
|
+ if (this.timeline && this.$maxDate - Date.now() > 300000) {
|
|
|
+ this.onUpdate()
|
|
|
+ } else {
|
|
|
+ this.getTimeline()
|
|
|
+ }
|
|
|
+ }
|
|
|
+ },
|
|
|
+ outView () {
|
|
|
+ if (!this.isOnline) {
|
|
|
+ return
|
|
|
+ }
|
|
|
+ console.log(this.device.name, 'outView')
|
|
|
+ clearTimeout(this.$refreshTimer)
|
|
|
+ clearTimeout(this.$timer)
|
|
|
+ this.$timer = -1
|
|
|
+ },
|
|
|
+ checkStatus () {
|
|
|
+ if (!this.isOnline) {
|
|
|
+ return
|
|
|
+ }
|
|
|
+ if (this.flag) {
|
|
|
+ if (this.flag > 0) {
|
|
|
+ this.intoView()
|
|
|
+ } else if (this.$timer === -1) {
|
|
|
+ this.timeline = null
|
|
|
+ } else {
|
|
|
+ this.getTimeline()
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ this.outView()
|
|
|
+ }
|
|
|
+ },
|
|
|
screenshot () {
|
|
|
- ScreenshotCache.screenshot(this.device.id)
|
|
|
+ ScreenshotCache.screenshot(this.device.id, true)
|
|
|
},
|
|
|
onScreenshotUpdate ({ waiting, base64 }) {
|
|
|
this.isShotting = waiting
|
|
|
@@ -181,72 +240,79 @@ export default {
|
|
|
params: { id: this.device.id }
|
|
|
})
|
|
|
},
|
|
|
- onMessage (topic, message) {
|
|
|
- if (message) {
|
|
|
- const result = new RegExp(`${this.device.productId}/${this.device.id}/(.+)`).exec(topic)
|
|
|
- if (result) {
|
|
|
- switch (result[1]) {
|
|
|
- case 'calendar/update':
|
|
|
- this.onCalendarUpdate(message)
|
|
|
- break
|
|
|
- default:
|
|
|
- break
|
|
|
+ getTimeline () {
|
|
|
+ clearTimeout(this.$refreshTimer)
|
|
|
+ clearTimeout(this.$timer)
|
|
|
+ this.loadingTimeline = true
|
|
|
+ this.timeline = null
|
|
|
+ this.current = null
|
|
|
+ this.next = null
|
|
|
+ const { from, to } = this.getTimeRange()
|
|
|
+ console.log(this.device.id, from, to)
|
|
|
+ this.$maxDate = toDate(to)
|
|
|
+ getTimelineByRange(this.device.id, from, to, { custom: true }).then(
|
|
|
+ events => {
|
|
|
+ const now = Date.now()
|
|
|
+ console.log(events)
|
|
|
+ this.timeline = events.filter((event, index) => {
|
|
|
+ const { priority, until } = event
|
|
|
+ const allow = priority > EventPriority.SHIM && (!until || now < toDate(until))
|
|
|
+ if (allow) {
|
|
|
+ event.key = index
|
|
|
+ }
|
|
|
+ return allow
|
|
|
+ }).sort((a, b) => {
|
|
|
+ if (b.priority === a.priority) {
|
|
|
+ return toDate(a.start) - toDate(b.start)
|
|
|
+ }
|
|
|
+ return b.priority - a.priority
|
|
|
+ })
|
|
|
+ this.onUpdate()
|
|
|
+ this.loadingTimeline = false
|
|
|
+ },
|
|
|
+ ({ isCancel }) => {
|
|
|
+ if (!isCancel && this.$timer !== -1) {
|
|
|
+ this.$timer = setTimeout(this.getTimeline, 2000)
|
|
|
+ } else {
|
|
|
+ this.loadingTimeline = false
|
|
|
}
|
|
|
}
|
|
|
- }
|
|
|
+ )
|
|
|
},
|
|
|
- onCalendarUpdate (message) {
|
|
|
- try {
|
|
|
- this.onUpdate(JSON.parse(message).eventDetail || [])
|
|
|
- } catch {
|
|
|
- this.getTimeline()
|
|
|
+ getTimeRange () {
|
|
|
+ const startDateTime = parseTime(new Date(), '{y}-{m}-{d} {h}:{i}:00')
|
|
|
+ const endDate = toDate(startDateTime)
|
|
|
+ endDate.setHours(endDate.getHours() + (new Date().getMinutes() >= 50 ? 2 : 1))
|
|
|
+ endDate.setMinutes(0)
|
|
|
+ return {
|
|
|
+ from: startDateTime,
|
|
|
+ to: parseTime(endDate, '{y}-{m}-{d} {h}:00:00')
|
|
|
}
|
|
|
},
|
|
|
- onUpdate (events) {
|
|
|
+ onUpdate () {
|
|
|
if (this.$timer === -1) {
|
|
|
return
|
|
|
}
|
|
|
- clearTimeout(this.$timer)
|
|
|
- if (events.length) {
|
|
|
- const now = Date.now()
|
|
|
- this.timeline = events.filter((event, index) => {
|
|
|
- const { until } = event
|
|
|
- const allow = !until || now < toDate(until)
|
|
|
- if (allow) {
|
|
|
- event.key = index
|
|
|
- }
|
|
|
- return allow
|
|
|
- }).sort((a, b) => {
|
|
|
- if (b.priority === a.priority) {
|
|
|
- return toDate(a.start) - toDate(b.start)
|
|
|
- }
|
|
|
- return b.priority - a.priority
|
|
|
- })
|
|
|
+ ScreenshotCache.check(60000)
|
|
|
+ const pointerDate = this.current?.pointerDate || this.next?.pointerDate
|
|
|
+ if (!pointerDate || pointerDate <= Date.now()) {
|
|
|
+ console.log('onUpdate', pointerDate, 'refresh')
|
|
|
this.checkTimeline()
|
|
|
} else {
|
|
|
- this.timeline = null
|
|
|
- this.current = null
|
|
|
- this.next = null
|
|
|
- this.loadingTimeline = false
|
|
|
+ console.log('onUpdate', pointerDate, 'use cache')
|
|
|
+ this.delayCheck(pointerDate, this.current?.event)
|
|
|
}
|
|
|
- },
|
|
|
- getTimeline () {
|
|
|
- clearTimeout(this.$timer)
|
|
|
- this.loadingTimeline = true
|
|
|
- getTimeline(this.device.id, { custom: true }).then(this.onUpdate).catch(({ isCancel }) => {
|
|
|
- if (!isCancel && this.$timer !== -1) {
|
|
|
- this.$timer = setTimeout(this.getTimeline, 2000)
|
|
|
- }
|
|
|
- })
|
|
|
+ clearTimeout(this.$refreshTimer)
|
|
|
+ // 避免多设备同时请求
|
|
|
+ this.$refreshTimer = setTimeout(this.getTimeline, this.$maxDate - Date.now() - 300000 + (Math.random() * 120 | 0) * 1000)
|
|
|
},
|
|
|
checkTimeline (target) {
|
|
|
- this.loadingTimeline = false
|
|
|
const now = new Date()
|
|
|
let current = target
|
|
|
if (!current) {
|
|
|
for (let i = 0; i < this.timeline.length; i++) {
|
|
|
const event = this.timeline[i]
|
|
|
- if (!current && isHit(event, now)) {
|
|
|
+ if (isHit(event, now)) {
|
|
|
current = event
|
|
|
break
|
|
|
}
|
|
|
@@ -268,34 +334,39 @@ export default {
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
- console.log('current', current, currentEndDate)
|
|
|
- console.log('next', next, nextStartDate)
|
|
|
+ console.log(this.device.id, this.device.name)
|
|
|
+ console.log('current', current, 'next', next)
|
|
|
if (nextStartDate && (!currentEndDate || currentEndDate > nextStartDate)) {
|
|
|
currentEndDate = nextStartDate
|
|
|
}
|
|
|
- this.current = current && this.getEventInfo(current, getStartDate(current, now), currentEndDate)
|
|
|
- this.next = next && this.getEventInfo(next, nextStartDate)
|
|
|
+ this.current = current && this.getEventInfo(current, getStartDate(current, now), currentEndDate, currentEndDate)
|
|
|
+ this.next = next && this.getEventInfo(next, nextStartDate, null, nextStartDate)
|
|
|
|
|
|
clearTimeout(this.$timer)
|
|
|
if (currentEndDate) {
|
|
|
const minUntil = currentEndDate.getTime()
|
|
|
- this.timeline = this.timeline.filter(({ until }) => !until || toDate(until).getTime() > minUntil)
|
|
|
-
|
|
|
- const delay = currentEndDate - now
|
|
|
- // delay有最大限制2^31-1,超过后会直接执行
|
|
|
- // 当前限制最多1天
|
|
|
- if (delay > 86400000) {
|
|
|
- this.$timer = setTimeout(this.checkTimeline, 86400000, current)
|
|
|
- } else {
|
|
|
- this.$timer = setTimeout(this.checkTimeline, delay, next)
|
|
|
- }
|
|
|
+ const minPriority = current ? current.priority : -1
|
|
|
+ const now = Date.now()
|
|
|
+ this.timeline = this.timeline.filter(({ priority, until }) => !until || now < toDate(until) && (toDate(until) >= minUntil || priority > minPriority))
|
|
|
+ this.delayCheck(currentEndDate, current)
|
|
|
+ }
|
|
|
+ },
|
|
|
+ delayCheck (pointerDate, current) {
|
|
|
+ const delay = pointerDate - Date.now()
|
|
|
+ // delay有最大限制2^31-1,超过后会直接执行
|
|
|
+ // 当前限制最多1天
|
|
|
+ if (delay >= ONE_DAY) {
|
|
|
+ this.$timer = setTimeout(this.checkTimeline, ONE_DAY, current)
|
|
|
+ } else {
|
|
|
+ this.$timer = setTimeout(this.checkTimeline, delay)
|
|
|
}
|
|
|
},
|
|
|
- getEventInfo (event, startDate, endDate) {
|
|
|
- const target = event.target
|
|
|
+ getEventInfo (event, startDate, endDate, pointerDate) {
|
|
|
+ const { priority, target } = event
|
|
|
return {
|
|
|
- target,
|
|
|
- name: target.name || EventPriorityInfo[event.priority],
|
|
|
+ event,
|
|
|
+ pointerDate,
|
|
|
+ name: target.name || EventPriorityInfo[priority],
|
|
|
startDate: parseTime(startDate, '{y}.{m}.{d}'),
|
|
|
startTime: parseTime(startDate, '{h}:{i}:{s}'),
|
|
|
endDate: endDate ? parseTime(endDate, '{y}.{m}.{d}') : '',
|