index.tsx 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280
  1. import {
  2. defineComponent,
  3. nextTick,
  4. onMounted,
  5. ref,
  6. shallowRef,
  7. watch
  8. } from 'vue'
  9. import styles from './index.module.less'
  10. import * as echarts from 'echarts/core'
  11. import {
  12. LineChart
  13. // LineSeriesOption
  14. } from 'echarts/charts'
  15. // import { PieChart } from 'echarts/charts'
  16. import {
  17. TitleComponent,
  18. // 组件类型的定义后缀都为 ComponentOption
  19. // TitleComponentOption,
  20. TooltipComponent,
  21. // TooltipComponentOption,
  22. GridComponent,
  23. // 数据集组件
  24. DatasetComponent,
  25. // DatasetComponentOption,
  26. // 内置数据转换器组件 (filter, sort)
  27. // TransformComponent,
  28. LegendComponent,
  29. ToolboxComponent,
  30. DataZoomComponent
  31. } from 'echarts/components'
  32. import { LabelLayout } from 'echarts/features'
  33. import { CanvasRenderer } from 'echarts/renderers'
  34. import { formatSecToHMS } from '..'
  35. // 注册必须的组件
  36. echarts.use([
  37. TitleComponent,
  38. TooltipComponent,
  39. GridComponent,
  40. DatasetComponent,
  41. // TransformComponent,
  42. LabelLayout,
  43. // UniversalTransition,
  44. CanvasRenderer,
  45. // PieChart,
  46. ToolboxComponent,
  47. LegendComponent,
  48. DataZoomComponent,
  49. LineChart
  50. ])
  51. const lineChartOption = (params: {
  52. xAxisData: any
  53. seriesData: any
  54. colors: {
  55. lineColor?: string
  56. startColor?: string
  57. endColor?: string
  58. unit?: string
  59. }
  60. }) => {
  61. return {
  62. title: {
  63. text: '单位:' + (params.colors.unit || '人'),
  64. textStyle: {
  65. color: '#777777',
  66. fontSize: 13,
  67. fontWeight: 400
  68. }
  69. },
  70. legend: { show: false },
  71. emphasis: { lineStyle: { width: 2 } },
  72. xAxis: {
  73. boundaryGap: false,
  74. data: params.xAxisData,
  75. type: 'category',
  76. axisLine: { lineStyle: { color: '#8C8C8C' } },
  77. lineStyle: { color: '#F2F2F2' }
  78. },
  79. color: [
  80. params.colors.lineColor || '#2DC7AA'
  81. // '#FF6079'
  82. // '#2DC7AA',
  83. // '#FF602C',
  84. // '#91DD1C',
  85. // '#FFA92C',
  86. // '#BE7E2E',
  87. // '#1C96DD',
  88. // '#D22CFF',
  89. // '#FF3C3C',
  90. // '#1AEE3E',
  91. // '#00c9ff'
  92. ],
  93. series: [
  94. {
  95. lineStyle: { width: 1 },
  96. data: params.seriesData,
  97. symbol: 'circle',
  98. name: '购买次数',
  99. type: 'line',
  100. areaStyle: {
  101. color: {
  102. type: 'linear',
  103. x: 0,
  104. y: 0,
  105. x2: 0,
  106. y2: 1,
  107. colorStops: [
  108. {
  109. offset: 0,
  110. color: params.colors.startColor || 'rgba(45, 199, 170, 0.23)'
  111. // 0% 处的颜色
  112. },
  113. {
  114. offset: 1,
  115. // 100% 处的颜色
  116. color: params.colors.endColor || 'rgba(45, 199, 170, 0)'
  117. }
  118. ]
  119. }
  120. },
  121. emphasis: { lineStyle: { width: 1 } }
  122. }
  123. ],
  124. grid: {
  125. bottom: '3%',
  126. containLabel: true,
  127. left: '3%',
  128. right: '5%',
  129. top: '40'
  130. },
  131. tooltip: {
  132. trigger: 'axis',
  133. confine: true,
  134. formatter: function (params: any) {
  135. return params[0].name
  136. },
  137. backgroundColor: '#FF6079',
  138. borderWidth: 0,
  139. borderRadius: 24,
  140. padding: [1, 4],
  141. textStyle: {
  142. color: '#FFFFFF',
  143. fontSize: 12
  144. }
  145. },
  146. yAxis: {
  147. type: 'value',
  148. splitLine: {
  149. axisLine: { lineStyle: { color: '#8C8C8C' } },
  150. lineStyle: { color: ['#f2f2f2'], type: 'dashed' }
  151. }
  152. },
  153. dataZoom: [{ type: 'inside', throttle: 100 }],
  154. toolbox: { feature: { saveAsImage: { show: false } } }
  155. }
  156. }
  157. export default defineComponent({
  158. name: 'eChats-model',
  159. props: {
  160. obj: {
  161. type: Object,
  162. default: () => ({})
  163. },
  164. type: {
  165. type: String as PropType<'TIME' | 'NUM'>,
  166. default: 'TIME'
  167. }
  168. },
  169. setup(props) {
  170. const chartId = 'eChart_' + Date.now() + props.type
  171. const color = props.type === 'NUM' ? '#FF955D' : '#2DC7AA'
  172. const statisticCounts = ref({
  173. time: '' as any,
  174. count: 0 as any
  175. })
  176. let myChart: echarts.ECharts
  177. nextTick(() => {
  178. myChart = echarts.init(document.getElementById(chartId) as HTMLDivElement)
  179. })
  180. const _initData = () => {
  181. nextTick(() => {
  182. statisticCounts.value.time = props.obj.time || ''
  183. statisticCounts.value.count =
  184. props.type === 'NUM'
  185. ? props.obj.count
  186. : formatSecToHMS(props.obj.count).all
  187. myChart.clear()
  188. lineChartOption &&
  189. myChart.setOption(
  190. lineChartOption({
  191. xAxisData: props.obj.xAxisData,
  192. seriesData: props.obj.yAxisData,
  193. colors: {
  194. lineColor: color,
  195. startColor:
  196. props.type === 'NUM'
  197. ? 'rgba(255, 149, 93, 0.23)'
  198. : 'rgba(45, 199, 170, 0.23)',
  199. endColor:
  200. props.type === 'NUM'
  201. ? 'rgba(255, 149, 93, 0)'
  202. : 'rgba(45, 199, 170, 0)',
  203. unit: props.type === 'NUM' ? '人' : '分钟'
  204. }
  205. })
  206. )
  207. myChart.on('highlight', function (params: any) {
  208. const batch = params.batch || []
  209. // const options: any = myChart.getOption()
  210. batch.forEach((item: any) => {
  211. const batchIndex = item.dataIndex
  212. const count =
  213. props.type === 'NUM'
  214. ? props.obj.yAxisData[batchIndex]
  215. : formatSecToHMS(props.obj.yAxisData[batchIndex] || 0).all
  216. const time = props.obj.xAxisData[batchIndex]
  217. statisticCounts.value = {
  218. count,
  219. time
  220. }
  221. })
  222. })
  223. })
  224. }
  225. nextTick(() => {
  226. myChart = echarts.init(document.getElementById(chartId) as HTMLDivElement)
  227. _initData()
  228. })
  229. watch(
  230. () => props.obj,
  231. () => {
  232. _initData()
  233. },
  234. {
  235. deep: true
  236. }
  237. )
  238. return () => (
  239. <div class={styles.eChartSection}>
  240. <div class={styles.eChartTitle}>
  241. <div class={styles.left}>
  242. <div class={styles.item} style={{ '--color': color } as any}>
  243. {/* <span class={styles.line}></span> */}
  244. {props.type === 'NUM' ? (
  245. <>
  246. <span class={styles.text}>
  247. {statisticCounts.value.time} 练习人数
  248. </span>
  249. <span class={styles.num}>
  250. {statisticCounts.value.count || 0}人
  251. </span>
  252. </>
  253. ) : (
  254. <>
  255. <span class={styles.text}>
  256. {statisticCounts.value.time} 练习时长
  257. </span>
  258. <span class={styles.num}>{statisticCounts.value.count}</span>
  259. </>
  260. )}
  261. </div>
  262. </div>
  263. </div>
  264. <div class={styles.eChart}>
  265. <div id={chartId} style="width: 100%; height: 100%;"></div>
  266. </div>
  267. </div>
  268. )
  269. }
  270. })