index.vue 28 KB

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