StationHouse.vue 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332
  1. <script lang="ts" setup>
  2. import {onMounted, onUnmounted, reactive, ref} from 'vue'
  3. import {useRoute} from 'vue-router'
  4. import play from '@/assets/svg/play2.svg'
  5. import pause from '@/assets/svg/pause2.svg'
  6. import stop from '@/assets/svg/stop2.svg'
  7. import RightFrame from '@/components/RightFrame.vue'
  8. import Card01 from '@/components/card/Card01.vue'
  9. import Chart from '@/components/Chart.vue'
  10. import StripeTable from '@/components/StripeTable.vue'
  11. import {getAlarmInfo} from '@/api/alarm.ts'
  12. import StationRightButtonGroup from "@/components/StationRightButtonGroup.vue";
  13. import GwVideo from "@/components/Video/index.vue";
  14. import {getVideoCodeByMark} from "@/components/Video/video";
  15. import {Operate} from "@/utils/tdInstruction";
  16. import {getWaterQualityData} from "@/api/nanshui";
  17. import {HexToRgb} from "@/utils/color";
  18. import bus from "@/utils/bus";
  19. import DataTag from "@/components/tag/DataTag.vue";
  20. import {Timer, VideoPlay} from '@element-plus/icons-vue'
  21. const route = useRoute()
  22. const videoSrc = ref(new URL('@/assets/images/video.png', import.meta.url).href)
  23. const simulateSrc = ref(new URL('@/assets/images/simulate.png', import.meta.url).href)
  24. const tempWarnSrc = ref(new URL('@/assets/images/tempWarn.png', import.meta.url).href)
  25. const overflowWarnSrc = ref(new URL('@/assets/images/overflowWarn.png', import.meta.url).href)
  26. const fireWarnSrc = ref(new URL('@/assets/images/fireWarn.png', import.meta.url).href)
  27. const wetWarnSrc = ref(new URL('@/assets/images/wetWarn.png', import.meta.url).href)
  28. // 绿色
  29. const GREEN = '#67C23A'
  30. const RGB_GREEN = HexToRgb(GREEN)
  31. // 浅绿色
  32. const LIGHT_GREEN = `rgba(${RGB_GREEN[0]}, ${RGB_GREEN[1]}, ${RGB_GREEN[2]}, 0.3)`
  33. // 红色
  34. const RED = '#F56C6C'
  35. const RGB_RED = HexToRgb(RED)
  36. // 浅红色
  37. const LIGHT_RED = `rgba(${RGB_RED[0]}, ${RGB_RED[1]}, ${RGB_RED[2]}, 0.3)`
  38. const frequency = ref([2, 8])
  39. const wqData = ref({})
  40. // 水质测验模拟 0:结束 1:播放 2:暂停
  41. const testSimulationStatus = ref(0)
  42. // 获取视频CODE
  43. const videoCode = ref(getVideoCodeByMark(route.params.stcd + '', "室内"))
  44. const alarmType = ref({
  45. '1': '巡检维护',
  46. '2': '故障',
  47. '3': '仪器校准',
  48. '4': '提醒'
  49. })
  50. const alarmColumns = [
  51. {
  52. label: '报警类型', prop: 'warnType', width: '100', convertFn: (data) => {
  53. return data ? alarmType.value[data.trim()] : ''
  54. }
  55. },
  56. {
  57. label: '时间', prop: 'reportTime', convertFn: (data) => {
  58. return data ? data.substring(5, 16) : ''
  59. }
  60. },
  61. {
  62. label: '告警内容', prop: 'warnContent', width: '180', convertFn: (data) => {
  63. return data ? data.trim() : ''
  64. }
  65. },
  66. ]
  67. const alarmData = reactive([])
  68. const left1Ref = ref(null)
  69. /**
  70. * 测验模拟
  71. * @param mode 播放、暂停、继续、结束
  72. */
  73. function handleTestSimulation(mode) {
  74. switch (mode) {
  75. case "play":
  76. if (testSimulationStatus.value === 0) {
  77. Operate.testSimulation(route.params.stcd, '播放')
  78. } else {
  79. Operate.testSimulation(route.params.stcd, '继续')
  80. }
  81. testSimulationStatus.value = 1
  82. break
  83. case "pause":
  84. Operate.testSimulation(route.params.stcd, '暂停')
  85. testSimulationStatus.value = 2
  86. break
  87. case "stop":
  88. Operate.testSimulation(route.params.stcd, '结束')
  89. testSimulationStatus.value = 0
  90. break
  91. default:
  92. }
  93. }
  94. /**
  95. * 获取最新水质数据
  96. */
  97. function getLatestWaterQuality() {
  98. getWaterQualityData(route.params.stcd).then(res => {
  99. if (res.data.wqdata && res.data.wqdata.length > 0) {
  100. wqData.value = Object.keys(res.data.wqdata).reduce((acc, key) => {
  101. acc[key.toLowerCase()] = res.data.wqdata[key];
  102. return acc;
  103. }, {});
  104. }
  105. })
  106. }
  107. function getAlarmList() {
  108. const data = {
  109. 'page': 1,
  110. 'pageSize': 200,
  111. 'stationCode': route.params.stcd
  112. };
  113. getAlarmInfo(data).then(res => {
  114. if (res.status == 200) {
  115. alarmData.push(...res.data.records)
  116. }
  117. })
  118. }
  119. async function reloadLeft1() {
  120. const colors = ['#5470C6', '#91CC75', '#EE6666'];
  121. const option = {
  122. // title: {
  123. // text: '环境温湿度',
  124. // textStyle: {
  125. // fontSize: 14,
  126. // color: '#fff',
  127. // },
  128. // left:'50'
  129. //
  130. // },
  131. tooltip: {
  132. trigger: 'axis'
  133. },
  134. legend: {
  135. data: ['温度', '湿度'],
  136. textStyle: {
  137. fontSize: 12,
  138. color: '#fff'
  139. }
  140. },
  141. grid: {
  142. left: '5%',
  143. right: '4%',
  144. bottom: '1%',
  145. top: '20%',
  146. containLabel: true
  147. },
  148. xAxis: {
  149. type: 'category',
  150. boundaryGap: false,
  151. data: ['11::30', '11:35', '11:40', '11:45', '11:50', '11:55', '12:00', '12:05', '12:10', '12:15']
  152. },
  153. yAxis: [{
  154. type: 'value',
  155. name: ' %',
  156. position: 'right',
  157. alignTicks: true,
  158. axisLine: {
  159. show: true,
  160. lineStyle: {
  161. color: colors[0]
  162. }
  163. },
  164. axisLabel: {
  165. formatter: '{value} %'
  166. }
  167. }, {
  168. type: 'value',
  169. name: ' °C',
  170. position: 'left',
  171. alignTicks: true,
  172. axisLine: {
  173. show: true,
  174. lineStyle: {
  175. color: colors[1]
  176. }
  177. },
  178. axisLabel: {
  179. formatter: '{value} °C'
  180. }
  181. }],
  182. series: [
  183. {
  184. name: '温度',
  185. type: 'line',
  186. stack: 'Total',
  187. data: [20, 21, 25, 26, 32, 30, 26, 39, 29, 30]
  188. },
  189. {
  190. name: '湿度',
  191. type: 'line',
  192. stack: 'Total',
  193. data: [40, 45, 30, 31, 36, 33, 31, 50, 30, 20]
  194. }
  195. ]
  196. };
  197. left1Ref.value.loadChart(option)
  198. }
  199. onMounted(() => {
  200. reloadLeft1()
  201. getAlarmList()
  202. getLatestWaterQuality()
  203. })
  204. onUnmounted(() => {
  205. if (testSimulationStatus.value !== 0) {
  206. handleTestSimulation('stop')
  207. }
  208. })
  209. // 底板回调监听
  210. bus.on('test_simulation', (data) => {
  211. if (data.Category && data.Category === 'ClickMesh' && data.Data.Type === '动画结束') {
  212. // 动画结束,修改状态
  213. testSimulationStatus.value = 0
  214. }
  215. })
  216. </script>
  217. <template>
  218. <right-frame>
  219. <template #leftModule>
  220. <card01 style="height: 45%;" title="运行监控">
  221. <el-row :gutter="10" justify="space-around" style="height: 100%;">
  222. <div style="width:100%;height: 50%;">
  223. <chart ref="left1Ref" style="width: 100%;height: 100%;"></chart>
  224. </div>
  225. <el-col :span="12" style="height: 23%;">
  226. <img :src="tempWarnSrc" alt="" class="difang-image"/>
  227. </el-col>
  228. <el-col :span="12" style="height: 23%;">
  229. <img :src="overflowWarnSrc" alt="" class="difang-image"/>
  230. </el-col>
  231. <el-col :span="12" style="height: 23%;">
  232. <img :src="fireWarnSrc" alt="" class="difang-image"/>
  233. </el-col>
  234. <el-col :span="12" style="height: 23%;">
  235. <img :src="wetWarnSrc" alt="" class="difang-image"/>
  236. </el-col>
  237. </el-row>
  238. </card01>
  239. <card01 style="height: 55%" title="告警记录">
  240. <stripe-table :columns="alarmColumns" :data="alarmData"></stripe-table>
  241. </card01>
  242. </template>
  243. <template #rightModule>
  244. <card01 style="height: 65%" title="监测流程">
  245. <el-form label-width="auto">
  246. <el-form-item label="检测频率">
  247. <div style="width: 100%;display: flex;align-items: center;justify-content: space-between;">
  248. <el-select v-model="frequency" multiple placeholder="Select" style="width: 200px">
  249. <el-option v-for="item in 24" :key="item" :label="item + '时'" :value="item"></el-option>
  250. <template #tag>
  251. <el-tag v-for="color in frequency" :key="color" color="#4167F0" style="color: #fff;">{{
  252. color + '时'
  253. }}
  254. </el-tag>
  255. </template>
  256. </el-select>
  257. <el-button :icon="VideoPlay" style="margin-left: 10px;width: 6rem;" type="primary" @click="">水质测验
  258. </el-button>
  259. </div>
  260. </el-form-item>
  261. </el-form>
  262. <div :style="{ 'background-image': `url(${simulateSrc})`}" class="video-control-bar test-simulation">
  263. <icon v-if="testSimulationStatus == 0 || testSimulationStatus == 2" :data="play" class="video-btn"
  264. @click="handleTestSimulation('play')"/>
  265. <icon v-if="testSimulationStatus == 1" :data="pause" class="video-btn"
  266. @click="handleTestSimulation('pause')"/>
  267. <icon v-if="testSimulationStatus != 0" :data="stop" class="video-btn" @click="handleTestSimulation('stop')"/>
  268. </div>
  269. <div>
  270. <h3 style="display: flex;align-items: center;justify-content: space-between;">
  271. 测验结果:
  272. <span style="font-size: 1rem;display: flex;align-items: center;">
  273. <Timer style="width: 1em; height: 1em; margin-right: 8px"/>
  274. {{ wqData.tm }}
  275. </span>
  276. </h3>
  277. <DataTag :data="wqData"></DataTag>
  278. </div>
  279. </card01>
  280. <card01 style="height: 35%" title="站房监控">
  281. <gw-video :code="videoCode" :imageSrc="videoSrc"></gw-video>
  282. </card01>
  283. </template>
  284. <template #btnGroup>
  285. <station-right-button-group></station-right-button-group>
  286. </template>
  287. </right-frame>
  288. </template>
  289. <style lang="scss" scoped>
  290. @use "@/assets/styles/introduce.scss";
  291. @use "@/assets/styles/video.scss";
  292. .difang-water-level {
  293. position: absolute;
  294. bottom: 10px;
  295. width: 80%;
  296. height: 60%;
  297. background-color: rgba(0, 204, 255, 0.6);
  298. border-top: 3px solid rgba(0, 204, 255);
  299. .difang-water-level-value {
  300. position: absolute;
  301. top: -2rem;
  302. font-size: 1.2rem;
  303. color: #fff;
  304. }
  305. }
  306. .difang-image {
  307. position: relative;
  308. width: 100%;
  309. height: 100%;
  310. }
  311. .test-simulation {
  312. background-size: 100% 100%;
  313. height: 76px;
  314. margin-bottom: 18px;
  315. }
  316. </style>