index.vue 54 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624
  1. <template>
  2. <div class="scene-box" >
  3. <!-- <div class="top-header">智能通风管理系统</div> -->
  4. <div class="select-node" :class="{ 'node-select-show': !treeShow, 'node-select-hide': treeShow, }"
  5. @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"
  11. @click="showTree('treeShow', false)" />
  12. <div class="device-select-box">
  13. <a-tree :show-line="true" :tree-data="treeData" v-model:selectedKeys="selectedKeys" :autoExpandParent="true"
  14. v-model:expandedKeys="expandedKeys" @select="onSelect">
  15. </a-tree>
  16. </div>
  17. </div>
  18. <div class="location-icon"
  19. :class="{ 'location-btn-show': !locationSettingShow, 'location-btn-hide': locationSettingShow, }"
  20. @click="showTree('location', true)">
  21. <SvgIcon size="18" name="put-away" />
  22. <span class="location-text">定位图标显示</span>
  23. </div>
  24. <div class="location-select"
  25. :class="{ 'location-select-show': locationSettingShow, 'location-select-hide': !locationSettingShow, }">
  26. <div class="location-select-box">
  27. <div class="location-top-title" @click="showTree('location', false)">
  28. <SvgIcon class="is-expansion-icon location-expansion-icon" size="28" name="expansion" />
  29. <div class="title">定位图标显示</div>
  30. </div>
  31. <div class="location-container">
  32. <template v-for="location in locationList" :key="location.deviceType">
  33. <div class="location-item">
  34. <div class="item-title">{{ location.title }}&nbsp;:</div>
  35. <div>
  36. <a-radio-group v-model:value="location.Visible" :name="location.deviceType">
  37. <a-radio :value="1">是</a-radio>
  38. <a-radio :value="0">否</a-radio>
  39. </a-radio-group>
  40. </div>
  41. </div>
  42. </template>
  43. <div class="location-bottom-btn">
  44. <span @click="setLocation">提交</span>
  45. </div>
  46. </div>
  47. </div>
  48. </div>
  49. <div class="tabs-box bottom-tabs-box" :class="{'table-hide': tableShow, 'table-show': !tableShow }" @mousedown="setDivHeight($event, 230, scroll, 0)" id="monitorBox">
  50. <div :style="`padding: 5px; height: ${scroll.y + 100}px`">
  51. <div class="to-small" @click="toHome"></div>
  52. <div class="device-button-group" v-if="deviceList.length > 0">
  53. <!-- 关联设备 -->
  54. <div class="device-button" :class="{ 'device-active': deviceActive == device.deviceType }"
  55. v-for="(device, index) in deviceList" :key="index" @click="monitorChange(index)">{{ device.deviceName }}
  56. </div>
  57. <!-- 场景详情进入 -->
  58. <div v-if="haveSysDetailArr.find((item) => deviceType.startsWith(item))" class="enter-detail"
  59. @click.stop="goDetail()">
  60. <send-outlined />
  61. {{ treeNodeTitle }}详情
  62. </div>
  63. </div>
  64. <div v-if="deviceType == 'gaspatrol'">
  65. <div class="device-button-group">
  66. <div class="enter-detail" @click="exportXls()">
  67. <send-outlined />
  68. 导出
  69. </div>
  70. </div>
  71. </div>
  72. <div class="table-hide-icon" @click="toHide">
  73. <FullscreenExitOutlined />
  74. 隐藏
  75. </div>
  76. <!-- 是人员定位表单代码,由于放在tab中,表格对已知刷新,导致表单数据也在刷寻,造成输入一半的中文时会清空输入框的内容,导致的输入不上数据 -->
  77. <div v-if="deviceType.startsWith('location')" class="location-form" style="position: absolute; z-index: 9999; top: 50px;">
  78. <div class="location-form-item">
  79. <span class="location-form-label">人员名称:</span>
  80. <Input style="width: 200px;" v-model:value="locationForm.strname" />
  81. </div>
  82. <div class="location-form-item">
  83. <span class="location-form-label">所属部门:</span>
  84. <MTreeSelect style="width: 200px;" v-model:value="locationForm.department" placeholder="请选择所属部门" api="/ventanaly-device/getDepartmentInfo" :virtual="false" :isGetPopupContainer="false"/>
  85. </div>
  86. <div class="location-form-item">
  87. <span class="location-form-label">分站名称:</span>
  88. <Input style="width: 200px;" v-model:value="locationForm.stationname" />
  89. </div>
  90. </div>
  91. <div style="color: #fff;">{{ deviceType }}</div>
  92. <a-tabs class="tabs-box" v-model:activeKey="activeKey" @change="tabChange" id="tabsBox">
  93. <a-tab-pane key="1" tab="实时监测">
  94. <template
  95. v-if="(deviceType.startsWith('fanlocal') || deviceType.startsWith('fanmain')) && activeKey == '1'">
  96. <GroupMonitorTable ref="MonitorDataTable" :dataSource="dataSource" :columnsType="`${deviceType}_monitor`"
  97. :scroll="scroll" :isAction="true" :isShowSelect="false">
  98. <template #action="{ record }">
  99. <TableAction :actions="haveDetailArr.find((item) => deviceType.startsWith(item)) ? [
  100. {
  101. label: '详情',
  102. onClick: goDetail.bind(null, record),
  103. },
  104. {
  105. label: '定位',
  106. onClick: goLocation.bind(null, record),
  107. },
  108. ] : [
  109. {
  110. label: '定位',
  111. onClick: goLocation.bind(null, record),
  112. },
  113. ]" />
  114. </template>
  115. </GroupMonitorTable>
  116. </template>
  117. <template v-else-if="deviceType == 'majorpath' && activeKey == '1'">
  118. <a-table :columns="majorColumns" :data-source="dataSource" bordered :scroll="{ y: scroll.y - 30 }"
  119. :pagination="false"></a-table>
  120. </template>
  121. <template v-else-if="deviceType.startsWith('safetymonitor') && activeKey == '1'">
  122. <MonitorTable ref="monitorTable" :columnsType="`${deviceType}_monitor`" :deviceType="deviceType"
  123. :dataSource="dataSource" design-scope="device_monitor" :isShowActionColumn="true" :isShowSelect="false"
  124. title="设备监测" :form-config="formConfig" :scroll="{ y: scroll.y - 110 }">
  125. <template #action="{ record }">
  126. <TableAction :actions="haveDetailArr.find((item) => deviceType.startsWith(item)) ? [
  127. {
  128. label: '详情',
  129. onClick: goDetail.bind(null, record),
  130. },
  131. {
  132. label: '定位',
  133. onClick: goLocation.bind(null, record),
  134. },
  135. ] : [
  136. {
  137. label: '定位',
  138. onClick: goLocation.bind(null, record),
  139. },
  140. ]" />
  141. </template>
  142. <template #filterCell="{ column, record }">
  143. <div v-if="!record.devicename && column.dataIndex === 'devicename'">-</div>
  144. <div v-if="!record.V && column.dataIndex === 'V'">-</div>
  145. <div v-if="!record.PointUnit && column.dataIndex === 'PointUnit'">-</div>
  146. <div v-if="!record.highRange && column.dataIndex === 'highRange'">-</div>
  147. <div v-if="!record.lowRange && column.dataIndex === 'lowRange'">-</div>
  148. <div v-if="!record.dataTypeName && column.dataIndex === 'dataTypeName'">-</div>
  149. <a-tag v-if="column.dataIndex === 'netStatus'" :color="record.netStatus == '0' ? '#f00' : 'green'">{{
  150. record.netStatus == '0' ? '断开' : '连接'
  151. }}</a-tag>
  152. </template>
  153. </MonitorTable>
  154. </template>
  155. <template v-else-if="deviceType.startsWith('location') && activeKey == '1'">
  156. <MonitorTable ref="monitorTable" :columnsType="`${deviceType}_monitor`" :deviceType="deviceType"
  157. :dataSource="dataSource" design-scope="device_monitor" :isShowActionColumn="true" :isShowSelect="false"
  158. title="设备监测" :scroll="{ y: scroll.y - 110 }" style="margin-top: 60px;">
  159. <template #action="{ record }">
  160. <TableAction :actions="[
  161. {
  162. label: '定位',
  163. onClick: goLocation.bind(null, record),
  164. },
  165. ]" />
  166. </template>
  167. </MonitorTable>
  168. </template>
  169. <template v-else-if="deviceType.startsWith('vehicle') && activeKey == '1'">
  170. <MonitorTable ref="monitorTable" :columnsType="`${deviceType}_monitor`" :deviceType="deviceType"
  171. :dataSource="dataSource" design-scope="device_monitor" :isShowActionColumn="true" :isShowSelect="false"
  172. title="设备监测" :form-config="vehicleFormConfig" :scroll="{ y: scroll.y - 110 }">
  173. <template #action="{ record }">
  174. <TableAction :actions="[
  175. {
  176. label: '定位',
  177. onClick: goLocation.bind(null, record),
  178. },
  179. ]" />
  180. </template>
  181. </MonitorTable>
  182. </template>
  183. <template v-else>
  184. <!-- 工作面echarts图标 -->
  185. <BarAndLine v-if="activeKey == '1' && deviceType == 'surface_history'" class="echarts-line"
  186. xAxisPropType="time" :dataSource="surfaceEchartsData" height="300px"
  187. :chartsColumns="surfaceChartsColumns" :option="echatsOption" chartsType="listMonitor" />
  188. <MonitorTable v-else-if="activeKey == '1'" ref="monitorTable" :columnsType="`${deviceType}_monitor`"
  189. :dataSource="dataSource" design-scope="device_monitor" :isShowActionColumn="true" :isShowSelect="false"
  190. title="设备监测" :scroll="{ y: scroll.y - 30 }">
  191. <template #action="{ record }">
  192. <TableAction :actions="haveDetailArr.find((item) => deviceType.startsWith(item)) ? [
  193. {
  194. label: '详情',
  195. onClick: goDetail.bind(null, record),
  196. },
  197. {
  198. label: '定位',
  199. onClick: goLocation.bind(null, record),
  200. },
  201. ] : [
  202. {
  203. label: '定位',
  204. onClick: goLocation.bind(null, record),
  205. },
  206. ]" />
  207. </template>
  208. <template #filterCell="{ column, record }">
  209. <template v-if="deviceType.startsWith('gate')">
  210. <template v-if="record.frontGateOpenCtrl == 1 || record.frontGateOpenCtrl === true">
  211. <a-tag
  212. v-if="column.dataIndex === 'frontGateOpen' && record.frontGateOpen == 0 && record.frontGateClose == 0"
  213. color="red">正在打开</a-tag>
  214. <a-tag v-else-if="column.dataIndex === 'frontGateOpen'" color="processing">打开</a-tag>
  215. </template>
  216. <template v-else-if="record.frontGateOpenCtrl == 0 || record.frontGateOpenCtrl === false">
  217. <a-tag
  218. v-if="column.dataIndex === 'frontGateOpen' && record.frontGateOpen == 0 && record.frontGateClose == 0"
  219. color="red">正在关闭</a-tag>
  220. <a-tag
  221. v-else-if="column.dataIndex === 'frontGateOpen' && record.frontGateOpen == 0 && record.frontGateClose == 1"
  222. color="default">关闭</a-tag>
  223. <a-tag
  224. v-else-if="column.dataIndex === 'frontGateOpen' && record.frontGateOpen == 1 && record.frontGateClose == 0"
  225. color="default">打开</a-tag>
  226. </template>
  227. <template v-if="record.rearGateOpenCtrl == 1 || record.rearGateOpenCtrl === true">
  228. <a-tag
  229. v-if="column.dataIndex === 'rearGateOpen' && record.rearGateOpen == 0 && record.rearGateClose == 0"
  230. color="red">正在打开</a-tag>
  231. <a-tag v-else-if="column.dataIndex === 'rearGateOpen'" color="processing">打开</a-tag>
  232. </template>
  233. <template v-else-if="record.rearGateOpenCtrl == 0 || record.rearGateOpenCtrl === false">
  234. <a-tag
  235. v-if="column.dataIndex === 'rearGateOpen' && record.rearGateOpen == 0 && record.rearGateClose == 0"
  236. color="red">正在关闭</a-tag>
  237. <a-tag
  238. v-else-if="column.dataIndex === 'rearGateOpen' && record.rearGateOpen == 0 && record.rearGateClose == 1"
  239. color="default">关闭</a-tag>
  240. <a-tag
  241. v-else-if="column.dataIndex === 'rearGateOpen' && record.rearGateOpen == 1 && record.rearGateClose == 0"
  242. color="default">打开</a-tag>
  243. </template>
  244. <template v-if="column.dataIndex === 'ndoortype'">
  245. <span v-if="record.ndoortype == 0" color="red">行车风门</span>
  246. <span v-else color="default">行人风门</span>
  247. </template>
  248. </template>
  249. <template v-else-if="deviceType.startsWith('windrect')">
  250. <a-tag v-if="column.dataIndex === 'sign'"
  251. :color="record.sign == 0 ? '#95CF65' : record.sign == 1 ? '#4590EA' : '#9876AA'"> {{
  252. record.sign == 0 ? '高位' : record.sign == 1 ? '中位' : '低位'
  253. }}</a-tag>
  254. <template v-if="record && column && column.dataIndex === 'isRun' && record.isRun">
  255. <a-tag v-if="record.isRun == -2 || record.isRun == -1"
  256. :color="record.isRun == -2 ? '#95CF65' : '#ED5700'">{{
  257. record.isRun == -2 ? '空闲' : '等待'
  258. }}</a-tag>
  259. <a-tag v-else-if="record.isRun == 100" color="#4693FF">完成</a-tag>
  260. <Progress v-else :percent="Number(record.isRun)" size="small" status="active" />
  261. </template>
  262. </template>
  263. <template v-else-if="deviceType.startsWith('safetymonitor')">
  264. <div v-if="!record.devicename && column.dataIndex === 'devicename'">-</div>
  265. <div v-if="!record.V && column.dataIndex === 'V'">-</div>
  266. <div v-if="!record.PointUnit && column.dataIndex === 'PointUnit'">-</div>
  267. <div v-if="!record.highRange && column.dataIndex === 'highRange'">-</div>
  268. <div v-if="!record.lowRange && column.dataIndex === 'lowRange'">-</div>
  269. <div v-if="!record.dataTypeName && column.dataIndex === 'dataTypeName'">-</div>
  270. </template>
  271. <template v-else-if="deviceType.startsWith('atomizing')">
  272. <a-tag
  273. v-if="column.dataIndex === 'stateConn' && record.stateConn == '1'" color="green">连接</a-tag>
  274. <a-tag
  275. v-if="column.dataIndex === 'stateConn' && record.stateConn == '0'" color="red">断开</a-tag>
  276. </template>
  277. <a-tag v-if="column.dataIndex === 'warnFlag'"
  278. :color="record.warnFlag == 0 ? 'green' : record.warnFlag == 1 ? '#FF5812' : 'gray'"> {{
  279. record.warnFlag == 0 ? '正常' : record.warnFlag == 1 ? '报警' : record.warnFlag == 2 ? '断开' : '未监测'
  280. }}</a-tag>
  281. <template v-else-if="column.dataIndex === 'warnLevel'">
  282. <a-tag v-if="record.warnLevel == '101'" color="green">低风险</a-tag>
  283. <a-tag v-else-if="record.warnLevel == '102'" color="#FF5812">一般风险</a-tag>
  284. <a-tag v-else-if="record.warnLevel == '103'" color="#FF5812">较大风险</a-tag>
  285. <a-tag v-else-if="record.warnLevel == '104'" color="#FF5812">重大风险</a-tag>
  286. <a-tag v-else-if="record.warnLevel == '201'" color="#FF0000">报警</a-tag>
  287. <a-tag v-else-if="record.warnLevel == '10000'" color="#FF5812">数据超限</a-tag>
  288. <a-tag v-else-if="record.warnLevel == '1001'" color="default">网络中断</a-tag>
  289. <a-tag v-else color="green">正常</a-tag>
  290. </template>
  291. <a-tag v-if="column.dataIndex === 'netStatus'" :color="record.netStatus == '0' ? '#f00' : 'green'">{{
  292. record.netStatus == '0' ? '断开' : '连接'
  293. }}</a-tag>
  294. </template>
  295. </MonitorTable>
  296. </template>
  297. </a-tab-pane>
  298. <a-tab-pane key="2" tab="历史数据" v-if="!(noHistoryArr()).find((item) => deviceType.startsWith(item))">
  299. <div class="tab-item">
  300. <HistoryTable ref="historyTable" v-if="activeKey == '2'" :sysId="systemID" :columns-type="`${deviceType}`"
  301. :device-type="deviceType" designScope="device-history" :scroll="scroll" />
  302. </div>
  303. </a-tab-pane>
  304. <a-tab-pane key="3" tab="报警历史" v-if="!noWarningArr.find((item) => deviceType.startsWith(item))">
  305. <div class="tab-item">
  306. <AlarmHistoryTable ref="alarmHistoryTable" v-if="activeKey == '3'" :sysId="systemID" columns-type="alarm"
  307. :device-type="deviceType"
  308. :device-list-api="getDeviceList.bind(null, { devicekind: deviceType, sysId: systemID, pageSize: 10000 })"
  309. :scroll="scroll" designScope="alarm-history" />
  310. </div>
  311. </a-tab-pane>
  312. <a-tab-pane key="4" tab="操作历史" v-if="haveHandlerArr.find((item) => deviceType.startsWith(item))">
  313. <div class="tab-item">
  314. <HandlerHistoryTable ref="handlerHistoryTable" v-if="activeKey == '4'" :sysId="systemID"
  315. columns-type="operator_history" :device-type="deviceType"
  316. :device-list-api="getDeviceList.bind(null, { devicekind: deviceType, sysId: systemID })"
  317. :scroll="scroll" designScope="operator-history" />
  318. </div>
  319. </a-tab-pane>
  320. </a-tabs>
  321. </div>
  322. </div>
  323. <mainPath v-if="deviceType == 'majorpath'" :dataSource="majorPathEchartsData"
  324. style="width: 300px; height: 300px; position: absolute; left: 250px; top: 40px;" />
  325. <component v-if="modalVisible" :is="currentModal" v-model:visible="modalVisible" :dataSource="dataSource"
  326. :activeID="activeID" />
  327. </div>
  328. </template>
  329. <script setup lang="ts">
  330. import { ref, onMounted, onUnmounted, ComponentOptions, shallowRef, reactive, defineProps, watch } from 'vue'
  331. import { SendOutlined, FullscreenExitOutlined } from '@ant-design/icons-vue';
  332. import { list, getDeviceList, getDeviceTypeList, devPosition, getDepartmentInfo,getExportUrl } from './device.api'
  333. import AlarmHistoryTable from '../../../comment/AlarmHistoryTable.vue';
  334. import HistoryTable from '../../../comment/HistoryTable.vue';
  335. import HandlerHistoryTable from '../../../comment/HandlerHistoryTable.vue';
  336. import MonitorTable from '../../../comment/MonitorTable.vue';
  337. import GroupMonitorTable from '../../../comment/GroupMonitorTable.vue';
  338. import { TreeProps, message, Progress, Input, Select } from 'ant-design-vue';
  339. import { TableAction } from '/@/components/Table';
  340. import { SvgIcon } from '/@/components/Icon';
  341. import { getActions } from '/@/qiankun/state';
  342. import { useRouter } from 'vue-router';
  343. import { setDivHeight } from '/@/utils/event';
  344. import { majorColumns, haveSysDetailArr, haveDetailArr, haveHandlerArr, noWarningArr, surfaceChartsColumns, noHistoryArr, getMonitorComponent, vehicleFormConfig } from './device.data'
  345. import mainPath from './modal/mainPath.vue'
  346. import { formConfig } from '../../../safetyMonitor/safety.data'
  347. import { getDictItemsByCode } from '/@/utils/dict';
  348. import BarAndLine from '/@/components/chart/BarAndLine.vue';
  349. import MTreeSelect from '/@/components/Form/src/jeecg/components/MTreeSelect.vue';
  350. // import ApiSelect from '/@/components/Form/src/components/ApiSelect.vue';
  351. import { nextTick } from 'vue';
  352. import { useMethods } from '/@/hooks/system/useMethods';
  353. import { useGo } from '/@/hooks/web/usePage';
  354. // import { BorderBox8 as DvBorderBox8 } from '@kjgl77/datav-vue3';
  355. const { FiberModal, BundleModal, DustModal, BallvalveModal, AtomizingModal, GaspatrolModal } = getMonitorComponent()
  356. type DeviceType = { deviceType: string, deviceName: string, datalist: any[] };
  357. const props = defineProps({
  358. pageData: {
  359. type: Object,
  360. default: () => { }
  361. }
  362. })
  363. const { handleExportXls } = useMethods();
  364. const go = useGo()
  365. const echatsOption = {
  366. grid: {
  367. top: '35',
  368. left: '30',
  369. right: '45',
  370. bottom: '25',
  371. containLabel: true
  372. },
  373. toolbox: {
  374. feature: {}
  375. },
  376. }
  377. const router = useRouter()
  378. const actions = getActions();
  379. // actions.setGlobalState({ pageObj: { pageType: 'home' } });
  380. const locationForm = reactive({
  381. strname:'',
  382. department: '',
  383. stationname: ''
  384. })
  385. const safetymonitorForm = reactive({
  386. dataTypeName:'',
  387. strinstallpos: '',
  388. })
  389. const monitorTable = ref()
  390. const historyTable = ref()
  391. const alarmHistoryTable = ref()
  392. const handlerHistoryTable = ref()
  393. // const routerParam = ref('home') // 默认进来时首页
  394. const isRefresh = ref(true)
  395. // 模态框
  396. const currentModal = shallowRef<Nullable<ComponentOptions>>(null); //模态框
  397. const modalVisible = ref<Boolean>(false); // 模态框是否可见
  398. // const drawerHeight = ref(240) // 监测框最小高度
  399. const treeShow = ref(true) //是否显示树形菜单
  400. const tableShow = ref(true) //是否显示树形菜单
  401. const locationSettingShow = ref(false) //是否显示树形菜单
  402. const treeNodeTitle = ref('') // 选中的树形标题
  403. const locationList = ref([]) //巷道定位图标显示列表
  404. const deviceList = ref<DeviceType[]>([]) //关联设备列表
  405. const deviceActive = ref('')
  406. const activeKey = ref('1'); // tab key
  407. const dataSource = shallowRef([]) // 实时监测数据
  408. const majorPathEchartsData = ref({}) // 关键路线echarts数据
  409. const surfaceEchartsData = ref<any[]>() // 工作面历史记录,echarts数据
  410. const activeID = ref('') // 打开详情modal时监测的设备id
  411. const deviceType = ref('') // 监测设备类型
  412. const systemType = ref('')
  413. const systemID = ref('') // 系统监测时,系统id
  414. const selectedKeys = ref<string[]>([]);
  415. const expandedKeys = ref<string[]>([]);
  416. const scroll = reactive({
  417. y: 180
  418. })
  419. const treeData = ref<TreeProps['treeData']>([]);
  420. let departmentInfo: Null | Object = null
  421. let startMonitorTimer = 0
  422. //树形菜单选择事件
  423. const onSelect: TreeProps['onSelect'] = (keys, e) => {
  424. deviceType.value = ''
  425. systemID.value = ''
  426. deviceList.value = []
  427. const title = e.node.title; // 在
  428. if (e.node.parent && (e.node.parent.node.type.toString()).startsWith('sys')) {
  429. systemType.value = e.node.parent.node.type
  430. if(deviceType.value != e.node.parent.node.type)deviceType.value = e.node.parent.node.type
  431. systemID.value = e.node.type
  432. // 传递工作面id信息,用于定位
  433. go(`/micro-vent-3dModal/dashboard/analysis?type=tunMonitor&deviceType=${deviceType.value}&deviceid=${systemID.value}`)
  434. } else {
  435. systemType.value = e.node.type
  436. if(deviceType.value != e.node.type)deviceType.value = e.node.type
  437. go(`/micro-vent-3dModal/dashboard/analysis?type=tunMonitor&deviceType=${deviceType.value}&deviceid=`)
  438. }
  439. clearTimeout(timer)
  440. timer = undefined
  441. if (startMonitorTimer) {
  442. clearTimeout(startMonitorTimer)
  443. }
  444. dataSource.value = []
  445. startMonitorTimer = setTimeout(() => {
  446. expandedKeys.value = keys
  447. selectedKeys.value = keys
  448. treeNodeTitle.value = e.node.title
  449. activeKey.value = '1'
  450. timer = null
  451. if (e.node.children?.length < 1) {
  452. getMonitor(true)
  453. }
  454. }, 1000)
  455. };
  456. function tabChange(activeKeyVal) {
  457. activeKey.value = activeKeyVal;
  458. };
  459. function showTree(flag, value) {
  460. if (flag == 'treeShow') treeShow.value = value
  461. if (flag == 'location') locationSettingShow.value = value
  462. }
  463. async function getDeviceType(sysType?) {
  464. if (treeData.value?.length > 0) return
  465. const result = await getDeviceTypeList({})
  466. if (result.length > 0) {
  467. const dataSource = <TreeProps['treeData']>[]
  468. let key = '0'
  469. const getData = (resultList, dataSourceList, keyVal) => {
  470. resultList.forEach((item, index) => {
  471. if (item.deviceType != 'sys' && item.children && item.children.length > 0) {
  472. const children = getData(item.children, [], `${keyVal}-${index}`)
  473. // 判断关键阻力路线
  474. if (item.itemValue.startsWith(sysType) && children[0]) {
  475. systemID.value = item.children[0]['itemValue']
  476. }
  477. dataSourceList.push({
  478. children: children,
  479. title: item.itemText,
  480. key: `${keyVal}-${index}`,
  481. type: item.itemValue,
  482. parentKey: `${keyVal}`
  483. });
  484. } else {
  485. dataSourceList.push({
  486. children: [],
  487. title: item.itemText,
  488. key: `${keyVal}-${index}`,
  489. type: item.itemValue,
  490. parentKey: `${keyVal}`
  491. });
  492. }
  493. });
  494. return dataSourceList
  495. }
  496. treeData.value = getData(result, dataSource, key)
  497. }
  498. }
  499. // https获取监测数据
  500. let timer: null | NodeJS.Timeout = undefined;
  501. function getMonitor(flag?) {
  502. if (deviceType.value) {
  503. if (timer) timer = null
  504. if (Object.prototype.toString.call(timer) === '[object Null]') {
  505. timer = setTimeout(async () => {
  506. await getDataSource()
  507. if (timer) {
  508. getMonitor();
  509. }
  510. }, flag ? 0 : 1000);
  511. }
  512. }
  513. };
  514. async function getDataSource() {
  515. if (deviceType.value && deviceType.value.startsWith('sys') && systemID.value) {
  516. const res = await list({ devicetype: 'sys', systemID: systemID.value });
  517. const result = res.msgTxt;
  518. const deviceArr = <DeviceType[]>[]
  519. result.forEach(item => {
  520. const data = item['datalist'].filter((data: any) => {
  521. const readData = data.readData;
  522. return Object.assign(data, readData);
  523. })
  524. if (item.type != 'sys') {
  525. if (item.type === 'majorpath') {
  526. deviceArr.unshift({ deviceType: item.type, deviceName: item['typeName'], datalist: item['datalist'][0]['paths'] })
  527. majorPathEchartsData.value = item['datalist'][0]
  528. } else if (item.type.startsWith('surface_history')) {
  529. surfaceEchartsData.value = item['datalist'][0]
  530. deviceArr.unshift({ deviceType: item.type, deviceName: item['typeName'] ? item['typeName'] : item['datalist'][0]['typeName'], datalist: data })
  531. } else {
  532. deviceArr.unshift({ deviceType: item.type, deviceName: item['typeName'] ? item['typeName'] : item['datalist'][0]['typeName'], datalist: data })
  533. }
  534. }
  535. })
  536. deviceList.value = deviceArr
  537. if (deviceArr.length > 0) {
  538. // if (deviceArr[1]) {
  539. // deviceActive.value = deviceArr[1].deviceType
  540. // monitorChange(1)
  541. // } else {
  542. // deviceActive.value = deviceArr[0].deviceType
  543. // monitorChange(0)
  544. // }
  545. deviceActive.value = deviceArr[0].deviceType
  546. monitorChange(0)
  547. }
  548. } else {
  549. let res = null
  550. if (systemID.value) {
  551. res = await list({ devicetype: 'sys', types: deviceType.value, systemID: systemID.value })
  552. if (res && res.msgTxt) {
  553. const result = res.msgTxt;
  554. result.forEach(item => {
  555. const data = item['datalist'].filter((data: any) => {
  556. const readData = data.readData;
  557. return Object.assign(data, readData);
  558. })
  559. if (item.type != 'sys') {
  560. if (item.type.startsWith('majorpath') && item.type == deviceType.value) {
  561. dataSource.value = item['datalist'][0]['paths']
  562. majorPathEchartsData.value = item['datalist'][0]
  563. return
  564. } else if (item.type == deviceType.value) {
  565. if (item.type == 'surface_history') { // 工作面图标数据
  566. surfaceEchartsData.value = item['datalist'][0]
  567. } else {
  568. dataSource.value = data
  569. console.log('关联设备数据--------------->', data)
  570. }
  571. return
  572. }
  573. }
  574. })
  575. }
  576. } else {
  577. let resultData, searchForm;
  578. if(monitorTable.value){
  579. const formData = monitorTable.value.getForm()
  580. searchForm = formData.getFieldsValue()
  581. }
  582. if (monitorTable.value) {
  583. if (deviceType.value.startsWith('safetymonitor')) {
  584. resultData = await list({ devicetype: deviceType.value, pagetype: 'normal', filterParams: { ...searchForm } })
  585. } else if (deviceType.value.startsWith('location')) {
  586. if (!departmentInfo) {
  587. departmentInfo = await getDepartmentInfo({})
  588. }
  589. let department = null
  590. if (departmentInfo && locationForm && locationForm['department']) {
  591. for (const key in departmentInfo) {
  592. const item = departmentInfo[key]
  593. if (item['id'] === locationForm['department']) {
  594. department = item
  595. break;
  596. }
  597. }
  598. }
  599. resultData = await list({ devicetype: deviceType.value, pagetype: 'normal', filterParams: { strinstallpos: locationForm['stationname'] ? locationForm['stationname'] : '', userName: locationForm['strname'] ? locationForm['strname'] : '', userJson: department && department['name'] ? department['name'] : '' } })
  600. } else if (deviceType.value.startsWith('vehicle')) {
  601. resultData = await list({ devicetype: deviceType.value, pagetype: 'normal', filterParams: { strinstallpos: locationForm['stationname'] ? locationForm['stationname'] : '', vehicleName: locationForm['strname'] ? locationForm['strname'] : '' } })
  602. } else {
  603. resultData = await list({ devicetype: deviceType.value, pagetype: 'normal' })
  604. }
  605. } else {
  606. // 非安全监控
  607. resultData = await list({ devicetype: deviceType.value, pagetype: 'normal' })
  608. }
  609. if (resultData && resultData.msgTxt) {
  610. const result = resultData.msgTxt[0];
  611. if (result) {
  612. const data = result['datalist'].filter((data: any) => {
  613. const readData = data.readData;
  614. return Object.assign(data, readData);
  615. })
  616. if (deviceType.value.startsWith('safetymonitor')) {
  617. const resultData = <any[]>[]
  618. // 如果是安全监控的数据时需要过滤常见设备数据,根据设定的常用安全监控字典去匹配
  619. const dictCodes = getDictItemsByCode('safetynormal')
  620. if (searchForm && !searchForm['dataTypeName'] && dictCodes && dictCodes.length) {
  621. for (let i = 0; i < dictCodes.length; i++) {
  622. const dict = dictCodes[i]
  623. data.forEach((item) => {
  624. if (dict['value'] == item['dataTypeName']) {
  625. resultData.push(item)
  626. }
  627. })
  628. }
  629. dataSource.value = resultData
  630. } else {
  631. dataSource.value = data
  632. }
  633. } else {
  634. let tableData: any[] = []
  635. let noNetData: any[] = []
  636. data.filter(el => {
  637. if (el.netStatus == 1) {
  638. tableData.push(el)
  639. } else {
  640. noNetData.push(el)
  641. }
  642. })
  643. dataSource.value = [...tableData, ...noNetData]
  644. }
  645. } else {
  646. dataSource.value = []
  647. }
  648. } else {
  649. dataSource.value = []
  650. }
  651. }
  652. }
  653. }
  654. function goLocation(record) {
  655. actions.setGlobalState({ locationId: record.deviceID, locationObj: null, pageObj: null });
  656. }
  657. function goDetail(record?) {
  658. if (record) {
  659. activeID.value = record.deviceID
  660. if (deviceType.value.startsWith('fiber')) {
  661. currentModal.value = FiberModal
  662. modalVisible.value = true;
  663. } else if (deviceType.value.startsWith('dusting')) {
  664. currentModal.value = DustModal
  665. modalVisible.value = true;
  666. } else if (deviceType.value.startsWith('bundletube')) {
  667. currentModal.value = BundleModal
  668. // currentModal.value = BallvalveModal
  669. modalVisible.value = true;
  670. } else if (deviceType.value.startsWith('ballvalve')) {
  671. currentModal.value = BallvalveModal
  672. modalVisible.value = true;
  673. } else if (deviceType.value.startsWith('atomizing')) {
  674. currentModal.value = AtomizingModal
  675. modalVisible.value = true;
  676. } else if (deviceType.value.startsWith('gaspatrol')) {
  677. currentModal.value = GaspatrolModal
  678. modalVisible.value = true;
  679. } else if (deviceType.value.indexOf("gate") != -1) {
  680. const newPage = router.resolve({ path: '/monitorChannel/monitor-gate', query: { id: activeID.value } })
  681. window.open(newPage.href, '_blank')
  682. } else if (deviceType.value.indexOf("window") != -1) {
  683. const newPage = router.resolve({ path: '/monitorChannel/monitor-window', query: { id: activeID.value } })
  684. window.open(newPage.href, '_blank')
  685. } else if (deviceType.value.indexOf("windrect") != -1) {
  686. const newPage = router.resolve({ path: '/monitorChannel/monitor-windrect', query: { id: activeID.value } })
  687. window.open(newPage.href, '_blank')
  688. } else if (deviceType.value.indexOf("fanmain") != -1) {
  689. const newPage = router.resolve({ path: '/monitorChannel/monitor-fanmain', query: { id: activeID.value } })
  690. window.open(newPage.href, '_blank')
  691. } else if (deviceType.value.indexOf("fanlocal") != -1) {
  692. const newPage = router.resolve({ path: '/monitorChannel/monitor-fanlocal', query: { id: activeID.value, deviceType: deviceType.value } })
  693. window.open(newPage.href, '_blank')
  694. } else if (deviceType.value.indexOf("pulping") != -1) {
  695. const newPage = router.resolve({ path: '/grout-home', query: { id: activeID.value } })
  696. window.open(newPage.href, '_blank')
  697. } else if (deviceType.value.indexOf("pressurefan") != -1) {
  698. const newPage = router.resolve({ path: '/nitrogen/home', query: { id: activeID.value } })
  699. window.open(newPage.href, '_blank')
  700. } else if (deviceType.value.indexOf("chamber") != -1) {
  701. const newPage = router.resolve({ path: '/chamber-home', query: { id: activeID.value } })
  702. window.open(newPage.href, '_blank')
  703. } else if (deviceType.value.indexOf("safetymonitor") != -1) {
  704. const newPage = router.resolve({ path: '/monitorChannel/device-monitor/safetymonitor', query: { id: activeID.value } })
  705. window.open(newPage.href, '_blank')
  706. } else if (deviceType.value.indexOf("pump") != -1) {
  707. const newPage = router.resolve({ path: '/monitorChannel/gasPump-home', query: { id: activeID.value } })
  708. window.open(newPage.href, '_blank')
  709. } else if (systemType.value.indexOf("nitrogen") != -1) {
  710. const newPage = router.resolve({ path: '/nitrogen-home', query: { id: systemID.value } })
  711. window.open(newPage.href, '_blank')
  712. } else {
  713. message.info('待开发。。。')
  714. }
  715. } else {
  716. if (systemType.value.indexOf("sys_dongshi") != -1) {
  717. const newPage = router.resolve({ path: '/chamber-home', query: { id: systemID.value } })
  718. window.open(newPage.href, '_blank')
  719. } else if (systemType.value.indexOf("sys_obfurage") != -1) {
  720. const newPage = router.resolve({ path: '/monitorChannel/obfurage-home', query: { id: systemID.value } })
  721. window.open(newPage.href, '_blank')
  722. } else if (systemType.value.indexOf("sys_surface_caimei") != -1) {
  723. const newPage = router.resolve({ path: '/monitorChannel/wokerFace-home', query: { id: systemID.value } })
  724. window.open(newPage.href, '_blank')
  725. } else if (systemType.value.indexOf("sys_surface_juejin") != -1) {
  726. const newPage = router.resolve({ path: '/monitorChannel/tunFace-home', query: { id: systemID.value } })
  727. window.open(newPage.href, '_blank')
  728. } else if (systemType.value.indexOf("sys_maintunnel_leather") != -1) {
  729. const newPage = router.resolve({ path: '/monitorChannel/beltTun-home', query: { id: systemID.value } })
  730. window.open(newPage.href, '_blank')
  731. } else if (systemType.value.indexOf("sys_surface_junya") != -1) {
  732. const newPage = router.resolve({ path: '/monitorChannel/balancePress-home', query: { id: systemID.value } })
  733. window.open(newPage.href, '_blank')
  734. } else if (systemType.value.indexOf("sys_nitrogen") != -1) {
  735. const newPage = router.resolve({ path: '/nitrogen-home', query: { id: systemID.value } })
  736. window.open(newPage.href, '_blank')
  737. } else if (deviceType.value.indexOf("forcFan") != -1) {
  738. const newPage = router.resolve({ path: '/forcFan/home', query: { id: activeID.value } })
  739. window.open(newPage.href, '_blank')
  740. } else {
  741. message.info('待开发。。。')
  742. }
  743. }
  744. }
  745. function exportXls() {
  746. handleExportXls('瓦斯巡检记录', getExportUrl, { devicetype: deviceType.value })
  747. }
  748. function toHome() {
  749. deviceList.value = []
  750. if (timer) clearTimeout(timer)
  751. timer = undefined
  752. deviceType.value = ''
  753. go(`/micro-vent-3dModal/dashboard/analysis`)
  754. // actions.setGlobalState({ pageObj: { pageType: 'home' } });
  755. }
  756. function toHide() {
  757. tableShow.value = !tableShow.value;
  758. if(!tableShow.value){
  759. document.getElementById('monitorBox').style.display = 'none';
  760. }
  761. }
  762. async function findTreeDataValue(obj) {
  763. ;
  764. const findDeviceType = (data: [], obj) => {
  765. let type = ''
  766. if (obj.deviceid) {
  767. type = obj.deviceid
  768. } else {
  769. type = obj.deviceType
  770. }
  771. data.find((item: any) => {
  772. if (item.children.length > 0) {
  773. findDeviceType(item.children, obj)
  774. }
  775. if (item.type == type) {
  776. if(obj.deviceid && deviceType.value != 'sys'){
  777. deviceType.value = 'sys'
  778. }else if(!obj.deviceid && deviceType.value !== item.type){
  779. deviceType.value = item.type
  780. }
  781. if (type.startsWith('sys_') && item.children[0]) {
  782. systemID.value = item.children[0]['type']
  783. selectedKeys.value = [item.children[0]['key']]
  784. expandedKeys.value = [item.children[0]['key']]
  785. treeNodeTitle.value = item.children[0]['title']
  786. if(deviceType.value !== type.substring(4)) deviceType.value = type.substring(4)
  787. } else {
  788. if (obj.deviceid) systemID.value = obj.deviceid
  789. selectedKeys.value = [item.key]
  790. expandedKeys.value = [item.key]
  791. treeNodeTitle.value = item.title
  792. }
  793. // const setKey = (item) => {
  794. // if(item.parentKey){
  795. // selectedKeys.value.push(item.parentKey)
  796. // expandedKeys.value.push(item.parentKey)
  797. // }
  798. // selectedKeys.value.push(item.key)
  799. // expandedKeys.value.push(item.key)
  800. // }
  801. // setKey(item)
  802. return true
  803. }
  804. return false
  805. })
  806. }
  807. findDeviceType(treeData.value, obj)
  808. // 无类型时
  809. if (!treeNodeTitle.value && treeData.value && treeData.value[0] && treeData.value[0]['children']) {
  810. const defaultData = treeData.value[0]['children'][0]
  811. if(deviceType.value !== defaultData.type)deviceType.value = defaultData.type
  812. selectedKeys.value = [(defaultData.key as string)]
  813. expandedKeys.value = [(defaultData.key as string)]
  814. treeNodeTitle.value = defaultData.title
  815. }
  816. if (timer === undefined) {
  817. timer = null
  818. await getDataSource()
  819. getMonitor(true)
  820. }
  821. }
  822. function monitorChange(index) {
  823. dataSource.value = []
  824. deviceActive.value = deviceList.value[index].deviceType
  825. if(deviceType.value != deviceActive.value) deviceType.value = deviceActive.value
  826. if (activeKey.value == '1' && monitorTable.value) {
  827. monitorTable.value.setLoading(true)
  828. dataSource.value = deviceList.value[index].datalist
  829. }
  830. if (activeKey.value == '2' && historyTable.value) {
  831. historyTable.value.setLoading(true)
  832. }
  833. if (activeKey.value == '3' && alarmHistoryTable.value) {
  834. alarmHistoryTable.value.setLoading(true)
  835. }
  836. if (activeKey.value == '4' && handlerHistoryTable.value) {
  837. handlerHistoryTable.value.setLoading(true)
  838. }
  839. }
  840. /**
  841. * 设置巷道设备定位图标的显示与隐藏
  842. */
  843. function setLocation() {
  844. let locationStr = ''
  845. locationList.value.forEach((item: any) => {
  846. if (item.Visible) {
  847. locationStr = locationStr ? locationStr + ',' + item.value : item.value
  848. }
  849. })
  850. actions.setGlobalState({ locationId: null, locationObj: null, pageObj: null, locationPlane: locationStr });
  851. setTimeout(() => {
  852. message.success('设置成功')
  853. }, 600)
  854. }
  855. watch(() => props.pageData, async (pageObj) => {
  856. isRefresh.value = false
  857. if (!treeData.value || treeData.value?.length < 1) {
  858. await getDeviceType()
  859. }
  860. nextTick(() => {
  861. isRefresh.value = true
  862. if (pageObj.deviceid) {
  863. findTreeDataValue({ deviceid: pageObj.deviceid })
  864. } else if (pageObj.pageType) {
  865. findTreeDataValue({ deviceType: pageObj.pageType })
  866. }
  867. })
  868. })
  869. onMounted(async () => {
  870. const pageObj = props.pageData
  871. if (!pageObj) return
  872. if (pageObj.deviceid) {
  873. await getDeviceType()
  874. findTreeDataValue({ deviceid: pageObj.deviceid })
  875. } else {
  876. if (pageObj.pageType.startsWith('sys_')) {
  877. await getDeviceType(pageObj.pageType)
  878. findTreeDataValue({ deviceid: systemID.value })
  879. } else {
  880. await getDeviceType()
  881. findTreeDataValue({ deviceType: pageObj.pageType })
  882. }
  883. }
  884. // 定位
  885. const posShowData = pageObj.locationPlane
  886. if (posShowData) {
  887. locationList.value = posShowData
  888. } else {
  889. locationList.value = await devPosition({})
  890. }
  891. // safetyOption.value = await safetyDeviceList(null, { devicetype: 'safetymonitor', code: 'dataTypeName' })
  892. })
  893. onUnmounted(() => {
  894. if (timer) {
  895. clearTimeout(timer);
  896. }
  897. timer = undefined;
  898. })
  899. </script>
  900. <style lang="less" scoped>
  901. @import '/@/design/vent/modal.less';
  902. @ventSpace: zxm;
  903. .top-header {
  904. position: fixed;
  905. width: 100%;
  906. height: 56px;
  907. background: url('/@/assets/images/vent/home/modal-top.png');
  908. text-align: center;
  909. line-height: 56px;
  910. font-size: 28px;
  911. color: #ffffffdd;
  912. font-weight: 600;
  913. z-index: 1;
  914. letter-spacing: 2px;
  915. font-size: 30px;
  916. }
  917. .select-node {
  918. position: fixed;
  919. top: 100px;
  920. left: 10px;
  921. color: #fff;
  922. display: flex;
  923. justify-content: center;
  924. font-size: 22px;
  925. .title {
  926. margin-left: 10px;
  927. }
  928. }
  929. .expansion-icon {
  930. background: url('/@/assets/images/vent/home/tree-icon-bg.png') no-repeat;
  931. background-size: contain;
  932. position: absolute;
  933. left: 190px;
  934. top: 25px;
  935. &:hover {
  936. background: url('/@/assets/images/vent/home/tree-icon-hover-bg.png') no-repeat;
  937. background-size: contain;
  938. }
  939. }
  940. .device-select {
  941. width: 250px;
  942. height: 500px;
  943. background: url('/@/assets/images/vent/home/tree-bg.png') no-repeat;
  944. position: fixed;
  945. top: 100px;
  946. left: 10px;
  947. background-size: contain;
  948. pointer-events: auto;
  949. padding: 20px 10px 30px 10px;
  950. }
  951. .is-expansion-icon {
  952. padding: 5px;
  953. pointer-events: auto;
  954. z-index: 999;
  955. }
  956. .device-select-show {
  957. left: 10px;
  958. animation-name: treeShow;
  959. /* 持续时间 */
  960. animation-duration: 1s;
  961. transition: all 1s cubic-bezier(0.165, 0.84, 0.44, 1) .5s;
  962. }
  963. .device-select-hide {
  964. left: -250px;
  965. animation-name: treeHide;
  966. /* 持续时间 */
  967. animation-duration: 1s;
  968. transition: all 1s cubic-bezier(0.165, 0.84, 0.44, 1) .5s;
  969. }
  970. .node-select-show {
  971. width: 276px;
  972. height: 44px;
  973. background: url('/@/assets/images/vent/home/tree-expansion-bg.png') no-repeat;
  974. left: 10px;
  975. animation-name: treeShow;
  976. /* 持续时间 */
  977. animation-duration: 1s;
  978. transition: all 1s cubic-bezier(0.165, 0.84, 0.44, 1) .5s;
  979. display: flex;
  980. align-items: center;
  981. margin-left: 0;
  982. justify-content: flex-start;
  983. pointer-events: auto;
  984. &:hover {
  985. background: url('/@/assets/images/vent/home/tree-expansion-hover-bg.png') no-repeat;
  986. }
  987. .put-away-icon {
  988. position: relative;
  989. display: inline-block;
  990. left: 4px;
  991. }
  992. }
  993. .node-select-hide {
  994. left: -400px;
  995. animation-name: treeHide;
  996. /* 持续时间 */
  997. animation-duration: 1s;
  998. transition: all 1s cubic-bezier(0.165, 0.84, 0.44, 1) .5s;
  999. }
  1000. .device-select-box {
  1001. width: 208px;
  1002. height: 450px;
  1003. overflow-y: auto;
  1004. color: #fff;
  1005. :deep(.zxm-tree) {
  1006. background: transparent !important;
  1007. color: #fff !important;
  1008. .zxm-tree-switcher {
  1009. background: transparent !important;
  1010. }
  1011. .zxm-tree-node-content-wrapper.zxm-tree-node-selected {
  1012. background-color: #00b1c8;
  1013. }
  1014. .zxm-tree-node-content-wrapper:hover {
  1015. background-color: #00b1c855;
  1016. }
  1017. input {
  1018. height: 0px !important;
  1019. }
  1020. }
  1021. &::-webkit-scrollbar-track {
  1022. -webkit-box-shadow: inset 0 0 5px rgba(0, 0, 0, 0.2);
  1023. border-radius: 10px;
  1024. background: #ededed22;
  1025. height: 100px;
  1026. }
  1027. &::-webkit-scrollbar-thumb {
  1028. -webkit-box-shadow: inset 0 0 5px rgba(0, 0, 0, 0.2);
  1029. background: #4288A444;
  1030. }
  1031. }
  1032. .location-icon {
  1033. width: 46px;
  1034. height: 178px;
  1035. position: absolute;
  1036. top: 100px;
  1037. // right: 0;
  1038. background: url('/@/assets/images/vent/home/location-bg.png') no-repeat;
  1039. background-size: contain;
  1040. writing-mode: vertical-lr;
  1041. line-height: 46px;
  1042. color: #fff;
  1043. padding-top: 10px;
  1044. pointer-events: auto;
  1045. cursor: pointer;
  1046. &:hover {
  1047. background: url('/@/assets/images/vent/home/location-hover-bg.png') no-repeat;
  1048. }
  1049. .location-text {
  1050. padding-top: 20px;
  1051. letter-spacing: 3px;
  1052. font-size: 16px;
  1053. }
  1054. }
  1055. .location-select {
  1056. position: fixed;
  1057. top: 100px;
  1058. // right: 240px;
  1059. pointer-events: auto;
  1060. .location-select-box {
  1061. width: 100%;
  1062. height: 100%;
  1063. position: relative;
  1064. &::before {
  1065. content: "";
  1066. position: absolute;
  1067. width: 230px;
  1068. height: 500px;
  1069. top: 0;
  1070. left: 0;
  1071. background: url('/@/assets/images/vent/home/tree-bg.png') no-repeat;
  1072. background-size: contain;
  1073. transform: rotateY(180deg);
  1074. z-index: -1;
  1075. // &:hover {
  1076. // background: url('/@/assets/images/vent/home/tree-icon-hover-bg.png') no-repeat;
  1077. // background-size: contain;
  1078. // }
  1079. }
  1080. .location-top-title {
  1081. color: #fff;
  1082. position: absolute;
  1083. width: 225px;
  1084. height: 68px;
  1085. background: url('/@/assets/images/vent/home/turn-location-top-bg.png') no-repeat;
  1086. background-size: contain;
  1087. top: 5px;
  1088. left: 5px;
  1089. display: flex;
  1090. flex-direction: row;
  1091. justify-content: space-between;
  1092. align-items: flex-end;
  1093. .title {
  1094. font-size: 18px;
  1095. position: relative;
  1096. top: -14px;
  1097. right: 15px;
  1098. }
  1099. }
  1100. .location-expansion-icon {
  1101. background: url('/@/assets/images/vent/home/tree-icon-cover-bg.png') no-repeat;
  1102. background-size: contain;
  1103. position: relative;
  1104. left: 10px;
  1105. top: -15px;
  1106. padding: 5px;
  1107. &:hover {
  1108. background: url('/@/assets/images/vent/home/tree-icon-cover-hover-bg.png') no-repeat;
  1109. background-size: contain;
  1110. }
  1111. }
  1112. }
  1113. .location-container {
  1114. width: 200px;
  1115. height: 390px;
  1116. position: absolute;
  1117. display: flex;
  1118. flex-direction: column;
  1119. top: 80px;
  1120. left: 18px;
  1121. overflow-y: auto;
  1122. .location-item {
  1123. color: #fff;
  1124. line-height: 30px;
  1125. display: flex;
  1126. justify-content: space-between;
  1127. background-image: linear-gradient(to left, #39f5ff05, #39f5ff10);
  1128. margin: 3px 0;
  1129. .item-title {
  1130. width: 80px;
  1131. text-align: right;
  1132. color: #87f1ff;
  1133. }
  1134. }
  1135. .location-bottom-btn {
  1136. width: 100%;
  1137. color: #fff;
  1138. display: flex;
  1139. justify-content: flex-end;
  1140. margin-top: 20px;
  1141. span {
  1142. display: inline-block;
  1143. width: 100%;
  1144. background: #00709955;
  1145. border-radius: 3px;
  1146. border: 1px solid rgba(174, 243, 255, 0.3);
  1147. text-align: center;
  1148. padding: 2px 0;
  1149. cursor: pointer;
  1150. &:hover {
  1151. background: #00557422;
  1152. }
  1153. }
  1154. }
  1155. }
  1156. }
  1157. .location-select-show {
  1158. right: 240px;
  1159. animation-name: locationShow;
  1160. /* 持续时间 */
  1161. animation-duration: 1s;
  1162. transition: all 1s cubic-bezier(0.165, 0.84, 0.44, 1) .5s;
  1163. }
  1164. .location-select-hide {
  1165. right: -2px;
  1166. animation-name: locationHide;
  1167. /* 持续时间 */
  1168. animation-duration: 1s;
  1169. transition: all 1s cubic-bezier(0.165, 0.84, 0.44, 1) .5s;
  1170. }
  1171. .location-btn-show {
  1172. right: -0px;
  1173. animation-name: locationBtnShow;
  1174. /* 持续时间 */
  1175. animation-duration: 1s;
  1176. transition: all 1s cubic-bezier(0.165, 0.84, 0.44, 1) .5s;
  1177. }
  1178. .location-btn-hide {
  1179. right: -240px;
  1180. animation-name: locationBtnHide;
  1181. /* 持续时间 */
  1182. animation-duration: 1s;
  1183. transition: all 1s cubic-bezier(0.165, 0.84, 0.44, 1) .5s;
  1184. }
  1185. .tabs-box{
  1186. // height: 290px;
  1187. }
  1188. .bottom-tabs-box {
  1189. position: relative;
  1190. .tabs-box {
  1191. width: calc(100% - 12px) !important;
  1192. bottom: 3px !important;
  1193. }
  1194. .to-small {
  1195. width: 60px;
  1196. height: 60px;
  1197. background: url('/@/assets/images/vent/home/tohome.png') no-repeat center;
  1198. background-size: auto;
  1199. position: absolute;
  1200. top: -65px;
  1201. right: 36px;
  1202. border-radius: 10px;
  1203. padding: 8px;
  1204. backdrop-filter: blur(10px);
  1205. background-color: rgba(45, 86, 137, 0.418);
  1206. &:hover {
  1207. background-color: rgba(79, 104, 134, 0.418);
  1208. }
  1209. }
  1210. .device-button-group {
  1211. position: absolute;
  1212. top: -30px;
  1213. display: flex;
  1214. width: 100%;
  1215. .device-button {
  1216. height: 26px;
  1217. padding: 0 20px;
  1218. background: linear-gradient(45deg, #04e6fb55, #0c5cab55);
  1219. clip-path: polygon(10px 0,
  1220. 0 50%,
  1221. 10px 100%,
  1222. 100% 100%,
  1223. calc(100% - 10px) 50%,
  1224. 100% 0);
  1225. display: flex;
  1226. justify-content: center;
  1227. align-items: center;
  1228. color: #FFF;
  1229. position: relative;
  1230. cursor: pointer;
  1231. &:nth-child(1) {
  1232. left: calc(-6px * 1);
  1233. }
  1234. &:nth-child(2) {
  1235. left: calc(-6px * 2);
  1236. }
  1237. &:nth-child(3) {
  1238. left: calc(-6px * 3);
  1239. }
  1240. &:nth-child(4) {
  1241. left: calc(-6px * 4);
  1242. }
  1243. &:nth-child(5) {
  1244. left: calc(-6px * 5);
  1245. }
  1246. &:nth-child(6) {
  1247. left: calc(-6px * 6);
  1248. }
  1249. &:nth-child(7) {
  1250. left: calc(-6px * 7);
  1251. }
  1252. &:nth-child(8) {
  1253. left: calc(-6px * 8);
  1254. }
  1255. &:nth-child(9) {
  1256. left: calc(-6px * 9);
  1257. }
  1258. &:nth-child(10) {
  1259. left: calc(-6px * 10);
  1260. }
  1261. &:nth-child(11) {
  1262. left: calc(-6px * 11);
  1263. }
  1264. &:nth-child(12) {
  1265. left: calc(-6px * 12);
  1266. }
  1267. &:nth-child(13) {
  1268. left: calc(-6px * 13);
  1269. }
  1270. &:nth-child(14) {
  1271. left: calc(-6px * 14);
  1272. }
  1273. &:nth-child(15) {
  1274. left: calc(-6px * 15);
  1275. }
  1276. &:nth-child(16) {
  1277. left: calc(-6px * 16);
  1278. }
  1279. &:nth-child(17) {
  1280. left: calc(-6px * 17);
  1281. }
  1282. &:nth-child(18) {
  1283. left: calc(-6px * 18);
  1284. }
  1285. &:nth-child(19) {
  1286. left: calc(-6px * 19);
  1287. }
  1288. &:first-child {
  1289. clip-path: polygon(0 0,
  1290. 10px 50%,
  1291. 0 100%,
  1292. 100% 100%,
  1293. calc(100% - 10px) 50%,
  1294. 100% 0);
  1295. }
  1296. }
  1297. .device-active {
  1298. background: linear-gradient(45deg, #04e6fb, #0c5cab);
  1299. &::before {
  1300. border-color: #0efcff;
  1301. box-shadow: 1px 1px 3px 1px #0efcff inset;
  1302. }
  1303. }
  1304. }
  1305. .table-hide-icon{
  1306. color: #fff;
  1307. cursor: pointer;
  1308. position: absolute;
  1309. right: 20px;
  1310. top: 10px;
  1311. z-index: 9999
  1312. }
  1313. .enter-detail {
  1314. color: #fff;
  1315. cursor: pointer;
  1316. position: absolute;
  1317. right: 20px;
  1318. top: 35px;
  1319. padding: 5px;
  1320. border-radius: 5px;
  1321. margin-left: 8px;
  1322. margin-right: 8px;
  1323. width: auto;
  1324. height: 33px !important;
  1325. display: flex;
  1326. align-items: center;
  1327. justify-content: center;
  1328. color: #fff;
  1329. padding: 5px 15px 5px 15px;
  1330. z-index: 999;
  1331. cursor: pointer;
  1332. &:hover {
  1333. background: linear-gradient(#2cd1ff55, #1eb0ff55);
  1334. }
  1335. &::before {
  1336. width: calc(100% - 6px);
  1337. height: 27px;
  1338. content: '';
  1339. position: absolute;
  1340. top: 3px;
  1341. right: 0;
  1342. left: 3px;
  1343. bottom: 0;
  1344. z-index: -1;
  1345. border-radius: inherit;
  1346. /*important*/
  1347. background: linear-gradient(#1fa6cb, #127cb5);
  1348. }
  1349. }
  1350. }
  1351. .table-hide{
  1352. animation-name: tableHide;
  1353. /* 持续时间 */
  1354. animation-duration: 1s;
  1355. transition: all 1s cubic-bezier(0.165, 0.84, 0.44, 1) .5s;
  1356. }
  1357. .table-show{
  1358. animation-name: tableShow;
  1359. /* 持续时间 */
  1360. animation-duration: 1s;
  1361. transition: all 1s cubic-bezier(0.165, 0.84, 0.44, 1) .5s;
  1362. }
  1363. .location-form{
  1364. display: flex;
  1365. margin: 8px;
  1366. .location-form-item{
  1367. width: 400px;
  1368. .location-form-label{
  1369. width: 100px;
  1370. display: inline-block;
  1371. color: #fff;
  1372. }
  1373. input{
  1374. background: transparent !important;
  1375. color: #fff;
  1376. border: 1px solid #3ad8ff77 !important
  1377. }
  1378. }
  1379. .zxm-select-selector{
  1380. width: 200px !important;
  1381. }
  1382. }
  1383. @keyframes tableShow {
  1384. 0% {
  1385. height: 0px;
  1386. opacity: 0;
  1387. }
  1388. 100% {
  1389. height: 290px;
  1390. opacity: 1;
  1391. }
  1392. }
  1393. @keyframes tableHide {
  1394. 0% {
  1395. opacity: 1;
  1396. }
  1397. 100% {
  1398. height: 0px ;
  1399. opacity: 0 ;
  1400. }
  1401. }
  1402. @keyframes treeShow {
  1403. 0% {
  1404. left: -400px;
  1405. opacity: 0;
  1406. }
  1407. 100% {
  1408. left: 10px;
  1409. opacity: 1;
  1410. }
  1411. }
  1412. @keyframes treeHide {
  1413. 0% {
  1414. left: 10px;
  1415. opacity: 1;
  1416. }
  1417. 100% {
  1418. left: -400px;
  1419. opacity: 0;
  1420. }
  1421. }
  1422. @keyframes locationShow {
  1423. 0% {
  1424. right: 0px;
  1425. opacity: 0;
  1426. }
  1427. 100% {
  1428. right: 240px;
  1429. opacity: 1;
  1430. }
  1431. }
  1432. @keyframes locationHide {
  1433. 0% {
  1434. right: 240px;
  1435. opacity: 1;
  1436. }
  1437. 100% {
  1438. right: 0;
  1439. opacity: 0;
  1440. }
  1441. }
  1442. @keyframes locationBtnShow {
  1443. 0% {
  1444. right: -240px;
  1445. opacity: 0;
  1446. }
  1447. 100% {
  1448. right: -2px;
  1449. opacity: 1;
  1450. }
  1451. }
  1452. @keyframes locationBtnHide {
  1453. 0% {
  1454. right: -2px;
  1455. opacity: 1;
  1456. }
  1457. 100% {
  1458. right: -240px;
  1459. opacity: 0;
  1460. }
  1461. }
  1462. :deep(.@{ventSpace}-tabs-tabpane-active) {
  1463. // overflow: auto;
  1464. height: 100%;
  1465. }
  1466. :deep(.zxm-select-dropdown) {
  1467. left: 0 !important;
  1468. color: #000000 !important;
  1469. }
  1470. :deep(.zxm-select-selector) {
  1471. height: 34px !important;
  1472. line-height: 34px !important;
  1473. }
  1474. :deep(.zxm-input) {
  1475. height: 32px !important;
  1476. line-height: 32px !important;
  1477. .zxm-select-selection-item {
  1478. line-height: 32px !important;
  1479. }
  1480. }
  1481. // :deep(.@{ventSpace}-pagination){
  1482. // margin-right: 20px !important;
  1483. // margin-top: 5px !important;
  1484. // display: flex;
  1485. // align-items: center;
  1486. // }</style>