index.tsx 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570
  1. import {
  2. Button,
  3. Cell,
  4. Checkbox,
  5. CheckboxGroup,
  6. Col,
  7. DatetimePicker,
  8. Picker,
  9. Popup,
  10. Row
  11. } from 'vant'
  12. import { defineComponent, markRaw } from 'vue'
  13. import styles from './index.module.less'
  14. import * as echarts from 'echarts/core'
  15. import {
  16. BarChart,
  17. // 系列类型的定义后缀都为 SeriesOption
  18. BarSeriesOption,
  19. LineChart,
  20. LineSeriesOption
  21. } from 'echarts/charts'
  22. import { PieChart } from 'echarts/charts'
  23. import {
  24. TitleComponent,
  25. // 组件类型的定义后缀都为 ComponentOption
  26. TitleComponentOption,
  27. TooltipComponent,
  28. TooltipComponentOption,
  29. GridComponent,
  30. GridComponentOption,
  31. // 数据集组件
  32. DatasetComponent,
  33. DatasetComponentOption,
  34. // 内置数据转换器组件 (filter, sort)
  35. TransformComponent,
  36. LegendComponent,
  37. ToolboxComponent,
  38. DataZoomComponent
  39. } from 'echarts/components'
  40. import { LabelLayout, UniversalTransition } from 'echarts/features'
  41. import { CanvasRenderer } from 'echarts/renderers'
  42. // 通过 ComposeOption 来组合出一个只有必须组件和图表的 Option 类型
  43. type ECOption = echarts.ComposeOption<
  44. | BarSeriesOption
  45. | LineSeriesOption
  46. | TitleComponentOption
  47. | TooltipComponentOption
  48. | GridComponentOption
  49. | DatasetComponentOption
  50. >
  51. // 注册必须的组件
  52. echarts.use([
  53. TitleComponent,
  54. TooltipComponent,
  55. GridComponent,
  56. DatasetComponent,
  57. TransformComponent,
  58. BarChart,
  59. LabelLayout,
  60. UniversalTransition,
  61. CanvasRenderer,
  62. PieChart,
  63. ToolboxComponent,
  64. LegendComponent,
  65. DataZoomComponent,
  66. LineChart
  67. ])
  68. import { lineChartOption, pieChartOption } from './echarts'
  69. import request from '@/helpers/request'
  70. import dayjs from 'dayjs'
  71. import { formatterDate, moneyFormat } from '@/helpers/utils'
  72. export const getAssetsHomeFile = (fileName: string) => {
  73. const path = `./images/${fileName}`
  74. const modules = import.meta.globEager('./images/*')
  75. return modules[path].default
  76. }
  77. const yearColumns: any = []
  78. const year = dayjs().year()
  79. let defaultIndex = 10
  80. for (let i = year - 10; i <= year + 10; i++) {
  81. yearColumns.push({
  82. text: `${i}年`,
  83. value: i
  84. })
  85. }
  86. export default defineComponent({
  87. name: 'IncomeConsus',
  88. data() {
  89. return {
  90. moneyInfo: {
  91. totalSingleRate: 0,
  92. totalShareRate: 0,
  93. totalInAmount: 0,
  94. practiceAmount: 0,
  95. practiceRate: 0,
  96. liveAmount: 0,
  97. liveRate: 0,
  98. videoAmount: 0,
  99. videoRate: 0,
  100. musicAmount: 0,
  101. musicRate: 0,
  102. vipShareAmount: 0,
  103. vipShareRate: 0,
  104. liveShareAmount: 0,
  105. liveShareRate: 0,
  106. videoShareAmount: 0,
  107. videoShareRate: 0,
  108. mallShareAmount: 0,
  109. mallShareRate: 0,
  110. musicShareAmount: 0,
  111. musicShareRate: 0,
  112. albumShareAmount: 0,
  113. albumShareRate: 0,
  114. actiRegistShareAmount: 0,
  115. actiRegistShareRate: 0
  116. },
  117. params: {
  118. timeType: 'YEAR' as 'YEAR' | 'MONTH',
  119. dateTime: `${year}`
  120. },
  121. dateTimeStr: `${year}年`,
  122. myChart: null as any,
  123. myChart2: null as any,
  124. timerStatus: false,
  125. currentDate: new Date()
  126. }
  127. },
  128. async mounted() {
  129. this.myChart = markRaw(
  130. echarts.init(document.getElementById('incomeClass') as HTMLDivElement)
  131. )
  132. this.myChart2 = markRaw(
  133. echarts.init(document.getElementById('structrueClass') as HTMLDivElement)
  134. )
  135. this.getList()
  136. },
  137. methods: {
  138. async getList() {
  139. try {
  140. const params = this.params
  141. const res = await request.post(
  142. '/api-teacher/userAccount/accountTotal',
  143. {
  144. data: params
  145. }
  146. )
  147. const result = res.data || {}
  148. this.moneyInfo = {
  149. totalSingleRate:
  150. result.practiceRate +
  151. result.liveRate +
  152. result.videoRate +
  153. result.musicRate,
  154. totalShareRate:
  155. result.vipShareRate +
  156. result.liveShareRate +
  157. result.videoShareRate +
  158. result.musicShareRate +
  159. result.mallShareRate +
  160. result.actiRegistShareRate +
  161. result.albumShareRate || 0,
  162. totalInAmount: result.totalInAmount || 0,
  163. practiceAmount: result.practiceAmount || 0,
  164. practiceRate: result.practiceRate || 0,
  165. liveAmount: result.liveAmount || 0,
  166. liveRate: result.liveRate || 0,
  167. videoAmount: result.videoAmount || 0,
  168. videoRate: result.videoRate || 0,
  169. musicAmount: result.musicAmount || 0,
  170. musicRate: result.musicRate || 0,
  171. vipShareAmount: result.vipShareAmount || 0,
  172. vipShareRate: result.vipShareRate || 0,
  173. liveShareAmount: result.liveShareAmount || 0,
  174. liveShareRate: result.liveShareRate || 0,
  175. videoShareAmount: result.videoShareAmount || 0,
  176. videoShareRate: result.videoShareRate || 0,
  177. mallShareAmount: result.mallShareAmount || 0,
  178. mallShareRate: result.mallShareRate || 0,
  179. musicShareAmount: result.musicShareAmount || 0,
  180. musicShareRate: result.musicShareRate || 0,
  181. albumShareAmount: result.albumShareAmount || 0,
  182. albumShareRate: result.albumShareRate || 0,
  183. actiRegistShareAmount: result.actiRegistShareAmount || 0,
  184. actiRegistShareRate: result.actiRegistShareRate || 0
  185. }
  186. // 处理折线图数据
  187. const lineData = {
  188. xAxis: [] as any,
  189. practiceAmount: [] as any,
  190. liveAmount: [] as any,
  191. videoAmount: [] as any,
  192. musicAmount: [] as any,
  193. vipShareAmount: [] as any,
  194. liveShareAmount: [] as any,
  195. videoShareAmount: [] as any,
  196. mallShareAmount: [] as any,
  197. musicShareAmount: [] as any,
  198. albumShareAmount: [] as any,
  199. actiRegistShareAmount: [] as any
  200. }
  201. ;(result.infoList || []).forEach((item: any) => {
  202. if (params.timeType === 'YEAR') {
  203. lineData.xAxis.push(dayjs(item.timeStr).format('MM月'))
  204. } else if (params.timeType === 'MONTH') {
  205. lineData.xAxis.push(dayjs(item.timeStr).format('DD日'))
  206. }
  207. lineData.practiceAmount.push(item.practiceAmount)
  208. lineData.liveAmount.push(item.liveAmount)
  209. lineData.videoAmount.push(item.videoAmount)
  210. lineData.musicAmount.push(item.musicAmount)
  211. lineData.vipShareAmount.push(item.vipShareAmount) // 小酷Ai
  212. lineData.liveShareAmount.push(item.liveShareAmount)
  213. lineData.videoShareAmount.push(item.videoShareAmount)
  214. lineData.mallShareAmount.push(item.mallShareAmount)
  215. lineData.musicShareAmount.push(item.musicShareAmount)
  216. lineData.albumShareAmount.push(item.albumShareAmount || 0)
  217. lineData.actiRegistShareAmount.push(item.actiRegistShareAmount)
  218. })
  219. // 初始化折线图
  220. lineChartOption.xAxis.data = lineData.xAxis
  221. lineChartOption.series[0].data = lineData.practiceAmount
  222. lineChartOption.series[1].data = lineData.liveAmount
  223. lineChartOption.series[2].data = lineData.videoAmount
  224. lineChartOption.series[3].data = lineData.musicAmount
  225. lineChartOption.series[4].data = lineData.vipShareAmount
  226. lineChartOption.series[5].data = lineData.liveShareAmount
  227. lineChartOption.series[6].data = lineData.videoShareAmount
  228. lineChartOption.series[7].data = lineData.mallShareAmount
  229. lineChartOption.series[8].data = lineData.musicShareAmount
  230. lineChartOption.series[9].data = lineData.albumShareAmount
  231. lineChartOption.series[10].data = lineData.actiRegistShareAmount
  232. // console.log(lineChartOption)
  233. this.myChart.clear()
  234. this.myChart.setOption(lineChartOption)
  235. // 处理饼图数据
  236. pieChartOption.series[0].data[0].value = result.practiceAmount
  237. pieChartOption.series[0].data[1].value = result.liveAmount
  238. pieChartOption.series[0].data[2].value = result.videoAmount
  239. pieChartOption.series[0].data[3].value = result.musicAmount
  240. pieChartOption.series[0].data[4].value = result.vipShareAmount
  241. pieChartOption.series[0].data[5].value = result.liveShareAmount
  242. pieChartOption.series[0].data[6].value = result.videoShareAmount
  243. pieChartOption.series[0].data[7].value = result.mallShareAmount
  244. pieChartOption.series[0].data[8].value = result.musicShareAmount
  245. pieChartOption.series[0].data[9].value = result.albumShareAmount
  246. pieChartOption.series[0].data[10].value = result.actiRegistShareAmount
  247. this.myChart2.clear()
  248. this.myChart2.setOption(pieChartOption)
  249. } catch (e) {
  250. // console.log(e)
  251. }
  252. }
  253. },
  254. render() {
  255. return (
  256. <div style={{ overflow: 'hidden' }}>
  257. <div class={styles.incomeConsus}>
  258. <Cell
  259. class={styles.income}
  260. title="总收入(元)"
  261. v-slots={{
  262. label: () => (
  263. <span class={styles.countPrice}>
  264. {moneyFormat(this.moneyInfo.totalInAmount)}
  265. </span>
  266. ),
  267. value: () => (
  268. <span
  269. class={styles.searchTime}
  270. onClick={() => (this.timerStatus = true)}
  271. >
  272. {this.dateTimeStr}
  273. </span>
  274. )
  275. }}
  276. ></Cell>
  277. <div class={styles.section}>
  278. <Row class={styles.numberCount}>
  279. <Col span={6}>
  280. <i></i>
  281. <div class={styles.type}>
  282. <span>陪练课</span>
  283. <span class={styles.price}>
  284. {moneyFormat(this.moneyInfo.practiceAmount)}
  285. </span>
  286. </div>
  287. </Col>
  288. <Col span={6}>
  289. <i class={styles.color1}></i>
  290. <div class={styles.type}>
  291. <span>直播课</span>
  292. <span class={styles.price}>
  293. {moneyFormat(this.moneyInfo.liveAmount)}
  294. </span>
  295. </div>
  296. </Col>
  297. <Col span={6}>
  298. <i class={styles.color2}></i>
  299. <div class={styles.type}>
  300. <span>视频课</span>
  301. <span class={styles.price}>
  302. {moneyFormat(this.moneyInfo.videoAmount)}
  303. </span>
  304. </div>
  305. </Col>
  306. <Col span={6}>
  307. <i class={styles.color3}></i>
  308. <div class={styles.type}>
  309. <span>乐谱</span>
  310. <span class={styles.price}>
  311. {moneyFormat(this.moneyInfo.musicAmount)}
  312. </span>
  313. </div>
  314. </Col>
  315. <Col span={6}>
  316. <i class={styles.color4}></i>
  317. <div class={styles.type}>
  318. <span>小酷Ai推广</span>
  319. <span class={styles.price}>
  320. {moneyFormat(this.moneyInfo.vipShareAmount)}
  321. </span>
  322. </div>
  323. </Col>
  324. <Col span={6}>
  325. <i class={styles.color5}></i>
  326. <div class={styles.type}>
  327. <span>直播课推荐</span>
  328. <span class={styles.price}>
  329. {moneyFormat(this.moneyInfo.liveShareAmount)}
  330. </span>
  331. </div>
  332. </Col>
  333. <Col span={6}>
  334. <i class={styles.color6}></i>
  335. <div class={styles.type}>
  336. <span>视频课推荐</span>
  337. <span class={styles.price}>
  338. {moneyFormat(this.moneyInfo.videoShareAmount)}
  339. </span>
  340. </div>
  341. </Col>
  342. <Col span={6}>
  343. <i class={styles.color7}></i>
  344. <div class={styles.type}>
  345. <span>商品推荐</span>
  346. <span class={styles.price}>
  347. {moneyFormat(this.moneyInfo.mallShareAmount)}
  348. </span>
  349. </div>
  350. </Col>
  351. <Col span={6}>
  352. <i class={styles.color8}></i>
  353. <div class={styles.type}>
  354. <span>乐谱推荐</span>
  355. <span class={styles.price}>
  356. {moneyFormat(this.moneyInfo.musicShareAmount)}
  357. </span>
  358. </div>
  359. </Col>
  360. <Col span={6}>
  361. <i class={styles.color10}></i>
  362. <div class={styles.type}>
  363. <span>专辑推荐</span>
  364. <span class={styles.price}>
  365. {moneyFormat(this.moneyInfo.musicShareAmount)}
  366. </span>
  367. </div>
  368. </Col>
  369. <Col span={6}>
  370. <i class={styles.color9}></i>
  371. <div class={styles.type}>
  372. <span>活动报名</span>
  373. <span class={styles.price}>
  374. {moneyFormat(this.moneyInfo.actiRegistShareAmount)}
  375. </span>
  376. </div>
  377. </Col>
  378. </Row>
  379. </div>
  380. <div id="incomeClass" class={styles.incomeLine}></div>
  381. <div class={styles.incomeTitle}>
  382. <i></i>收入结构
  383. </div>
  384. <div class={[styles.pieSection, 'van-hairline--bottom']}>
  385. <div id="structrueClass" class={styles.pieIncome}></div>
  386. <div class={styles.rateAll}>
  387. <div>
  388. <img src={getAssetsHomeFile('icon_user.png')} />
  389. <span>个人收入总占比</span>
  390. <span class={styles.rate}>
  391. {this.moneyInfo.totalSingleRate}%
  392. </span>
  393. </div>
  394. <div>
  395. <img src={getAssetsHomeFile('icon_fly.png')} />
  396. <span>推广收益总占比</span>
  397. <span class={styles.rate}>
  398. {this.moneyInfo.totalShareRate}%
  399. </span>
  400. </div>
  401. </div>
  402. </div>
  403. <div class={styles.pieData}>
  404. <div>
  405. <i class={styles.piePractice}></i>
  406. <span class={styles.pieTitle}>陪练课</span>
  407. <span>{this.moneyInfo.practiceRate}%</span>
  408. </div>
  409. <div>
  410. <i class={styles.pie1}></i>
  411. <span class={styles.pieTitle}>小酷Ai推广</span>
  412. <span>{this.moneyInfo.vipShareRate}%</span>
  413. </div>
  414. <div>
  415. <i class={styles.pieLive}></i>
  416. <span class={styles.pieTitle}>直播课</span>
  417. <span>{this.moneyInfo.liveRate}%</span>
  418. </div>
  419. <div>
  420. <i class={styles.pie2}></i>
  421. <span class={styles.pieTitle}>直播课推荐</span>
  422. <span>{this.moneyInfo.liveShareRate}%</span>
  423. </div>
  424. <div>
  425. <i class={styles.pieVideo}></i>
  426. <span class={styles.pieTitle}>视频课</span>
  427. <span>{this.moneyInfo.videoRate}%</span>
  428. </div>
  429. <div>
  430. <i class={styles.pie3}></i>
  431. <span class={styles.pieTitle}>视频课推荐</span>
  432. <span>{this.moneyInfo.videoShareRate}%</span>
  433. </div>
  434. <div>
  435. <i class={styles.pieMusic}></i>
  436. <span class={styles.pieTitle}>乐谱</span>
  437. <span>{this.moneyInfo.musicRate}%</span>
  438. </div>
  439. <div>
  440. <i class={styles.pie6}></i>
  441. <span class={styles.pieTitle}>活动报名</span>
  442. <span>{this.moneyInfo.actiRegistShareRate}%</span>
  443. </div>
  444. <div>
  445. <i class={styles.pie4}></i>
  446. <span class={styles.pieTitle}>商品推荐</span>
  447. <span>{this.moneyInfo.mallShareRate}%</span>
  448. </div>
  449. <div>
  450. <i class={styles.pie5}></i>
  451. <span class={styles.pieTitle}>乐谱推荐</span>
  452. <span>{this.moneyInfo.musicShareRate}%</span>
  453. </div>
  454. <div>
  455. <i class={styles.pie7}></i>
  456. <span class={styles.pieTitle}>专辑推荐</span>
  457. <span>{this.moneyInfo.mallShareRate}%</span>
  458. </div>
  459. </div>
  460. </div>
  461. <Popup
  462. v-model:show={this.timerStatus}
  463. position="bottom"
  464. round
  465. zIndex={99999999}
  466. >
  467. {this.params.timeType === 'MONTH' && (
  468. <DatetimePicker
  469. v-model={this.currentDate}
  470. type="year-month"
  471. title="选择时间"
  472. formatter={formatterDate}
  473. onCancle={() => (this.timerStatus = false)}
  474. onConfirm={(value: any) => {
  475. this.params.dateTime = dayjs(value).format('YYYY-MM')
  476. this.dateTimeStr = dayjs(value).format('YYYY年MM月')
  477. this.timerStatus = false
  478. this.getList()
  479. }}
  480. v-slots={{
  481. 'columns-top': () => (
  482. <div class={styles.timePopup}>
  483. <Button
  484. type="primary"
  485. plain={this.params.timeType !== 'MONTH'}
  486. size="mini"
  487. class={styles.timeMonth}
  488. onClick={() => (this.params.timeType = 'MONTH')}
  489. >
  490. 按月
  491. </Button>
  492. <Button
  493. type="primary"
  494. plain={this.params.timeType !== 'YEAR'}
  495. size="mini"
  496. class={styles.timeYear}
  497. onClick={() => (this.params.timeType = 'YEAR')}
  498. >
  499. 按年
  500. </Button>
  501. </div>
  502. )
  503. }}
  504. />
  505. )}
  506. {this.params.timeType === 'YEAR' && (
  507. <Picker
  508. v-model={this.currentDate}
  509. title="选择时间"
  510. columns={yearColumns}
  511. defaultIndex={defaultIndex}
  512. onCancel={() => (this.timerStatus = false)}
  513. onConfirm={(obj: any, index: number) => {
  514. this.params.dateTime = obj.value
  515. defaultIndex = index // 记录当前选择的年份
  516. this.dateTimeStr = obj.text
  517. this.timerStatus = false
  518. this.getList()
  519. }}
  520. v-slots={{
  521. 'columns-top': () => (
  522. <div class={styles.timePopup}>
  523. <Button
  524. type="primary"
  525. plain={this.params.timeType !== 'MONTH'}
  526. size="mini"
  527. class={styles.timeMonth}
  528. onClick={() => (this.params.timeType = 'MONTH')}
  529. >
  530. 按月
  531. </Button>
  532. <Button
  533. type="primary"
  534. plain={this.params.timeType !== 'YEAR'}
  535. onClick={() => (this.params.timeType = 'YEAR')}
  536. size="mini"
  537. class={styles.timeYear}
  538. >
  539. 按年
  540. </Button>
  541. </div>
  542. )
  543. }}
  544. />
  545. )}
  546. </Popup>
  547. </div>
  548. )
  549. }
  550. })