index.vue 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951
  1. <template>
  2. <div class="scene-box" v-if="routerParam !== 'home'">
  3. <!-- <div class="scene-box"> -->
  4. <div class="device-header">智能通风管控系统</div>
  5. <div class="select-node" :class="{ 'node-select-show': !treeShow, 'node-select-hide': treeShow, }">
  6. <SvgIcon class="is-expansion-icon put-away-icon" size="38" name="expansion" @click="showTree('treeShow', true)" />
  7. <span class="title">{{ treeNodeTitle }}</span>
  8. </div>
  9. <div class="device-select" :class="{ 'device-select-show': treeShow, 'device-select-hide': !treeShow, }">
  10. <SvgIcon class="is-expansion-icon expansion-icon" size="28" name="put-away" @click="showTree('treeShow', false)" />
  11. <div class="device-select-box">
  12. <a-tree :show-line="true" :tree-data="treeData" v-model:selectedKeys="selectedKeys"
  13. v-model:expandedKeys="expandedKeys" @select="onSelect">
  14. </a-tree>
  15. </div>
  16. </div>
  17. <div class="location-icon" :class="{ 'location-btn-show': !locationSettingShow, 'location-btn-hide': locationSettingShow, }">
  18. <SvgIcon size="18" name="put-away" @click="showTree('location', true)" />
  19. <span class="location-text">定位图标显示</span>
  20. </div>
  21. <div class="location-select" :class="{ 'location-select-show': locationSettingShow, 'location-select-hide': !locationSettingShow, }">
  22. <div class="location-select-box">
  23. <div class="location-top-title" >
  24. <SvgIcon class="is-expansion-icon location-expansion-icon" size="28" name="expansion" @click="showTree('location', false)" />
  25. <div class="title">定位图标显示</div>
  26. </div>
  27. <div class="location-container">
  28. <template v-for="location in locationList" :key="location.deviceType">
  29. <div class="location-item">
  30. <div class="item-title">{{ location.title }}&nbsp;:</div>
  31. <div>
  32. <a-radio-group v-model:value="location.isVisible" :name="location.deviceType">
  33. <a-radio :value="1">是</a-radio>
  34. <a-radio :value="0">否</a-radio>
  35. </a-radio-group>
  36. </div>
  37. </div>
  38. </template>
  39. </div>
  40. </div>
  41. </div>
  42. <div class="bottom-tabs-box" @mousedown="setDivHeight" id="monitorBox">
  43. <div class="to-small" @click="toHome"></div>
  44. <div class="device-button-group" v-if="deviceList.length > 0">
  45. <div class="device-button" :class="{ 'device-active': deviceActive == device.deviceType }"
  46. v-for="(device, index) in deviceList" :key="index" @click="monitorChange(index)">{{ device.deviceName }}</div>
  47. <div class="enter-detail" @click="goDetail()">
  48. <send-outlined />
  49. {{ treeNodeTitle }}详情
  50. </div>
  51. </div>
  52. <a-tabs class="tabs-box" v-model:activeKey="activeKey" @change="tabChange">
  53. <a-tab-pane key="1" tab="实时监测">
  54. <template v-if="deviceType == 'fan' && activeKey == '1'">
  55. <GroupMonitorTable :dataSource="dataSource" :columnsType="`${deviceType}_monitor`" />
  56. </template>
  57. <template v-else-if="activeKey == '1'">
  58. <MonitorTable ref="monitorTable" :columnsType="`${deviceType}_monitor`" :dataSource="dataSource"
  59. design-scope="device_monitor" :isShowPagination="false" :isShowActionColumn="true" title="设备监测">
  60. <template #action="{ record }">
  61. <TableAction :actions="[
  62. {
  63. label: '详情',
  64. onClick: goDetail.bind(null, record),
  65. },
  66. {
  67. label: '定位',
  68. onClick: goLocation.bind(null, record),
  69. },
  70. ]" />
  71. </template>
  72. </MonitorTable>
  73. </template>
  74. </a-tab-pane>
  75. <a-tab-pane key="2" tab="历史数据">
  76. <div class="tab-item">
  77. <HistoryTable ref="historyTable" v-if="activeKey == '2'" :sysId="systemID" :columns-type="`${deviceType}`"
  78. :device-type="deviceType"
  79. :device-list-api="getDeviceList.bind(null, { strtype: deviceType, sysId: systemID })"
  80. designScope="device-history" />
  81. </div>
  82. </a-tab-pane>
  83. <a-tab-pane key="3" tab="报警历史">
  84. <div class="tab-item">
  85. <AlarmHistoryTable ref="alarmHistoryTable" v-if="activeKey == '3'" :sysId="systemID" columns-type="alarm"
  86. :device-type="deviceType"
  87. :device-list-api="getDeviceList.bind(null, { strtype: deviceType, sysId: systemID })"
  88. designScope="alarm-history" />
  89. </div>
  90. </a-tab-pane>
  91. <a-tab-pane key="4" tab="操作历史">
  92. <div class="tab-item">
  93. <HandlerHistoryTable ref="handlerHistoryTable" v-if="activeKey == '4'" :sysId="systemID"
  94. columns-type="operatorhistory" :device-type="deviceType"
  95. :device-list-api="getDeviceList.bind(null, { strtype: deviceType, sysId: systemID })"
  96. designScope="operator-history" />
  97. </div>
  98. </a-tab-pane>
  99. </a-tabs>
  100. </div>
  101. <component v-if="modalVisible" :is="currentModal" v-model:visible="modalVisible" :dataSource="dataSource"
  102. :activeID="activeID" />
  103. </div>
  104. </template>
  105. <script setup lang="ts">
  106. import { ref, onMounted, onUnmounted, ComponentOptions, shallowRef, nextTick } from 'vue'
  107. import { SendOutlined } from '@ant-design/icons-vue';
  108. import { list, getDeviceList, getDeviceTypeList } from './device.api'
  109. import { locationList } from './device.data'
  110. import AlarmHistoryTable from '../comment/AlarmHistoryTable.vue';
  111. import HistoryTable from '../comment/HistoryTable.vue';
  112. import HandlerHistoryTable from '../comment/HandlerHistoryTable.vue';
  113. import MonitorTable from '../comment/MonitorTable.vue';
  114. import GroupMonitorTable from '../comment/GroupMonitorTable.vue';
  115. import { TreeProps, message } from 'ant-design-vue';
  116. import { TableAction } from '/@/components/Table';
  117. import FiberModal from './modal/fiber.modal.vue';
  118. import DustModal from './modal/dust.modal.vue'
  119. import { SvgIcon } from '/@/components/Icon';
  120. import { getActions } from '/@/qiankun/state';
  121. import { useRouter } from 'vue-router';
  122. type DeviceType = { deviceType: string, deviceName: string, datalist: any[] };
  123. const router = useRouter()
  124. const actions = getActions();
  125. actions.setGlobalState({ pageObj: { pageType: 'home' } });
  126. const monitorTable = ref()
  127. const historyTable = ref()
  128. const alarmHistoryTable = ref()
  129. const handlerHistoryTable = ref()
  130. const routerParam = ref('home') // 默认进来时首页
  131. // 模态框
  132. const currentModal = shallowRef<Nullable<ComponentOptions>>(null); //模态框
  133. const modalVisible = ref<Boolean>(false); // 模态框是否可见
  134. //
  135. const drawerHeight = ref(240) // 监测框最小高度
  136. const treeShow = ref(true) //是否显示树形菜单
  137. const locationSettingShow = ref(false) //是否显示树形菜单
  138. const treeNodeTitle = ref('') // 选中的树形标题
  139. const deviceList = ref<DeviceType[]>([])
  140. const deviceActive = ref('')
  141. const activeKey = ref('1'); // tab key
  142. const dataSource = shallowRef([]) // 实时监测数据
  143. const activeID = ref('') // 打开详情modal时监测的设备id
  144. const deviceType = ref('') // 监测设备类型
  145. const systemType = ref('')
  146. const systemID = ref('') // 系统监测时,系统id
  147. const selectedKeys = ref<string[]>([]);
  148. const expandedKeys = ref<string[]>([]);
  149. const scroll = ref({
  150. y: drawerHeight.value - 100
  151. })
  152. const treeData = ref<TreeProps['treeData']>([]);
  153. //树形菜单选择事件
  154. const onSelect: TreeProps['onSelect'] = (keys, e) => {
  155. deviceType.value = ''
  156. systemID.value = ''
  157. deviceList.value = []
  158. if (e.node.parent && (e.node.parent.node.type.toString()).startsWith('sys')) {
  159. systemType.value = e.node.parent.node.type
  160. deviceType.value = e.node.parent.node.type
  161. systemID.value = e.node.type
  162. // 传递工作面id信息,用于定位
  163. actions.setGlobalState({ locationObj: { pageType: deviceType.value, deviceid: systemID.value }, pageObj: null });
  164. } else {
  165. systemType.value = e.node.type
  166. deviceType.value = e.node.type
  167. }
  168. selectedKeys.values = keys
  169. treeNodeTitle.value = e.node.title
  170. debugger
  171. if(timer) clearTimeout(timer)
  172. timer = undefined
  173. if (monitorTable.value) monitorTable.value.setLoading(true)
  174. nextTick(() => {
  175. timer = null
  176. getMonitor()
  177. })
  178. };
  179. function tabChange(activeKeyVal) {
  180. activeKey.value = activeKeyVal;
  181. };
  182. function showTree(flag, value) {
  183. if(flag == 'treeShow') treeShow.value = value
  184. if (flag == 'location') locationSettingShow.value = value
  185. }
  186. async function getDeviceType() {
  187. const result = await getDeviceTypeList({})
  188. if (result.length > 0) {
  189. const dataSource = <TreeProps['treeData']>[]
  190. let key = '0'
  191. const getData = (resultList, dataSourceList, keyVal) => {
  192. resultList.forEach((item, index) => {
  193. if (item.children && item.children.length > 0) {
  194. const children = getData(item.children, [], `${keyVal}-${index}`)
  195. dataSourceList.push({
  196. children: children,
  197. title: item.itemText,
  198. key: `${keyVal}-${index}`,
  199. type: item.itemValue,
  200. });
  201. } else {
  202. dataSourceList.push({
  203. children: [],
  204. title: item.itemText,
  205. key: `${keyVal}-${index}`,
  206. type: item.itemValue,
  207. });
  208. }
  209. });
  210. return dataSourceList
  211. }
  212. console.log('树形菜单-------------->', treeData.value)
  213. treeData.value = getData(result, dataSource, key)
  214. }
  215. }
  216. // https获取监测数据
  217. let timer: null | NodeJS.Timeout = undefined;
  218. function getMonitor() {
  219. if (timer) timer = null
  220. if (Object.prototype.toString.call(timer) === '[object Null]' && deviceType.value) {
  221. timer = setTimeout(async () => {
  222. await getDataSource()
  223. if (timer) {
  224. getMonitor();
  225. }
  226. }, 1000);
  227. }
  228. };
  229. async function getDataSource() {
  230. if (deviceType.value.startsWith('sys') && systemID.value) {
  231. const res = await list({ devicetype: 'sys', systemID: systemID.value });
  232. const result = res.msgTxt;
  233. const deviceArr = <DeviceType[]>[]
  234. result.forEach(item => {
  235. const data = item['datalist'].filter((data: any) => {
  236. const readData = data.readData;
  237. return Object.assign(data, readData);
  238. })
  239. if (item.type != 'sys') {
  240. deviceArr.unshift({ deviceType: item.type, deviceName: item['typeName'] ? item['typeName'] : item['datalist'][0]['typeName'], datalist: data })
  241. }
  242. })
  243. console.log('关联设备列表', deviceArr)
  244. deviceList.value = deviceArr
  245. deviceActive.value = deviceArr[1].deviceType
  246. monitorChange(1)
  247. } else {
  248. const res = await list({ devicetype: deviceType.value, pagetype: 'normal' })
  249. if (res.msgTxt[0]) {
  250. dataSource.value = res.msgTxt[0].datalist || [];
  251. dataSource.value.filter((data: any) => {
  252. const readData = data.readData;
  253. return Object.assign(data, readData);
  254. });
  255. }
  256. }
  257. }
  258. function setDivHeight(e: MouseEvent) {
  259. const divObject = document.getElementById('monitorBox') as HTMLElement
  260. const divHeight = divObject.offsetHeight
  261. drawerHeight.value = divHeight
  262. const startY = e.clientY
  263. document.onmousemove = function (res) {
  264. res.preventDefault()
  265. const distY = Math.abs(res.clientY - startY)
  266. if (res.clientY > startY) {
  267. if (divHeight - distY >= 240) {
  268. drawerHeight.value = divHeight - distY
  269. } else {
  270. drawerHeight.value = 240
  271. }
  272. }
  273. if (res.clientY < startY) {
  274. drawerHeight.value = divHeight + distY
  275. }
  276. divObject.style.height = drawerHeight.value + 'px'
  277. }
  278. document.onmouseup = function () {
  279. document.onmousemove = null
  280. if (scroll.value.y != drawerHeight.value - 100) {
  281. scroll.value = { y: drawerHeight.value - 100 }
  282. // const tableBody = document.getElementsByClassName('zxm-table-container')[0].children[1] as HTMLElement
  283. // debugger
  284. // tableBody.style.height = `${drawerHeight.value - 350}px`
  285. }
  286. }
  287. }
  288. function goLocation(record) {
  289. actions.setGlobalState({ locationId: record.deviceID, locationObj: null, pageObj: null });
  290. }
  291. function goDetail(record?) {
  292. if (record) {
  293. if (deviceType.value.startsWith('fiber')) {
  294. activeID.value = record.deviceID
  295. currentModal.value = FiberModal
  296. modalVisible.value = true;
  297. } else if (deviceType.value.startsWith('dusting')) {
  298. activeID.value = record.deviceID
  299. currentModal.value = DustModal
  300. modalVisible.value = true;
  301. } else if (deviceType.value.indexOf("gate") != -1) {
  302. const newPage = router.resolve({ path: '/monitorChannel/monitor-gate' })
  303. window.open(newPage.href, '_blank')
  304. } else if (deviceType.value.indexOf("window") != -1) {
  305. const newPage = router.resolve({ path: '/monitorChannel/monitor-window' })
  306. window.open(newPage.href, '_blank')
  307. } else if (deviceType.value.indexOf("windrect") != -1) {
  308. const newPage = router.resolve({ path: '/monitorChannel/monitor-windrect' })
  309. window.open(newPage.href, '_blank')
  310. } else if (deviceType.value.indexOf("fanmain") != -1) {
  311. const newPage = router.resolve({ path: '/monitorChannel/monitor-fan-main' })
  312. window.open(newPage.href, '_blank')
  313. } else if (deviceType.value.indexOf("fanlocal") != -1) {
  314. const newPage = router.resolve({ path: '/monitorChannel/monitor-fan-local' })
  315. window.open(newPage.href, '_blank')
  316. } else {
  317. message.info('待开发。。。')
  318. }
  319. } else {
  320. if (systemType.value.indexOf("sys_dongshi") != -1) {
  321. const newPage = router.resolve({ path: '/chamber-home', query: { id: systemID.value } })
  322. window.open(newPage.href, '_blank')
  323. } else {
  324. message.info('待开发。。。')
  325. }
  326. }
  327. }
  328. function toHome() {
  329. deviceList.value = []
  330. if(timer) clearTimeout(timer)
  331. timer = undefined
  332. actions.setGlobalState({ pageObj: { pageType: 'home' } });
  333. }
  334. async function findTreeDataValue(data: [], obj) {
  335. const findDeviceType = (data: [], obj) => {
  336. let type = ''
  337. if (obj.deviceid) {
  338. type = obj.deviceid
  339. } else {
  340. type = obj.deviceType
  341. }
  342. data.find((item: any) => {
  343. if (item.children.length > 0) {
  344. findDeviceType(item.children, obj)
  345. }
  346. if (item.type == type) {
  347. deviceType.value = obj.deviceid ? 'sys' : item.type
  348. if (obj.deviceid) systemID.value = obj.deviceid
  349. selectedKeys.value = [item.key]
  350. expandedKeys.value = [item.key]
  351. treeNodeTitle.value = item.title
  352. }
  353. })
  354. }
  355. findDeviceType(data, obj)
  356. debugger
  357. if (timer === undefined) {
  358. timer = null
  359. await getDataSource()
  360. getMonitor()
  361. }
  362. }
  363. function monitorChange(index) {
  364. dataSource.value = []
  365. deviceActive.value = deviceType.value = deviceList.value[index].deviceType
  366. if (activeKey.value == '1' && monitorTable.value) {
  367. monitorTable.value.setLoading(true)
  368. dataSource.value = deviceList.value[index].datalist
  369. }
  370. if (activeKey.value == '2' && historyTable.value) {
  371. historyTable.value.setLoading(true)
  372. }
  373. if (activeKey.value == '3' && alarmHistoryTable.value) {
  374. alarmHistoryTable.value.setLoading(true)
  375. }
  376. if (activeKey.value == '4' && handlerHistoryTable.value) {
  377. handlerHistoryTable.value.setLoading(true)
  378. }
  379. }
  380. onMounted(async () => {
  381. actions.onGlobalStateChange((newState, prev) => {
  382. for (const key in newState) {
  383. if (key === 'pageObj') {
  384. const pageObj = newState[key]
  385. if (pageObj) {
  386. routerParam.value = pageObj.pageType
  387. if(routerParam.value !== 'home'){
  388. if (pageObj.deviceid) {
  389. findTreeDataValue(treeData.value, { deviceid: pageObj.deviceid })
  390. } else {
  391. findTreeDataValue(treeData.value, { deviceType: pageObj.pageType })
  392. }
  393. }
  394. }
  395. }
  396. }
  397. })
  398. await getDeviceType()
  399. // getMonitor()
  400. })
  401. onUnmounted(() => {
  402. if (timer) {
  403. clearTimeout(timer);
  404. }
  405. timer = undefined;
  406. })
  407. </script>
  408. <style lang="less" scoped >
  409. @import '/@/design/vent/modal.less';
  410. @ventSpace: zxm;
  411. .device-header {
  412. position: fixed;
  413. width: 100%;
  414. height: 56px;
  415. background: url('/@/assets/images/vent/home/modal-top.png');
  416. text-align: center;
  417. line-height: 56px;
  418. font-size: 28px;
  419. color: #ffffffdd;
  420. font-weight: 600;
  421. z-index: -1;
  422. }
  423. .select-node {
  424. position: fixed;
  425. top: 60px;
  426. left: 10px;
  427. color: #fff;
  428. display: flex;
  429. justify-content: center;
  430. font-size: 22px;
  431. .title {
  432. margin-left: 10px;
  433. }
  434. }
  435. .expansion-icon {
  436. background: url('/@/assets/images/vent/home/tree-icon-bg.png') no-repeat;
  437. background-size: contain;
  438. position: absolute;
  439. left: 190px;
  440. top: 25px;
  441. &:hover {
  442. background: url('/@/assets/images/vent/home/tree-icon-hover-bg.png') no-repeat;
  443. background-size: contain;
  444. }
  445. }
  446. .device-select {
  447. width: 250px;
  448. height: 500px;
  449. background: url('/@/assets/images/vent/home/tree-bg.png') no-repeat;
  450. position: fixed;
  451. top: 60px;
  452. left: 10px;
  453. background-size: contain;
  454. pointer-events: auto;
  455. padding: 20px 10px 30px 10px;
  456. }
  457. .is-expansion-icon {
  458. padding: 5px;
  459. pointer-events: auto;
  460. z-index: 999;
  461. }
  462. .device-select-show {
  463. left: 10px;
  464. animation-name: treeShow;
  465. /* 持续时间 */
  466. animation-duration: 1s;
  467. transition: all 1s cubic-bezier(0.165, 0.84, 0.44, 1) .5s;
  468. }
  469. .device-select-hide {
  470. left: -250px;
  471. animation-name: treeHide;
  472. /* 持续时间 */
  473. animation-duration: 1s;
  474. transition: all 1s cubic-bezier(0.165, 0.84, 0.44, 1) .5s;
  475. }
  476. .node-select-show {
  477. width: 276px;
  478. height: 44px;
  479. background: url('/@/assets/images/vent/home/tree-expansion-bg.png') no-repeat;
  480. left: 10px;
  481. animation-name: treeShow;
  482. /* 持续时间 */
  483. animation-duration: 1s;
  484. transition: all 1s cubic-bezier(0.165, 0.84, 0.44, 1) .5s;
  485. display: flex;
  486. align-items: center;
  487. margin-left: 0;
  488. justify-content: flex-start;
  489. pointer-events: auto;
  490. &:hover{
  491. background: url('/@/assets/images/vent/home/tree-expansion-hover-bg.png') no-repeat;
  492. }
  493. .put-away-icon {
  494. position: relative;
  495. display: inline-block;
  496. left: 4px;
  497. }
  498. }
  499. .node-select-hide {
  500. left: -400px;
  501. animation-name: treeHide;
  502. /* 持续时间 */
  503. animation-duration: 1s;
  504. transition: all 1s cubic-bezier(0.165, 0.84, 0.44, 1) .5s;
  505. }
  506. .device-select-box {
  507. width: 208px;
  508. height: 450px;
  509. overflow-y: auto;
  510. color: #fff;
  511. :deep(.zxm-tree) {
  512. background: transparent !important;
  513. color: #fff !important;
  514. .zxm-tree-switcher {
  515. background: transparent !important;
  516. }
  517. .zxm-tree-node-content-wrapper.zxm-tree-node-selected {
  518. background-color: #00b1c8;
  519. }
  520. .zxm-tree-node-content-wrapper:hover {
  521. background-color: #00b1c855;
  522. }
  523. input {
  524. height: 0px !important;
  525. }
  526. }
  527. &::-webkit-scrollbar-track {
  528. -webkit-box-shadow: inset 0 0 5px rgba(0, 0, 0, 0.2);
  529. border-radius: 10px;
  530. background: #ededed22;
  531. height: 100px;
  532. }
  533. &::-webkit-scrollbar-thumb {
  534. -webkit-box-shadow: inset 0 0 5px rgba(0, 0, 0, 0.2);
  535. background: #4288A444;
  536. }
  537. }
  538. .location-icon{
  539. width: 46px;
  540. height: 178px;
  541. position: absolute;
  542. top: 60px;
  543. // right: 0;
  544. background: url('/@/assets/images/vent/home/location-bg.png') no-repeat;
  545. background-size: contain;
  546. writing-mode: vertical-lr;
  547. line-height: 46px;
  548. color: #fff;
  549. padding-top: 10px;
  550. pointer-events: auto;
  551. cursor: pointer;
  552. &:hover{
  553. background: url('/@/assets/images/vent/home/location-hover-bg.png') no-repeat;
  554. }
  555. .location-text{
  556. padding-top: 20px;
  557. letter-spacing: 3px;
  558. font-size: 16px;
  559. }
  560. }
  561. .location-select{
  562. position: fixed;
  563. top: 60px;
  564. // right: 240px;
  565. pointer-events: auto;
  566. .location-select-box{
  567. width: 100%;
  568. height: 100%;
  569. position: relative;
  570. &::before{
  571. content: "";
  572. position: absolute;
  573. width: 230px;
  574. height: 500px;
  575. top: 0;
  576. left: 0;
  577. background: url('/@/assets/images/vent/home/tree-bg.png') no-repeat;
  578. background-size: contain;
  579. transform: rotateY(180deg);
  580. z-index: -1;
  581. // &:hover {
  582. // background: url('/@/assets/images/vent/home/tree-icon-hover-bg.png') no-repeat;
  583. // background-size: contain;
  584. // }
  585. }
  586. .location-top-title{
  587. color: #fff;
  588. position: absolute;
  589. width: 225px;
  590. height: 68px;
  591. background: url('/@/assets/images/vent/home/turn-location-top-bg.png') no-repeat;
  592. background-size: contain;
  593. top: 5px;
  594. left: 5px;
  595. display: flex;
  596. flex-direction: row;
  597. justify-content: space-between;
  598. align-items: flex-end;
  599. .title{
  600. font-size: 18px;
  601. position: relative;
  602. top: -14px;
  603. right: 15px;
  604. }
  605. }
  606. .location-expansion-icon {
  607. background: url('/@/assets/images/vent/home/tree-icon-cover-bg.png') no-repeat;
  608. background-size: contain;
  609. position: relative;
  610. left: 10px;
  611. top: -15px;
  612. padding: 5px;
  613. &:hover {
  614. background: url('/@/assets/images/vent/home/tree-icon-cover-hover-bg.png') no-repeat;
  615. background-size: contain;
  616. }
  617. }
  618. }
  619. .location-container{
  620. width: 200px;
  621. height: 390px;
  622. position: absolute;
  623. display: flex;
  624. flex-direction: column;
  625. top: 80px;
  626. left: 18px;
  627. overflow-y: auto;
  628. .location-item{
  629. color: #fff;
  630. line-height: 30px;
  631. display: flex;
  632. justify-content: space-between;
  633. background-image: linear-gradient(to left, #39f5ff05, #39f5ff10);
  634. margin: 3px 0;
  635. .item-title{
  636. width: 80px;
  637. text-align: right;
  638. color: #87f1ff;
  639. }
  640. }
  641. }
  642. }
  643. .location-select-show{
  644. right: 240px;
  645. animation-name: locationShow;
  646. /* 持续时间 */
  647. animation-duration: 1s;
  648. transition: all 1s cubic-bezier(0.165, 0.84, 0.44, 1) .5s;
  649. }
  650. .location-select-hide{
  651. right: -2px;
  652. animation-name: locationHide;
  653. /* 持续时间 */
  654. animation-duration: 1s;
  655. transition: all 1s cubic-bezier(0.165, 0.84, 0.44, 1) .5s;
  656. }
  657. .location-btn-show{
  658. right: -0px;
  659. animation-name: locationBtnShow;
  660. /* 持续时间 */
  661. animation-duration: 1s;
  662. transition: all 1s cubic-bezier(0.165, 0.84, 0.44, 1) .5s;
  663. }
  664. .location-btn-hide{
  665. right: -240px;
  666. animation-name: locationBtnHide;
  667. /* 持续时间 */
  668. animation-duration: 1s;
  669. transition: all 1s cubic-bezier(0.165, 0.84, 0.44, 1) .5s;
  670. }
  671. .bottom-tabs-box {
  672. position: relative;
  673. .to-small {
  674. width: 60px;
  675. height: 60px;
  676. background: url('/@/assets/images/vent/home/tosmall.png') no-repeat center;
  677. background-size: auto;
  678. position: absolute;
  679. top: -65px;
  680. right: 30px;
  681. border-radius: 10px;
  682. padding: 8px;
  683. backdrop-filter: blur(10px);
  684. background-color: rgba(0, 58, 128, 0.418);
  685. &:hover {
  686. background-color: rgba(42, 85, 138, 0.418);
  687. }
  688. }
  689. .device-button-group {
  690. position: absolute;
  691. top: -27px;
  692. left: 30px;
  693. display: flex;
  694. width: 100%;
  695. .device-button {
  696. width: 148px;
  697. height: 26px;
  698. background: url('/@/assets/images/vent/home/tab21.png');
  699. display: flex;
  700. justify-content: center;
  701. align-items: center;
  702. color: #FFF;
  703. position: relative;
  704. cursor: pointer;
  705. &:nth-child(1){
  706. left: calc(-8px * 1);
  707. }
  708. &:nth-child(2){
  709. left: calc(-8px * 2);
  710. }
  711. &:nth-child(3){
  712. left: calc(-8px * 3);
  713. }
  714. &:nth-child(4){
  715. left: calc(-8px * 4);
  716. }
  717. &:nth-child(5){
  718. left: calc(-8px * 5);
  719. }
  720. &:nth-child(6){
  721. left: calc(-8px * 6);
  722. }
  723. &:nth-child(7){
  724. left: calc(-8px * 7);
  725. }
  726. &:nth-child(8){
  727. left: calc(-8px * 8);
  728. }
  729. &:nth-child(9){
  730. left: calc(-8px * 9);
  731. }
  732. &:first-child
  733. {
  734. background: url('/@/assets/images/vent/home/tab11.png');
  735. }
  736. }
  737. .device-active {
  738. background: url('/@/assets/images/vent/home/tab2-active.png');
  739. &:first-child
  740. {
  741. background: url('/@/assets/images/vent/home/tab1-active.png');
  742. }
  743. // color: #0efcff;
  744. &::before {
  745. border-color: #0efcff;
  746. box-shadow: 1px 1px 3px 1px #0efcff inset;
  747. }
  748. }
  749. }
  750. .enter-detail {
  751. color: #fff;
  752. cursor: pointer;
  753. position: absolute;
  754. right: 120px;
  755. top: -10px;
  756. padding: 5px;
  757. // border: 1px transparent solid;
  758. border-radius: 5px;
  759. margin-left: 8px;
  760. margin-right: 8px;
  761. width: auto;
  762. // height: 40px;
  763. // border: 1px solid #65dbea;
  764. height: 33px !important;
  765. display: flex;
  766. align-items: center;
  767. justify-content: center;
  768. color: #fff;
  769. padding: 5px 15px 5px 15px;
  770. cursor: pointer;
  771. &:hover {
  772. background: linear-gradient(#2cd1ff55, #1eb0ff55);
  773. }
  774. &::before {
  775. width: calc(100% - 6px);
  776. height: 27px;
  777. content: '';
  778. position: absolute;
  779. top: 3px;
  780. right: 0;
  781. left: 3px;
  782. bottom: 0;
  783. z-index: -1;
  784. border-radius: inherit;
  785. /*important*/
  786. background: linear-gradient(#1fa6cb, #127cb5);
  787. }
  788. &::after {
  789. width: calc(100% + 32px);
  790. height: 10px;
  791. content: '';
  792. position: absolute;
  793. top: 35px;
  794. right: 0;
  795. left: -16px;
  796. bottom: 0;
  797. z-index: -1;
  798. border-radius: inherit;
  799. /*important*/
  800. background: url('/@/assets/images/vent/short-light.png') no-repeat;
  801. background-position: center;
  802. background-size: 100%;
  803. z-index: 999;
  804. }
  805. }
  806. }
  807. @keyframes treeShow {
  808. 0% {
  809. left: -400px;
  810. opacity: 0;
  811. }
  812. 100% {
  813. left: 10px;
  814. opacity: 1;
  815. }
  816. }
  817. @keyframes treeHide {
  818. 0% {
  819. left: 10px;
  820. opacity: 1;
  821. }
  822. 100% {
  823. left: -400px;
  824. opacity: 0;
  825. }
  826. }
  827. @keyframes locationShow {
  828. 0% {
  829. right: 0px;
  830. opacity: 0;
  831. }
  832. 100% {
  833. right: 240px;
  834. opacity: 1;
  835. }
  836. }
  837. @keyframes locationHide {
  838. 0% {
  839. right: 240px;
  840. opacity: 1;
  841. }
  842. 100% {
  843. right: 0;
  844. opacity: 0;
  845. }
  846. }
  847. @keyframes locationBtnShow {
  848. 0% {
  849. right: -240px;
  850. opacity: 0;
  851. }
  852. 100% {
  853. right: -2px;
  854. opacity: 1;
  855. }
  856. }
  857. @keyframes locationBtnHide {
  858. 0% {
  859. right: -2px;
  860. opacity: 1;
  861. }
  862. 100% {
  863. right: -240px;
  864. opacity: 0;
  865. }
  866. }
  867. :deep(.@{ventSpace}-tabs-tabpane-active) {
  868. overflow: auto;
  869. // height: 100%;
  870. }
  871. :deep(.zxm-select-dropdown) {
  872. left: 0 !important;
  873. }</style>