studentLeft.vue 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400
  1. <template>
  2. <div class="container">
  3. <!-- 基本信息区域 -->
  4. <div class="top">
  5. <div class="top_tilte">
  6. <img src="@/assets/images/box-icon.png" />
  7. 基本信息
  8. </div>
  9. <div class="top_detail">
  10. <div class="detail_photo">
  11. <img
  12. class="img"
  13. src="https://img1.baidu.com/it/u=1398895526,1958525606&fm=253&fmt=auto&app=120&f=JPEG?w=1280&h=800"
  14. />
  15. <div class="photo_icon">
  16. <el-icon size="20" color="#2493F1"><ArrowDownBold /></el-icon>
  17. </div>
  18. </div>
  19. <div class="detail_msg">
  20. <div>姓名:张晓晓</div>
  21. <div>性别:男</div>
  22. <div>编号:2216161</div>
  23. <div>部门:学生</div>
  24. </div>
  25. </div>
  26. </div>
  27. <!-- 考勤情况区域 -->
  28. <div class="bottom">
  29. <div class="bottom_title">
  30. <img src="@/assets/images/box-icon.png" />
  31. 考勤情况
  32. </div>
  33. <!-- 数据展示区域 -->
  34. <div class="bottom_msg">
  35. <div class="msg_change">
  36. <div
  37. class="change_box"
  38. :class="currentTimeRang === 0 ? 'active' : ''"
  39. @click="changeTimeRang(0)"
  40. >
  41. 本学期
  42. </div>
  43. <div
  44. class="change_box"
  45. :class="currentTimeRang === 1 ? 'active' : ''"
  46. @click="changeTimeRang(1)"
  47. >
  48. 本周
  49. </div>
  50. <div
  51. class="change_box"
  52. :class="currentTimeRang === 2 ? 'active' : ''"
  53. @click="changeTimeRang(2)"
  54. >
  55. 本月
  56. </div>
  57. </div>
  58. <div class="msg_detail">
  59. <div class="detail_box">
  60. <div class="box_num" ref="valueDom">{{ value }}</div>
  61. <div class="box_type">准时</div>
  62. </div>
  63. <div class="detail_box">
  64. <div class="box_num" ref="valueDom2">{{ value2 }}</div>
  65. <div class="box_type">请假</div>
  66. </div>
  67. <div class="detail_box">
  68. <div class="box_num" ref="valueDom3">{{ value3 }}</div>
  69. <div class="box_type">迟到</div>
  70. </div>
  71. <div class="detail_box">
  72. <div class="box_num" ref="valueDom4">{{ value4 }}</div>
  73. <div class="box_type">超时打卡</div>
  74. </div>
  75. <div class="detail_box">
  76. <div class="box_num" ref="valueDom5">{{ value5 }}</div>
  77. <div class="box_type">未打卡</div>
  78. </div>
  79. </div>
  80. </div>
  81. <!-- 图表展示区域 -->
  82. <div class="bottom_chart" ref="pieChart">123</div>
  83. </div>
  84. </div>
  85. </template>
  86. <script setup lang="ts">
  87. import { ref, onMounted } from "vue";
  88. import * as Echarts from "echarts";
  89. import { countUpNum } from "@/utils/countUpNum";
  90. // 引入用户画像相关的接口
  91. import { reqGetStudentAttendance } from "@/api/user/index";
  92. // 引入解密函数
  93. //@ts-ignore
  94. import { decryptDes } from "@/utils/des.ts";
  95. const value = ref(50);
  96. const value2 = ref(50);
  97. const value3 = ref(50);
  98. const value4 = ref(50);
  99. const value5 = ref(50);
  100. // DOM元素
  101. const valueDom = ref();
  102. const valueDom2 = ref();
  103. const valueDom3 = ref();
  104. const valueDom4 = ref();
  105. const valueDom5 = ref();
  106. let myPieChart: any;
  107. const pieChart = ref();
  108. // 切换考勤统计时间 0本学期 1本周 2本月
  109. const currentTimeRang = ref(0);
  110. const chartData = ref([
  111. { value: 5, name: "准时" },
  112. { value: 6, name: "请假" },
  113. { value: 3, name: "迟到" },
  114. { value: 2, name: "超时打卡" },
  115. { value: 1, name: "未打卡" },
  116. ]);
  117. onMounted(() => {
  118. // 获取学生历史出勤数据
  119. getStudentAttendance();
  120. myPieChart = Echarts.init(pieChart.value);
  121. initPieChart();
  122. getCountUpNum();
  123. });
  124. // 获取学生历史出勤数据
  125. const getStudentAttendance = async () => {
  126. const res = await reqGetStudentAttendance({
  127. userId: 7967,
  128. dateTime: 1,
  129. });
  130. // console.log(res);
  131. if ((res as any).code == 200) {
  132. const result = JSON.parse(decryptDes(res.data));
  133. console.log(result);
  134. }
  135. };
  136. const initPieChart = () => {
  137. const options = {
  138. title: {
  139. text: "总次数",
  140. left: "22%",
  141. top: "38%",
  142. textStyle: {
  143. fontSize: 14,
  144. color: "#D5E3EA",
  145. },
  146. subtext: "200",
  147. subtextStyle: {
  148. fontSize: 18,
  149. color: "#D5E3EA",
  150. align: "center",
  151. fontWeight: "bold",
  152. },
  153. itemGap: 15,
  154. },
  155. tooltip: {
  156. trigger: "item",
  157. },
  158. legend: {
  159. orient: "vertical",
  160. right: "4%",
  161. top: "center",
  162. itemWidth: 8,
  163. itemHeight: 8,
  164. itemGap: 25,
  165. textStyle: {
  166. padding: 8,
  167. color: "#fff",
  168. fontSize: 14,
  169. rich: {
  170. a: {
  171. fontSize: 16,
  172. fontWeight: "bold",
  173. align: "right",
  174. padding: [0, -100, 0, 0],
  175. },
  176. },
  177. },
  178. formatter: (params: any) => {
  179. const valueObj: any = chartData.value.find(
  180. (item) => item.name === params
  181. );
  182. return params + "{a|" + valueObj.value + "}";
  183. },
  184. },
  185. color: ["#50A4E1", "#FF85BE", "#FFC77D", "#93DE62", "#4AE8E8"],
  186. series: [
  187. {
  188. name: "考勤情况",
  189. type: "pie",
  190. center: ["28%", "50%"],
  191. radius: ["55%", "75%"],
  192. avoidLabelOverlap: false,
  193. label: {
  194. show: false,
  195. },
  196. itemStyle: {
  197. borderColor: "rgba(2, 27, 41, 0.1)",
  198. borderWidth: 5,
  199. },
  200. data: chartData.value,
  201. },
  202. ],
  203. };
  204. myPieChart.setOption(options);
  205. };
  206. // 考勤统计切换时间范围按钮回调
  207. const changeTimeRang = (value: number) => {
  208. if (currentTimeRang.value !== value) {
  209. if (value === 0) {
  210. currentTimeRang.value = 0;
  211. } else if (value === 1) {
  212. currentTimeRang.value = 1;
  213. } else if (value === 2) {
  214. currentTimeRang.value = 2;
  215. }
  216. }
  217. };
  218. // 让数字跳动
  219. const getCountUpNum = () => {
  220. countUpNum(valueDom.value, value.value);
  221. countUpNum(valueDom2.value, value2.value);
  222. countUpNum(valueDom3.value, value3.value);
  223. countUpNum(valueDom4.value, value4.value);
  224. countUpNum(valueDom5.value, value5.value);
  225. };
  226. </script>
  227. <style lang="scss" scoped>
  228. .container {
  229. display: flex;
  230. flex-direction: column;
  231. justify-content: space-between;
  232. width: 500px;
  233. height: 834px;
  234. color: #fff;
  235. .top {
  236. padding: 17px 0 0 22px;
  237. height: 272px;
  238. background-image: url(@/assets/images/box-bg2.png);
  239. background-size: 100% 100%;
  240. .top_tilte {
  241. display: flex;
  242. align-items: center;
  243. font-size: 16px;
  244. font-weight: bold;
  245. img {
  246. margin-right: 12px;
  247. width: 24px;
  248. height: 24px;
  249. }
  250. }
  251. .top_detail {
  252. margin-top: 40px;
  253. display: flex;
  254. align-items: center;
  255. .detail_photo {
  256. position: relative;
  257. display: flex;
  258. justify-content: center;
  259. align-items: center;
  260. width: 122px;
  261. height: 122px;
  262. border-radius: 50%;
  263. background-color: #2493f1;
  264. img {
  265. width: 112px;
  266. height: 112px;
  267. border-radius: 50%;
  268. object-fit: cover;
  269. }
  270. .photo_icon {
  271. position: absolute;
  272. top: 45px;
  273. right: -14px;
  274. display: flex;
  275. justify-content: center;
  276. align-items: center;
  277. width: 34px;
  278. height: 34px;
  279. border-radius: 50%;
  280. background-color: #fff;
  281. }
  282. }
  283. .detail_msg {
  284. display: flex;
  285. flex-direction: column;
  286. justify-content: space-between;
  287. margin-left: 63px;
  288. height: 122px;
  289. font-size: 14px;
  290. }
  291. }
  292. }
  293. .bottom {
  294. padding: 17px 54px 0 22px;
  295. height: 553px;
  296. background-image: url(@/assets/images/box-bg3.png);
  297. background-size: 100% 100%;
  298. .bottom_title {
  299. display: flex;
  300. align-items: center;
  301. font-size: 16px;
  302. font-weight: bold;
  303. img {
  304. margin-right: 12px;
  305. width: 24px;
  306. height: 24px;
  307. }
  308. }
  309. .bottom_msg {
  310. height: 262px;
  311. overflow: hidden;
  312. .msg_change {
  313. display: flex;
  314. justify-content: space-between;
  315. margin: 20px 0 33px 220px;
  316. padding: 2px;
  317. width: 200px;
  318. height: 32px;
  319. font-size: 14px;
  320. border-radius: 2px;
  321. border: 1px solid #9c9c9c;
  322. .change_box {
  323. display: flex;
  324. justify-content: center;
  325. align-items: center;
  326. width: 61px;
  327. border-radius: 2px;
  328. background-color: rgba(114, 151, 179, 0.3);
  329. cursor: pointer;
  330. }
  331. .active {
  332. border: 1px solid #70b7fa;
  333. background-color: rgba(114, 151, 179, 1);
  334. }
  335. }
  336. .msg_detail {
  337. display: flex;
  338. flex-wrap: wrap;
  339. justify-content: space-between;
  340. .detail_box {
  341. display: flex;
  342. flex-direction: column;
  343. align-items: center;
  344. width: 25%;
  345. height: 80px;
  346. .box_num {
  347. font-size: 28px;
  348. font-weight: bold;
  349. }
  350. .box_type {
  351. margin-top: 4px;
  352. font-size: 14px;
  353. }
  354. }
  355. }
  356. }
  357. .bottom_chart {
  358. height: 248px;
  359. }
  360. }
  361. }
  362. </style>