left.vue 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969
  1. <template>
  2. <el-aside class="left">
  3. <div class="left_top">
  4. <div class="title" :style="{ background: `url(${frame})` }">
  5. <div class="text">教室分类统计</div>
  6. </div>
  7. <div class="content">
  8. <div id="myChart"></div>
  9. <div class="list">
  10. <div class="item" v-for="(item, index) in classRoomCount" :key="index" :style="{
  11. borderRight:
  12. index == 0
  13. ? '2px solid #0BF'
  14. : index == 1
  15. ? '2px solid #00EB7D'
  16. : index == 2
  17. ? '2px solid #FB0'
  18. : '',
  19. }">
  20. <!-- <i :style="{ backgroundColor: item.color }"></i> -->
  21. <svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 14 14" fill="none"
  22. v-if="index === 0">
  23. <path
  24. d="M14 7C14 10.866 10.866 14 7 14C3.13401 14 0 10.866 0 7C0 3.13401 3.13401 0 7 0C10.866 0 14 3.13401 14 7ZM4.55 7C4.55 8.3531 5.6469 9.45 7 9.45C8.3531 9.45 9.45 8.3531 9.45 7C9.45 5.6469 8.3531 4.55 7 4.55C5.6469 4.55 4.55 5.6469 4.55 7Z"
  25. fill="#00BBFF" />
  26. </svg>
  27. <svg v-if="index === 1" xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 14 14"
  28. fill="none">
  29. <path
  30. d="M14 7C14 10.866 10.866 14 7 14C3.13401 14 0 10.866 0 7C0 3.13401 3.13401 0 7 0C10.866 0 14 3.13401 14 7ZM4.55 7C4.55 8.3531 5.6469 9.45 7 9.45C8.3531 9.45 9.45 8.3531 9.45 7C9.45 5.6469 8.3531 4.55 7 4.55C5.6469 4.55 4.55 5.6469 4.55 7Z"
  31. fill="#00EB7D" />
  32. </svg>
  33. <svg v-if="index === 2" xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 14 14"
  34. fill="none">
  35. <path
  36. d="M14 7C14 10.866 10.866 14 7 14C3.13401 14 0 10.866 0 7C0 3.13401 3.13401 0 7 0C10.866 0 14 3.13401 14 7ZM4.55 7C4.55 8.3531 5.6469 9.45 7 9.45C8.3531 9.45 9.45 8.3531 9.45 7C9.45 5.6469 8.3531 4.55 7 4.55C5.6469 4.55 4.55 5.6469 4.55 7Z"
  37. fill="#FFBB00" />
  38. </svg>
  39. <div class="descr">
  40. <span>{{ item.name }}</span>
  41. <span>{{ item.value }}</span>
  42. </div>
  43. </div>
  44. </div>
  45. </div>
  46. </div>
  47. <!-- <div class="left-center">
  48. <div class="title" :style="{ background: `url(${frame})` }">
  49. <div class="text">教室统计</div>
  50. </div>
  51. <div class="content">
  52. <div class="content-item">
  53. <div class="content-item-header">
  54. <div class="item-header-title">多媒体教室总数</div>
  55. <div class="item-header-total-num">
  56. <countTo :startVal="0" :endVal="summaryStatistic.mdeiaClassroomCount" :decimals="0" :duration="3000">
  57. </countTo>
  58. <span>间</span>
  59. </div>
  60. </div>
  61. <div class="content-item-body">
  62. <img class="body-left-icon" src="/public/img/duomeiti-left-icon.png" alt="" srcset="" />
  63. <div class="body-right-text">
  64. <div class="total-box">
  65. <div>总物联数量</div>
  66. <div class="num1">
  67. <countTo :startVal="0" :endVal="summaryStatistic.mediaClassroomDeviceCount" :decimals="0"
  68. :duration="3000">
  69. </countTo><span>个</span>
  70. </div>
  71. </div>
  72. <div class="online-box">
  73. <div>在线物联数量</div>
  74. <div class="num2">
  75. <countTo :startVal="0" :endVal="summaryStatistic.mediaClassroomOnlineDeviceCount" :decimals="0"
  76. :duration="3000">
  77. </countTo><span>个</span>
  78. </div>
  79. </div>
  80. </div>
  81. </div>
  82. </div>
  83. <div class="content-item">
  84. <div class="content-item-header">
  85. <div class="item-header-title">智慧教室总数</div>
  86. <div class="item-header-total-num">
  87. <countTo :startVal="0" :endVal="95" :decimals="0" :duration="3000">
  88. </countTo><span>间</span>
  89. </div>
  90. </div>
  91. <div class="content-item-body">
  92. <img class="body-left-icon" src="/public/img/zhihuijiaoshi-left-icon.png" alt="" srcset="" />
  93. <div class="body-right-text">
  94. <div class="total-box">
  95. <div>总物联数量</div>
  96. <div class="num1">
  97. <countTo :startVal="0" :endVal="summaryStatistic.wiseClassroomDeviceCount" :decimals="0"
  98. :duration="3000">
  99. </countTo><span>个</span>
  100. </div>
  101. </div>
  102. <div class="online-box">
  103. <div>在线物联数量</div>
  104. <div class="num2">
  105. <countTo :startVal="0" :endVal="summaryStatistic.wiseClassroomOnlineDeviceCount" :decimals="0"
  106. :duration="3000">
  107. </countTo><span>个</span>
  108. </div>
  109. </div>
  110. </div>
  111. </div>
  112. </div>
  113. </div>
  114. </div> -->
  115. <div class="left-bottom">
  116. <div class="title" :style="{ background: `url(${frame})` }">
  117. <div class="text">教室使用明细</div>
  118. </div>
  119. <div class="usering-free-container">
  120. <div class="usering-free">
  121. <div class="usering-box">
  122. <div class="text">
  123. 使用中:{{ getPercentage || 0 }}%
  124. <span class="num">{{ occupiedClassroomsCount || 0 }}间</span>
  125. </div>
  126. </div>
  127. <div class="free-box">
  128. <div class="text">
  129. 空闲中:{{ (100 - getPercentage).toFixed(2) || 0 }}%
  130. <span class="num">{{ classRoom.length - occupiedClassroomsCount || 0 }}间</span>
  131. </div>
  132. </div>
  133. </div>
  134. <el-progress :percentage="getPercentage" :show-text="false" color="#1BCEFF" />
  135. </div>
  136. <div class="search-container">
  137. <el-input v-model="searchData" clearable placeholder="请输入大楼名称、教室名称" />
  138. <el-button type="primary" :icon="Search" @click="searchHandel" />
  139. </div>
  140. <div class="content" style="height: 100%; overflow: hidden">
  141. <div class="table">
  142. <div class="dropdown-container">
  143. <el-dropdown trigger="click" @command="clickBuildingsropdown" max-height="150" popper-class="popper-class">
  144. <span class="dropdown-name">
  145. <div class="cureet-text" :title="cureetBuild">{{ cureetBuild }}</div>
  146. <el-icon class="el-icon--right">
  147. <arrow-down />
  148. </el-icon>
  149. <!-- <Edit style="width: 1em; height: 1em; margin-right: 8px" /> -->
  150. </span>
  151. <template #dropdown>
  152. <el-dropdown-menu>
  153. <el-dropdown-item :command="item.gis_building_code" v-for="(item, index) in buildings" :key="index">{{
  154. item.building_name }}</el-dropdown-item>
  155. </el-dropdown-menu>
  156. </template>
  157. </el-dropdown>
  158. <el-dropdown trigger="click" @command="clickCategoryTypedropdown" max-height="150">
  159. <span class="dropdown-name">
  160. {{ category || "全部类型" }}
  161. <el-icon>
  162. <arrow-down />
  163. </el-icon>
  164. </span>
  165. <template #dropdown>
  166. <el-dropdown-menu>
  167. <el-dropdown-item :command="item.category" v-for="(item, index) in categoryType" :key="index">{{
  168. item.category }}</el-dropdown-item>
  169. </el-dropdown-menu>
  170. </template>
  171. </el-dropdown>
  172. <el-dropdown trigger="click" @command="clickLeafsdropdown" max-height="150">
  173. <span class="dropdown-name">
  174. {{ cureetLeaf }}
  175. <el-icon>
  176. <arrow-down />
  177. </el-icon>
  178. </span>
  179. <template #dropdown>
  180. <el-dropdown-menu>
  181. <el-dropdown-item :command="item.leaf" v-for="(item, index) in leafs" :key="index">{{ item.leaf_name
  182. }}</el-dropdown-item>
  183. </el-dropdown-menu>
  184. </template>
  185. </el-dropdown>
  186. <el-dropdown trigger="click" @command="clickStatusesdropdown" max-height="150">
  187. <span class="dropdown-name">
  188. {{ cureetStatus }}
  189. <el-icon>
  190. <arrow-down />
  191. </el-icon>
  192. </span>
  193. <template #dropdown>
  194. <el-dropdown-menu>
  195. <el-dropdown-item :command="item.status_code" v-for="(item, index) in statuses" :key="index">{{
  196. item.status_name }}</el-dropdown-item>
  197. </el-dropdown-menu>
  198. </template>
  199. </el-dropdown>
  200. </div>
  201. <!-- <div
  202. ref="testMain"
  203. style="height: 442px; overflow: scroll; padding-top: 6px"
  204. class="scroll"
  205. > -->
  206. <!-- <div v-if="classRoomList.length > 0" style="width: 100%; height: 100%"> -->
  207. <div class="scroll-container" ref="scrollContainerRef">
  208. <div :style="{
  209. height: scrollContainerHeight + 'px',
  210. overflow: 'hidden',
  211. paddingTop: '10px',
  212. }" v-if="classRoomList.length > 0 && isShhow">
  213. <vue-auto-scroll :steep="0.5" scrollDirection="top" :isRoller="true" :rollerScrollDistance="50">
  214. <div class="li" v-for="(item, index) in classRoomList" :key="index">
  215. <div class="list-item">
  216. <div class="class-status-btn-container">
  217. <div class="left-class-status">
  218. <div style="margin-right: 16px">
  219. {{ item.classroom_name }}
  220. </div>
  221. <Tag :text="item.status_code"></Tag>
  222. </div>
  223. <div class="right-btn" @click.prevent="handleRoom(item)">
  224. 查看
  225. </div>
  226. </div>
  227. <div class="item-content">
  228. <div class="item-content-left">
  229. <div class="position" :title="item.location">位置:{{ item.location }}</div>
  230. <div class="course" v-if="item.course_name">
  231. 课程:{{ item.course_name }}
  232. </div>
  233. </div>
  234. <div class="item-content-right">
  235. <div>类型:{{ item.category }}</div>
  236. <div class="person-rate-container">
  237. <div v-if="item.actual != null">
  238. 实到/应到:{{ item.actual }}/{{ item.expected }}
  239. </div>
  240. <div style="margin-left: 8px" v-if="item.actual != null">
  241. 到课率:{{
  242. (item.actual / item.expected).toFixed(2) * 100 ||
  243. 0
  244. }}%
  245. </div>
  246. </div>
  247. </div>
  248. </div>
  249. </div>
  250. </div>
  251. </vue-auto-scroll>
  252. </div>
  253. <div v-else class="empty-container">
  254. <img :src="noData" alt="" srcset="">
  255. </div>
  256. </div>
  257. </div>
  258. <!-- </div> -->
  259. </div>
  260. </div>
  261. </el-aside>
  262. <div ref="popoverRef" v-if="roomVisible" style="
  263. background-color: rgba(245, 246, 248, 0.9);
  264. border-radius: 10px;
  265. position: absolute;
  266. top: 10vh;
  267. left: 50%;
  268. width: 366px;
  269. z-index: 999;
  270. transform: translateX(-50%);
  271. ">
  272. <div class="model-detail">
  273. <span><span class="title">教室状态: </span>
  274. <span :class="classInfo.online ? 'green' : 'red'">{{
  275. classInfo && classInfo.status
  276. }}</span>
  277. </span>
  278. <span><span class="title">班级: </span>
  279. <span style="width: 105px; display: inline-flex">{{
  280. classInfo && classInfo.className
  281. }}</span>
  282. </span>
  283. <span><span class="title">课程名称: </span>
  284. <span style="width: 94px; display: inline-flex">{{
  285. classInfo && classInfo.courseName
  286. }}</span>
  287. </span>
  288. <span><span class="title">应到人数: </span>{{ classInfo && classInfo.expected }}</span>
  289. <span><span class="title">教室: </span>
  290. <span style="width: 120px; display: inline-flex">
  291. {{ classInfo && classInfo.class }}
  292. </span>
  293. </span>
  294. <span><span class="title">实到人数: </span>{{ classInfo && classInfo.actual }}</span>
  295. <span><span class="title">老师: </span>{{ classInfo && classInfo.teacher }}</span>
  296. </div>
  297. </div>
  298. </template>
  299. <script>
  300. import * as echarts from "echarts";
  301. import {
  302. reactive,
  303. onMounted,
  304. ref,
  305. onBeforeUnmount,
  306. onUnmounted,
  307. nextTick,
  308. getCurrentInstance,
  309. computed,
  310. watch,
  311. } from "vue";
  312. import {
  313. ElScrollbar,
  314. ElPagination,
  315. ElDialog,
  316. ElCarousel,
  317. ElCarouselItem,
  318. ElIcon,
  319. } from "element-plus";
  320. import { Search, ArrowDown } from "@element-plus/icons-vue";
  321. import { getClass, classSelections, queryClassroom, summaryStatisticV3Api } from "../request/api";
  322. import CircleProgress from "./CircleProgress.vue";
  323. import {
  324. Vue3SeamlessScroll,
  325. VerticalScroll,
  326. HorizontalScroll,
  327. } from "vue3-seamless-scroll";
  328. import Scroll from "./ScrollView.vue";
  329. // import { callUIInteraction } from "../webrtcVideo";
  330. import Tag from "./Tag.vue";
  331. import axios from 'axios'
  332. import { CountTo } from "vue3-count-to";
  333. export default {
  334. name: "Histogram",
  335. components: {
  336. ElScrollbar,
  337. ElPagination,
  338. ElDialog,
  339. ElCarousel,
  340. ElCarouselItem,
  341. CircleProgress,
  342. Tag,
  343. CountTo,
  344. Vue3SeamlessScroll,
  345. VerticalScroll,
  346. Scroll,
  347. ArrowDown,
  348. },
  349. props: {
  350. isShow: {
  351. type: Boolean,
  352. default: true,
  353. },
  354. },
  355. setup(props, { emit }) {
  356. watch(
  357. () => props.isShow,
  358. (newValue) => {
  359. console.log("监听一下现在的位置", newValue);
  360. clearTimeoutTimer(); // 清除定时器
  361. if (newValue) {
  362. startTimeInterval();// 重新开始定时器
  363. } else {
  364. }
  365. }
  366. )
  367. // 教室分类统计
  368. const classRoomCount = ref([]);
  369. const isShhow = ref(true)
  370. const generateData = (totalNum, bigvalue, smallvalue, color) => {
  371. let dataArr = [];
  372. for (var i = 0; i < totalNum; i++) {
  373. if (i % 2 === 0) {
  374. dataArr.push({
  375. name: (i + 1).toString(),
  376. value: bigvalue,
  377. itemStyle: {
  378. normal: {
  379. color: color,
  380. borderWidth: 0,
  381. },
  382. },
  383. });
  384. } else {
  385. dataArr.push({
  386. name: (i + 1).toString(),
  387. value: smallvalue,
  388. itemStyle: {
  389. normal: {
  390. color: "rgba(0,0,0,0)",
  391. borderWidth: 0,
  392. },
  393. },
  394. });
  395. }
  396. }
  397. return dataArr;
  398. };
  399. let dolitData = generateData(60, 25, 20, "rgb(126,190,255)");
  400. const fontSize = (res) => {
  401. let clientWidth =
  402. window.innerWidth ||
  403. document.documentElement.clientWidth ||
  404. document.body.clientWidth;
  405. if (!clientWidth) return;
  406. // 此处的3840 为设计稿的宽度,记得修改!
  407. let fontSize = clientWidth / 1920;
  408. return res * fontSize;
  409. };
  410. const classPie = reactive({
  411. option: {
  412. color: ["#00bbff", "#00eb7d", "#ffbb00"],
  413. tooltip: {
  414. trigger: "item",
  415. position: "right",
  416. },
  417. series: [
  418. {
  419. type: "pie",
  420. radius: ["85%", "100%"],
  421. avoidLabelOverlap: false,
  422. zlevel: 9999,
  423. labelLine: {},
  424. label: {
  425. show: true,
  426. position: "center",
  427. color: "#fff",
  428. fontSize: fontSize(14),
  429. formatter: () => {
  430. // 格式化要展示的文本
  431. return `{a|总数}\n{b|${roomtotle.value}}{c|间}`;
  432. },
  433. rich: {
  434. a: {
  435. color: "rgba(255, 255, 255, 0.80)",
  436. lineHeight: fontSize(24),
  437. fontSize: fontSize(12),
  438. },
  439. b: {
  440. color: "#fff",
  441. fontSize: fontSize(20),
  442. fontWeight: 700,
  443. },
  444. c: {
  445. color: "rgba(255, 255, 255, 0.80)",
  446. fontSize: fontSize(12),
  447. },
  448. },
  449. },
  450. labelLine: {
  451. show: false,
  452. },
  453. data: classRoomCount,
  454. },
  455. {
  456. name: "虚线",
  457. type: "pie",
  458. zlevel: 10,
  459. silent: true,
  460. radius: ["58%", "56%"],
  461. label: {
  462. normal: {
  463. show: false,
  464. },
  465. },
  466. labelLine: {
  467. normal: {
  468. show: false,
  469. },
  470. },
  471. data: dolitData,
  472. },
  473. {
  474. name: "阴影圈",
  475. type: "pie",
  476. radius: ["100%", "70%"],
  477. center: ["50%", "50%"],
  478. emphasis: {
  479. scale: false,
  480. },
  481. tooltip: {
  482. show: false,
  483. },
  484. itemStyle: {
  485. // color: "rgba(255,225,255, 0.08)",
  486. color: "rgba(34, 81, 113,0.8)",
  487. },
  488. zlevel: 4,
  489. labelLine: {
  490. show: false,
  491. },
  492. data: [100],
  493. },
  494. {
  495. name: "阴影圈2",
  496. type: "pie",
  497. radius: ["70%", "52%"],
  498. center: ["50%", "50%"],
  499. emphasis: {
  500. scale: false,
  501. },
  502. tooltip: {
  503. show: false,
  504. },
  505. itemStyle: {
  506. // color: "rgba(255,225,255, 0.08)",
  507. color: "rgba(36, 66, 88,0.8)",
  508. },
  509. zlevel: 4,
  510. labelLine: {
  511. show: false,
  512. },
  513. data: [100],
  514. },
  515. {
  516. name: "中间圆",
  517. type: "pie",
  518. radius: ["0", "50%"],
  519. center: ["50%", "50%"],
  520. emphasis: {
  521. scale: false,
  522. },
  523. tooltip: {
  524. show: false,
  525. },
  526. itemStyle: {
  527. // color: "rgba(204,225,255, 0.08)",
  528. color: "rgba(34, 81, 113,0.5)",
  529. },
  530. zlevel: 4,
  531. labelLine: {
  532. show: false,
  533. },
  534. data: [100],
  535. },
  536. ],
  537. },
  538. });
  539. let myChart = ref(null);
  540. const initeCharts = () => {
  541. myChart.value = echarts.init(document.getElementById("myChart"));
  542. // 绘制图表
  543. console.log("绘制图表", classPie.option);
  544. myChart.value.setOption(classPie.option);
  545. };
  546. window.addEventListener("resize", function () {
  547. myChart.value.resize();
  548. if (scrollContainerHeight.value) {
  549. scrollContainerHeight.value = scrollContainerRef.value.clientHeight;
  550. }
  551. });
  552. // 物联设备类型统计
  553. const interDevice = ref([]);
  554. const roomVisible = ref(false);
  555. //消失面板
  556. const clearPanel = () => {
  557. roomVisible.value = false;
  558. };
  559. const popoverRef = ref(null);
  560. const triggerRef = ref({
  561. getBoundingClientRect() {
  562. // console.log("positon----方法返回元素的大小及其相对于视口的位置", position.value)
  563. return position.value;
  564. },
  565. });
  566. // 点击某个模型跟随移动
  567. const mousemoveHandler = (x, y) => {
  568. position.value = DOMRect.fromRect({
  569. width: 0,
  570. height: 0,
  571. x: x,
  572. y: y,
  573. });
  574. };
  575. const position = ref({
  576. top: 0,
  577. left: 0,
  578. bottom: 0,
  579. right: 0,
  580. });
  581. let classInfo = ref({});
  582. const handleRoom = function (item) {
  583. //查看前隐藏
  584. // let a1 = document.getElementById("popoverRef");
  585. // a1.style.display = "none";
  586. // emit("childMethod");
  587. // console.log("kankanitem", item);
  588. // setTimeout(() => {
  589. // roomVisible.value = true;
  590. // classInfo.value = item;
  591. // classInfo.value.online =
  592. // classInfo.value.status == "在用" ? true : false;
  593. // }, 2400);
  594. // mousemoveHandler(1000, 60);
  595. // let meg = item;
  596. // // let a2 =`roomName=${item.class}`
  597. // console.log("meg是多少", meg);
  598. //发消息给UE
  599. let data = {
  600. MainServiceName: "JiaoShiShiNei",
  601. ClassroomName: item.classroom_name,
  602. };
  603. console.log("data", JSON.stringify(data));
  604. emitUIInteraction(data);
  605. };
  606. // 本周课程统计数据
  607. const classCount = ref([]);
  608. // 智慧教室使用数据
  609. const classRoom = ref([]);
  610. const roomtotle = ref([]);
  611. const getClassData = async () => {
  612. let res = await getClass();
  613. console.log("res----教室分类统计", res);
  614. let { course, classroomDetail, category } = res.data;
  615. classRoomCount.value = category;
  616. //获取教室总数
  617. roomtotle.value = category.reduce(
  618. (accumulator, currentValue) => accumulator + currentValue.value,
  619. 0
  620. );
  621. console.log("categorycategory", roomtotle);
  622. if (classRoomCount.value) {
  623. initeCharts();
  624. }
  625. classCount.value = course;
  626. console.log("看一下颜色", classCount.value);
  627. classRoom.value = classroomDetail;
  628. };
  629. let timer = ref(null);
  630. let testMain = ref(null);
  631. let scrollContainerRef = ref(null);
  632. let scrollContainerHeight = ref(null);
  633. let setTimeoutTimerId = ref(null);
  634. const clearTimeoutTimer = () => {
  635. if (setTimeoutTimerId.value) {
  636. clearTimeout(setTimeoutTimerId.value);
  637. setTimeoutTimerId.value = null; // 重置定时器 ID
  638. }
  639. };
  640. const startTimeInterval = () => {
  641. setTimeoutTimerId.value = setInterval(() => {
  642. getClassData();
  643. //start();
  644. // 获取教师下拉选择数据
  645. getClassSelections();
  646. //获取教室列表数据
  647. getClassRoomList();
  648. getSummaryStatisticV3()
  649. }, 30000);
  650. };
  651. onMounted(() => {
  652. getClassData();
  653. // 获取教师下拉选择数据
  654. getClassSelections();
  655. //获取教室列表数据
  656. getClassRoomList();
  657. // 获取教师统计数据
  658. getSummaryStatisticV3()
  659. // summaryStatisticV3Api
  660. scrollContainerHeight.value = scrollContainerRef.value.clientHeight;
  661. clearTimeoutTimer();//清除定时器
  662. startTimeInterval();//开启定时器
  663. });
  664. let summaryStatistic = ref({
  665. mdeiaClassroomCount: 0,
  666. mediaClassroomOnlineDeviceCount: 0,
  667. mediaClassroomDeviceCount: 0,
  668. wiseClassroomCount: 0,
  669. wiseClassroomDeviceCount: 0,
  670. wiseClassroomOnlineDeviceCount: 0
  671. });
  672. const getSummaryStatisticV3 = () => {
  673. axios.get("https://weizhi.huanghuai.edu.cn/ioc-server/summaryStatisticV3/1").then(res => {
  674. console.log("教室统计数据s", res)
  675. if (res.data.code == 200) {
  676. summaryStatistic.value = res.data.data.wiseClassroom
  677. }
  678. })
  679. }
  680. onBeforeUnmount(() => {
  681. clearTimeout(timer.value);
  682. });
  683. onUnmounted(() => {
  684. clearTimeout(timer.value);
  685. });
  686. // 占用教室数量
  687. const occupiedClassroomsCount = computed(() => {
  688. return classRoom.value.filter((classroom) => classroom.status === "在用")
  689. .length;
  690. });
  691. // 计算属性:占用百分比
  692. const getPercentage = computed(() => {
  693. const total = classRoom.value.length;
  694. const occupied = occupiedClassroomsCount.value;
  695. return (((occupied / total) * 100).toFixed(2)) == 'NaN' ? 0 : (((occupied / total) * 100).toFixed(2));
  696. });
  697. // 获取教室下拉选择
  698. let buildings = ref({});
  699. let categoryType = ref({});
  700. let leafs = ref({});
  701. let statuses = ref({});
  702. const getClassSelections = async () => {
  703. let res = await classSelections();
  704. if (res.code == 200) {
  705. buildings.value = res.data.buildings;
  706. categoryType.value = res.data.categoryType;
  707. leafs.value = res.data.leafs;
  708. statuses.value = res.data.statuses;
  709. }
  710. };
  711. let cureetBuild = ref("全部大楼");
  712. const clickBuildingsropdown = (e) => {
  713. console.log("e选择大楼", e);
  714. gisBuildingCode.value = e;
  715. let build = buildings.value.find((item) => {
  716. return item.gis_building_code == e;
  717. });
  718. cureetBuild.value = build.building_name;
  719. searchHandel();
  720. };
  721. const clickCategoryTypedropdown = (e) => {
  722. console.log("e", e);
  723. category.value = e;
  724. searchHandel();
  725. };
  726. let cureetLeaf = ref("全部楼层");
  727. const clickLeafsdropdown = (e) => {
  728. console.log("e", e);
  729. gisLeaf.value = e;
  730. let leaf = leafs.value.find((item) => {
  731. return item.leaf == e;
  732. });
  733. cureetLeaf.value = leaf.leaf_name;
  734. searchHandel();
  735. };
  736. let cureetStatus = ref("全部教室");
  737. const clickStatusesdropdown = (e) => {
  738. console.log("e", e);
  739. statusCode.value = e;
  740. let status = statuses.value.find((item) => {
  741. return item.status_code == e;
  742. });
  743. cureetStatus.value = status.status_name;
  744. searchHandel();
  745. };
  746. // 搜索
  747. let searchData = ref("");
  748. let category = ref("");
  749. let gisBuildingCode = ref("");
  750. let gisLeaf = ref("");
  751. let statusCode = ref("");
  752. let scrollRef = ref(null);
  753. const offset = () => {
  754. console.log("滚动完成一次");
  755. };
  756. const searchHandel = async () => {
  757. getClassRoomList();
  758. clearTimeoutTimer();//清除定时器
  759. startTimeInterval()
  760. };
  761. let classRoomList = ref([]);
  762. const getClassRoomList = async () => {
  763. isShhow.value = false;
  764. let res = await queryClassroom({
  765. classRoomName: searchData.value,
  766. category: category.value,
  767. gisBuildingCode: gisBuildingCode.value,
  768. statusCode: statusCode.value,
  769. gisLeaf: gisLeaf.value,
  770. });
  771. classRoomList.value = [];
  772. // setTimeout(() => {
  773. classRoomList.value = res.data;
  774. isShhow.value = true;
  775. // scrollRef.value.reset()
  776. // }, 0);
  777. };
  778. let deviceDialog = ref(true);
  779. const showDeviceDialog = () => {
  780. deviceDialog.value = true;
  781. };
  782. const leftimg = ref("./img/");
  783. const frame = ref("./img/frame.png");
  784. const noData = ref("./img/no-data.png");
  785. return {
  786. roomVisible,
  787. classCount,
  788. classRoom,
  789. interDevice,
  790. handleRoom,
  791. testMain,
  792. popoverRef,
  793. classRoomCount,
  794. triggerRef,
  795. classInfo,
  796. leftimg,
  797. clearPanel,
  798. frame,
  799. ElIcon,
  800. Search,
  801. ArrowDown,
  802. ElIcon,
  803. searchData,
  804. searchHandel,
  805. getClassSelections,
  806. buildings,
  807. categoryType,
  808. leafs,
  809. statuses,
  810. clickCategoryTypedropdown,
  811. clickBuildingsropdown,
  812. clickLeafsdropdown,
  813. clickStatusesdropdown,
  814. // start,
  815. category,
  816. gisBuildingCode,
  817. gisLeaf,
  818. statusCode,
  819. getPercentage,
  820. occupiedClassroomsCount,
  821. classRoomList,
  822. deviceDialog,
  823. showDeviceDialog,
  824. cureetBuild,
  825. cureetLeaf,
  826. cureetStatus,
  827. scrollRef,
  828. offset,
  829. scrollContainerHeight,
  830. scrollContainerRef,
  831. noData,
  832. isShhow,
  833. summaryStatistic
  834. };
  835. },
  836. };
  837. </script>
  838. <style scoped lang="scss">
  839. @import "../assets/css/left.scss";
  840. </style>
  841. <style>
  842. .classpopover {
  843. .el-popper__arrow {
  844. top: 196px !important;
  845. }
  846. .el-popper[data-popper-placement^="bottom"],
  847. .el-popper__arrow::before {
  848. border-left-color: transparent !important;
  849. border-top-color: transparent !important;
  850. }
  851. }
  852. .el-popper.is-light {
  853. border-radius: 2px;
  854. }
  855. .el-popper {
  856. border: 2px solid #1a2d47 !important;
  857. background: rgba(1, 18, 35, 0.60) !important;
  858. border-radius: 4px !important;
  859. }
  860. .el-dropdown-menu {
  861. background: rgba(1, 18, 35, 0.60) !important;
  862. border: none !important;
  863. border-radius: 4px !important;
  864. padding: 2px !important;
  865. }
  866. .el-dropdown-menu__item {
  867. color: rgba(255, 255, 255, 0.72);
  868. border-radius: 4px !important;
  869. }
  870. .popper__arrow::after {
  871. background: rgba(255, 255, 255, 0.12);
  872. }
  873. .el-dropdown-menu__item:not(.is-disabled):hover {
  874. background: rgba(255, 255, 255, 0.12);
  875. color: rgba(255, 255, 255, 0.75);
  876. }
  877. .el-dropdown-menu__item:not(.is-disabled):hover {
  878. background: rgba(255, 255, 255, 0.12) !important;
  879. color: #fff !important;
  880. }
  881. .el-dropdown-menu__item:not(.is-disabled):focus {
  882. background: rgba(255, 255, 255, 0.12) !important;
  883. color: #fff !important;
  884. }
  885. .el-popper__arrow {
  886. display: none;
  887. }
  888. .el-input__inner {
  889. color: #fff !important;
  890. }
  891. </style>