Record.vue 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278
  1. <template>
  2. <box title="大屏实时画面">
  3. <template #title>
  4. <div
  5. class="has-active"
  6. @click="onSelect"
  7. >
  8. 大屏实时画面
  9. </div>
  10. </template>
  11. <multi-device-dialog
  12. ref="dialog"
  13. :cols="cols"
  14. :max="4"
  15. sortable
  16. append-to-body
  17. @confirm="onChange"
  18. />
  19. <div
  20. v-if="devices.length"
  21. class="l-flex__auto c-record-grid"
  22. >
  23. <div
  24. v-for="item in devices"
  25. :key="item.id"
  26. class="c-record-wrapper"
  27. :class="{ fullscreen: item.id === fullscreenId} "
  28. >
  29. <i
  30. v-if="item.id === fullscreenId"
  31. class="el-icon-circle-close c-record-close has-active"
  32. @click="onToggleFullscreen(item)"
  33. />
  34. <device-player
  35. :key="item.id"
  36. :device="item"
  37. controls
  38. autoplay
  39. retry
  40. keep
  41. check-online
  42. @click="onClick"
  43. @fullscreen="onToggleFullscreen(item)"
  44. >
  45. <!-- <template #header>
  46. <div class="l-flex--row l-flex__fill">
  47. <div class="l-flex__fill u-ellipsis">
  48. 温度: {{ item.temperature || '-' }}
  49. </div>
  50. <div class="l-flex__fill u-ellipsis u-text--right">
  51. 亮度: {{ item.brightness || '-' }}
  52. </div>
  53. </div>
  54. </template> -->
  55. </device-player>
  56. </div>
  57. </div>
  58. <div
  59. v-else
  60. class="l-flex__auto l-flex--col jcenter"
  61. >
  62. <status-wrapper />
  63. </div>
  64. </box>
  65. </template>
  66. <script>
  67. import { ThirdPartyDevice } from '@/constant'
  68. import { parseTime } from '@/utils'
  69. import { getSensorRecords } from '@/api/external'
  70. import { getSensorMap } from './api'
  71. import Box from './Box'
  72. export default {
  73. name: 'Record',
  74. components: {
  75. Box
  76. },
  77. data () {
  78. return {
  79. fullscreenId: '',
  80. devices: JSON.parse(window.localStorage.getItem('MSR_DASHBOARD_DEVICES') || '[]').map(this.transformDevice)
  81. }
  82. },
  83. computed: {
  84. cols () {
  85. return [
  86. { type: 'tag', render: ({ onlineStatus }) => onlineStatus === 0
  87. ? { type: 'primary', label: '待接入' }
  88. : onlineStatus === 1
  89. ? { type: 'success', label: '在线' }
  90. : { type: 'danger', label: '离线' } }
  91. ]
  92. }
  93. },
  94. beforeDestroy () {
  95. clearInterval(this.$timer)
  96. },
  97. methods: {
  98. transformDevice ({ id, name }) {
  99. return { id, name }
  100. },
  101. onSelect () {
  102. this.$refs.dialog.show([...this.devices])
  103. },
  104. onChange ({ value, done }) {
  105. this.devices = value.map(this.transformDevice)
  106. window.localStorage.setItem('MSR_DASHBOARD_DEVICES', JSON.stringify(this.devices))
  107. done()
  108. },
  109. onClick ({ id }) {
  110. if (this.fullscreenId !== id) {
  111. this.fullscreenId = id
  112. }
  113. },
  114. onToggleFullscreen ({ id }) {
  115. if (this.fullscreenId === id) {
  116. this.fullscreenId = ''
  117. } else {
  118. this.fullscreenId = id
  119. }
  120. },
  121. transfromData (data) {
  122. const map = {}
  123. const arr = []
  124. data.forEach(sensor => {
  125. if (sensor.value > -1000 && !map[sensor.port]) {
  126. map[sensor.port] = 1
  127. arr.push(this.transformSensorData(sensor))
  128. }
  129. })
  130. return arr
  131. },
  132. transformSensorData (data) {
  133. const { port, type, value, time } = data
  134. return {
  135. port, value, type,
  136. time: parseTime(time, '{y}-{m}-{d} {h}:{i}:{s}'),
  137. info: this.transformValue(type, value, data)
  138. }
  139. },
  140. transformValue (type, value, data) {
  141. switch (type) {
  142. case ThirdPartyDevice.SMOKE_SENSOR:
  143. return `${value}ppm`
  144. case ThirdPartyDevice.TEMPERATURE_SENSOR:
  145. return `${value}℃`
  146. case ThirdPartyDevice.LIGHT_SENSOR:
  147. return `${value}Lux`
  148. case ThirdPartyDevice.FLOODING_SENSOR:
  149. return value ? '是' : '否'
  150. case ThirdPartyDevice.TRANSLOCATION_SENSOR:
  151. return `x ${data.xvalue?.toFixed(3)} y ${data.yvalue?.toFixed(
  152. 3
  153. )} z ${data.zvalue?.toFixed(3)}`
  154. default:
  155. return value
  156. }
  157. },
  158. // 单独接口 目前使用
  159. getSensorMap () {
  160. const devices = this.devices
  161. if (!devices.length) {
  162. return
  163. }
  164. const now = Date.now()
  165. for (const device of devices) {
  166. this.getData(device, ThirdPartyDevice.TEMPERATURE_SENSOR, 'temperature', now)
  167. this.getData(device, ThirdPartyDevice.LIGHT_SENSOR, 'brightness', now)
  168. }
  169. },
  170. getData (device, type, key, now) {
  171. getSensorRecords({
  172. deviceId: device.id,
  173. sensorType: type,
  174. startTime: now - 10000,
  175. endTime: now
  176. }).then(({ data }) => {
  177. if (data.length) {
  178. const sensor = data.find(({ value }) => value > -1000)
  179. this.$set(device, key, sensor ? this.transformSensorData(sensor).info : null)
  180. }
  181. })
  182. },
  183. // 批量接口 目前不用
  184. getSensorMapM () {
  185. const devices = this.devices
  186. if (!devices.length) { return }
  187. const now = Date.now()
  188. function getParams (item, sensorType) {
  189. return {
  190. deviceId: item.id,
  191. sensorType,
  192. startTime: now - 10000,
  193. endTime: now
  194. }
  195. }
  196. getSensorMap(
  197. devices
  198. .map(i => getParams(i, ThirdPartyDevice.TEMPERATURE_SENSOR))
  199. .concat(
  200. devices.map(i => getParams(i, ThirdPartyDevice.LIGHT_SENSOR))
  201. )
  202. ).then(({ data }) => {
  203. for (const deviceid in data) {
  204. if (Object.hasOwnProperty.call(data, deviceid)) {
  205. const map = this.transfromData(data[deviceid])
  206. for (const device of devices) {
  207. if (device.id === deviceid) {
  208. this.$set(device, 'temperature', map.filter(i => i.type === ThirdPartyDevice.TEMPERATURE_SENSOR)[0]?.info)
  209. this.$set(device, 'brightness', map.filter(i => i.type === ThirdPartyDevice.LIGHT_SENSOR)[0]?.info)
  210. break
  211. }
  212. }
  213. }
  214. }
  215. })
  216. }
  217. }
  218. }
  219. </script>
  220. <style lang="scss" scoped>
  221. .c-record-grid {
  222. display: grid;
  223. grid-template-rows: 1fr 1fr;
  224. grid-template-columns: 1fr 1fr;
  225. grid-row-gap: 20px;
  226. grid-column-gap: 20px;
  227. }
  228. .c-record-close {
  229. position: absolute;
  230. top: -60px;
  231. right: -60px;
  232. font-size: 64px;
  233. }
  234. .c-record-wrapper.fullscreen {
  235. position: fixed;
  236. width: 3072px;
  237. top: 50%;
  238. left: 50%;
  239. border-bottom: none;
  240. transform: translate(-50%, -50%);
  241. overflow: visible;
  242. z-index: 999;
  243. &::before {
  244. content: "";
  245. position: absolute;
  246. top: -216px;
  247. left: -384px;
  248. width: 3840px;
  249. height: 2160px;
  250. background-color: rgba(#000, 0.6);
  251. z-index: -1;
  252. }
  253. ::v-deep .c-footer {
  254. padding: 32px 48px;
  255. font-size: 64px;
  256. .o-quality-menu__list {
  257. margin-bottom: 16px;
  258. font-size: 48px !important;
  259. }
  260. .o-quality-menu__item {
  261. padding: 12px 0;
  262. }
  263. .el-icon-full-screen {
  264. margin-left: 48px !important;
  265. }
  266. }
  267. }
  268. </style>