growth_track.js 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647
  1. // parents//pages/growth_track/growth_track.js
  2. import F2 from '../../../utils/f2-canvas/lib/f2';
  3. const wxCharts = require("../../../utils/wxcharts-min.js");
  4. let chart;
  5. import { routers, viewImage, sharePage, isFn, getGlobalVal } from '../../../utils/util.js'
  6. import { UserReadInfo, ThemeBorrowedList, ScanningBooksTwo, InitBorrowCar } from '../../../utils/api.js'
  7. const { navigateTo, redirectTo, navigateBack } = routers()
  8. const { globalData, hasLibraryService, hasVipService } = getApp()
  9. const { baseImgUrl, qrcodeInvalidToastText, isIphoneX } = globalData
  10. /**
  11. * 进度条颜色RGB
  12. */
  13. const colorRGB = '255,215,108'
  14. const colorRGB1 = '255,128,168'
  15. const colorRGB2 = '0,183,255'
  16. const colorRGB3 = '255,97,97'
  17. const colorRGB4 = '121,189,232'
  18. const colorRGB5 = '250,202,106'
  19. const colorRGB6 = '143,232,121'
  20. const colorRGB7 = '117,227,243'
  21. const colorRGB8 = '255,145,128'
  22. const colorRGB9 = '119,143,242'
  23. const blueRGB = '65,65, 76'
  24. const blackRGB = '108,108,128'
  25. Page({
  26. /**
  27. * 页面的初始数据
  28. */
  29. data: {
  30. baseImgUrl,
  31. isIphoneX,
  32. isLoaded: 1,
  33. opts: {
  34. lazyLoad: true // 延迟加载组件
  35. // onInit: initChart
  36. },
  37. pageNo: 1,
  38. pageSize: 5,
  39. isAll: 0,
  40. themeSelect:false,
  41. rankList:[
  42. // {
  43. // ranking:'一',
  44. // rankTimes:3,
  45. // rankMonth:6,
  46. // rankName: '../../../assets/no_one.png',
  47. // rankBg: '../../../assets/no_one_bg.png'
  48. // },
  49. // {
  50. // ranking: '二',
  51. // rankTimes: 5,
  52. // rankMonth: 6,
  53. // rankName: '../../../assets/no_two.png',
  54. // rankBg: '../../../assets/no_two_bg.png'
  55. // },
  56. // {
  57. // ranking: '三',
  58. // rankTimes: 3,
  59. // rankMonth: 6,
  60. // rankName: '../../../assets/no_three.png',
  61. // rankBg: '../../../assets/no_three_bg.png'
  62. // },
  63. ],
  64. themeInfoList:[
  65. // { percentage: "0.22", themeCode: "child1", themeName: "名著经典1" },
  66. // { percentage: "0.42", themeCode: "child2", themeName: "名著经典2" },
  67. // { percentage: "0.36", themeCode: "child3", themeName: "名著3" },
  68. // { percentage: "0.06", themeCode: "child4", themeName: "名著经典3" },
  69. // { percentage: "0.26", themeCode: "child5", themeName: "经典3" },
  70. // { percentage: "0.16", themeCode: "child6", themeName: "名著经典4" },
  71. // { percentage: "0.44", themeCode: "child7", themeName: "名著经典5" },
  72. // { percentage: "0.46", themeCode: "child8", themeName: "名著经典8" },
  73. // { percentage: "0.1", themeCode: "child9", themeName: "名著经典33" },
  74. // { percentage: "0.28", themeCode: "child10", themeName: "名著经典22" },
  75. ],
  76. monthList:[],
  77. yearList:[],
  78. footerData: {
  79. isIphoneX,
  80. actIndex:1,
  81. list: [
  82. {
  83. text: '找好书',
  84. icon: '../../../assets/book_gray.png',
  85. actIcon: '../../../assets/book_blue.png',
  86. url: 'parents/pages/main/main',
  87. zindex: 3,
  88. },
  89. {
  90. text: '成长轨迹',
  91. icon: '../../../assets/wish_gray.png',
  92. actIcon: '../../../assets/wish_blue.png',
  93. url: 'parents/pages/growth_track/growth_track',
  94. zindex: 3,
  95. },
  96. {
  97. text: '我的',
  98. icon: '../../../assets/me_gray.png',
  99. actIcon: '../../../assets/me_blue.png',
  100. url: 'parents/pages/me/me',
  101. zindex: 3,
  102. }
  103. ]
  104. },
  105. nodataArray: {
  106. text: "暂无阅读计划",
  107. margin: '140rpx auto'
  108. }
  109. },
  110. /**
  111. * 生命周期函数--监听页面加载
  112. */
  113. onLoad: function (options) {
  114. options.vipId = getGlobalVal('vipId', `vipId_${getGlobalVal('userId')}`)
  115. // options.vipId = '306330bd-5c8c-41aa-8a00-0f0c296ebb29',
  116. options.library = getGlobalVal('library')
  117. options.libId = getGlobalVal('library').id || ''
  118. this.setData({ options })
  119. // this.getData()
  120. },
  121. /**
  122. * 生命周期函数--监听页面初次渲染完成
  123. */
  124. onReady: function () {
  125. const obj = { navigateTo, redirectTo, navigateBack, viewImage }
  126. for (const i in obj) {
  127. this[i] = obj[i]
  128. }
  129. },
  130. /**
  131. * 生命周期函数--监听页面显示
  132. */
  133. onShow: function () {
  134. this.getData()
  135. const { options, isFirst } = this.data
  136. options.library = getGlobalVal('library')
  137. const userId = getGlobalVal('userId')
  138. options.vipId = getGlobalVal('vipId', `vipId_${userId}`) || ''
  139. options.libId = getGlobalVal('library').id || ''
  140. const bookList = getGlobalVal(`borrowBook_${userId}_${options.libId}_${options.vipId}`) || []
  141. this.setData({ options, bookList })
  142. },
  143. /**
  144. * 生命周期函数--监听页面隐藏
  145. */
  146. onHide: function () {
  147. },
  148. /**
  149. * 生命周期函数--监听页面卸载
  150. */
  151. onUnload: function () {
  152. },
  153. /**
  154. * 页面相关事件处理函数--监听用户下拉动作
  155. */
  156. onPullDownRefresh: function () {
  157. // this.setData(() => {
  158. // wx.stopPullDownRefresh()
  159. // })
  160. },
  161. /**
  162. * 页面上拉触底事件的处理函数
  163. */
  164. onReachBottom: function () {
  165. },
  166. /**
  167. * 用户点击右上角分享
  168. */
  169. onShareAppMessage: function () {
  170. if (isFn(sharePage)) return sharePage()
  171. },
  172. /**
  173. * 查看排名
  174. */
  175. setRanking:function(){
  176. if (!hasVipService()) return
  177. navigateTo({ url: 'parents/pages/ranking/ranking', zindex: 3 })
  178. },
  179. /**
  180. * 获取好书推荐
  181. */
  182. getData: function (cb) {
  183. const continuousFn = { fn: this.getData, param: { ...arguments } }
  184. const { libId = '', vipId = '' } = this.data.options
  185. if (!hasVipService()) return
  186. UserReadInfo({ data: { libId, vipId }, continuousFn }).then(res => {
  187. const { rankList, monthList, themeInfoList, themeTopList, yearList} = res.data
  188. console.log(rankList, monthList, themeInfoList, themeTopList, yearList)
  189. this.setData({ rankList, themeInfoList, monthList, themeTopList, yearList, isLoaded: true })
  190. this.goodBooksPicture()
  191. this.nearTwentyEight()
  192. this.everyReading()
  193. if (isFn(cb)) cb()
  194. }).catch(res => {
  195. this.setData({ isLoaded: true})
  196. if (isFn(cb)) cb()
  197. })
  198. },
  199. /**
  200. * 好书推荐图表
  201. */
  202. goodBooksPicture: function () {
  203. const { themeInfoList = [] } = this.data
  204. // console.log(themeInfoList)
  205. var that=this
  206. if (themeInfoList.length === 0) return
  207. this.selectComponent('#pieSelect').init(function (canvas, width, height) {
  208. // 数据
  209. const data = (list => {
  210. const arr = []
  211. for (const v of list) {
  212. const { themeName = '', percentage = 0, themeCode=''} = v
  213. arr.push({
  214. const: 'const',
  215. type: themeName,
  216. code: themeCode,
  217. percent: ~~(+percentage)
  218. })
  219. }
  220. return arr
  221. })(themeInfoList)
  222. // 生成画布
  223. const chart = new F2.Chart({
  224. el: canvas,
  225. width,
  226. height
  227. })
  228. chart.source(data)
  229. chart.coord('polar', {
  230. transposed: true,
  231. radius: 0.9,
  232. innerRadius: 0.5
  233. })
  234. chart.axis(false)
  235. chart.legend(false)
  236. chart.tooltip(false)
  237. chart.interval().position('const*percent').adjust('stack').color('type', [
  238. `rgba(${colorRGB}, 1)`,
  239. `rgba(${colorRGB1}, 1)`,
  240. `rgba(${colorRGB2}, 1)`,
  241. `rgba(${colorRGB3}, 1)`,
  242. `rgba(${colorRGB4}, 1)`,
  243. `rgba(${colorRGB5}, 1)`,
  244. `rgba(${colorRGB6}, 1)`,
  245. `rgba(${colorRGB7}, 1)`,
  246. `rgba(${colorRGB8}, 1)`,
  247. `rgba(${colorRGB9}, 1)`,
  248. ])
  249. chart.interaction('pie-select', {
  250. cancelable: false,
  251. animate: {
  252. duration: 300,
  253. easing: 'backOut'
  254. },
  255. onEnd: res => {
  256. // console.log(res)
  257. const { data } = res
  258. if(data){
  259. const { type, code } = data
  260. that.setData({
  261. pageNo: 1,
  262. message: type,
  263. code
  264. })
  265. that.getThemeData()
  266. }
  267. }
  268. });
  269. chart.pieLabel({
  270. sidePadding: 30,
  271. activeShape: true,
  272. label1: function label1(data) {
  273. return {
  274. text: data.percent + '%',
  275. fill: `rgba(${blueRGB}, 1)`,
  276. fontWeight: 'bold'
  277. };
  278. },
  279. label2: function label2(data) {
  280. return {
  281. text: data.type.length > 5 ? data.type.substring(0, 5) + '...' : data.type,
  282. fill: `rgba(${blackRGB}, 1)`,
  283. fontWeight: 'bold'
  284. };
  285. },
  286. onClick: res=> {
  287. console.log(res)
  288. const { data } = res
  289. if (data) {
  290. const { type, code } = data
  291. that.setData({
  292. pageNo: 1,
  293. message: type,
  294. code
  295. })
  296. that.getThemeData()
  297. }
  298. }
  299. });
  300. chart.render()
  301. return chart
  302. })
  303. },
  304. /**
  305. * 获取数据
  306. */
  307. getThemeData: function (cb) {
  308. const continuousFn = { fn: this.getData, param: { ...arguments } }
  309. const { pageNo, pageSize, options, list, code} = this.data
  310. const { vipId } = options
  311. wx.showLoading({
  312. title: '加载中',
  313. })
  314. ThemeBorrowedList({ data: { pageNo, pageSize, vipId, code}, continuousFn }).then(res => {
  315. wx.hideLoading()
  316. const { pages } = res.data
  317. const newList = res.data.list
  318. const listTemp = (res => {
  319. for (let i in res) {
  320. if (res[i].summary.length > 30) {
  321. res[i].summary = res[i].summary.slice(0, 30) + '...'
  322. } else {
  323. res[i].summary = res[i].summary
  324. }
  325. }
  326. return res
  327. })(newList)
  328. let arr = []
  329. if (pageNo == 1) {
  330. arr = [...listTemp]
  331. } else {
  332. arr = [...list, ...listTemp]
  333. }
  334. this.setData({ themeSelect: true, list: arr, pages,isAll: newList.length < pageSize, pageNo: newList.length == pageSize ? pageNo + 1 : pageNo, isLoaded: true })
  335. cb && cb()
  336. }).catch(res => {
  337. this.setData({ isLoaded: true })
  338. cb && cb()
  339. })
  340. },
  341. /**
  342. * 近28天阅读量对比
  343. */
  344. nearTwentyEight(canvas, width, height) {
  345. const { monthList } = this.data
  346. var max = monthList[0].borrowNum;
  347. for (var i = 1; i < monthList.length; i++) {
  348. var cur = monthList[i].borrowNum;
  349. cur > max ? max = cur : null
  350. }
  351. this.selectComponent('#twentyEightCanvas').init(function (canvas, width, height) {
  352. // 数据
  353. const data = (list => {
  354. const arr = []
  355. for (const v of list) {
  356. const { endTime = '', borrowNum = 0, startTime = '' } = v
  357. arr.push({
  358. year: startTime.slice(5, 10) + '-' + endTime.slice(5, 10),
  359. sales: borrowNum
  360. })
  361. }
  362. return arr
  363. })(monthList)
  364. chart = new F2.Chart({
  365. el: canvas,
  366. width:wx.getSystemInfoSync().windowWidth - 30,
  367. height
  368. });
  369. chart.source(data, {
  370. sales: {
  371. tickCount: 10,
  372. max: max+10,
  373. min:0
  374. }
  375. });
  376. chart.axis('sales', {
  377. line: {
  378. lineWidth: 1,
  379. stroke: '#E6E6EC',
  380. top: false, // 展示在最上层
  381. },
  382. tickLine: {
  383. lineWidth: 1,
  384. stroke: '#A1A1B3',
  385. length: 2, // 刻度线长度
  386. top:false
  387. },
  388. grid:null,
  389. label: (text, index, total) => {
  390. const cfg = {
  391. textAlign: 'center',
  392. color: '#A1A1B3',
  393. fontSize:10
  394. }
  395. cfg.text = Math.floor(text)
  396. return cfg;
  397. },
  398. })
  399. chart.axis('year', {
  400. line: {
  401. lineWidth: 1,
  402. stroke: '#E6E6EC',
  403. top: true, // 展示在最上层
  404. },
  405. grid: null,
  406. label: (text, index, total) => {
  407. const cfg = {
  408. textAlign: 'center',
  409. color: '#41414C',
  410. fontSize: 12
  411. }
  412. return cfg;
  413. },
  414. })
  415. chart.animate(true)
  416. chart.tooltip(false);
  417. chart.interval()
  418. .position('year*sales')
  419. .color('#FFD76C');
  420. chart.render();
  421. // 绘制柱状图文本
  422. const offset = -5;
  423. const chartCanvas = chart.get('canvas');
  424. const group = chartCanvas.addGroup();
  425. const shapes = {};
  426. data.map(obj => {
  427. const point = chart.getPosition(obj);
  428. const text = group.addShape('text', {
  429. attrs: {
  430. x: point.x,
  431. y: point.y + offset,
  432. fontSize: 11,
  433. text: obj.sales == 0 ?'暂\n无\n数\n据':obj.sales+'本',
  434. textAlign: 'center',
  435. textBaseline: 'bottom',
  436. fill: '#A1A1B3'
  437. }
  438. });
  439. shapes[obj.year] = text; // 缓存该 shape, 便于后续查找
  440. });
  441. return chart;
  442. });
  443. },
  444. /**
  445. * 每月阅读量对比
  446. */
  447. everyReading(canvas, width, height) {
  448. const { yearList } = this.data
  449. var max = yearList[0].borrowNum;
  450. for (var i = 1; i < yearList.length; i++) {
  451. var cur = yearList[i].borrowNum;
  452. cur > max ? max = cur : null
  453. }
  454. this.selectComponent('#readCanvas').init(function (canvas, width, height) {
  455. // 数据
  456. const data = (list => {
  457. const arr = []
  458. for (const v of list) {
  459. const { months = '', borrowNum = 0 } = v
  460. arr.push({
  461. year: months.slice(5, 7) + '月',
  462. sales: borrowNum
  463. })
  464. }
  465. return arr
  466. })(yearList)
  467. chart = new F2.Chart({
  468. el: canvas,
  469. width: wx.getSystemInfoSync().windowWidth - 30,
  470. height
  471. });
  472. chart.source(data, {
  473. sales: {
  474. tickCount: 10,
  475. max: max + 10,
  476. min: 0
  477. }
  478. });
  479. chart.axis('sales', {
  480. line: {
  481. lineWidth: 1,
  482. stroke: '#E6E6EC',
  483. top: false, // 展示在最上层
  484. },
  485. tickLine: {
  486. lineWidth: 1,
  487. stroke: '#A1A1B3',
  488. length: 2, // 刻度线长度
  489. top: false
  490. },
  491. grid: null,
  492. label: (text, index, total) => {
  493. const cfg = {
  494. textAlign: 'center',
  495. color: '#A1A1B3',
  496. fontSize: 10
  497. }
  498. cfg.text = Math.floor(text)
  499. return cfg;
  500. },
  501. })
  502. chart.axis('year', {
  503. line: {
  504. lineWidth: 1,
  505. stroke: '#E6E6EC',
  506. top: true, // 展示在最上层
  507. },
  508. grid: null,
  509. label: (text, index, total) => {
  510. const cfg = {
  511. textAlign: 'center',
  512. color: '#41414C',
  513. fontSize: 12
  514. }
  515. return cfg;
  516. },
  517. })
  518. chart.animate(true)
  519. chart.tooltip(false);
  520. chart.interval()
  521. .position('year*sales')
  522. .color('#FF6464');
  523. chart.render();
  524. // 绘制柱状图文本
  525. const offset = -5;
  526. const chartCanvas = chart.get('canvas');
  527. const group = chartCanvas.addGroup();
  528. const shapes = {};
  529. data.map(obj => {
  530. const point = chart.getPosition(obj);
  531. const text = group.addShape('text', {
  532. attrs: {
  533. x: point.x,
  534. y: point.y + offset,
  535. fontSize: 11,
  536. text: obj.sales == 0 ? '暂\n无\n数\n据' : obj.sales + '本',
  537. textAlign: 'center',
  538. textBaseline: 'bottom',
  539. fill: '#A1A1B3'
  540. }
  541. });
  542. shapes[obj.year] = text; // 缓存该 shape, 便于后续查找
  543. });
  544. return chart;
  545. });
  546. },
  547. /**
  548. * 调用微信扫一扫之前判断可借书多少本
  549. */
  550. scanCtl: function () {
  551. const continuousFn = { fn: this.scanCtl, param: { ...arguments } }
  552. const { library, vipId, userId } = this.data.options
  553. console.log(library)
  554. const libId = library.id || ''
  555. if (!hasVipService()) return
  556. InitBorrowCar({ data: { vipId, libId }, continuousFn }).then(res => {
  557. const { canBorrowNum, borrowNumTotal } = res.data
  558. wx.showToast({
  559. title: `您还可以借${canBorrowNum}本书`,
  560. icon: 'none'
  561. })
  562. if (this.data.bookList.length > 0) {
  563. navigateTo({ url: 'parents/pages/borrow_car/borrow_car', paras: { canBorrowNum } })
  564. return
  565. }
  566. if (canBorrowNum - this.data.bookList.length > 0) {
  567. this.scanFn()
  568. }
  569. this.setData({ ...res.data })
  570. })
  571. },
  572. /**
  573. * 调用微信扫一扫
  574. */
  575. scanFn: function () {
  576. wx.scanCode({
  577. success: res => {
  578. const url = res.result
  579. const detailsId = url.split('_')[1].split('.')[0]
  580. if (!detailsId) {
  581. wx.showToast({
  582. title: qrcodeInvalidToastText,
  583. icon: 'none'
  584. })
  585. return
  586. }
  587. this.scanningBooksFn(detailsId)
  588. }
  589. })
  590. },
  591. /**
  592. * 扫一扫借书
  593. */
  594. scanningBooksFn: function (detailsId) {
  595. const continuousFn = { fn: this.scanningBooksFn, param: { ...arguments } }
  596. const { vipId } = this.data.options
  597. const { canBorrowNum, bookList } = this.data
  598. ScanningBooksTwo({ data: { detailsId, vipId }, continuousFn }).then(res => {
  599. const { detailsId } = res.data;
  600. for (var i in bookList) {
  601. if (detailsId == bookList[i].detailsId) {
  602. wx.showToast({
  603. title: '此二维码已经扫过',
  604. icon: 'none'
  605. })
  606. }
  607. }
  608. if (detailsId) {
  609. navigateTo({ url: 'parents/pages/borrow_car/borrow_car', paras: { ...res.data, canBorrowNum } })
  610. }
  611. }).catch(res => {
  612. wx.showToast({
  613. title: res.msg,
  614. icon: 'none'
  615. })
  616. })
  617. }
  618. })