index.vue 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604
  1. <template>
  2. <div class="inspection">
  3. <layout>
  4. <template #left>
  5. <div class="left_spection">
  6. <HeadlineTag value="出入口列表"></HeadlineTag>
  7. <div class="box_arch_point">
  8. <div class="point_box" style="margin-top: 10px;margin-left: 15px;">
  9. <el-input v-model="input" placeholder="按出入口名称搜索" />
  10. </div>
  11. <access :resultData="leftData.DeviceList"></access>
  12. <!-- <div style="height: calc(100% - 160px);">
  13. <Empty></Empty>
  14. </div>
  15. <div class="center_in">
  16. <pagination :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize"
  17. layout="total, prev, pager, next" @pagination="getList" />
  18. </div> -->
  19. </div>
  20. </div>
  21. </template>
  22. <template #right>
  23. <div class="right_spection">
  24. <div class="operation_spection">
  25. <HeadlineTag type="right" value="监控设备"></HeadlineTag>
  26. <div class="box_arch" style="margin-right: 15px;margin-top: 10px;height: calc(100% - 55px);">
  27. <dv-border-box-1>
  28. <div class="box_monitoring">
  29. <div class="flex_spection box_tion_zx">
  30. <div class="line_blue">
  31. <div class="blue_dot"></div>
  32. </div>
  33. <div class="monit_title">空闲车位</div>
  34. <span class="monit_num">{{ leftData.Online }}</span>
  35. </div>
  36. <div class="camera">
  37. <div class="entry-box">
  38. <div class="entry-box-item">
  39. <div class="item-center-line"></div>
  40. <div class="item-center-pie"></div>
  41. </div>
  42. </div>
  43. <div class="img_camera">
  44. <svg class="camera_box_icon" aria-hidden="true">
  45. <defs>
  46. <linearGradient id="myGradientil" x1="0%" y1="100%" x2="0%" y2="0%">
  47. <stop offset="0%" stop-color="rgb(46, 139, 221)" />
  48. <stop offset="100%" stop-color="rgb(4, 223, 247)" />
  49. </linearGradient>
  50. </defs>
  51. <use xlink:href="#icon-parkingSpot" fill="url('#myGradientil')" />
  52. </svg>
  53. </div>
  54. </div>
  55. <div class="flex_spection box_tion_lx">
  56. <div class="line_green">
  57. <div class="green_dot"></div>
  58. </div>
  59. <div class="monit_title">已占车位</div>
  60. <span class="monit_num1">{{ leftData.Offline }}</span>
  61. </div>
  62. </div>
  63. </dv-border-box-1>
  64. </div>
  65. </div>
  66. <!-- <div class="flex_spection">
  67. <HeadlineTag type="right" value="实时巡检"></HeadlineTag>
  68. <div class="box_arch">
  69. <dv-scroll-board :config="config" style="width:97%;height:calc(100% - 10px);margin-top: 10px;" />
  70. </div>
  71. </div> -->
  72. <div class="flex_spection">
  73. <HeadlineTag type="right" value="设备出入统计排名(Top5)"></HeadlineTag>
  74. <div class="box_arch">
  75. <div ref="chartRouting" style="width: 100%;height: 100%;"></div>
  76. </div>
  77. </div>
  78. <div class="flex_spection">
  79. <HeadlineTag type="right" value="出入人员统计"></HeadlineTag>
  80. <div class="box_arch">
  81. <Personnel :resultData="leftData"></Personnel>
  82. </div>
  83. </div>
  84. </div>
  85. </template>
  86. </layout>
  87. </div>
  88. </template>
  89. <script setup>
  90. import { getAccess } from "@/api/system/passageway"
  91. import layout from "@/components/layout_/index.vue";
  92. import HeadlineTag from '@/components/HeadlineTag'
  93. import Personnel from './Personnel.vue'
  94. import access from './access.vue'
  95. import Empty from '@/components/Empty'
  96. import * as echarts from 'echarts'
  97. const total = ref(0);
  98. const queryParams = ref({
  99. pageNum: 1,
  100. pageSize: 10,
  101. });
  102. const input = ref('')
  103. const config = ref({
  104. headerBGC: '#10285c',
  105. oddRowBGC: '#10285c7f',
  106. evenRowBGC: '#10285c00',
  107. header: ['名称', '位置', '列3'],
  108. data: [
  109. ['行1列1', '行1列2', '行1列3'],
  110. ['行2列1', '行2列2', '行2列3'],
  111. ['行3列1', '行3列2', '行3列3'],
  112. ['行4列1', '行4列2', '行4列3'],
  113. ['行5列1', '行5列2', '行5列3'],
  114. ['行6列1', '行6列2', '行6列3'],
  115. ['行7列1', '行7列2', '行7列3'],
  116. ['行8列1', '行8列2', '行8列3'],
  117. ['行9列1', '行9列2', '行9列3'],
  118. ['行10列1', '行10列2', '行10列3']
  119. ]
  120. })
  121. /** 查询列表 */
  122. function getList() {
  123. };
  124. const chartRouting = ref(null);
  125. let chartInstance = null;
  126. // 初始化图表
  127. const initChart = () => {
  128. // var data = [91, 82, 73, 61, 54, 46];
  129. var data = [];
  130. // var yAxis = ['北京市', '天津市', '河北省', '吉林省', '辽宁省', '内蒙古']
  131. var yAxis = []
  132. chartInstance = echarts.init(chartRouting.value);
  133. chartInstance.setOption({
  134. tooltip: {
  135. textStyle: {
  136. fontSize: 16
  137. },
  138. formatter: function (res) {
  139. return `${res.name} : ${res.data}万人`;
  140. },
  141. textStyle: {
  142. color: '#fafafa',
  143. },
  144. borderColor: 'transparent',
  145. backgroundColor: 'rgba(0, 0, 0, 0.5)',
  146. extraCssText: 'backdrop-filter: blur(6px);',
  147. },
  148. legend: {
  149. selectedMode: false,
  150. show: false
  151. },
  152. grid: {
  153. left: '2%',
  154. right: '5%',
  155. bottom: '0%',
  156. top: 5,
  157. containLabel: true
  158. },
  159. xAxis: [{
  160. type: 'value',
  161. show: false
  162. }],
  163. yAxis: [{
  164. splitLine: {
  165. show: false
  166. },
  167. axisLine: { // y轴
  168. show: false
  169. },
  170. type: 'category',
  171. inverse: true, /// 柱状图顺序
  172. axisTick: {
  173. show: false
  174. },
  175. data: yAxis,
  176. axisLabel: {
  177. show: true,
  178. textStyle: {
  179. color: '#ffffff'
  180. },
  181. formatter: (res, index) => {
  182. var num = 0;
  183. num = index + 1;
  184. if (index === 0) {
  185. return '{no1|' + 'TOP' + num + '}' + '{data|' + res + '}';
  186. } else if (index === 1) {
  187. return '{no2|' + 'TOP' + num + '}' + '{data|' + res + '}';
  188. } else if (index === 2) {
  189. return '{no3|' + 'TOP' + num + '}' + '{data|' + res + '}';
  190. } else if (index === 3) {
  191. return '{no4|' + 'TOP' + num + '}' + '{data|' + res + '}';
  192. } else if (index === 4) {
  193. return '{no5|' + 'TOP' + num + '}' + '{data|' + res + '}';
  194. } else if (index === 5) {
  195. return '{no6|' + 'TOP' + num + '}' + '{data|' + res + '}';
  196. }
  197. return res;
  198. },
  199. rich: {
  200. no1: {
  201. color: '#EF5525',
  202. fontSize: 14
  203. },
  204. data: {
  205. color: '#fff',
  206. fontSize: 14
  207. },
  208. no2: {
  209. color: '#EFAF25',
  210. fontSize: 14
  211. },
  212. no3: {
  213. color: '#D0EF25',
  214. fontSize: 14
  215. },
  216. no4: {
  217. color: '#26EFC2',
  218. fontSize: 14
  219. },
  220. no5: {
  221. color: '#2BE4FF',
  222. fontSize: 14
  223. },
  224. no6: {
  225. color: '#2BE4FF',
  226. fontSize: 14
  227. }
  228. }
  229. }
  230. }],
  231. series: [{
  232. name: '标准化',
  233. type: 'bar',
  234. barWidth: 14, // 柱子宽度
  235. label: {
  236. show: true,
  237. position: 'right', // 位置
  238. color: '#fff',
  239. fontSize: 14,
  240. distance: 20 // 距离
  241. }, // 柱子上方的数值
  242. itemStyle: {
  243. barBorderRadius: [20, 20, 20, 20],
  244. color: new echarts.graphic.LinearGradient(0, 0, 1, 0, [
  245. '#4C67EB', '#00F6FF'
  246. ].map((color, offset) => ({
  247. color,
  248. offset
  249. }))) // 渐变
  250. },
  251. data: data
  252. }]
  253. }
  254. );
  255. };
  256. // 生命周期
  257. onMounted(() => {
  258. intervalId.value = setInterval(getAccessData, 10000);
  259. getAccessData()
  260. initChart()
  261. });
  262. onUnmounted(() => {
  263. clearInterval(intervalId.value);
  264. })
  265. const intervalId = ref(null)
  266. const leftData = ref({})
  267. function getAccessData() {
  268. getAccess().then((res) => {
  269. if (res.code == 200) {
  270. leftData.value = res.data
  271. }
  272. })
  273. }
  274. watch(() => leftData.value, (newVal) => {
  275. if (chartInstance) {
  276. let result = newVal.DeviceRanking.map(person => person.DeviceName)
  277. var firstFive = result.slice(0, 5)
  278. let result1 = newVal.DeviceRanking.map(person => person.Value)
  279. var firstFive1 = result1.slice(0, 5)
  280. chartInstance.setOption({
  281. yAxis: [{
  282. data: firstFive,
  283. }],
  284. series: [{
  285. name: '标准化',
  286. data: firstFive1,
  287. }],
  288. })
  289. }
  290. }, { deep: true, immediate: true } // 开启深度监听
  291. )
  292. // 窗口自适应
  293. window.addEventListener('resize', () => {
  294. chartInstance?.resize();
  295. });
  296. </script>
  297. <style scoped lang="scss">
  298. .inspection {
  299. position: relative;
  300. width: 100%;
  301. height: 100%;
  302. overflow: hidden;
  303. }
  304. .left_spection {
  305. position: absolute;
  306. left: 0;
  307. width: 100%;
  308. height: 100%;
  309. display: flex;
  310. flex-direction: column;
  311. }
  312. .right_spection {
  313. position: absolute;
  314. right: 0;
  315. width: 100%;
  316. height: 100%;
  317. display: flex;
  318. flex-direction: column;
  319. }
  320. .box_arch_point {
  321. height: calc(100% - 40px);
  322. }
  323. .operation_spection {
  324. height: 30%;
  325. color: #fff;
  326. }
  327. .flex_spection {
  328. flex: 1;
  329. color: #fff;
  330. }
  331. .box_arch {
  332. display: flex;
  333. align-items: center;
  334. height: calc(100% - 40px);
  335. }
  336. .image_tubbiness {
  337. position: relative;
  338. flex: none;
  339. width: 200px;
  340. height: 100%;
  341. background: url("@/assets/images/tubbiness.png");
  342. background-size: 80% 80%;
  343. background-position: center center;
  344. background-repeat: no-repeat;
  345. .work_num {
  346. position: absolute;
  347. top: 60px;
  348. left: 0;
  349. right: 0;
  350. text-align: center;
  351. color: rgb(84, 218, 250);
  352. font-size: 20px;
  353. span {
  354. font-size: 14px;
  355. color: rgb(158, 174, 195);
  356. }
  357. }
  358. .work_title {
  359. position: absolute;
  360. bottom: 36px;
  361. left: 0px;
  362. right: 0px;
  363. text-align: center;
  364. }
  365. }
  366. .right_content {
  367. flex: 1;
  368. height: 100%;
  369. display: flex;
  370. flex-direction: column;
  371. justify-content: space-evenly;
  372. .work_week {
  373. display: flex;
  374. align-items: center;
  375. font-size: 22px;
  376. font-weight: bold;
  377. color: #fff;
  378. span {
  379. padding-right: 10px;
  380. font-size: 16px;
  381. color: rgb(214, 218, 222);
  382. }
  383. }
  384. }
  385. .color_line_xj {
  386. width: 6px;
  387. height: 6px;
  388. margin-right: 10px;
  389. }
  390. .box_tion_zx {
  391. padding-left: 20px;
  392. display: flex;
  393. flex-direction: column;
  394. align-items: center;
  395. }
  396. .box_tion_lx {
  397. padding-right: 20px;
  398. display: flex;
  399. flex-direction: column;
  400. align-items: center;
  401. }
  402. .box_monitoring {
  403. display: flex;
  404. align-items: center;
  405. height: 100%;
  406. }
  407. .line_blue {
  408. position: relative;
  409. height: 5px;
  410. width: 70%;
  411. background-color: rgba(12, 208, 67, .5);
  412. margin-bottom: 10px;
  413. }
  414. .blue_dot {
  415. position: absolute;
  416. left: 5px;
  417. top: 0;
  418. bottom: 0;
  419. width: 20px;
  420. border-left: 5px solid rgb(5, 26, 52);
  421. border-right: 5px solid rgb(5, 26, 52);
  422. background-color: rgba(12, 208, 67, 1);
  423. }
  424. .line_green {
  425. position: relative;
  426. height: 5px;
  427. width: 70%;
  428. background-color: rgba(254, 33, 44, .5);
  429. margin-bottom: 10px;
  430. }
  431. .green_dot {
  432. position: absolute;
  433. left: 5px;
  434. top: 0;
  435. bottom: 0;
  436. width: 20px;
  437. border-left: 5px solid rgb(5, 26, 52);
  438. border-right: 5px solid rgb(5, 26, 52);
  439. background-color: rgba(254, 33, 44, 1);
  440. }
  441. .img_camera {
  442. position: absolute;
  443. width: 120px;
  444. height: 120px;
  445. top: calc(50% - 60px);
  446. left: calc(50% - 60px);
  447. border-radius: 50%;
  448. border: 1px solid rgb(15, 39, 66);
  449. box-shadow: inset 0px 0px 20px 2px rgb(42, 147, 223);
  450. }
  451. .camera_box_icon {
  452. width: 70px;
  453. height: 70px;
  454. position: absolute;
  455. top: calc(50% - 35px);
  456. left: calc(50% - 35px);
  457. vertical-align: -2px;
  458. }
  459. .camera {
  460. width: 190px;
  461. height: 100%;
  462. display: flex;
  463. position: relative;
  464. .entry-box {
  465. width: 100%;
  466. height: 100%;
  467. object-fit: fill;
  468. position: absolute;
  469. top: 0;
  470. left: 0;
  471. display: flex;
  472. align-items: center;
  473. justify-content: center;
  474. }
  475. .entry-box-item {
  476. width: 100%;
  477. height: 180px;
  478. color: #fff;
  479. display: flex;
  480. justify-content: center;
  481. align-items: center;
  482. position: relative;
  483. background: radial-gradient(circle,
  484. rgba(51, 149, 233, 0) 100px,
  485. rgba(51, 149, 233, 0) 100px);
  486. .item-center-line {
  487. width: 180px;
  488. height: 180px;
  489. background-color: transparent;
  490. border-top: 3px solid rgb(22, 110, 191);
  491. border-bottom: 3px solid rgb(22, 110, 191);
  492. border-radius: 50%;
  493. box-sizing: border-box;
  494. position: absolute;
  495. top: calc(50% - 90px);
  496. left: calc(50% - 90px);
  497. animation: rotate 8s infinite linear;
  498. }
  499. .item-center-pie {
  500. width: 150px;
  501. height: 150px;
  502. background-color: transparent;
  503. border-top: 2px solid rgb(22, 110, 191);
  504. border-bottom: 2px solid rgb(22, 110, 191);
  505. border-radius: 50%;
  506. box-sizing: border-box;
  507. position: absolute;
  508. top: calc(50% - 75px);
  509. left: calc(50% - 75px);
  510. animation: rotate1 8s infinite linear;
  511. }
  512. }
  513. }
  514. /* 定义中间球体顺时针转动 */
  515. @keyframes rotate {
  516. from {
  517. transform: rotate(0deg);
  518. }
  519. to {
  520. transform: rotate(360deg);
  521. }
  522. }
  523. /* 定义中间圆逆时针转动 */
  524. @keyframes rotate1 {
  525. from {
  526. transform: rotate(0deg);
  527. }
  528. to {
  529. transform: rotate(-360deg);
  530. }
  531. }
  532. .monit_title {
  533. font-size: 16px;
  534. background-image: -webkit-linear-gradient(bottom, rgb(120, 173, 221), rgb(229, 232, 236));
  535. -webkit-background-clip: text;
  536. -webkit-text-fill-color: transparent;
  537. padding: 6px 0px;
  538. }
  539. .monit_num {
  540. font-size: 30px;
  541. color: rgba(12, 208, 67, 1);
  542. font-weight: bold;
  543. }
  544. .monit_num1 {
  545. font-size: 30px;
  546. color: rgba(254, 33, 44, 1);
  547. font-weight: bold;
  548. }
  549. </style>
  550. <style lang="scss" scoped>
  551. .point_box :deep(.el-input__wrapper) {
  552. background-color: transparent !important;
  553. box-shadow: 0 0 0 1px rgb(58, 86, 117) inset !important;
  554. }
  555. .point_box :deep(.el-input__wrapper.is-focus) {
  556. box-shadow: 0 0 0 1px #409EFF inset !important;
  557. }
  558. .point_box :deep(.el-input__inner) {
  559. color: #ffffff !important;
  560. }
  561. </style>