Attendance.tsx 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219
  1. import {
  2. PropType,
  3. defineComponent,
  4. nextTick,
  5. onMounted,
  6. ref,
  7. toRefs,
  8. watch
  9. } from 'vue';
  10. import styles from '../index.module.less';
  11. import icons from '../icons.json';
  12. import { Badge, Icon, Image, Tab, Tabs } from 'vant';
  13. import * as echarts from 'echarts';
  14. import { IStudentAttendance } from '../type';
  15. import { useRouter } from 'vue-router';
  16. import icon_4 from '../image/icon_4.png';
  17. import { browser } from '@/helpers/utils';
  18. import { postMessage } from '@/helpers/native-message';
  19. type EChartsOption = echarts.EChartsOption;
  20. const colors = [
  21. {
  22. color: new echarts.graphic.LinearGradient(0, 0, 1, 0, [
  23. { offset: 0, color: '#02E2DB' },
  24. { offset: 1, color: '#01C1B5' }
  25. ]),
  26. name: '正常',
  27. key: 'normalNum',
  28. background: 'linear-gradient(180deg, #02E2DB 0%, #01C1B5 100%)'
  29. },
  30. {
  31. color: new echarts.graphic.LinearGradient(0, 0, 1, 0, [
  32. { offset: 0, color: '#5B8FF9' },
  33. { offset: 1, color: '#94C2FD' }
  34. ]),
  35. name: '迟到',
  36. key: 'lateNum',
  37. background:
  38. 'linear-gradient(180deg, rgba(148, 194, 253, 0.85) 0%, rgba(91, 143, 249, 0.85) 100%)'
  39. },
  40. {
  41. color: new echarts.graphic.LinearGradient(0, 0, 1, 0, [
  42. { offset: 0, color: '#FBE031' },
  43. { offset: 1, color: '#F6BD16' }
  44. ]),
  45. name: '请假',
  46. key: 'leaveNum',
  47. background:
  48. 'linear-gradient(180deg, rgba(251,224,49,0.85) 0%, rgba(246,189,22,0.85) 100%)'
  49. },
  50. {
  51. color: new echarts.graphic.LinearGradient(0, 0, 1, 0, [
  52. { offset: 0, color: '#F5A181' },
  53. { offset: 1, color: '#E8684A' }
  54. ]),
  55. name: '旷课',
  56. key: 'truantNum',
  57. background:
  58. 'linear-gradient(180deg, rgba(245,161,129,0.85) 0%, rgba(232,104,74,0.85) 100%)'
  59. }
  60. ];
  61. export default defineComponent({
  62. name: 'Attendance',
  63. props: {
  64. data: {
  65. type: Object as PropType<IStudentAttendance>,
  66. default: () => ({})
  67. }
  68. },
  69. emits: ['change'],
  70. setup(props, { emit }) {
  71. const firstInit = ref(false);
  72. const echratsRef = ref();
  73. const router = useRouter();
  74. const { data } = toRefs(props);
  75. watch(
  76. () => data.value,
  77. () => {
  78. firstInit.value = true;
  79. nextTick(() => {
  80. handleInit();
  81. });
  82. }
  83. );
  84. let myChart: echarts.ECharts;
  85. const handleInit = () => {
  86. // if (!data.value.totalNum) return;
  87. if (myChart) {
  88. myChart.dispose();
  89. }
  90. myChart = echarts.init(echratsRef.value);
  91. const option: EChartsOption = {
  92. title: {
  93. text: `${data.value.attendanceRate}%`,
  94. subtext: '出勤率',
  95. textAlign: 'center',
  96. left: '48%',
  97. top: '34%',
  98. textStyle: {
  99. fontSize: '18px',
  100. fontWeight: 'bold',
  101. color: '#333',
  102. fontFamily: 'DINAlternate-Bold, DINAlternate'
  103. },
  104. subtextStyle: {
  105. fontSize: '12px',
  106. color: '#777'
  107. }
  108. },
  109. tooltip: {
  110. trigger: 'item',
  111. confine: true,
  112. borderWidth: 0,
  113. borderRadius: 6,
  114. formatter: function (item: any) {
  115. return `<span style="display: inline-block; vertical-align: middle;margin-right:4px;border-radius:50%;width:6px;height:6px;background:linear-gradient(${item.color.colorStops[0].color} 0%, ${item.color.colorStops[1].color} 100%);"></span>
  116. <span style="margin-right:10px; font-size:12px;color: #777;">${item.name}</span>
  117. <span style="font-size:14px;color: #333;font-weight: bold;font-family: DINAlternate-Bold, DINAlternate;">${item.value}</span>`;
  118. }
  119. },
  120. series: [
  121. {
  122. type: 'pie',
  123. radius: ['54%', '70%'],
  124. itemStyle: {
  125. borderRadius: 2,
  126. borderColor: '#fff',
  127. borderWidth: 1
  128. },
  129. label: {
  130. show: false
  131. },
  132. labelLine: {
  133. show: false
  134. },
  135. avoidLabelOverlap: false,
  136. data: colors.map(item => {
  137. return {
  138. name: item.name,
  139. value: data.value[item.key],
  140. itemStyle: {
  141. color: item.color
  142. }
  143. };
  144. })
  145. }
  146. ]
  147. };
  148. option && myChart.setOption(option);
  149. };
  150. const gotoStudnetManage = () => {
  151. if (browser().isApp) {
  152. const url = `${location.origin}${location.pathname}#/student-manage`;
  153. postMessage({
  154. api: 'openWebView',
  155. content: {
  156. url,
  157. orientation: 1,
  158. isHideTitle: false
  159. }
  160. });
  161. } else {
  162. router.push({
  163. path: '/student-manage'
  164. });
  165. }
  166. };
  167. return () => (
  168. <div class={styles.item}>
  169. <div class={styles.top}>
  170. <Image class={styles.iconRight} src={icons.right} />
  171. <span>学员出勤</span>
  172. <Image class={styles.iconLeft} src={icons.left} />
  173. </div>
  174. <div class={styles.tabsContainer}>
  175. <Tabs
  176. shrink
  177. onChange={value => {
  178. emit('change', value);
  179. }}>
  180. <Tab name="week" title="本周"></Tab>
  181. <Tab name="month" title="本月"></Tab>
  182. <Tab name="term" title="本学期"></Tab>
  183. </Tabs>
  184. <div class={styles.tagRight} onClick={() => gotoStudnetManage()}>
  185. 学员信息 <Icon name="arrow" color="rgba(216,216,216,1)" />
  186. </div>
  187. </div>
  188. <div
  189. // style={{ display: data.value.totalNum ? '' : 'none' }}
  190. class={styles.attendanceContainer}>
  191. <div class={styles.attendanceEcharts} ref={echratsRef}></div>
  192. <div class={styles.tags}>
  193. <div class={styles.unitTitle}>(单位: 人次)</div>
  194. {colors.map((item, index) => (
  195. <div class={styles.tag}>
  196. <div
  197. class={styles.rect}
  198. style={{ background: item.background }}
  199. />
  200. <div class={styles.des}>{item.name}</div>
  201. <span class={styles.tagNum}>{data.value[item.key] || 0}</span>
  202. </div>
  203. ))}
  204. </div>
  205. </div>
  206. {/* {!data.value.totalNum && (
  207. <div class={[styles.gradeContainer, styles.itemEmtry]}>
  208. <Image src={icon_4} />
  209. </div>
  210. )} */}
  211. </div>
  212. );
  213. }
  214. });