Index.vue 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865
  1. <template>
  2. <el-skeleton :loading="loading" animated>
  3. <el-row :gutter="8">
  4. <!-- 第一部分 -->
  5. <el-col :xs="24" :sm="24" :md="24" :lg="14" :xl="10">
  6. <el-card class="h-940px mb-10px">
  7. <el-card shadow="never" class="h-100%">
  8. <template #header>
  9. <div class="h-7 flex justify-between fw-800 text-20px">
  10. <span>基本信息</span>
  11. </div>
  12. </template>
  13. <el-row style="flex-wrap: wrap; ">
  14. <el-col v-for="(item, index) in projects" :key="`card-${index}`" :xs="24" :sm="24" :md="24" :lg="8" :xl="8">
  15. <el-card shadow="hover" class="mr-5px mt-5px " style="background-color:#2585a6 ">
  16. <div class="flex items-center h-75px ">
  17. <!-- <Icon :icon="item.icon" :size="25" class="mr-8px" /> -->
  18. <Icon :icon="item.icon" :size="38" class="mr-8px " />
  19. <span class="text-17px c-white">{{ item.name }}</span>
  20. </div>
  21. <div class="mb-18px text-32px c-white ml-20px text-center">{{ t(item.message) }}</div>
  22. <!-- <div class="mt-12px flex justify-between text-12px text-gray-400"> </div> -->
  23. </el-card>
  24. </el-col>
  25. </el-row>
  26. </el-card>
  27. <el-card shadow="never" class=" h-100% mt-10px ">
  28. <template #header>
  29. <div class="h-5 flex justify-between fw-800 text-20px">
  30. <span>实时出勤统计</span>
  31. </div>
  32. </template>
  33. <el-card shadow="never" class="ml-2px pr-10px mt-10px" style="background-color:#33a3dc ;opacity: 0.8; ">
  34. <div class="h-70px flex items-center justify-center flex-wrap mt-10px c-white">
  35. <div class="px-25px text-center" style="margin: auto;">
  36. <div class="mb-16px text-18px text-white ">打卡人数</div>
  37. <CountTo class="text-28px" :start-val="0" :end-val="totalSate.normalNum" :duration="2600" />
  38. </div>
  39. <el-divider direction="vertical" border-style="dashed" />
  40. <div class="px-8px text-center" style="margin: auto;">
  41. <div class="mb-16px text-18px text-white ">未打卡人数</div>
  42. <CountTo class="text-28px" :start-val="0" :end-val="totalSate.errorNum" :duration="2600" />
  43. </div>
  44. <!-- <el-divider direction="vertical" border-style="dashed" />-->
  45. <!-- <div class="px-8px text-center" style="margin: auto;">-->
  46. <!-- <div class="mb-16px text-18px text-white ">请假人数</div>-->
  47. <!-- <CountTo class="text-28px" :start-val="0" :end-val="totalSate.excuseNum" :duration="2600" />-->
  48. <!-- </div>-->
  49. </div>
  50. </el-card>
  51. </el-card>
  52. <el-card shadow="hover" class=" mt-10px">
  53. <template #header>
  54. <div class="h-5 flex justify-between fw-800 text-20px">
  55. <span>毕业条件达成统计</span>
  56. </div>
  57. </template>
  58. <el-skeleton :loading="loading" animated>
  59. <Echart :options="pieOptionsData" :height="250" />
  60. </el-skeleton>
  61. </el-card>
  62. </el-card>
  63. </el-col>
  64. <!-- 第二部分 -->
  65. <el-col :xs="24" :sm="24" :md="24" :lg="10" :xl="7" class="h-480px">
  66. <!-- 第一个el-row -->
  67. <el-row :gutter="15">
  68. <el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24">
  69. <el-card shadow="never" class=" mb-10px h-465px ">
  70. <template #header>
  71. <div class="h-7 flex justify-between fw-800 text-20px">
  72. <span>周出勤情况</span>
  73. </div>
  74. </template>
  75. <el-card shadow="hover" class=" h-365px ">
  76. <el-skeleton :loading="loading" animated >
  77. <Echart :options="barOptionsData" :height="350" style="margin-top: -30px;"/>
  78. </el-skeleton>
  79. </el-card>
  80. </el-card>
  81. </el-col>
  82. <el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24">
  83. <el-card shadow="never" class="mb-10px h-465px ">
  84. <template #header>
  85. <div class="h-7 flex justify-between fw-800 text-20px">
  86. <span>实时打卡状态</span>
  87. </div>
  88. </template>
  89. <div class="demo">
  90. <div class="table-header">
  91. <div class="header">
  92. <el-row class="shouye" style="border: none;">
  93. <el-col :span="6" class="center text-18px" style="border: none;">
  94. <div>姓名</div>
  95. </el-col>
  96. <el-col :span="6" class="center text-18px" style="border: none;">
  97. <div>学号</div>
  98. </el-col>
  99. <el-col :span="6" class="center text-18px" style="border: none;">
  100. <div>工作间</div>
  101. </el-col>
  102. <el-col :span="6" class="center text-18px" style="border: none;">
  103. <div>打卡时间</div>
  104. </el-col>
  105. <!-- <el-col :span="10" class="center text-18px" style="border: none;">
  106. <div>缺勤时间段</div>
  107. </el-col> -->
  108. </el-row>
  109. </div>
  110. </div>
  111. <vue3ScrollSeamless v-if="list.length > 0" class="scroll-wrap text-color" :classOptions="classOptions" :dataList="list">
  112. <div v-if="list.length > 0">
  113. <el-row
  114. v-for="(item, i) of list" :key="i" class="shouye"
  115. style="margin-bottom: 10px; display: flex; justify-content: center;">
  116. <el-col
  117. :span="6" class="center"
  118. style="display: flex; justify-content: center; align-items: center; padding: 6px;">
  119. <div>{{ item.studentName }}</div>
  120. </el-col>
  121. <el-col
  122. :span="6" class="center"
  123. style="display: flex; justify-content: center; align-items: center; padding: 6px;">
  124. <div>{{ item.userNumber }}</div>
  125. </el-col>
  126. <el-col
  127. :span="6" class="center"
  128. style="display: flex; justify-content: center; align-items: center; padding: 6px;">
  129. <div>{{ item.daptName }}</div>
  130. </el-col>
  131. <el-col
  132. :span="6" class="center"
  133. style="display: flex; justify-content: center; align-items: center; padding: 6px;">
  134. <div>{{ formatDate(item.clockInTime) }}</div>
  135. </el-col>
  136. </el-row>
  137. </div>
  138. <!-- <div v-if="list.length == 0"
  139. style="width: 100%; height: 100px; display: flex; justify-content: center; align-items: center; color: white; font-size: 18px;">
  140. 暂无预测记录
  141. </div> -->
  142. </vue3ScrollSeamless>
  143. <div v-if="list.length == 0" style="width: 100%; height: 100px; display: flex; justify-content: center; align-items: center; margin-top: -230px;">
  144. <el-empty description="暂无数据"/>
  145. </div>
  146. </div>
  147. </el-card>
  148. </el-col>
  149. </el-row>
  150. </el-col>
  151. <!-- 第二个el-row -->
  152. <el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="7">
  153. <el-row :gutter="15" align="center">
  154. <el-col :xs="24" :sm="24" :md="24" :lg="12" :xl="24">
  155. <el-card shadow="never" class=" h-465px mb-10px "> <!-- 移除 el-card 的边框 -->
  156. <template #header>
  157. <div class="h-7 flex justify-between fw-800 text-20px">
  158. <span>缺勤预警</span>
  159. </div>
  160. </template>
  161. <div class="demos">
  162. <div class="table-header">
  163. <div class="header">
  164. <el-row class="shouye" style="border: none;">
  165. <el-col :span="6" class="center text-18px" style="border: none;">
  166. <div>姓名</div>
  167. </el-col>
  168. <el-col :span="6" class="center text-18px" style="border: none;">
  169. <div>学号</div>
  170. </el-col>
  171. <el-col :span="6" class="center text-18px" style="border: none;">
  172. <div>工作间</div>
  173. </el-col>
  174. <el-col :span="6" class="center text-18px" style="border: none;">
  175. <div>导师</div>
  176. </el-col>
  177. <!-- <el-col :span="10" class="center text-18px" style="border: none;">
  178. <div>缺勤时间段</div>
  179. </el-col> -->
  180. </el-row>
  181. </div>
  182. </div>
  183. <vue3ScrollSeamless v-if="list2.length > 0" class="scroll-wraps text-color" :classOptions="class2Options" :dataList="list2">
  184. <div v-if="list2.length > 0">
  185. <el-row v-for="(item, i) of list2" :key="i" class="shouye" >
  186. <!-- <el-col :span="6" class="center" style="padding: 10px; border: none;">
  187. <div>{{ item.ID }}</div>
  188. </el-col> -->
  189. <el-col :span="6" class="center" style="padding: 10px; border: none;">
  190. <div>{{ item.studentName }}</div>
  191. </el-col>
  192. <el-col :span="6" class="center" style="padding: 10px; border: none;">
  193. <div>{{ item.userNumber }}</div>
  194. </el-col>
  195. <el-col :span="6" class="center" style="padding: 10px; border: none;">
  196. <div>{{ item.deptName }}</div>
  197. </el-col>
  198. <el-col :span="6" class="center" style="padding: 10px; border: none;">
  199. <div>{{ item.supervisor }}</div>
  200. </el-col>
  201. </el-row>
  202. </div>
  203. <!-- <div v-if="list2.length == 0"
  204. style="width: 100%; height: 100px; display: flex; justify-content: center; align-items: center; color: white; font-size: 18px;">
  205. 暂无预测记录
  206. </div> -->
  207. </vue3ScrollSeamless>
  208. <div v-if="list2.length == 0" style="width: 100%; height: 100px; display: flex; justify-content: center; align-items: center; margin-top: -230px;">
  209. <el-empty description="暂无数据"/>
  210. </div>
  211. </div>
  212. </el-card>
  213. </el-col>
  214. <el-col :xs="24" :sm="24" :md="24" :lg="12" :xl="24">
  215. <el-card shadow="never" class=" mt-1px h-465px ">
  216. <template #header>
  217. <div class="h-7 flex justify-between fw-800 text-20px">
  218. <span>学生毕业条件达成率</span>
  219. </div>
  220. </template>
  221. <div class="demoss">
  222. <div class="header">
  223. <el-row class="shouye h-25px" style="border: none;">
  224. <el-col :span="12" class="center text-18px" style="border: none;padding: 8px;margin-left: 5px; margin-top: -5px;">
  225. <div>工作间</div>
  226. </el-col>
  227. <el-col :span="12" class="center text-18px" style="border: none;padding: 8px;margin-left: -35px; margin-top: -5px;">
  228. <div>达成率</div>
  229. </el-col>
  230. </el-row>
  231. </div>
  232. <vue3ScrollSeamless class="scroll-wrapss text-color" :classOptions="list1Options" :dataList="list1" v-if="list1.length > 0">
  233. <div v-if="list1.length > 0">
  234. <el-row v-for="(item, i) of list1" :key="i" class="shouye" :style="{ marginBottom: '10px' }">
  235. <!-- 增加行与行之间的间距 -->
  236. <el-col :span="12" class="center" style="padding: 8px;"> <!-- 增加内边距 -->
  237. <div>{{ item.name }}</div>
  238. </el-col>
  239. <el-col :span="12" class="center" style="padding: 8px;">
  240. <div>{{ item.graduationRate }}%</div>
  241. </el-col>
  242. </el-row>
  243. </div>
  244. <div
  245. v-if="list1.length == 0"
  246. style="width: 100%; height: 100px; display: flex; justify-content: center; align-items: center; color: white; font-size: 18px;">
  247. 暂无预测记录
  248. </div>
  249. </vue3ScrollSeamless>
  250. </div>
  251. </el-card>
  252. </el-col>
  253. </el-row>
  254. </el-col>
  255. </el-row>
  256. </el-skeleton>
  257. </template>
  258. <script lang="ts" setup>
  259. import { EChartsOption, List } from 'echarts'
  260. import { formatTime } from '@/utils'
  261. import {formatDate} from "@/utils/formatTime";
  262. import { useUserStore } from '@/store/modules/user'
  263. import { useWatermark } from '@/hooks/web/useWatermark'
  264. import type { WorkplaceTotal, Project, Notice, Shortcut } from './types'
  265. import { pieOptions, barOptions } from './echarts-data'
  266. import { reactive, onMounted, watchEffect } from "vue";
  267. import {vue3ScrollSeamless} from "vue3-scroll-seamless";
  268. import * as UserApi from '@/api/system/user'
  269. import * as DeptApi from '@/api/system/dept'
  270. import { StudentAttendanceApi } from '@/api/system/studentAttendance'
  271. defineOptions({ name: 'Home' })
  272. const { t } = useI18n()
  273. const userStore = useUserStore()
  274. const { setWatermark } = useWatermark()
  275. const loading = ref(true)
  276. const avatar = userStore.getUser.avatar
  277. const username = userStore.getUser.nickname
  278. /*基本信息*/
  279. const detail = reactive({
  280. deptNum: undefined,
  281. teacherNum: undefined,
  282. studentNum: undefined
  283. })
  284. const getDetail = async () => {
  285. const data = await UserApi.getDetail()
  286. console.log("基本信息", data);
  287. detail.deptNum = data.deptNum
  288. detail.teacherNum = data.teacherNum
  289. detail.studentNum = data.studentNum
  290. }
  291. // 获取项目数
  292. let projects = reactive<Project[]>([])
  293. const getProject = async () => {
  294. const data = [
  295. {
  296. name: '学院工作间数量',
  297. icon: 'svg-icon:gzs',
  298. message: String(detail.deptNum) + '个',
  299. time: new Date()
  300. },
  301. {
  302. name: '导师数量',
  303. icon: 'svg-icon:ds',
  304. message: String(detail.teacherNum) + '人',
  305. time: new Date()
  306. },
  307. {
  308. name: '在校生数量',
  309. icon: 'svg-icon:zxs',
  310. message: String(detail.studentNum) + '人',
  311. time: new Date()
  312. }
  313. ]
  314. projects = Object.assign(projects, data)
  315. }
  316. /**实时出勤统计 */
  317. // 获取统计数
  318. let totalSate = reactive<WorkplaceTotal>({
  319. normalNum: 0,
  320. errorNum: 0,
  321. excuseNum: 0,
  322. })
  323. const getCount = async () => {
  324. const data = await StudentAttendanceApi.getDayAttendance()
  325. console.log("实时出勤统计", data);
  326. totalSate = Object.assign(totalSate, data)
  327. }
  328. // /**毕业达成统计 */
  329. let pieOptionsData = reactive<EChartsOption>(pieOptions) as EChartsOption
  330. const getGraduateCount = async () => {
  331. const data = await UserApi.getGraduateCount()
  332. console.log("毕业达成统计", data);
  333. const studentNum = data.studentNum;
  334. const graduateNum = data.graduateNum;
  335. const options = {
  336. title: {
  337. text: null,
  338. left: 'center',
  339. top: '20px'
  340. },
  341. tooltip: {
  342. trigger: 'item',
  343. },
  344. legend: {
  345. top: '10%', // 顶部位置
  346. left: 'left', // 左侧位置
  347. },
  348. series: [
  349. {
  350. type: 'pie',
  351. radius: ['120px', '70px'], // 设定内圈和外圈半径
  352. center: ['50%', '85%'], // 中心位置
  353. startAngle: 180,
  354. endAngle: 360,
  355. data: [
  356. {
  357. value: graduateNum, // 畢業生数量
  358. name: '已达成', // 国际化名称或直接用字符串 '毕业生'
  359. label: {
  360. show: true,
  361. position: 'outside', // 拉出标注
  362. formatter: '{b}: {c}', // 显示名称和数值
  363. emphasis: {
  364. show: true,
  365. },
  366. },
  367. labelLine: {
  368. show: true,
  369. length: 75,
  370. length2: 10,
  371. smooth: true,
  372. lineDash: [5, 5],
  373. },
  374. },
  375. {
  376. value: studentNum, // 在校生数量(总在校生减去毕业生)
  377. name: '未达成', // 国际化名称或直接用字符串 '在校生'
  378. label: {
  379. show: true,
  380. position: 'outside',
  381. formatter: '{b}: {c}',
  382. emphasis: {
  383. show: true,
  384. },
  385. },
  386. labelLine: {
  387. show: true,
  388. length: 75,
  389. length2: 10,
  390. smooth: true,
  391. lineDash: [5, 5],
  392. },
  393. },
  394. ],
  395. itemStyle: {
  396. // 设置饼图的颜色
  397. color: function (params) {
  398. const colorList = ['#2585a6','#5cb5e3' ]; // 定义颜色数组
  399. return colorList[params.dataIndex]; // 根据数据索引返回对应的颜色
  400. }
  401. }
  402. },
  403. ],
  404. };
  405. // // set(
  406. // // pieOptionsData,
  407. // // 'legend.data',
  408. // // data.map((v) => t(v.name))
  409. // // );
  410. pieOptionsData = Object.assign(pieOptionsData, options);
  411. };
  412. /**周出勤情况 */
  413. let barOptionsData = reactive<EChartsOption>(barOptions) as EChartsOption
  414. const getWeekend = async () => {
  415. const data = await StudentAttendanceApi.getWeekendAttendance();
  416. console.log("周出勤情况", data);
  417. const normalData = data.dailyNormalList
  418. const errorData = data.dailyErrorList;
  419. const excuseData = data.dailyExcuseList;
  420. barOptionsData.series[0].data = normalData;
  421. barOptionsData.series[1].data = errorData;
  422. barOptionsData.series[2].data = excuseData;
  423. };
  424. /**缺勤预警 */
  425. let list2 = reactive([]);
  426. const getStudentAttendanceError = async () => {
  427. const data = await StudentAttendanceApi.getDayStudentErrorAttendance()
  428. console.log("缺勤列表", data);
  429. list2.splice(0, list2.length, ...data);
  430. }
  431. const class2Options = reactive({
  432. step: 0.5,//滚动速度值越大越快,但是值太小会卡顿
  433. limitMoveNum: list2.length,//无缝滚动列表元素的长度,一般设置为列表的长度
  434. direction: 1,//方向: 0 往下 1 往上 2 向左 3 向右。
  435. });
  436. /**实时打卡状态 */
  437. //打卡滚动列表
  438. const list = reactive([]);
  439. const getStudentAttendance = async () => {
  440. const data = await StudentAttendanceApi.getDayStudentAttendance()
  441. console.log("打卡列表", data);
  442. list.splice(0, list.length, ...data);
  443. }
  444. const classOptions = reactive({
  445. step: 0.5,//滚动速度值越大越快,但是值太小会卡顿
  446. limitMoveNum: list.length,//无缝滚动列表元素的长度,一般设置为列表的长度
  447. direction: 1,//方向: 0 往下 1 往上 2 向左 3 向右。
  448. });
  449. /** 学生毕业条件达成率 */
  450. //在线情况滚动列表
  451. const list1 = reactive([]);
  452. const getGraduationSource = async () => {
  453. const data = await DeptApi.getGraduationSource()
  454. console.log("毕业条件达成率", data);
  455. list1.splice(0, list1.length, ...data);
  456. }
  457. const list1Options = reactive({
  458. step: 0.5,//滚动速度值越大越快,但是值太小会卡顿
  459. limitMoveNum: list1.length,//无缝滚动列表元素的长度,一般设置为列表的长度
  460. direction: 1,//方向: 0 往下 1 往上 2 向左 3 向右。
  461. });
  462. onMounted(() => {
  463. getDetail()
  464. getWeekend()
  465. getProject()
  466. getCount()
  467. getStudentAttendanceError()
  468. getStudentAttendance()
  469. getGraduationSource()
  470. getGraduateCount()
  471. })
  472. // // 获取通知公告
  473. // let notice = reactive<Notice[]>([])
  474. // const getNotice = async () => {
  475. // const data = [
  476. // {
  477. // title: '系统支持 JDK 8/17/21,Vue 2/3',
  478. // type: '通知',
  479. // keys: ['通知', '8', '17', '21', '2', '3'],
  480. // date: new Date()
  481. // },
  482. // {
  483. // title: '后端提供 Spring Boot 2.7/3.2 + Cloud 双架构',
  484. // type: '公告',
  485. // keys: ['公告', 'Boot', 'Cloud'],
  486. // date: new Date()
  487. // },
  488. // {
  489. // title: '全部开源,个人与企业可 100% 直接使用,无需授权',
  490. // type: '通知',
  491. // keys: ['通知', '无需授权'],
  492. // date: new Date()
  493. // },
  494. // {
  495. // title: '国内使用最广泛的快速开发平台,超 300+ 人贡献',
  496. // type: '公告',
  497. // keys: ['公告', '最广泛'],
  498. // date: new Date()
  499. // }
  500. // ]
  501. // notice = Object.assign(notice, data)
  502. // }
  503. // // 获取基本信息
  504. // let basic = reactive<Basic[]>([])
  505. // const getBasic = async () => {
  506. // const data = [
  507. // {
  508. // title: '学院工作间数量',
  509. // type: '通知',
  510. // keys: ['通知', '8', '17', '21', '2', '3'],
  511. // date: new Date()
  512. // },
  513. // {
  514. // title: '硕士研究生数量',
  515. // type: '公告',
  516. // keys: ['公告', 'Boot', 'Cloud'],
  517. // date: new Date()
  518. // },
  519. // {
  520. // title: '博士研究生数量',
  521. // type: '通知',
  522. // keys: ['通知', '无需授权'],
  523. // date: new Date()
  524. // },
  525. // {
  526. // title: '硕士研究生导师数量',
  527. // type: '公告',
  528. // keys: ['公告', '最广泛'],
  529. // date: new Date()
  530. // },
  531. // {
  532. // title: '博士生导师数量',
  533. // type: '公告',
  534. // keys: ['公告', '最广泛'],
  535. // date: new Date()
  536. // }
  537. // ]
  538. // basic = Object.assign(basic, data)
  539. // }
  540. // 获取快捷入口
  541. // let shortcut = reactive<Shortcut[]>([])
  542. // const getShortcut = async () => {
  543. // const data = [
  544. // {
  545. // name: 'Github',
  546. // icon: 'akar-icons:github-fill',
  547. // url: 'github.io'
  548. // },
  549. // {
  550. // name: 'Vue',
  551. // icon: 'logos:vue',
  552. // url: 'vuejs.org'
  553. // },
  554. // {
  555. // name: 'Vite',
  556. // icon: 'vscode-icons:file-type-vite',
  557. // url: 'https://vitejs.dev/'
  558. // },
  559. // {
  560. // name: 'Angular',
  561. // icon: 'logos:angular-icon',
  562. // url: 'github.io'
  563. // },
  564. // {
  565. // name: 'React',
  566. // icon: 'logos:react',
  567. // url: 'github.io'
  568. // },
  569. // {
  570. // name: 'Webpack',
  571. // icon: 'logos:webpack',
  572. // url: 'github.io'
  573. // }
  574. // ]
  575. // shortcut = Object.assign(shortcut, data)
  576. // }
  577. // 用户来源
  578. // const getUserAccessSource = async () => {
  579. // const data = [
  580. // { value: 1048, name: '达成人数' },
  581. // { value: 735, name: '未达成人数' },
  582. // ];
  583. // const options = {
  584. // title: {
  585. // text: null,
  586. // left: 'center',
  587. // top: '20px'
  588. // },
  589. // tooltip: {
  590. // trigger: 'item',
  591. // },
  592. // legend: {
  593. // top: '10%', // 顶部位置
  594. // left: 'left', // 左侧位置
  595. // },
  596. // series: [
  597. // {
  598. // type: 'pie',
  599. // radius: ['120px', '70px'], // 设定内圈和外圈半径
  600. // center: ['50%', '85%'], // 中心位置
  601. // startAngle: 180,
  602. // endAngle: 360,
  603. // data: data.map(v => ({
  604. // value: v.value,
  605. // name: t(v.name),
  606. // label: {
  607. // show: true,
  608. // position: 'outside', // 拉出标注
  609. // formatter: '{b}: {c}', // 显示名称和数值
  610. // // 可以自定义引线的样式
  611. // emphasis: {
  612. // show: true,
  613. // },
  614. // },
  615. // // 自定义引线样式
  616. // labelLine: {
  617. // show: true,
  618. // length: 75, // 引线长度
  619. // length2: 10, // 后半段引线的长度
  620. // smooth: true, // 引线是否平滑
  621. // lineDash: [5, 5], // 引线虚线样式
  622. // },
  623. // })),
  624. // itemStyle: {
  625. // // 设置饼图的颜色
  626. // color: function (params) {
  627. // const colorList = ['#94d6da', '#00a6ac']; // 定义颜色数组
  628. // return colorList[params.dataIndex]; // 根据数据索引返回对应的颜色
  629. // }
  630. // }
  631. // },
  632. // ],
  633. // };
  634. // set(
  635. // pieOptionsData,
  636. // 'legend.data',
  637. // data.map((v) => t(v.name))
  638. // );
  639. // pieOptionsData = Object.assign(pieOptionsData, options);
  640. // };
  641. // 周活跃量
  642. // const getWeeklyUserActivity = async () => {
  643. // const data = [
  644. // { value: 13253, name: '异常人数' },
  645. // { value: 34235, name: '正常人数' },
  646. // ];
  647. // const options = {
  648. // title: {
  649. // text: null,
  650. // },
  651. // tooltip: {
  652. // trigger: 'item',
  653. // },
  654. // grid: {
  655. // left: '80px',
  656. // top: '10px', // 上方偏移
  657. // },
  658. // series: [
  659. // {
  660. // name: '人数',
  661. // type: 'bar',
  662. // barWidth: '40%', // 设置柱子的宽度为40%
  663. // data: data.map((v) => v.value), // 设置Y轴数据
  664. // itemStyle: {
  665. // // 设置每个柱状的颜色
  666. // color: function (params) {
  667. // const colorList = ['#145b7d', '#33a3dc']; // 定义颜色数组
  668. // return colorList[params.dataIndex]; // 根据数据索引返回对应的颜色
  669. // }
  670. // }
  671. // }
  672. // ]
  673. // };
  674. // set(
  675. // barOptionsData,
  676. // 'xAxis.data',
  677. // data.map((v) => t(v.name))
  678. // );
  679. // barOptionsData = Object.assign(barOptionsData, options);
  680. // };
  681. const getAllApi = async () => {
  682. await Promise.all([
  683. await getDetail(),
  684. getCount(),
  685. getProject(),
  686. getWeekend(),
  687. getStudentAttendanceError(),
  688. getStudentAttendance(),
  689. getGraduationSource(),
  690. getGraduateCount(),
  691. // getNotice(),
  692. // getBasic(),
  693. // getShortcut(),
  694. // getUserAccessSource(),
  695. // getWeeklyUserActivity()
  696. ])
  697. loading.value = false
  698. }
  699. getAllApi()
  700. </script>
  701. <style scoped>
  702. .center {
  703. text-align: center;
  704. }
  705. /* 滚动列表 */
  706. .title-container {
  707. display: flex;
  708. align-items: center;
  709. justify-content: center;
  710. height: 20px;
  711. margin-bottom: 30px;
  712. }
  713. .title {
  714. font-size: 19px;
  715. }
  716. .demo {
  717. width: 99%;
  718. height: 362px;
  719. }
  720. .demos {
  721. width: 95%;
  722. height: 100%;
  723. }
  724. .demoss {
  725. width: 95%;
  726. height: 100%;
  727. }
  728. .scroll-wrap {
  729. width: 100%;
  730. height: 330px;
  731. margin: 0 auto;
  732. overflow: hidden;
  733. /* background-color: #feeeed; */
  734. opacity: 0.6;
  735. font-size: 15px;
  736. margin-top: 20px;
  737. margin-left: 18px;
  738. }
  739. .scroll-wraps {
  740. width: 101%;
  741. height: 350px;
  742. margin: 0 auto;
  743. overflow: hidden;
  744. opacity: 0.6;
  745. font-size: 15px;
  746. border: none;
  747. margin-top: 20px;
  748. }
  749. .scroll-wrapss {
  750. width: 90%;
  751. height: 350px;
  752. margin: 0 auto;
  753. overflow: hidden;
  754. /* background-color: rgba(198, 204, 238, 0.3); */
  755. /* background-color: #feeeed; */
  756. opacity: 0.6;
  757. font-size: 15px;
  758. margin-top: 10px;
  759. }
  760. /* 轮播图的导航条
  761. .table-header {
  762. font-family: Arial, sans-serif;
  763. height: 30px;
  764. display: flex;
  765. align-items: center;
  766. border: 1px solid;
  767. width: 280px;
  768. flex-wrap: nowrap;
  769. padding-right: 10px;
  770. }
  771. .header {
  772. width: 660px;
  773. font-size: 16px;
  774. } */
  775. .border {
  776. border: 1px solid;
  777. }
  778. .center {
  779. display: flex;
  780. align-items: center;
  781. justify-content: center;
  782. }
  783. /* .text-color {
  784. color: rgb(15, 131, 233);
  785. } */
  786. .shouye {
  787. flex-wrap: nowrap;
  788. border-bottom: 1px solid;
  789. }
  790. ::v-deep .el-divider.el-divider--vertical {
  791. border-left: 1px solid white;
  792. }
  793. </style>