Index.vue 31 KB

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