StationRightButtonGroup.vue 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548
  1. <script lang="ts" setup>
  2. import {computed, onUnmounted, ref, watch} from 'vue'
  3. import {Operate, Setting, View} from "@/utils/tdInstruction";
  4. import {Hide, View as Elview} from '@element-plus/icons-vue'
  5. import {getStation} from '@/utils/station'
  6. import {useRoute} from "vue-router";
  7. import {jumpPage} from "@/utils";
  8. import {useAppStore} from '@/stores/app'
  9. import {useStationStore} from '@/stores/station'
  10. import handle from "@/assets/svg/handle.svg";
  11. import underwater from "@/assets/svg/underwater.svg";
  12. import horizontalContract from "@/assets/svg/horizontal-contract.svg";
  13. import horizontalExpand from "@/assets/svg/horizontal-expand.svg";
  14. import roam from "@/assets/svg/roam.svg";
  15. import bus from "@/utils/bus";
  16. import {changeWeatherByRainfall} from "@/utils/rainfall";
  17. import play from "@/assets/svg/play2.svg";
  18. import pause from "@/assets/svg/pause2.svg";
  19. import stop from "@/assets/svg/stop2.svg";
  20. const route = useRoute()
  21. const appStore = useAppStore()
  22. const stationStore = useStationStore()
  23. const btnBackSrc = ref(new URL('@/assets/images/btn-back.png', import.meta.url).href)
  24. const homeSrc = ref(new URL('@/assets/images/home.png', import.meta.url).href)
  25. const weatherSrc = ref(new URL('@/assets/images/weather.png', import.meta.url).href)
  26. const flagSrc = ref(new URL('@/assets/images/flag.png', import.meta.url).href)
  27. const walkSrc = ref(new URL('@/assets/images/walk.png', import.meta.url).href)
  28. const cultureSrc = ref(new URL('@/assets/images/culture.png', import.meta.url).href)
  29. const backgroundSrc = ref(new URL('@/assets/images/btn-background.png', import.meta.url).href)
  30. const waterSliderBackground = (new URL('@/assets/images/card/card01.png', import.meta.url).href)
  31. // 河道漫游 0:结束 1:播放 2:暂停
  32. const riverRoamStatus = ref(0)
  33. // 测站漫游 0:结束 1:播放 2:暂停
  34. const stationRoamStatus = ref(0)
  35. /**
  36. * 测验模拟
  37. * @param type river:河道漫游, station:测站漫游
  38. * @param mode 播放、暂停、继续、结束
  39. */
  40. function handleRoam(type, mode) {
  41. let status = (type === 'river' ? riverRoamStatus : stationRoamStatus)
  42. switch (mode) {
  43. case "play":
  44. if (status.value === 0) {
  45. Operate.roam(type, '播放')
  46. } else {
  47. Operate.roam(type, '继续')
  48. }
  49. status.value = 1
  50. break
  51. case "pause":
  52. Operate.roam(type, '暂停')
  53. status.value = 2
  54. break
  55. case "stop":
  56. Operate.roam(type, '结束')
  57. status.value = 0
  58. break
  59. default:
  60. }
  61. }
  62. // 测站信息
  63. const station = computed(() => getStation(route.params.stcd))
  64. // 是否显示返回按钮
  65. const hasBack = computed(() => route.path.indexOf('/sthouse/') > -1 || route.path.indexOf('/device/') > -1)
  66. // 是否显示模拟按钮
  67. const hasHandle = computed(() => route.path.indexOf('/situational/') > -1)
  68. const underwaterState = ref(false)
  69. // 测站标签
  70. const label1State = computed({
  71. get: () => stationStore.labelState['测站主页'],
  72. set: () => stationStore.setLabelState('测站主页')
  73. });
  74. // 仪器运维标签
  75. const label2State = computed({
  76. get: () => stationStore.labelState['仪器运维'],
  77. set: () => stationStore.setLabelState('仪器运维')
  78. });
  79. // 模拟模式
  80. const simulationMode = ref('无')
  81. const waterLevel = ref(2.72)
  82. const waterLevelStep = ref(0.01)
  83. const waterLevelMin = ref(2.72)
  84. const waterLevelMax = ref(4.39)
  85. const waterLevelMarks = ref({
  86. 2.72: {
  87. label: '2.72m'
  88. },
  89. 4.19: {
  90. style: {
  91. color: '#E6A23C'
  92. },
  93. label: '4.19m'
  94. },
  95. 4.29: {
  96. style: {
  97. color: '#F56C6C'
  98. },
  99. label: '4.29m'
  100. },
  101. 4.39: '4.39m'
  102. })
  103. function formatWaterLevelTooltip(val: number) {
  104. switch (simulationMode.value) {
  105. case "水位":
  106. return (val).toFixed(2) + ' m' as string
  107. case "雨量":
  108. return val + ' mm' as string
  109. case "流量":
  110. return (val).toFixed(2) + ' m³/s' as string
  111. }
  112. }
  113. function handleHome() {
  114. // 跳转页面
  115. jumpPage(`/station/${route.params.stcd}`)
  116. // 关闭所有标签
  117. stationStore.closeLabel()
  118. // 切换测站远视角
  119. View.changeView(station.value.stnm)
  120. }
  121. function back() {
  122. if (route.path.indexOf('/device/') > -1 && appStore.hasEnterSthouse) {
  123. // 进过站房页面, 并且在仪器详情界面
  124. // 切换站房视角
  125. View.changeDeviceView("转跳", route.params.stcd)
  126. // 跳转站房页面
  127. jumpPage(`/sthouse/${route.params.stcd}`)
  128. } else {
  129. // 切换近视角
  130. View.changeView(station.value.stnm + '近')
  131. // 跳转上个页面
  132. jumpPage(`/${appStore.homePage}/${route.params.stcd}`)
  133. appStore.exitSthouse()
  134. }
  135. }
  136. async function handleSimulationModeChange(mode) {
  137. switch (mode) {
  138. case "水位":
  139. waterLevelMin.value = 2.72
  140. waterLevelMax.value = 4.39
  141. waterLevelStep.value = 0.01
  142. waterLevelMarks.value = {
  143. 2.72: {
  144. label: '2.72m'
  145. },
  146. 3: {
  147. style: {
  148. color: '#409EFF'
  149. },
  150. label: '3.00m'
  151. },
  152. 3.5: {
  153. style: {
  154. color: '#409EFF'
  155. },
  156. label: '3.50m'
  157. },
  158. 4: {
  159. style: {
  160. color: '#409EFF'
  161. },
  162. label: '4.00m'
  163. },
  164. 4.19: {
  165. style: {
  166. color: '#E6A23C'
  167. },
  168. label: '4.19m'
  169. },
  170. 4.29: {
  171. style: {
  172. color: '#F56C6C'
  173. },
  174. label: '4.29m'
  175. },
  176. 4.39: '4.39m'
  177. }
  178. waterLevel.value = await stationStore.getZ()
  179. break
  180. case "雨量":
  181. waterLevelMin.value = 0
  182. waterLevelMax.value = 300
  183. waterLevelStep.value = 1
  184. waterLevelMarks.value = {
  185. 10: {
  186. label: '10mm'
  187. },
  188. 25: {
  189. style: {
  190. color: '#67C23A'
  191. },
  192. label: '25mm'
  193. },
  194. 50: {
  195. style: {
  196. color: '#409EFF'
  197. },
  198. label: '50mm'
  199. },
  200. 100: {
  201. style: {
  202. color: '#E6A23C'
  203. },
  204. label: '100mm'
  205. },
  206. 250: {
  207. style: {
  208. color: '#F56C6C'
  209. },
  210. label: '250mm'
  211. }
  212. }
  213. waterLevel.value = await stationStore.getDrp()
  214. break
  215. case "流量":
  216. waterLevelMin.value = -300
  217. waterLevelMax.value = 300
  218. waterLevelStep.value = 1
  219. waterLevelMarks.value = {
  220. '-300': '-300m³/s',
  221. '-200': '-200m³/s',
  222. '-100': '-100m³/s',
  223. '0': '0',
  224. '100': '100m³/s',
  225. '200': '200m³/s',
  226. '300': '300m³/s'
  227. }
  228. waterLevel.value = await stationStore.getQ()
  229. break
  230. }
  231. handleWaterLevelChange()
  232. }
  233. function handleWaterLevelChange() {
  234. switch (simulationMode.value) {
  235. case "水位":
  236. Operate.setWaterLevel(route.params.stcd, waterLevel.value)
  237. break
  238. case "雨量":
  239. changeWeatherByRainfall(waterLevel.value)
  240. break
  241. case "流量":
  242. Operate.setWaterLevel(route.params.stcd, null, waterLevel.value)
  243. break
  244. }
  245. }
  246. bus.on('set-water-level', value => waterLevel.value = value)
  247. watch(() => waterLevel, value => handleWaterLevelChange(), {deep: true})
  248. // 路由监听
  249. watch(() => route.path, path => {
  250. // 态势感知 近视角 仪器标签
  251. if (path.indexOf('/situational/') > -1 || path.indexOf('/intelloper/') > -1) {
  252. View.changeView(station.value.stnm + '近')
  253. stationStore.setLabelState2('测站主页', false)
  254. stationStore.setLabelState2('仪器运维', true)
  255. }
  256. if (route.path.indexOf('/situational/') === -1) {
  257. simulationMode.value = '无'
  258. }
  259. }, {deep: true, immediate: true})
  260. watch(() => underwaterState.value, (value) => {
  261. Operate.setUnderwaterState(route.params.stcd, value)
  262. })
  263. onUnmounted(() => {
  264. if (riverRoamStatus.value !== 0) {
  265. Operate.roam('river', '结束')
  266. }
  267. if (stationRoamStatus.value !== 0) {
  268. Operate.roam('station', '结束')
  269. }
  270. })
  271. // 底板回调监听
  272. bus.on('handle_ue_response', (data) => {
  273. if (data.Data && data.Data.Name && data.Data.Name === '漫游结束') {
  274. if (riverRoamStatus.value !== 0) {
  275. riverRoamStatus.value = 0
  276. }
  277. if (stationRoamStatus.value !== 0) {
  278. stationRoamStatus.value = 0
  279. }
  280. }
  281. })
  282. watch(() => riverRoamStatus.value, (value) => {
  283. bus.emit("roam", value !== 0)
  284. })
  285. watch(() => stationRoamStatus.value, (value) => {
  286. bus.emit("roam", value !== 0)
  287. })
  288. </script>
  289. <template>
  290. <div class="right-btn-container">
  291. <div v-show="hasBack" class="right-btn-item" @click="back">
  292. <img :src="btnBackSrc" alt="返回"/>
  293. </div>
  294. <div class="right-btn-item" @click="handleHome">
  295. <img :src="homeSrc" alt="主页"/>
  296. </div>
  297. <el-popover placement="left-start" trigger="hover" width="auto">
  298. <template #reference>
  299. <div class="right-btn-item">
  300. <img :src="walkSrc" alt="视角"/>
  301. </div>
  302. </template>
  303. <el-button-group>
  304. <el-button @click="View.changeView(station.stnm)">远</el-button>
  305. <el-button @click="View.changeView(station.stnm+'近')">近</el-button>
  306. </el-button-group>
  307. </el-popover>
  308. <el-popover placement="left-start" trigger="hover" width="auto">
  309. <template #reference>
  310. <div class="right-btn-item">
  311. <img :src="flagSrc" alt="标签"/>
  312. </div>
  313. </template>
  314. 测站标签&nbsp;<el-switch v-model="label1State" :active-action-icon="Elview" :inactive-action-icon="Hide"/>
  315. 仪器运维&nbsp;<el-switch v-model="label2State" :active-action-icon="Elview" :inactive-action-icon="Hide"/>
  316. </el-popover>
  317. <el-popover placement="left-start" trigger="hover" width="auto">
  318. <template #reference>
  319. <div class="right-btn-item">
  320. <img :src="weatherSrc" alt="天气"/>
  321. </div>
  322. </template>
  323. <el-button-group>
  324. <el-button v-for="item in ['晴','小雨','中雨','大雨']" :key="item"
  325. @click="Setting.setWeather(item)">{{ item }}
  326. </el-button>
  327. </el-button-group>
  328. </el-popover>
  329. <el-popover placement="left-start" trigger="hover" width="auto">
  330. <template #reference>
  331. <div class="right-btn-item">
  332. <img :src="backgroundSrc" alt="" style="position: absolute;"/>
  333. <icon :data="underwater"/>
  334. </div>
  335. </template>
  336. 水下地形&nbsp;<el-switch v-model="underwaterState" :active-action-icon="Elview" :inactive-action-icon="Hide"/>
  337. </el-popover>
  338. <el-popover placement="left-start" trigger="hover" width="auto">
  339. <template #reference>
  340. <div v-if="route.params.stcd === '63304700'" class="right-btn-item">
  341. <img :src="backgroundSrc" alt="" style="position: absolute;"/>
  342. <icon :data="roam"/>
  343. </div>
  344. </template>
  345. <el-row>
  346. <el-col :span="24"><label>河道漫游</label></el-col>
  347. <el-col :span="24" class="video-control-bar roam">
  348. <icon v-if="riverRoamStatus == 0 || riverRoamStatus == 2" :data="play" class="video-btn"
  349. @click="handleRoam('river','play')"/>
  350. <icon v-if="riverRoamStatus == 1" :data="pause" class="video-btn"
  351. @click="handleRoam('river','pause')"/>
  352. <icon v-if="riverRoamStatus != 0" :data="stop" class="video-btn" @click="handleRoam('river','stop')"/>
  353. </el-col>
  354. <el-col :span="24"><label>站内漫游</label></el-col>
  355. <el-col :span="24" class="video-control-bar roam">
  356. <icon v-if="stationRoamStatus == 0 || stationRoamStatus == 2" :data="play" class="video-btn"
  357. @click="handleRoam('station','play')"/>
  358. <icon v-if="stationRoamStatus == 1" :data="pause" class="video-btn"
  359. @click="handleRoam('station','pause')"/>
  360. <icon v-if="stationRoamStatus != 0" :data="stop" class="video-btn"
  361. @click="handleRoam('station','stop')"/>
  362. </el-col>
  363. </el-row>
  364. </el-popover>
  365. <el-popover placement="left-start" trigger="hover" width="auto">
  366. <template #reference>
  367. <div v-show="hasHandle" class="right-btn-item">
  368. <img :src="backgroundSrc" alt="" style="position: absolute;"/>
  369. <icon :data="handle"/>
  370. </div>
  371. </template>
  372. <el-radio-group v-model="simulationMode" size="large" @change="handleSimulationModeChange">
  373. <el-radio-button v-for="item in ['水位','雨量','流量','无']" :key="item" :label="item" :value="item"/>
  374. </el-radio-group>
  375. </el-popover>
  376. <div class="right-btn-item" @click="appStore.setExpand(!appStore.isExpand)">
  377. <img :src="backgroundSrc" alt="" style="position: absolute;"/>
  378. <icon :data="appStore.isExpand ? horizontalExpand : horizontalContract"/>
  379. </div>
  380. <div v-if="simulationMode !== '无'" class="slider-wrapper">
  381. <div :style="{'background-image': `url(${waterSliderBackground})`}" class="water-level-slider-container">
  382. <div class="water-level-slider-main">
  383. <el-slider v-model="waterLevel" :format-tooltip="formatWaterLevelTooltip" :marks="waterLevelMarks"
  384. :max="waterLevelMax" :min="waterLevelMin" :step="waterLevelStep" height="90%" placement="right"
  385. tooltip-class="slider-tooltip" vertical
  386. @input="value => bus.emit('set-water-level', value)"/>
  387. <span class="water-level-slider-title">{{ simulationMode }}动态模拟</span>
  388. </div>
  389. </div>
  390. </div>
  391. </div>
  392. </template>
  393. <style lang="scss" scoped>
  394. @use "@/assets/styles/video.scss";
  395. .right-btn-container {
  396. display: flex;
  397. flex-direction: column;
  398. .right-btn-item {
  399. width: 50px;
  400. height: 50px;
  401. cursor: pointer;
  402. position: relative;
  403. display: flex;
  404. justify-content: center;
  405. align-items: center;
  406. //background-size: 100% 100%;
  407. img {
  408. width: 100%;
  409. height: 100%;
  410. }
  411. svg {
  412. width: 1.2rem;
  413. height: 1.2rem;
  414. fill: #84b1e3;
  415. z-index: 1;
  416. }
  417. &:hover, &.active {
  418. svg {
  419. fill: #00cbe6;
  420. }
  421. img {
  422. background-color: rgba(0, 203, 230, 0.6);
  423. border-radius: 8px;
  424. }
  425. > .right-btn-option-list {
  426. display: block;
  427. }
  428. }
  429. .right-btn-option-list {
  430. display: none;
  431. position: absolute;
  432. top: 0;
  433. right: 2.2rem;
  434. width: 160px;
  435. padding: 0 20px;
  436. }
  437. .right-btn-option {
  438. padding: 10px;
  439. margin-bottom: 10px;
  440. border-radius: 4px;
  441. background-color: #394139;
  442. text-align: center;
  443. color: #fff;
  444. box-sizing: border-box;
  445. display: flex;
  446. justify-content: center;
  447. align-items: center;
  448. font-size: 1rem;
  449. svg {
  450. width: 1rem;
  451. height: 1rem;
  452. margin-left: .5rem;
  453. }
  454. }
  455. }
  456. }
  457. .slider-wrapper {
  458. position: fixed;
  459. left: -150px;
  460. bottom: 0;
  461. .water-level-slider-container {
  462. background-size: 100% 100%;
  463. width: 120px;
  464. height: 240px;
  465. padding: 2%;
  466. .water-level-slider-main {
  467. width: 100%;
  468. height: 100%;
  469. display: flex;
  470. align-items: center;
  471. .water-level-slider-title {
  472. writing-mode: vertical-lr;
  473. height: 60%;
  474. position: absolute;
  475. top: 50%;
  476. right: 8%;
  477. transform: translateY(-50%);
  478. color: #fff;
  479. font-weight: bold;
  480. font-size: 1rem;
  481. letter-spacing: 0.2em;
  482. }
  483. }
  484. }
  485. }
  486. .roam {
  487. padding: 5px 0;
  488. }
  489. </style>
  490. <style>
  491. .water-level-slider .el-slider__marks-text {
  492. width: 80px;
  493. }
  494. .slider-tooltip {
  495. background: #000;
  496. color: #fff;
  497. }
  498. </style>