Home.vue 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438
  1. <template>
  2. <div class="app-container">
  3. <a-spin :spinning="loading1 || loading2">
  4. <!-- 基础数据展示 -->
  5. <div class="count-basic-data">
  6. <div
  7. class="count-basic-data-item"
  8. v-for="(item, index) in basicList"
  9. :key="index"
  10. >
  11. <div class="count-basic-data-item-main">
  12. <div class="count-basic-data-item-title">{{ item.title }}</div>
  13. <div class="count-basic-data-item-count">
  14. {{ item.count | formatNumberToDollar }}
  15. </div>
  16. </div>
  17. <div class="count-basic-data-item-up">
  18. <div class="count-basic-data-item-title">{{ item.upTitle }}</div>
  19. <div class="count-basic-data-item-up-count">
  20. {{ item.monthUp | formatNumberToDollar }}
  21. </div>
  22. </div>
  23. </div>
  24. </div>
  25. <!-- 柱状图 -->
  26. <div class="common-card a-card-margin-top">
  27. <div class="count-echarts-bar-title">
  28. <div class="count-echarts-bar-title-left">考试平均成绩</div>
  29. <div class="count-echarts-bar-title-right">
  30. <div
  31. :class="{
  32. 'count-echarts-bar-title-right-btn': true,
  33. 'count-echarts-bar-title-right-btn-checked':
  34. barTabChecked === item.id,
  35. }"
  36. v-for="(item, index) in barDataTab"
  37. :key="index"
  38. @click="handleEchartsTab(item)"
  39. >
  40. {{ item.title }}
  41. </div>
  42. </div>
  43. </div>
  44. <EchartsBar ref="echartsBarRef" width="100%" height="400px" />
  45. </div>
  46. <!-- 扇形图 -->
  47. <div class="a-card-margin-top count-echarts-pie">
  48. <div class="count-echarts-pie-item">
  49. <div class="count-echarts-pie-item-title">文章类别占比</div>
  50. <EchartsDoughnut ref="echartsPieOneRef" width="100%" height="360px" />
  51. </div>
  52. <div class="count-echarts-pie-item">
  53. <div class="count-echarts-pie-item-title">试题类型占比</div>
  54. <EchartsDoughnut ref="echartsPieTwoRef" width="100%" height="360px" />
  55. </div>
  56. </div>
  57. </a-spin>
  58. </div>
  59. </template>
  60. <script>
  61. import { mapGetters } from 'vuex';
  62. import EchartsBar from '@/components/echarts/EchartsBar';
  63. import EchartsDoughnut from '@/components/echarts/EchartsDoughnut';
  64. export default {
  65. props: {},
  66. components: {
  67. EchartsBar,
  68. EchartsDoughnut,
  69. },
  70. data() {
  71. return {
  72. loading1: false, // 是否显示加载动画
  73. loading2: false, // 是否显示加载动画
  74. loading3: false, // 是否显示加载动画
  75. basicList: [], // 基础数据列表
  76. // 统计图
  77. barDataTab: [
  78. { id: 1, title: '本周' },
  79. { id: 2, title: '本月' },
  80. { id: 3, title: '本年' },
  81. ], // 统计图的tab栏
  82. barTabChecked: 1, // 当前选中的tab栏ID
  83. barData: {}, // 统计图数据
  84. // 扇形-文章类型占比
  85. articlesProportion: {},
  86. // 扇形-试题类型占比
  87. examsProportion: {},
  88. };
  89. },
  90. created() {},
  91. mounted() {
  92. this.initDataFun(); // 初始化数据
  93. },
  94. beforeDestroy() {},
  95. watch: {},
  96. computed: {
  97. ...mapGetters(['userInfo']),
  98. },
  99. methods: {
  100. // 初始化数据
  101. async initDataFun() {
  102. this.basicList = [
  103. {
  104. title: '文章总数',
  105. count: 0,
  106. upTitle: '本月新增',
  107. monthUp: 0,
  108. },
  109. {
  110. title: '题目总数',
  111. count: 0,
  112. upTitle: '本月新增',
  113. monthUp: 0,
  114. },
  115. {
  116. title: '考试总数',
  117. count: 0,
  118. upTitle: '本月新增',
  119. monthUp: 0,
  120. },
  121. ];
  122. this.getArticleCount(this.basicList); // 查询:文章总数
  123. this.getAverageTestScore(); // 查询:统计图-考试平均成绩:本周、本月、全年
  124. },
  125. // 查询:文章总数
  126. getArticleCount(basicList) {
  127. this.loading1 = true;
  128. this.$_http
  129. .get(this.$_API.INTERFACE_GET_COUNT_ARTICLE)
  130. .then((res) => {
  131. basicList[0].count = res.data;
  132. this.getArticleCountUp(basicList); // 查询:本月新增文章数量
  133. this.getArticlesProportion(); // 查询:文章类别占比
  134. })
  135. .catch(() => {
  136. this.loading1 = false;
  137. });
  138. },
  139. // 查询:本月新增文章数量
  140. getArticleCountUp(basicList) {
  141. this.$_http
  142. .get(this.$_API.INTERFACE_GET_COUNT_ARTICLE_UP)
  143. .then((res) => {
  144. basicList[0].monthUp = res.data;
  145. this.getQuestionsCount(basicList); // 查询:试题总数
  146. })
  147. .catch(() => {
  148. this.loading1 = false;
  149. });
  150. },
  151. // 查询:试题总数
  152. getQuestionsCount(basicList) {
  153. this.$_http
  154. .get(this.$_API.INTERFACE_GET_COUNT_QUESTIONS)
  155. .then((res) => {
  156. basicList[1].count = res.data;
  157. this.getQuestionsCountUp(basicList); // 查询:本月新增试题数量
  158. })
  159. .catch(() => {
  160. this.loading1 = false;
  161. });
  162. },
  163. // 查询:本月新增试题数量
  164. getQuestionsCountUp(basicList) {
  165. this.$_http
  166. .get(this.$_API.INTERFACE_GET_COUNT_QUESTIONS_UP)
  167. .then((res) => {
  168. basicList[1].monthUp = res.data;
  169. this.getExamsCount(basicList); // 查询:考试总数
  170. })
  171. .catch(() => {
  172. this.loading1 = false;
  173. });
  174. },
  175. // 查询:考试总数
  176. getExamsCount(basicList) {
  177. this.$_http
  178. .get(this.$_API.INTERFACE_GET_COUNT_EXAMS)
  179. .then((res) => {
  180. basicList[2].count = res.data;
  181. this.getExamsCountUp(basicList);
  182. })
  183. .catch(() => {
  184. this.loading1 = false;
  185. });
  186. },
  187. // 查询:本月新增考试数量
  188. getExamsCountUp(basicList) {
  189. this.$_http
  190. .get(this.$_API.INTERFACE_GET_COUNT_EXAMS_UP)
  191. .then((res) => {
  192. basicList[2].monthUp = res.data;
  193. this.$refs.echartsBarRef.initDataFun(this.barData);
  194. this.loading1 = false;
  195. })
  196. .catch(() => {
  197. this.loading1 = false;
  198. });
  199. },
  200. // 查询:统计图-考试平均成绩:本周、本月、全年
  201. getAverageTestScore() {
  202. this.loading2 = true;
  203. this.barData = {
  204. xAxis: {
  205. data: [
  206. '期终考试',
  207. '期中考试',
  208. '期末考试',
  209. '4月',
  210. '5月',
  211. '6月',
  212. '7月',
  213. '8月',
  214. '9月',
  215. '10月',
  216. '11月',
  217. '12月',
  218. ],
  219. }, // x轴数据
  220. series: {
  221. data: [
  222. 1113,
  223. 823,
  224. 1140,
  225. 1110,
  226. 405,
  227. 813,
  228. 823,
  229. 389,
  230. 678,
  231. 407,
  232. 1178,
  233. 789,
  234. ],
  235. }, // 移入提示数据
  236. };
  237. this.loading2 = false;
  238. // this.$_http
  239. // .get(this.$_API.INTERFACE_GET_COUNT_BAR)
  240. // .then((res) => {
  241. // this.loading2 = false;
  242. // })
  243. },
  244. // 查询:文章类别占比
  245. getArticlesProportion() {
  246. this.loading3 = true;
  247. this.$_http
  248. .get(this.$_API.INTERFACE_GET_COUNT_ARTICLE_PROPORTION)
  249. .then((res) => {
  250. let dataArr = [];
  251. for (let key in res.data) {
  252. dataArr.push({
  253. name: key,
  254. value: formate(res.data[key]),
  255. });
  256. }
  257. function formate(value) {
  258. if (value.includes('%')) {
  259. return Math.round(Number(value.replace('%', '')));
  260. } else {
  261. return value;
  262. }
  263. }
  264. this.articlesProportion = {
  265. title: '文章总计',
  266. seriesLabel: '文章类别占比',
  267. count: this.basicList[0].count,
  268. data: dataArr,
  269. };
  270. this.$refs.echartsPieOneRef.initDataFun(this.articlesProportion);
  271. this.getExamssProportion(); // 查询:试题类别占比
  272. })
  273. .catch(() => {
  274. this.loading3 = false;
  275. });
  276. },
  277. // 查询:试题类别占比
  278. getExamssProportion(count) {
  279. this.$_http
  280. .get(this.$_API.INTERFACE_GET_COUNT_QUESTIONS_PROPORTION)
  281. .then((res) => {
  282. let dataArr = [];
  283. for (let key in res.data) {
  284. dataArr.push({
  285. name: key,
  286. value: formate(res.data[key]),
  287. });
  288. }
  289. function formate(value) {
  290. if (value.includes('%')) {
  291. return Math.round(Number(value.replace('%', '')));
  292. } else {
  293. return value;
  294. }
  295. }
  296. this.articlesProportion = {
  297. title: '试题总计',
  298. seriesLabel: '试题类别占比',
  299. count: count,
  300. data: dataArr,
  301. };
  302. console.log(this.articlesProportion);
  303. this.$refs.echartsPieTwoRef.initDataFun(this.articlesProportion);
  304. this.loading3 = false;
  305. })
  306. .catch(() => {
  307. this.loading3 = false;
  308. });
  309. },
  310. // 操作:切换统计图的tab
  311. handleEchartsTab(item) {
  312. if (this.barTabChecked === item.id) {
  313. return;
  314. }
  315. this.barTabChecked = item.id;
  316. },
  317. },
  318. };
  319. </script>
  320. <style lang="less" scoped>
  321. @import '~@/styles/common/variable.less';
  322. .app-container {
  323. overflow-y: auto;
  324. overflow-x: hidden;
  325. .count-basic-data {
  326. display: flex;
  327. .count-basic-data-item {
  328. width: 264px;
  329. height: 188px;
  330. margin-right: @paddingMarginVal;
  331. padding: @paddingMarginVal;
  332. background-color: @mainColorWhite;
  333. display: flex;
  334. flex-direction: column;
  335. justify-content: space-between;
  336. .count-basic-data-item-title {
  337. font-size: 14px;
  338. color: @mainColorBlack45;
  339. flex-wrap: nowrap;
  340. white-space: nowrap;
  341. }
  342. .count-basic-data-item-main {
  343. width: 100%;
  344. .count-basic-data-item-title {
  345. width: 100%;
  346. }
  347. .count-basic-data-item-count {
  348. width: 100%;
  349. font-size: 30px;
  350. color: @mainColorBlack85;
  351. word-break: break-all;
  352. word-wrap: break-word;
  353. }
  354. }
  355. .count-basic-data-item-up {
  356. padding-top: 10px;
  357. border-top: 1px solid @mainColorBorder;
  358. display: flex;
  359. align-items: center;
  360. .count-basic-data-item-title {
  361. margin-right: @paddingMarginVal;
  362. }
  363. .count-basic-data-item-up-count {
  364. font-size: 20px;
  365. color: @mainColorBlack85;
  366. }
  367. }
  368. }
  369. }
  370. .count-echarts-bar-title {
  371. width: 100%;
  372. min-width: 400px;
  373. height: 40px;
  374. border-bottom: 1px solid @mainColorBorder;
  375. display: flex;
  376. justify-content: space-between;
  377. flex-wrap: nowrap;
  378. .count-echarts-bar-title-left {
  379. height: 100%;
  380. display: flex;
  381. align-items: center;
  382. font-size: 14px;
  383. color: @mainColorBlack65;
  384. flex-wrap: nowrap;
  385. white-space: nowrap;
  386. }
  387. .count-echarts-bar-title-right {
  388. height: 100%;
  389. display: flex;
  390. flex-wrap: nowrap;
  391. .count-echarts-bar-title-right-btn {
  392. display: flex;
  393. justify-content: center;
  394. align-items: center;
  395. width: 66px;
  396. height: 100%;
  397. color: @mainColorBlack65;
  398. font-size: 14px;
  399. border-bottom: 2px solid transparent;
  400. flex-wrap: nowrap;
  401. white-space: nowrap;
  402. cursor: pointer;
  403. &:hover {
  404. color: @mainColorBlueNormal;
  405. border-bottom: 2px solid @mainColorBlueNormal;
  406. }
  407. }
  408. .count-echarts-bar-title-right-btn-checked {
  409. color: @mainColorBlueNormal;
  410. border-bottom: 2px solid @mainColorBlueNormal;
  411. }
  412. }
  413. }
  414. .count-echarts-pie {
  415. width: 100%;
  416. display: flex;
  417. justify-content: space-between;
  418. .count-echarts-pie-item {
  419. width: calc(50% - 8px);
  420. // overflow-x: hidden;
  421. background-color: @mainColorWhite;
  422. .count-echarts-pie-item-title {
  423. padding: @paddingMarginVal;
  424. width: 100%;
  425. border-bottom: 1px solid @mainColorBorder;
  426. display: flex;
  427. align-items: center;
  428. font-size: 14px;
  429. color: @mainColorBlack65;
  430. flex-wrap: nowrap;
  431. white-space: nowrap;
  432. }
  433. }
  434. }
  435. }
  436. </style>