dashboard.js 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552
  1. define(['jquery', 'bootstrap', 'backend', 'table', 'form', 'moment'], function ($, undefined, Backend, Table, Form, Moment) {
  2. var Controller = {
  3. index: () => {
  4. const { reactive, onMounted } = Vue
  5. const index = {
  6. setup() {
  7. const state = reactive({
  8. total: {
  9. user: {
  10. data: {},
  11. color: '#806AF6',
  12. color1: 'rgba(128, 106, 246, 0.4)',
  13. color2: 'rgba(128, 106, 246, 0)',
  14. title: '用户数量',
  15. tip: '今日新增用户',
  16. footer: '本周新增用户人数',
  17. },
  18. agent: {
  19. data: {},
  20. color: '#409EFF',
  21. color1: 'rgba(64, 158, 255, 0.4)',
  22. color2: ' rgba(64, 158, 255, 0)',
  23. title: '分销商数量',
  24. tip: '今日新增人数',
  25. footer: '本周新增分销商人数',
  26. },
  27. share: {
  28. data: {},
  29. color: '#21C732',
  30. color1: 'rgba(33, 199, 50, 0.4)',
  31. color2: 'rgba(33, 199, 50, 0)',
  32. title: '分享次数',
  33. tip: '今日分享次数',
  34. footer: '本周新增分享次数',
  35. },
  36. },
  37. })
  38. function getTotal() {
  39. Fast.api.ajax({
  40. url: 'shopro/dashboard/total',
  41. type: 'GET',
  42. }, function (ret, res) {
  43. state.total.agent.data = res.data.agent_data;
  44. state.total.share.data = res.data.share_data;
  45. state.total.user.data = res.data.user_data;
  46. for (var key in state.total) {
  47. if (state.total[key].data) {
  48. initChartTotal(key)
  49. }
  50. }
  51. return false
  52. }, function (ret, res) { })
  53. }
  54. function initChartTotal(key) {
  55. var myChart = echarts.init(document.getElementById(`${key}Total`));
  56. window.onresize = () => {
  57. myChart.resize()
  58. }
  59. var option = {
  60. grid: {
  61. left: 6,
  62. top: 6,
  63. right: 6,
  64. bottom: 6,
  65. },
  66. tooltip: {
  67. trigger: 'axis',
  68. axisPointer: {
  69. type: 'none',
  70. },
  71. },
  72. xAxis: {
  73. type: 'category',
  74. data: ['分', 20, 36, 10, 10, 20],
  75. boundaryGap: false,
  76. axisTick: {
  77. show: false,
  78. },
  79. axisLabel: {
  80. show: false,
  81. },
  82. axisLine: {
  83. show: false,
  84. },
  85. },
  86. yAxis: {
  87. type: 'value',
  88. splitLine: {
  89. show: false,
  90. },
  91. axisLabel: {
  92. show: false,
  93. },
  94. },
  95. series: [{
  96. // name: state.total.user.title,
  97. data: [5, 20, 36, 10, 10, 20], // [5, 20, 36, 10, 10, 20]
  98. type: 'line',
  99. smooth: true,
  100. showSymbol: false,
  101. symbol: 'circle',
  102. symbolSize: 6,
  103. itemStyle: {
  104. color: state.total[key].color,
  105. },
  106. areaStyle: {
  107. color: new echarts.graphic.LinearGradient(
  108. 0,
  109. 0,
  110. 0,
  111. 1,
  112. [
  113. {
  114. offset: 0,
  115. color: state.total[key].color1,
  116. },
  117. {
  118. offset: 1,
  119. color: state.total[key].color2,
  120. },
  121. ],
  122. false,
  123. ),
  124. },
  125. lineStyle: {
  126. width: 2,
  127. },
  128. }]
  129. };
  130. initIntervalTotal(24, 'hours', option, key)
  131. myChart.setOption(option);
  132. }
  133. function initIntervalTotal(interval, kld, option, key) {
  134. let dateTime = `${Moment().format('YYYY-MM-DD')} 00:00:00`;
  135. let x = [];
  136. let y = [];
  137. let timeStamp = [];
  138. for (let i = 0; i <= interval; i++) {
  139. x.push(Moment(dateTime).add(i, kld).format('HH:mm'));
  140. y.push(0);
  141. timeStamp.push(Moment(dateTime).add(i, kld).valueOf());
  142. }
  143. x.forEach((item, index) => {
  144. state.total[key].data.array.forEach((item) => {
  145. if (
  146. timeStamp[index + 1] &&
  147. item.createtime_unix > timeStamp[index] &&
  148. item.createtime_unix <= timeStamp[index + 1]
  149. ) {
  150. y[index]++;
  151. }
  152. });
  153. });
  154. option.xAxis.data = x;
  155. option.series[0].data = y;
  156. }
  157. const chart = reactive({
  158. tabsData: {
  159. order: '订单数',
  160. payOrder: '支付订单',
  161. payAmount: '支付金额',
  162. },
  163. tabActive: 'order',
  164. dateTime: getTimeSlot(),
  165. shortcuts: [
  166. {
  167. text: '今天',
  168. value: getTimeSlot(),
  169. },
  170. {
  171. text: '昨天',
  172. value: () => {
  173. return getTimeSlot('yesterday');
  174. },
  175. },
  176. {
  177. text: '近一周',
  178. value: () => {
  179. return getTimeSlot('week');
  180. },
  181. },
  182. ],
  183. data: {
  184. payAmountArr: [], // 销售额
  185. payOrderArr: [], // 订单
  186. orderArr: [], //订单数
  187. },
  188. });
  189. function onChangeTabActive(type) {
  190. chart.tabActive = type;
  191. chartOption.series[0].name = chart.tabsData[chart.tabActive];
  192. initChart();
  193. }
  194. function onChangeDateTime(e) {
  195. // 时间date必选
  196. e && getChart();
  197. }
  198. const statistics = reactive({
  199. order: {
  200. num: 0,
  201. text: '订单数',
  202. path: '',
  203. tip: '时间区间内总的下单数量(包含未支付订单)',
  204. status: 'all',
  205. },
  206. payAmount: {
  207. num: 0,
  208. text: '支付金额',
  209. path: '',
  210. tip: '时间区间内支付订单的支付总金额(包含退款订单)',
  211. status: 'paid',
  212. },
  213. payOrder: {
  214. num: 0,
  215. text: '支付订单',
  216. path: '',
  217. tip: '时间区间内支付的订单数量(包含退款订单)',
  218. status: 'paid',
  219. },
  220. noSend: {
  221. num: 0,
  222. text: '待发货订单',
  223. path: '',
  224. tip: '时间区间内待发货订单数量',
  225. status: 'nosend',
  226. },
  227. aftersale: {
  228. num: 0,
  229. text: '售后维权',
  230. path: '',
  231. tip: '时间区间内申请售后维权的订单数量',
  232. status: 'aftersale',
  233. },
  234. refund: {
  235. num: 0,
  236. text: '退款订单',
  237. path: '',
  238. tip: '时间区间内退款的订单数量',
  239. status: 'refund',
  240. },
  241. });
  242. async function getChart() {
  243. Fast.api.ajax({
  244. url: 'shopro/dashboard/chart',
  245. type: 'GET',
  246. data: {
  247. date: chart.dateTime.join(' - '),
  248. }
  249. }, function (ret, res) {
  250. for (let key in statistics) {
  251. statistics[key].num = res.data[`${key}Num`];
  252. }
  253. chart.data.payAmountArr = res.data.payAmountArr; // 销售额
  254. chart.data.payOrderArr = res.data.payOrderArr; // 订单
  255. chart.data.orderArr = res.data.orderArr; //订单数
  256. initChart();
  257. return false
  258. }, function (ret, res) { })
  259. }
  260. // 柱状图参数
  261. const chartOption = reactive({
  262. grid: {
  263. left: '10px',
  264. top: '20px',
  265. bottom: '20px',
  266. right: '20px',
  267. containLabel: true,
  268. },
  269. xAxis: {
  270. type: 'category',
  271. data: [],
  272. offset: 5,
  273. axisLine: {
  274. show: false,
  275. },
  276. axisTick: {
  277. show: false,
  278. },
  279. },
  280. yAxis: {
  281. type: 'value',
  282. offset: 5,
  283. splitLine: {
  284. show: false,
  285. },
  286. axisTick: {
  287. show: false,
  288. },
  289. axisLine: {
  290. show: false,
  291. },
  292. },
  293. tooltip: {
  294. trigger: 'axis',
  295. axisPointer: {
  296. show: true,
  297. status: 'shadow',
  298. z: -1,
  299. shadowStyle: {
  300. color: 'rgba(191, 191, 191, 0.24)',
  301. },
  302. type: 'shadow',
  303. },
  304. },
  305. series: [
  306. {
  307. name: chart.tabsData[chart.tabActive],
  308. type: 'bar',
  309. data: [],
  310. zlevel: 1,
  311. z: 1,
  312. label: {
  313. show: false,
  314. position: 'top',
  315. },
  316. itemStyle: {
  317. color: '#806af6',
  318. },
  319. showBackground: true,
  320. backgroundStyle: {
  321. color: 'rgba(191, 191, 191, 0.24)',
  322. },
  323. },
  324. ],
  325. });
  326. // 获取时间刻度
  327. function initChart() {
  328. if (chart.dateTime) {
  329. let time =
  330. (new Date(chart.dateTime[1].replace(/-/g, '/')).getTime() -
  331. new Date(chart.dateTime[0].replace(/-/g, '/')).getTime()) /
  332. 1000 +
  333. 1;
  334. let kld = '';
  335. let interval = 0;
  336. if (time <= 60 * 60) {
  337. interval = parseInt(time / 60);
  338. kld = 'minutes';
  339. } else if (time <= 60 * 60 * 24) {
  340. interval = parseInt(time / (60 * 60));
  341. kld = 'hours';
  342. } else if (time <= 60 * 60 * 24 * 30 * 1.5) {
  343. interval = parseInt(time / (60 * 60 * 24));
  344. kld = 'days';
  345. } else if (time < 60 * 60 * 24 * 30 * 24) {
  346. interval = parseInt(time / (60 * 60 * 24 * 30));
  347. kld = 'months';
  348. } else if (time >= 60 * 60 * 24 * 30 * 24) {
  349. interval = parseInt(time / (60 * 60 * 24 * 30 * 12));
  350. kld = 'years';
  351. }
  352. drawX(interval, kld);
  353. console.log(chartOption, 'chartOption')
  354. var myChart2 = echarts.init(document.getElementById(`chartContent`));
  355. window.onresize = () => {
  356. myChart2.resize()
  357. }
  358. myChart2.setOption(chartOption);
  359. } else {
  360. chartOption.xAxis.data = [];
  361. chartOption.series[0].data = [];
  362. }
  363. }
  364. // 给柱状图数据赋值
  365. function drawX(interval, kld) {
  366. let x = [];
  367. let y = [];
  368. let timeStamp = [];
  369. for (let i = 0; i <= interval - 1; i++) {
  370. if (kld == 'minutes' || kld == 'hours') {
  371. x.push(Moment(chart.dateTime[0]).add(i, kld).format('DD HH:mm'));
  372. y.push(0);
  373. } else if (kld == 'days') {
  374. x.push(Moment(chart.dateTime[0]).add(i, kld).format('YYYY-MM-DD'));
  375. y.push(0);
  376. } else if (kld == 'months') {
  377. x.push(Moment(chart.dateTime[0]).add(i, kld).format('YYYY-MM'));
  378. y.push(0);
  379. } else {
  380. x.push(Moment(chart.dateTime[0]).add(i, kld).format('YYYY'));
  381. y.push(0);
  382. }
  383. }
  384. for (let i = 1; i <= interval; i++) {
  385. timeStamp.push(Moment(chart.dateTime[0]).add(i, kld).valueOf());
  386. }
  387. x.forEach((item, index) => {
  388. chart.data[`${chart.tabActive}Arr`].forEach((item) => {
  389. if (
  390. item.createtime > (index - 1 >= 0 ? timeStamp[index - 1] : 0) &&
  391. item.createtime <= timeStamp[index]
  392. ) {
  393. if (chart.tabActive == 'payAmount') {
  394. y[index] = (Number(y[index]) + Number(item.counter)).toFixed(2);
  395. } else {
  396. y[index]++;
  397. }
  398. }
  399. });
  400. });
  401. chartOption.xAxis.data = x;
  402. chartOption.series[0].data = y;
  403. }
  404. // 默认获取当天的时间赋值
  405. function getTimeSlot(e) {
  406. let beginTime = Moment(new Date()).format('YYYY-MM-DD');
  407. let endTime = Moment(new Date()).format('YYYY-MM-DD');
  408. switch (e) {
  409. case 'yesterday':
  410. endTime = Moment().subtract(1, 'days').format('YYYY-MM-DD');
  411. beginTime = endTime;
  412. break;
  413. case 'week':
  414. beginTime = Moment().subtract(1, 'weeks').format('YYYY-MM-DD');
  415. break;
  416. case 'month':
  417. beginTime = Moment().subtract(1, 'months').format('YYYY-MM-DD');
  418. }
  419. let timeSlot = [beginTime + ' 00:00:00', endTime + ' 23:59:59'];
  420. return timeSlot;
  421. }
  422. const ranking = reactive({
  423. goods: [],
  424. hot_search: []
  425. })
  426. const pieOption = reactive({
  427. tooltip: {
  428. trigger: 'item',
  429. formatter: '{a} <br/>{b}: {c} ({d}%)',
  430. },
  431. legend: {
  432. show: false,
  433. },
  434. series: [
  435. {
  436. name: '热搜榜',
  437. type: 'pie',
  438. radius: ['52%', '90%'],
  439. avoidLabelOverlap: false,
  440. label: {
  441. show: false,
  442. position: 'center',
  443. },
  444. zlevel: 1,
  445. z: 1,
  446. emphasis: {
  447. label: {
  448. show: true,
  449. fontSize: '16',
  450. fontWeight: 'normal',
  451. },
  452. },
  453. labelLine: {
  454. show: false,
  455. },
  456. data: [],
  457. },
  458. ],
  459. });
  460. function getRanking() {
  461. Fast.api.ajax({
  462. url: 'shopro/dashboard/ranking',
  463. type: 'GET',
  464. }, function (ret, res) {
  465. ranking.goods = res.data.goods
  466. ranking.hot_search = res.data.hot_search
  467. pieOption.series[0].data = []
  468. ranking.hot_search.forEach(item => {
  469. pieOption.series[0].data.push({
  470. name: item.keyword,
  471. value: item.num,
  472. });
  473. })
  474. var myChart3 = echarts.init(document.getElementById(`rankingContent`));
  475. window.onresize = () => {
  476. myChart3.resize()
  477. }
  478. myChart3.setOption(pieOption);
  479. return false
  480. }, function (ret, res) { })
  481. }
  482. function onOpen(status) {
  483. Fast.api.open(`shopro/order/order/index?status=${status}&createtime=${encodeURI(JSON.stringify(chart.dateTime))}`, "订单", {
  484. callback() {
  485. getChart()
  486. }
  487. })
  488. }
  489. onMounted(() => {
  490. Config.cardList.forEach(item => {
  491. if (item.name == 'total' && item.status) {
  492. getTotal()
  493. }
  494. if (item.name == 'chart' && item.status) {
  495. getChart()
  496. }
  497. if (item.name == 'ranking' && item.status) {
  498. getRanking()
  499. }
  500. })
  501. })
  502. return {
  503. state,
  504. getTotal,
  505. chart,
  506. onChangeTabActive,
  507. onChangeDateTime,
  508. statistics,
  509. getChart,
  510. chartOption,
  511. initChart,
  512. drawX,
  513. getTimeSlot,
  514. ranking,
  515. onOpen,
  516. }
  517. }
  518. }
  519. createApp('index', index);
  520. },
  521. };
  522. return Controller;
  523. });