practiceData.tsx 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329
  1. import { Ref, computed, defineComponent, onMounted, reactive, ref } from 'vue';
  2. import styles from '../index.module.less';
  3. import { NButton, NDataTable, NNumberAnimation } from 'naive-ui';
  4. import numeral from 'numeral';
  5. import { useECharts } from '@/hooks/web/useECharts';
  6. import Pagination from '/src/components/pagination';
  7. import { getTestStat } from '@/views/data-module/api';
  8. import { getMinutes, getSecend, getTimes } from '/src/utils/dateFormat';
  9. import { useRoute, useRouter } from 'vue-router';
  10. import { getTrainingStatList } from '../../classList/api';
  11. import dayjs from 'dayjs';
  12. import TheEmpty from '/src/components/TheEmpty';
  13. export default defineComponent({
  14. name: 'home-practiceData',
  15. props: {
  16. timer: {
  17. type: Array,
  18. defaut: () => []
  19. }
  20. },
  21. setup(props, { expose }) {
  22. const chartRef = ref<HTMLDivElement | null>(null);
  23. const { setOptions } = useECharts(chartRef as Ref<HTMLDivElement>);
  24. const practiceFlag = ref(true);
  25. const payForm = reactive({
  26. height: '360px',
  27. width: '100%',
  28. practiceUserCount: 0,
  29. paymentAmount: 0,
  30. practiceDurationAvg: 0,
  31. practiceDays: 0,
  32. practiceDurationTotal: 0,
  33. dateList: [],
  34. timeList: []
  35. });
  36. const state = reactive({
  37. loading: false,
  38. pagination: {
  39. page: 1,
  40. rows: 10,
  41. pageTotal: 4
  42. },
  43. tableList: [] as any,
  44. goCourseVisiable: false
  45. });
  46. const currentTimer = computed(() => {
  47. return props.timer;
  48. });
  49. const columns = () => {
  50. return [
  51. {
  52. title: '日期',
  53. key: 'date'
  54. },
  55. {
  56. title: '练习人数',
  57. key: 'practiceUserCount',
  58. render(row: any) {
  59. return <>{row.practiceUserCount}人</>;
  60. }
  61. },
  62. {
  63. title: '平均练习时长(分钟)',
  64. key: 'practiceDuration',
  65. render(row: any) {
  66. return (
  67. <>
  68. {' '}
  69. <>
  70. {row.practiceDuration
  71. ? getMinutes(row.practiceDuration) > 0
  72. ? getMinutes(row.practiceDuration) +
  73. '分' +
  74. getSecend(row.practiceDuration) +
  75. '秒'
  76. : getSecend(row.practiceDuration) + '秒'
  77. : 0 + '分钟'}
  78. </>
  79. </>
  80. );
  81. }
  82. }
  83. ];
  84. };
  85. const getList = async () => {
  86. try {
  87. const res = await getTrainingStatList({
  88. page: 1,
  89. rows: 999,
  90. ...getTimes(
  91. currentTimer.value,
  92. ['startTime', 'endTime'],
  93. 'YYYY-MM-DD'
  94. )
  95. });
  96. const res2 = await getTestStat({
  97. page: 1,
  98. rows: 999,
  99. ...getTimes(
  100. currentTimer.value,
  101. ['startTime', 'endTime'],
  102. 'YYYY-MM-DD'
  103. )
  104. });
  105. state.tableList = res.data.rows;
  106. payForm.practiceDurationAvg = res2.data.practiceDurationAvg;
  107. payForm.practiceUserCount = res2.data.practiceUserCount;
  108. payForm.dateList = res2.data.trainingStatDetailList.map((item: any) => {
  109. return item.date;
  110. });
  111. payForm.timeList = res2.data.trainingStatDetailList.map((item: any) => {
  112. return item.practiceUserCount;
  113. });
  114. console.log('trainingStatDetailList', payForm.timeList);
  115. setChart();
  116. } catch (e) {
  117. console.log(e);
  118. }
  119. };
  120. expose({ getList });
  121. const setChart = () => {
  122. setOptions({
  123. tooltip: {
  124. trigger: 'axis',
  125. axisPointer: {
  126. type: 'shadow'
  127. }
  128. },
  129. legend: {
  130. show: false,
  131. selected: {
  132. //在这里设置默认展示就ok了
  133. 练习人数: practiceFlag.value
  134. }
  135. },
  136. xAxis: {
  137. type: 'category',
  138. boundaryGap: true,
  139. axisLabel: {
  140. show: true,
  141. interval: 0
  142. },
  143. data: payForm.dateList
  144. },
  145. yAxis: [
  146. {
  147. type: 'value',
  148. axisLabel: {
  149. formatter: '{value}人'
  150. },
  151. axisTick: {
  152. show: false
  153. },
  154. splitArea: {
  155. show: false,
  156. areaStyle: {
  157. color: ['rgba(255,255,255,0.2)']
  158. }
  159. },
  160. minInterval: 1,
  161. splitNumber: 5
  162. }
  163. ],
  164. grid: {
  165. left: '1%',
  166. right: '1%',
  167. top: '2%',
  168. bottom: 0,
  169. containLabel: true
  170. },
  171. series: [
  172. {
  173. // smooth: true,
  174. data: payForm.timeList,
  175. type: 'line',
  176. smooth: true,
  177. // barWidth: '48px',
  178. // label: {
  179. // // 柱图头部显示值
  180. // show: true,
  181. // position: 'top',
  182. // color: '#333',
  183. // fontSize: '12px',
  184. // fontWeight: 600
  185. // },
  186. itemStyle: {
  187. normal: {
  188. //这里设置柱形图圆角 [左上角,右上角,右下角,左下角]
  189. barBorderRadius: [8, 8, 0, 0],
  190. color: '#D5E9FF'
  191. },
  192. emphasis: {
  193. color: '#3583FA' //hover时改变柱子颜色
  194. // borderWidth: 4,
  195. // borderColor: 'rgba(213, 233, 255,.4)',
  196. // borderType: 'solid'
  197. }
  198. } as any
  199. }
  200. ],
  201. formatter: (item: any) => {
  202. if (Array.isArray(item)) {
  203. return [
  204. item[0].axisValueLabel,
  205. ...item.map((d: any) => {
  206. return `<br/>${d.marker}<span style="margin-top:10px;margin-left:5px;font-size: 13px;font-weight: 500;
  207. color: #131415;font-weight: 600;
  208. margin-top:12px
  209. line-height: 18px;">练习人数: ${d.value}人 </span>`;
  210. })
  211. ].join('');
  212. } else {
  213. return item;
  214. }
  215. }
  216. // dataZoom: [
  217. // {
  218. // type: 'slider',
  219. // start: 5,
  220. // end: 100,
  221. // filterMode: 'empty'
  222. // }
  223. // ]
  224. });
  225. };
  226. onMounted(() => {
  227. getList();
  228. });
  229. return () => (
  230. <>
  231. <div class={styles.homeTrainData}>
  232. <div class={styles.TrainDataTop}>
  233. <div class={styles.TrainDataTopLeft}>
  234. <div class={styles.TrainDataItem}>
  235. <p class={styles.TrainDataItemTitle}>
  236. <span>
  237. <NNumberAnimation
  238. from={0}
  239. to={payForm.practiceUserCount}></NNumberAnimation>
  240. </span>
  241. </p>
  242. <p class={styles.TrainDataItemsubTitle}>练习人数</p>
  243. </div>
  244. <div class={styles.TrainDataItem}>
  245. <p class={styles.TrainDataItemTitle}>
  246. {getMinutes(payForm.practiceDurationAvg) > 0 ? (
  247. <div>
  248. <span>
  249. <NNumberAnimation
  250. from={0}
  251. to={getMinutes(
  252. payForm.practiceDurationAvg
  253. )}></NNumberAnimation>
  254. </span>{' '}
  255. </div>
  256. ) : null}
  257. <div>
  258. <span>
  259. <NNumberAnimation
  260. from={0}
  261. to={getSecend(
  262. payForm.practiceDurationAvg
  263. )}></NNumberAnimation>
  264. </span>{' '}
  265. </div>
  266. </p>
  267. <p class={styles.TrainDataItemsubTitle}>平均练习时长</p>
  268. </div>
  269. </div>
  270. <div class={styles.TrainDataTopRight}>
  271. <div
  272. // onClick={() => {
  273. // practiceFlag.value = !practiceFlag.value;
  274. // setChart();
  275. // }}
  276. class={[
  277. styles.DataTopRightItem,
  278. practiceFlag.value ? '' : styles.DataTopRightItemDis
  279. ]}>
  280. <div
  281. class={[
  282. styles.DataTopRightDot,
  283. styles.DataTopRightDotBlue
  284. ]}></div>
  285. <p>练习人数</p>
  286. </div>
  287. </div>
  288. </div>
  289. <div class={styles.chatrs}>
  290. <div
  291. ref={chartRef}
  292. style={{ height: payForm.height, width: payForm.width }}></div>
  293. </div>
  294. <div class={styles.tableWrap}>
  295. <NDataTable
  296. v-slots={{
  297. empty: () => <TheEmpty></TheEmpty>
  298. }}
  299. class={styles.classTable}
  300. loading={state.loading}
  301. columns={columns()}
  302. data={state.tableList}></NDataTable>
  303. {/* <Pagination
  304. v-model:page={state.pagination.page}
  305. v-model:pageSize={state.pagination.rows}
  306. v-model:pageTotal={state.pagination.pageTotal}
  307. onList={getList}
  308. sync
  309. saveKey="orchestraRegistration-key"
  310. /> */}
  311. </div>
  312. </div>
  313. </>
  314. );
  315. }
  316. });