index.vue 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369
  1. <script setup lang="ts">
  2. import DataCard from "@/views/dashboard/components/DataCard.vue";
  3. import LiquidChart from "@/views/charts-components/LiquidChart.vue";
  4. import CircleChart from "@/views/charts-components/CircleChart.vue";
  5. import PercentBarChart from "@/views/charts-components/PercentBarChart.vue";
  6. import {watch} from "vue";
  7. import {useUserStore} from "@/store/modules/user";
  8. import {getDashboardData, getDashboardTop} from "@/api/dashboard";
  9. import {DashboardCard, DashboardData} from "@/api/dashboard/types";
  10. import {getGradeSelect} from "@/api/grade";
  11. import {GradeList} from "@/api/grade/types";
  12. const userStore = useUserStore();
  13. defineOptions({
  14. name: "DashboardIndex",
  15. inheritAttrs: false,
  16. });
  17. /**
  18. * 数据卡片
  19. */
  20. const cardStatus = ref(false);
  21. const cards = ref<DashboardCard>();
  22. async function getDataCard(schoolId: number) {
  23. getDashboardTop(schoolId)
  24. .then(({ data }) => {
  25. cards.value = data
  26. cardStatus.value = true;
  27. })
  28. .catch((error) => {
  29. console.log(error);
  30. });
  31. }
  32. /**
  33. * 班级数据
  34. */
  35. const gradeData = ref<GradeList[]>();
  36. // 班级编号
  37. let gradeId = ref(0);
  38. async function getGradeData(schoolId: number) {
  39. getGradeSelect(schoolId)
  40. .then(({ data }) => {
  41. gradeData.value = data;
  42. gradeData.value?.unshift({ id: 0, name: "全部班级" })
  43. })
  44. .catch((error) => {
  45. gradeData.value = [];
  46. gradeData.value?.unshift({ id: 0, name: "全部班级" })
  47. console.log(error);
  48. });
  49. }
  50. /**
  51. * 图表数据
  52. */
  53. const chartStatus = ref(false);
  54. const chartMessage = ref("加载中...");
  55. const chartData = ref<DashboardData>();
  56. // let chartData: DashboardData = reactive({
  57. // frontAverage: 0, // 初期专注力估值
  58. // afterAverage: 0, // 近期专注力估值
  59. // front: 0, // 初期50分以上的占比
  60. // after: 0, // 近期50分以上的占比
  61. // frontProportion: { num: [], percentage: [] }, // 初期分期占比分析
  62. // afterProportion: { num: [], percentage: [] }, // 近期分期占比分析
  63. // });
  64. async function getChartData(schoolId:number, gradeId: number) {
  65. chartStatus.value = false;
  66. getDashboardData(schoolId, gradeId)
  67. .then(({ data }) => {
  68. chartData.value = data;
  69. chartStatus.value = true;
  70. })
  71. .catch((error) => {
  72. chartStatus.value = false;
  73. chartMessage.value = error.message;
  74. console.log(error.message);
  75. });
  76. }
  77. // 改变班级重新加载图表数据
  78. function changeGrade() {
  79. getChartData(userStore.schoolId, gradeId.value);
  80. }
  81. onMounted(() => {
  82. // 获取班级
  83. getGradeData(userStore.schoolId);
  84. // 数据卡片
  85. getDataCard(userStore.schoolId);
  86. // 图表数据
  87. getChartData(userStore.schoolId, gradeId.value);
  88. });
  89. watch(
  90. () => userStore.schoolId,
  91. (newValue, oldValue) => {
  92. console.log("userStore.schoolId", newValue, oldValue);
  93. // 学校切换后重新加载数据
  94. gradeId.value = 0;
  95. getGradeData(newValue);
  96. getDataCard(newValue);
  97. getChartData(newValue,0);
  98. }
  99. );
  100. </script>
  101. <template>
  102. <div class="dashboard-container">
  103. <!-- 数据卡片 -->
  104. <template v-if="cardStatus">
  105. <DataCard
  106. :key="cards.toString()"
  107. :classes="cards.grade"
  108. :teachers="cards.teacher"
  109. :students="cards.student"
  110. :equipments="cards.equipment"
  111. :trainings="cards.game"
  112. />
  113. </template>
  114. <!-- 班级选择 及 案例展示 -->
  115. <div class="class-select clear">
  116. <el-select
  117. v-model="gradeId"
  118. placeholder="全部班级"
  119. size="large"
  120. @change="changeGrade()"
  121. >
  122. <el-option
  123. v-for="item in gradeData"
  124. :key="item.id"
  125. :label="item.name"
  126. :value="item.id"
  127. />
  128. </el-select>
  129. <router-link to="/dashboard/example">优秀教学效果示例</router-link>
  130. </div>
  131. <!-- Echarts 图表 -->
  132. <el-row v-if="chartStatus" :gutter="20">
  133. <el-col :md="24" :lg="8" :xl="8">
  134. <div class="charts-item">
  135. <p class="title">学员专注力平均值整体对比分析</p>
  136. <el-row justify="space-between">
  137. <el-col :xs="24" :sm="12">
  138. <div class="item">
  139. <LiquidChart
  140. id="liquidChart1"
  141. :key="chartData.frontAverage"
  142. :data="chartData.frontAverage || 0"
  143. height="200px"
  144. width="200px"
  145. color="#3a7fc2"
  146. bg-color="#accded"
  147. class="chart"
  148. />
  149. <p>全体学员初期</p>
  150. <p>专注力评估均值</p>
  151. </div>
  152. </el-col>
  153. <el-col :xs="24" :sm="12">
  154. <div class="item">
  155. <LiquidChart
  156. id="liquidChart2"
  157. :key="chartData.afterAverage"
  158. :data="chartData.afterAverage ? chartData.afterAverage : 0"
  159. height="200px"
  160. width="200px"
  161. color="#5563ac"
  162. bg-color="#cacce6"
  163. class="chart"
  164. />
  165. <p>全体学员训练近期</p>
  166. <p>专注力评估均值</p>
  167. </div>
  168. </el-col>
  169. </el-row>
  170. <el-row justify="space-between">
  171. <el-col :xs="24" :sm="12">
  172. <div class="item">
  173. <CircleChart
  174. id="circleChart1"
  175. :key="chartData.front"
  176. :data="chartData.front ? chartData.front : 0"
  177. height="200px"
  178. width="200px"
  179. color="#3a7fc2"
  180. bg-color="#e4e7f4"
  181. font-color="#3a7fc2"
  182. font-size="30px"
  183. :round-cap="Boolean(true)"
  184. />
  185. <p>初期训练</p>
  186. <p>专注力50以上人数比例</p>
  187. </div>
  188. </el-col>
  189. <el-col :xs="24" :sm="12">
  190. <div class="item">
  191. <CircleChart
  192. id="circleChart2"
  193. :key="chartData.after.toString()"
  194. :data="chartData.after ? chartData.after : 0"
  195. height="200px"
  196. width="200px"
  197. color="#5563ac"
  198. bg-color="#e4e7f4"
  199. font-color="#5563ac"
  200. font-size="30px"
  201. :round-cap="Boolean(true)"
  202. />
  203. <p>近期训练</p>
  204. <p>专注力50以上人数比例</p>
  205. </div>
  206. </el-col>
  207. </el-row>
  208. </div>
  209. </el-col>
  210. <!-- 学员专注力评分分级占比分析 -->
  211. <el-col :md="24" :lg="16" :xl="16">
  212. <div class="charts-item">
  213. <p class="title">学员专注力评分分级占比分析</p>
  214. <el-row justify="space-between">
  215. <el-col :xs="24" :sm="24" :md="12" :lg="12" :xl="12">
  216. <div class="bar">
  217. <PercentBarChart
  218. id="barChart1"
  219. :key="chartData.frontProportion.toString()"
  220. width="400px"
  221. height="500px"
  222. title="全体学员初期训练专注力评分占比"
  223. :percent="chartData.frontProportion.percentage"
  224. :data="chartData.frontProportion.num"
  225. class="chart"
  226. />
  227. </div>
  228. </el-col>
  229. <el-col :xs="24" :sm="24" :md="12" :lg="12" :xl="12">
  230. <div class="bar">
  231. <PercentBarChart
  232. id="barChart2"
  233. :key="chartData.afterProportion.toString()"
  234. width="400px"
  235. height="500px"
  236. title="全体学员训练近期专注力评分平均占比"
  237. :percent="chartData.afterProportion.percentage"
  238. :data="chartData.afterProportion.num"
  239. class="chart"
  240. />
  241. </div>
  242. </el-col>
  243. </el-row>
  244. </div>
  245. </el-col>
  246. </el-row>
  247. <el-row v-else :gutter="20">
  248. <el-col :md="24" :lg="8">
  249. <div class="charts-item">
  250. <p class="title">学员专注力平均值整体对比分析</p>
  251. <!-- <div v-if="dataStatus == 2" class="empty">-->
  252. <!-- <p>筛选条件的学生人群训练3次以上才能进行训练数据分析,</p>-->
  253. <!-- <p>当前训练数据不足以进行数据分析!</p>-->
  254. <!-- </div>-->
  255. <!-- <div v-if="dataStatus == 3" class="empty">-->
  256. <!-- <p class="red">合作已过期,无法进行数据看板的查看!</p>-->
  257. <!-- </div>-->
  258. <!-- <div v-if="dataStatus == 4" class="empty">-->
  259. <!-- <p>您的学校还没有任何训练数据!</p>-->
  260. <!-- </div>-->
  261. <div class="empty">
  262. <img src="../../assets/empty.png" alt="数据为空">
  263. <p>{{ chartMessage }}</p>
  264. </div>
  265. </div>
  266. </el-col>
  267. <el-col :md="24" :lg="16">
  268. <div class="charts-item">
  269. <p class="title">学员专注力评分分级占比分析</p>
  270. <!-- <div v-if="dataStatus == 2" class="empty">-->
  271. <!-- <p>筛选条件的学生人群训练3次以上才能进行训练数据分析,</p>-->
  272. <!-- <p>当前训练数据不足以进行数据分析!</p>-->
  273. <!-- </div>-->
  274. <!-- <div v-if="dataStatus == 3" class="empty">-->
  275. <!-- <p class="red">合作已过期,无法进行数据看板的查看!</p>-->
  276. <!-- </div>-->
  277. <!-- <div v-if="dataStatus == 4" class="empty">-->
  278. <!-- <p>您的学校还没有任何训练数据!</p>-->
  279. <!-- </div>-->
  280. <div class="empty">
  281. <img src="../../assets/empty.png" alt="数据为空">
  282. <p>{{ chartMessage }}</p>
  283. </div>
  284. </div>
  285. </el-col>
  286. </el-row>
  287. </div>
  288. </template>
  289. <style lang="scss" scoped>
  290. .dashboard-container {
  291. position: relative;
  292. padding: 30px;
  293. }
  294. .class-select {
  295. margin: 30px auto;
  296. .el-select {
  297. width: 160px;
  298. margin: 0 20px 0 0;
  299. }
  300. a {
  301. display: inline-block;
  302. height: 38px;
  303. line-height: 38px;
  304. padding: 0 30px;
  305. background: #4284f2;
  306. border-radius: 12px;
  307. color: #ffffff;
  308. }
  309. }
  310. /* 自定义 el-select 样式 */
  311. :deep(.el-input__wrapper) {
  312. background: #ffffff;
  313. border-radius: 12px;
  314. }
  315. /* el-select 各种边框线隐藏**/
  316. :deep(.el-select) {
  317. --el-select-input-focus-border-color: none !important;
  318. }
  319. :deep(.el-input__wrapper) {
  320. box-shadow: none !important;
  321. }
  322. :deep(.el-select .el-input__wrapper.is-focus) {
  323. box-shadow: none !important;
  324. }
  325. :deep(.el-select:hover:not(.el-select--disabled) .el-input__wrapper) {
  326. box-shadow: none !important;
  327. }
  328. .charts-item {
  329. background: #ffffff;
  330. border: 1px solid #e8eaec;
  331. border-radius: 24px;
  332. text-align: center;
  333. position: relative;
  334. .title {
  335. margin: 0;
  336. height: 78px;
  337. line-height: 78px;
  338. text-align: left;
  339. text-indent: 2em;
  340. font-size: 18px;
  341. }
  342. .item {
  343. padding-bottom: 30px;
  344. }
  345. .chart {
  346. margin: 0 auto;
  347. }
  348. p {
  349. margin: 0;
  350. line-height: 24px;
  351. font-size: 16px;
  352. }
  353. .bar {
  354. margin-top: 60px;
  355. }
  356. .empty {
  357. padding: 200px 0;
  358. }
  359. }
  360. </style>