dataOverview.vue 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798
  1. <template>
  2. <div class="content-box">
  3. <div class="left">
  4. <!-- <el-icon :size="23" class="camera"><VideoCameraFilled /></el-icon> -->
  5. <div class="cameratxt">数据总览</div>
  6. </div>
  7. <!-- 处置情况 -->
  8. <!-- <div class="system_title">
  9. <h4>处置情况</h4>
  10. </div> -->
  11. <ul class="dispose" style="margin-top: 20px">
  12. <li v-for="i in disposeList" :key="i.icon">
  13. <SvgIcon :name="i.icon" color="#fff" size="55"></SvgIcon>
  14. <div class="dispose_content">
  15. <p style="color: rgba(128, 128, 128, 1); font-size: 18px">
  16. {{ i.title }}
  17. </p>
  18. <p style="font-weight: 600; font-size: 30px">
  19. <span>{{ i.num }}</span>
  20. <span v-if="i.numTotal">&nbsp;/&nbsp;</span>
  21. <span v-if="i.numTotal">{{ i.numTotal }}</span>
  22. </p>
  23. </div>
  24. </li>
  25. <li v-if="carSchool == 'huang'">
  26. <SvgIcon name="carNum" color="#fff" size="55"></SvgIcon>
  27. <div class="dispose_content">
  28. <p
  29. class="yuyue"
  30. style="color: rgba(128, 128, 128, 1); font-size: 18px"
  31. >
  32. <span @click="carSchoolChange('mo')" style="margin-right: 20px"
  33. >墨轩湖</span
  34. >
  35. <span @click="carSchoolChange('huang')" class="active">黄家湖</span>
  36. </p>
  37. <p style="color: rgba(128, 128, 128, 1); font-size: 18px">
  38. 今日约车牌数 / 剩余车位数
  39. </p>
  40. <p style="font-weight: 600; font-size: 30px">
  41. <span
  42. @click="callerClick"
  43. style="color: rgba(0, 97, 255, 1); cursor: pointer"
  44. >{{ carArr.huang.num }}</span
  45. >
  46. <span>&nbsp;/&nbsp;</span>
  47. <span>{{ carArr.huang.numTotal }}</span>
  48. </p>
  49. </div>
  50. </li>
  51. <li v-if="carSchool == 'mo'">
  52. <SvgIcon name="carNum" color="#fff" size="55"></SvgIcon>
  53. <div class="dispose_content">
  54. <p
  55. class="yuyue"
  56. style="color: rgba(128, 128, 128, 1); font-size: 18px"
  57. >
  58. <span
  59. class="active"
  60. @click="carSchoolChange('mo')"
  61. style="margin-right: 20px"
  62. >墨轩湖</span
  63. >
  64. <span @click="carSchoolChange('huang')">黄家湖</span>
  65. </p>
  66. <p style="color: rgba(128, 128, 128, 1); font-size: 18px">
  67. 今日约车牌数 / 剩余车位数
  68. </p>
  69. <p style="font-weight: 600; font-size: 30px">
  70. <span
  71. @click="callerClick"
  72. style="color: rgba(0, 97, 255, 1); cursor: pointer"
  73. >{{ carArr.mo.num }}</span
  74. >
  75. <span>&nbsp;/&nbsp;</span>
  76. <span>{{ carArr.mo.numTotal }}</span>
  77. </p>
  78. </div>
  79. </li>
  80. </ul>
  81. <!-- 学院新生报到 -->
  82. <div class="echarts">
  83. <div class="echarts_register">
  84. <div class="system_title">
  85. <h4>学院新生报到情况</h4>
  86. </div>
  87. <div id="echarts_register"></div>
  88. </div>
  89. <div class="echarts_traffic">
  90. <div class="system_title">
  91. <h4>交通方式情况</h4>
  92. </div>
  93. <div id="echarts_traffic"></div>
  94. </div>
  95. </div>
  96. <!-- 性别比例 -->
  97. <div class="system_title">
  98. <h4>学院新生性别比例</h4>
  99. </div>
  100. <div class="gender">
  101. <div id="gender" ref="genderRef"></div>
  102. </div>
  103. </div>
  104. </template>
  105. <script setup>
  106. import {
  107. ref,
  108. watch,
  109. reactive,
  110. nextTick,
  111. onMounted,
  112. onBeforeMount,
  113. onBeforeUnmount,
  114. onUnmounted,
  115. } from "vue";
  116. import { useRouter } from "vue-router";
  117. import { ElMessage, ElMessageBox } from "element-plus";
  118. import { dayjs } from "element-plus";
  119. import lodash from "lodash";
  120. import * as echarts from "echarts";
  121. import { https } from "@/utils/request"; // 绝对路径
  122. import { storeToRefs } from "pinia";
  123. import { useCounterStore } from "@/stores/index";
  124. import { right } from "@popperjs/core";
  125. const api = ref("");
  126. const router = useRouter();
  127. const store = useCounterStore();
  128. const tableData = reactive({
  129. list: [],
  130. });
  131. const currentPage = ref(1); // 当前页
  132. const pageSize = ref(10);
  133. const total = ref(0); // 当前总数
  134. // 为避免解构时失去响应性
  135. const { name, age, isCollapse, realAge } = storeToRefs(store);
  136. // 处置情况
  137. const disposeList = ref([
  138. {
  139. icon: "luqu",
  140. num: 1,
  141. title: "录取人数",
  142. },
  143. {
  144. icon: "yubao",
  145. num: 1,
  146. title: "预报到人数",
  147. },
  148. {
  149. icon: "jiaofei",
  150. num: 1,
  151. title: "已缴费人数",
  152. },
  153. {
  154. icon: "ruzhu",
  155. num: "1 / 10",
  156. title: "入住寝室数/总数",
  157. },
  158. {
  159. icon: "yuyue",
  160. num: "2 / 12",
  161. title: "今日预约车牌数/总数",
  162. },
  163. ]);
  164. const carSchool = ref("mo");
  165. const carArr = reactive({
  166. huang: {},
  167. mo: {},
  168. });
  169. const carSchoolChange = (title) => {
  170. carSchool.value = title;
  171. console.log(disposeList.value);
  172. disposeList.value.forEach((i) => {
  173. if (i.icon == "carNum") {
  174. if (carSchool.value == "huang") {
  175. i = carArr.huang;
  176. } else if (carSchool.value == "mo") {
  177. i = carArr.mo;
  178. }
  179. }
  180. });
  181. };
  182. // 学院新生报到情况
  183. let registerEcharts = null;
  184. // 学院新生报到情况
  185. let trafficEcharts = null;
  186. // 性别比例
  187. let genderEcharts = null;
  188. // 处置情况
  189. const studentOverview = async () => {
  190. let res = await https.get(
  191. "/welcome/api/welcomeStudent/studentOverview",
  192. "params"
  193. );
  194. console.log(res, "处置情况");
  195. if (res.code == 200) {
  196. carArr.huang = {
  197. icon: "carNum",
  198. num: res.data.hvisitorTotal,
  199. numTotal: res.data.hcarTotal,
  200. title: "今日约车牌数 / 剩余车位数",
  201. };
  202. carArr.mo = {
  203. icon: "carNum",
  204. num: res.data.mvisitorTotal,
  205. numTotal: res.data.mcarTotal,
  206. title: "今日约车牌数 / 剩余车位数",
  207. };
  208. disposeList.value = [
  209. {
  210. icon: "luqu",
  211. num: res.data.enrollmentTotal,
  212. title: "录取人数",
  213. },
  214. {
  215. icon: "jiaofei",
  216. num: res.data.payCount,
  217. title: "已缴费人数",
  218. },
  219. {
  220. icon: "ruzhu",
  221. num: res.data.checkInBedTotal,
  222. numTotal: `${res.data.registrationRate}%`,
  223. title: "已入住床位数 / 报到率",
  224. },
  225. ];
  226. } else {
  227. ElMessage({
  228. type: "error",
  229. showClose: true,
  230. message: res.message,
  231. center: true,
  232. });
  233. }
  234. };
  235. // 跳转到访客信息管理
  236. const callerClick = () => {
  237. router.push({
  238. path: `/caller`,
  239. });
  240. };
  241. // 表格斑马纹颜色修改
  242. const tableRowClassName = ({ row, rowIndex }) => {
  243. if (rowIndex % 2 === 0) {
  244. return "even";
  245. } else if (rowIndex % 2 !== 0) {
  246. return "odd";
  247. }
  248. return "";
  249. };
  250. // 每页显示条数
  251. const handleSizeChange = (value) => {
  252. console.log(value, "每页显示条数");
  253. pageSize.value = value;
  254. };
  255. // 分页
  256. const handleCurrentChange = (value) => {
  257. // console.log(value);
  258. currentPage.value = value;
  259. };
  260. const register = async () => {
  261. let dom = document.getElementById("echarts_register");
  262. registerEcharts = echarts.init(dom);
  263. let res = await https.get(
  264. "/welcome/api/welcomeStudent/studentRegister",
  265. "params"
  266. );
  267. console.log(res, "新生报到情况");
  268. if (res.code == 200) {
  269. // const data = genData(20);
  270. const data = {
  271. legendData: [],
  272. seriesData: [],
  273. };
  274. let arr = res.data.slice(0, -1);
  275. data.seriesData = arr.map((i) => {
  276. data.legendData.push(i.collegeName);
  277. return {
  278. name: i.collegeName,
  279. value: i.count,
  280. };
  281. });
  282. const option = {
  283. tooltip: {
  284. trigger: "item",
  285. formatter: "{a} <br/>{b} : {c}人 ({d}%)",
  286. },
  287. legend: {
  288. type: "scroll",
  289. orient: "vertical",
  290. right: "10%",
  291. top: 10,
  292. bottom: 30,
  293. data: data.legendData,
  294. },
  295. series: [
  296. {
  297. name: "报到人数",
  298. type: "pie",
  299. radius: "60%",
  300. center: ["35%", "50%"],
  301. data: data.seriesData,
  302. emphasis: {
  303. itemStyle: {
  304. shadowBlur: 10,
  305. shadowOffsetX: 0,
  306. shadowColor: "rgba(0, 0, 0, 0.5)",
  307. },
  308. },
  309. },
  310. ],
  311. };
  312. registerEcharts.setOption(option);
  313. } else {
  314. ElMessage({
  315. type: "error",
  316. showClose: true,
  317. message: res.message,
  318. center: true,
  319. });
  320. }
  321. };
  322. const traffic = async () => {
  323. var chartDom = document.getElementById("echarts_traffic");
  324. trafficEcharts = echarts.init(chartDom);
  325. var option;
  326. let res = await https.get(
  327. "/welcome/api/welcomeStudent/studentTraffic",
  328. "params"
  329. );
  330. console.log(res, "学生交通方式");
  331. if (res.code == 200) {
  332. let data = [];
  333. data = res.data.map((i) => {
  334. return { value: i.count, name: i.trafficMethod };
  335. });
  336. option = {
  337. tooltip: {
  338. trigger: "item",
  339. },
  340. // legend: {
  341. // top: "5%",
  342. // left: "center",
  343. // },
  344. series: [
  345. {
  346. name: "交通方式",
  347. type: "pie",
  348. radius: ["50%", "70%"],
  349. avoidLabelOverlap: false,
  350. padAngle: 5,
  351. itemStyle: {
  352. borderRadius: 10,
  353. },
  354. label: {
  355. show: true,
  356. // position: "center",
  357. // alignTo: "edge",
  358. formatter: "{name|{b}}\n{time|{c} ({d}%)}",
  359. // minMargin: 5,
  360. // edgeDistance: 10,
  361. lineHeight: 18,
  362. rich: {
  363. time: {
  364. // fontSize: 10,
  365. color: "#999",
  366. },
  367. percent: {
  368. // fontSize: 10,
  369. color: "#999",
  370. },
  371. },
  372. },
  373. emphasis: {
  374. label: {
  375. show: true,
  376. fontSize: 20,
  377. fontWeight: "bold",
  378. },
  379. },
  380. labelLine: {
  381. show: false,
  382. },
  383. data: data,
  384. },
  385. ],
  386. };
  387. trafficEcharts.setOption(option);
  388. } else {
  389. ElMessage({
  390. type: "error",
  391. showClose: true,
  392. message: res.message,
  393. center: true,
  394. });
  395. }
  396. };
  397. const gender = async () => {
  398. var chartDom = document.getElementById("gender");
  399. genderEcharts = echarts.init(chartDom);
  400. let res = await https.get(
  401. "/welcome/api/welcomeStudent/studentSexRatio",
  402. "params"
  403. );
  404. console.log(res, "学生性别比例");
  405. if (res.code == 200) {
  406. let data = [];
  407. res.data.slice(0, -1).forEach((i) => {
  408. if (!i.girlCount) {
  409. i.girlCount = 0;
  410. } else if (!i.manCount) {
  411. i.manCount = 0;
  412. }
  413. if (i) {
  414. data.push(i);
  415. }
  416. });
  417. console.log(data);
  418. const option = {
  419. legend: {
  420. right: "5%",
  421. padding: [
  422. 10, // 上
  423. 10, // 右
  424. 5, // 下
  425. 10, // 左
  426. ],
  427. },
  428. tooltip: {},
  429. grid: {
  430. left: "5%",
  431. right: "5%",
  432. top: "18%",
  433. bottom: "2%",
  434. containLabel: true,
  435. },
  436. dataset: {
  437. dimensions: ["collegeName", "manCount", "girlCount"],
  438. source: data,
  439. },
  440. xAxis: {
  441. type: "category",
  442. axisLine: {
  443. show: false,
  444. },
  445. axisTick: {
  446. show: false,
  447. },
  448. },
  449. yAxis: {
  450. name: "人",
  451. // nameLocation:""
  452. },
  453. series: [
  454. {
  455. type: "bar",
  456. name: "男",
  457. barMinWidth: 20,
  458. barMaxWidth: 30,
  459. label: {
  460. show: true,
  461. position: "top",
  462. },
  463. itemStyle: {
  464. color: "rgba(0, 97, 255, 1)",
  465. },
  466. },
  467. {
  468. type: "bar",
  469. name: "女",
  470. barMinWidth: 20,
  471. barMaxWidth: 30,
  472. label: {
  473. show: true,
  474. position: "top",
  475. },
  476. itemStyle: {
  477. color: "rgba(0, 186, 173, 1)",
  478. },
  479. },
  480. ],
  481. };
  482. genderEcharts.setOption(option);
  483. } else {
  484. ElMessage({
  485. type: "error",
  486. showClose: true,
  487. message: res.message,
  488. center: true,
  489. });
  490. }
  491. };
  492. // 学生住宿情况
  493. const studentStay = async () => {
  494. let res = await https.get(
  495. "/welcome/api/welcomeStudent/studentStay",
  496. "params"
  497. );
  498. console.log(res, "学生住宿情况");
  499. if (res.code == 200) {
  500. tableData.list = res.data;
  501. } else {
  502. ElMessage({
  503. type: "error",
  504. showClose: true,
  505. message: res.message,
  506. center: true,
  507. });
  508. }
  509. };
  510. const updateChartSize = () => {
  511. if (registerEcharts) {
  512. registerEcharts.resize();
  513. }
  514. if (trafficEcharts) {
  515. trafficEcharts.resize();
  516. }
  517. if (genderEcharts) {
  518. genderEcharts.resize();
  519. }
  520. };
  521. onMounted(() => {
  522. studentOverview();
  523. register();
  524. traffic();
  525. gender();
  526. studentStay();
  527. window.addEventListener("resize", updateChartSize);
  528. });
  529. onBeforeMount(() => {
  530. // studentOverview();
  531. // studentRegister();
  532. // studentTraffic();
  533. // studentSexRatio();
  534. // studentStay();
  535. });
  536. onUnmounted(() => {
  537. // document.removeEventListener("keyup", Enters);
  538. });
  539. onBeforeUnmount(() => {
  540. if (registerEcharts) {
  541. registerEcharts.dispose();
  542. }
  543. if (trafficEcharts) {
  544. trafficEcharts.dispose();
  545. }
  546. if (genderEcharts) {
  547. genderEcharts.dispose();
  548. }
  549. window.removeEventListener("resize", updateChartSize);
  550. });
  551. </script>
  552. <style scoped lang="scss">
  553. .content-box {
  554. // min-width: calc(100% - 40px);
  555. width: calc(100% - 40px);
  556. height: calc(100% - 105px);
  557. margin: 20px auto;
  558. background-color: #fff;
  559. color: #000;
  560. display: flex;
  561. flex-direction: column;
  562. overflow: auto;
  563. .left {
  564. height: 60px;
  565. margin: 0 30px;
  566. border-bottom: 1px solid #ccc;
  567. color: #000;
  568. font-size: 18px;
  569. font-weight: 600;
  570. .cameratxt {
  571. margin-right: 15px;
  572. height: 60px;
  573. line-height: 60px;
  574. }
  575. }
  576. .system_title {
  577. // width: 100%;
  578. height: 45px;
  579. opacity: 1;
  580. border-radius: 0px 12px 0px 0px;
  581. background: rgb(243, 249, 255);
  582. margin: 15px 30px;
  583. display: flex;
  584. align-items: center;
  585. // justify-content: center;
  586. h4 {
  587. font-size: 15px;
  588. padding: 0 5px 0 20px;
  589. }
  590. .wain {
  591. font-size: 13px;
  592. color: rgba(212, 48, 48, 1);
  593. }
  594. }
  595. // 处置情况
  596. .dispose {
  597. margin: 0 30px;
  598. display: flex;
  599. justify-content: space-between;
  600. list-style: none;
  601. padding: 0;
  602. li {
  603. flex: 1;
  604. margin: 0 10px;
  605. height: 133px;
  606. border: 1px solid rgba(143, 143, 143, 1);
  607. border-radius: 6.98px;
  608. background: rgba(250, 252, 255, 1);
  609. display: flex;
  610. align-items: center;
  611. // justify-content: space-around;
  612. .el-icon {
  613. margin: 0 30px;
  614. }
  615. .dispose_content {
  616. p {
  617. margin: 15px 0;
  618. }
  619. }
  620. .yuyue {
  621. span {
  622. cursor: pointer;
  623. }
  624. .active {
  625. color: rgb(248, 130, 11);
  626. }
  627. }
  628. }
  629. }
  630. // 学院新生报到情况
  631. .echarts {
  632. display: flex;
  633. .echarts_register {
  634. flex: 1;
  635. #echarts_register {
  636. width: calc(100% - 60px);
  637. height: 300px;
  638. margin: 0 auto;
  639. }
  640. }
  641. .echarts_traffic {
  642. flex: 1;
  643. #echarts_traffic {
  644. width: calc(100% - 60px);
  645. height: 300px;
  646. margin: 0 auto;
  647. }
  648. }
  649. }
  650. .gender {
  651. width: calc(100% - 60px);
  652. height: 300px;
  653. margin: 0 auto 10px;
  654. #gender {
  655. width: 100%;
  656. height: 300px;
  657. }
  658. }
  659. .footer {
  660. width: 100%;
  661. margin-bottom: 25px;
  662. .el-table--fit {
  663. width: calc(100% - 60px);
  664. margin: 0 auto;
  665. :deep(.el-table__header-wrapper) {
  666. background-color: #000;
  667. font-size: 15px;
  668. color: #000;
  669. .cell {
  670. color: #000;
  671. }
  672. }
  673. :deep(.el-table__row) {
  674. height: 50px;
  675. font-size: 15px;
  676. color: #000;
  677. }
  678. :deep(.el-table__row td) {
  679. padding: 0;
  680. border: 0;
  681. }
  682. .el-button--primary {
  683. margin-left: 5px;
  684. }
  685. :deep(.el-table__body .even) {
  686. background-color: #fff;
  687. }
  688. :deep(.el-table__body .odd) {
  689. background-color: rgba(240, 243, 247, 1);
  690. }
  691. :deep(.options) {
  692. display: flex;
  693. justify-content: center;
  694. align-items: center;
  695. .edit {
  696. margin: 0 15px 0 0;
  697. color: rgba(0, 186, 173, 1);
  698. cursor: pointer;
  699. }
  700. .delete {
  701. color: rgba(212, 48, 48, 1);
  702. cursor: pointer;
  703. }
  704. }
  705. }
  706. .pageSize {
  707. display: flex;
  708. align-items: center;
  709. justify-content: space-between;
  710. margin: 0 30px;
  711. height: 60px;
  712. span {
  713. color: #000;
  714. }
  715. .el-pagination {
  716. // width: 1600px;
  717. :deep(.el-pagination__total) {
  718. color: #000;
  719. }
  720. :deep(.el-pagination__goto) {
  721. color: #000;
  722. }
  723. :deep(.el-pagination__classifier) {
  724. color: #000;
  725. }
  726. :deep(.el-input__wrapper) {
  727. border: 1px solid rgba(0, 0, 0, 1);
  728. border-radius: 5px;
  729. box-shadow: none;
  730. }
  731. :deep(.el-pager li) {
  732. margin: 0 5px;
  733. border: 1px solid rgba(0, 0, 0, 1);
  734. border-radius: 5px;
  735. background-color: transparent;
  736. }
  737. :deep(.el-pager li.is-active) {
  738. // background-color: rgba(0, 97, 255, 0.8);
  739. border: 1px solid rgba(0, 97, 255, 1);
  740. color: rgba(0, 97, 255, 1);
  741. }
  742. :deep(.btn-prev) {
  743. margin-right: 5px;
  744. border: 1px solid rgba(0, 0, 0, 1);
  745. border-radius: 5px;
  746. background-color: transparent;
  747. }
  748. :deep(.btn-next) {
  749. margin-left: 5px;
  750. border: 1px solid rgba(0, 0, 0, 1);
  751. border-radius: 5px;
  752. background-color: transparent;
  753. }
  754. }
  755. }
  756. }
  757. }
  758. </style>