Record.vue 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302
  1. <template>
  2. <box title="大屏实时画面">
  3. <div
  4. v-if="options.list.length"
  5. class="l-flex__auto c-record-grid"
  6. >
  7. <div
  8. v-for="item in options.list"
  9. :key="item.id"
  10. :class="{fullscreen:item.id===fullscreenId}"
  11. class="c-record-wrapper"
  12. >
  13. <i
  14. v-if="item.id===fullscreenId"
  15. class="el-icon-circle-close c-record-close has-active"
  16. @click="fullscreenId=''"
  17. />
  18. <device-player
  19. :device="item"
  20. controls
  21. autoplay
  22. retry
  23. keep
  24. >
  25. <!-- <template #header>
  26. <div class="l-flex--row l-flex__fill">
  27. <div class="l-flex__fill u-ellipsis">
  28. 温度: {{ item.temperature || '-' }}
  29. </div>
  30. <div class="l-flex__fill u-ellipsis u-text--right">
  31. 亮度: {{ item.brightness || '-' }}
  32. </div>
  33. </div>
  34. </template> -->
  35. <template #controls="{ waitingOrLoading, online, isPlaying }">
  36. <i
  37. v-if="item.id!==fullscreenId&&item.onlineStatus===1"
  38. class="c-sibling-item el-icon-full-screen has-active c-record-full-screen"
  39. @click="onFullScreen(item.id)"
  40. />
  41. <img
  42. v-if="item.id!==fullscreenId"
  43. class="c-sibling-item"
  44. :src="getStatusIcon(waitingOrLoading, online, isPlaying)"
  45. >
  46. </template>
  47. </device-player>
  48. </div>
  49. </div>
  50. <div
  51. v-else
  52. class="l-flex__auto l-flex--col jcenter"
  53. >
  54. <status-wrapper />
  55. </div>
  56. </box>
  57. </template>
  58. <script>
  59. import { getSensorRecords } from '@/api/external'
  60. import { getDeviceAttentionList } from '@/api/device'
  61. import { getSensorMap } from './api'
  62. import {
  63. createListOptions, parseTime
  64. } from '@/utils'
  65. import { Record } from './config'
  66. import Box from './Box'
  67. import { ThirdPartyDevice } from '@/constant'
  68. const offlineIcon = require('@/assets/v1/icon_offline.svg')
  69. const onlineIcon = require('@/assets/v1/icon_online.svg')
  70. const waitIcon = require('@/assets/v1/icon_wait.svg')
  71. export default {
  72. name: 'Record',
  73. components: {
  74. Box
  75. },
  76. data () {
  77. return {
  78. fullscreenId: '',
  79. options: createListOptions({ activate: 1, pageSize: 4 })
  80. }
  81. },
  82. created () {
  83. this.getDevices()
  84. this.$timer = setInterval(this.getDevices, Record.timer)
  85. },
  86. beforeDestroy () {
  87. clearInterval(this.$timer)
  88. },
  89. methods: {
  90. onFullScreen (id) {
  91. if (this.fullscreenId === id) {
  92. this.fullscreenId = ''
  93. } else {
  94. this.fullscreenId = id
  95. }
  96. },
  97. transfromData (data) {
  98. const map = {}
  99. const arr = []
  100. data.forEach(sensor => {
  101. if (!map[sensor.port]) {
  102. map[sensor.port] = 1
  103. arr.push(this.transformSensorData(sensor))
  104. }
  105. })
  106. return arr
  107. },
  108. transformSensorData (data) {
  109. const { port, type, value, time } = data
  110. return {
  111. port, value, type,
  112. time: parseTime(time, '{y}-{m}-{d} {h}:{i}:{s}'),
  113. info: this.transformValue(type, value, data)
  114. }
  115. },
  116. transformValue (type, value, data) {
  117. switch (type) {
  118. case ThirdPartyDevice.SMOKE_SENSOR:
  119. return `${value}ppm`
  120. case ThirdPartyDevice.TEMPERATURE_SENSOR:
  121. return `${value}℃`
  122. case ThirdPartyDevice.LIGHT_SENSOR:
  123. return `${value}Lux`
  124. case ThirdPartyDevice.FLOODING_SENSOR:
  125. return value ? '是' : '否'
  126. case ThirdPartyDevice.TRANSLOCATION_SENSOR:
  127. console.log(data)
  128. return `x ${data.xvalue?.toFixed(3)} y ${data.yvalue?.toFixed(
  129. 3
  130. )} z ${data.zvalue?.toFixed(3)}`
  131. default:
  132. return value
  133. }
  134. },
  135. getStatusIcon (waitingOrLoading, online, isPlaying) {
  136. if (!online) {
  137. return offlineIcon
  138. }
  139. if (waitingOrLoading) {
  140. return waitIcon
  141. }
  142. if (isPlaying) {
  143. return onlineIcon
  144. }
  145. return offlineIcon
  146. },
  147. updateDevices (data) {
  148. data.forEach(device => {
  149. if (this.$deviceMap[device.id]) {
  150. this.$deviceMap[device.id].onlineStatus = device.onlineStatus
  151. }
  152. })
  153. },
  154. getDevices () {
  155. getDeviceAttentionList(this.options.params, { custom: true }).then(({ data }) => {
  156. data.sort((a, b) => (a.onlineStatus === 1 && b.onlineStatus !== 1) ? -1 : 1)
  157. if (this.options.list.length) {
  158. this.updateDevices(data)
  159. }
  160. if (data.length <= 4) {
  161. this.options.list = data
  162. } else {
  163. const devices = []
  164. const devicesOffline = []
  165. const length = data.length
  166. for (let i = 0; i < length; i++) {
  167. if (data[i].onlineStatus === 1) {
  168. devices.push(data[i])
  169. } else {
  170. devicesOffline.push(data[i])
  171. }
  172. if (devices.length === 4) {
  173. break
  174. }
  175. }
  176. if (devices.length < 4) {
  177. devices.push(...devicesOffline.slice(0, 4 - devices.length))
  178. }
  179. this.options.list = devices
  180. }
  181. const map = {}
  182. this.options.list.forEach(device => {
  183. map[device.id] = device
  184. })
  185. this.$deviceMap = map
  186. // this.getSensorMap(this.options.list)
  187. })
  188. },
  189. // 单独接口 目前使用
  190. getSensorMap (deviceList) {
  191. if (!deviceList.length) {
  192. return
  193. }
  194. const now = Date.now()
  195. for (const device of deviceList) {
  196. this.getData(device, ThirdPartyDevice.TEMPERATURE_SENSOR, 'temperature', now)
  197. this.getData(device, ThirdPartyDevice.LIGHT_SENSOR, 'brightness', now)
  198. }
  199. },
  200. getData (device, type, key, now) {
  201. getSensorRecords({
  202. deviceId: device.id,
  203. sensorType: type,
  204. startTime: now - 10000,
  205. endTime: now
  206. }).then(({ data }) => {
  207. if (data.length) {
  208. this.$set(device, key, this.transformSensorData(data[0])?.info)
  209. }
  210. })
  211. },
  212. // 批量接口 目前不用
  213. getSensorMapM (deviceList) {
  214. if (!deviceList.length) { return }
  215. const now = Date.now()
  216. function getParams (item, sensorType) {
  217. return {
  218. deviceId: item.id,
  219. sensorType,
  220. startTime: now - 10000,
  221. endTime: now
  222. }
  223. }
  224. getSensorMap(
  225. deviceList
  226. .map(i => getParams(i, ThirdPartyDevice.TEMPERATURE_SENSOR))
  227. .concat(
  228. deviceList.map(i => getParams(i, ThirdPartyDevice.LIGHT_SENSOR))
  229. )
  230. ).then(({ data }) => {
  231. for (const deviceid in data) {
  232. if (Object.hasOwnProperty.call(data, deviceid)) {
  233. const map = this.transfromData(data[deviceid])
  234. for (const device of deviceList) {
  235. if (device.id === deviceid) {
  236. this.$set(device, 'temperature', map.filter(i => i.type === ThirdPartyDevice.TEMPERATURE_SENSOR)[0]?.info)
  237. this.$set(device, 'brightness', map.filter(i => i.type === ThirdPartyDevice.LIGHT_SENSOR)[0]?.info)
  238. break
  239. }
  240. }
  241. }
  242. }
  243. })
  244. }
  245. }
  246. }
  247. </script>
  248. <style lang="scss" scoped>
  249. .c-record-grid {
  250. display: grid;
  251. grid-template-rows: 1fr 1fr;
  252. grid-template-columns: 1fr 1fr;
  253. grid-row-gap: 20px;
  254. grid-column-gap: 20px;
  255. }
  256. .c-record-close{
  257. font-size: 64px;
  258. position: absolute;
  259. top: -60px;
  260. right: -60px;
  261. }
  262. .c-record-wrapper{
  263. .c-record-full-screen{
  264. display: none;
  265. }
  266. &:hover{
  267. .c-record-full-screen{
  268. display: block;
  269. }
  270. }
  271. }
  272. .fullscreen {
  273. position: fixed;
  274. width: 3072px;
  275. height: 1728px;
  276. top: 50%;
  277. left: 50%;
  278. border-bottom: none;
  279. transform: translate(-50%, -50%);
  280. overflow: visible;
  281. z-index: 999;
  282. &::before {
  283. content: "";
  284. position: absolute;
  285. top: -216px;
  286. left: -384px;
  287. width: 3840px;
  288. height: 2160px;
  289. background-color: rgba(#000, 0.6);
  290. z-index: -1;
  291. }
  292. ::v-deep.c-footer{
  293. font-size: 56px;
  294. }
  295. }
  296. </style>