statistics.vue 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672
  1. <template>
  2. <view>
  3. <!-- 公共组件-每个页面必须引入 -->
  4. <public-module></public-module>
  5. <!-- 头部信息Start -->
  6. <view class="headers " :style="headerStyle">
  7. <view class="dis a-c j-c">
  8. <text>统计</text>
  9. <!-- <view class="headers-right">
  10. <image @click="weChatService" src="/static/image/my/kefu.png" mode="">
  11. </image>
  12. <text>客服</text>
  13. </view> -->
  14. </view>
  15. </view>
  16. <view class="body-box" style="margin-top: 100px" v-if="type == 1">
  17. <view class=" dis j-s a-c" style="padding: 10px 10px 0 0;">
  18. <view class="statistics-title">新增人员汇总统计</view>
  19. <view class="search-data">
  20. <text v-for="(val, index) in year" :key="index" :class="val.startShow ? 'active' : ''"
  21. @click="onSeachYear(val, index, 1)">{{ val.lable }}</text>
  22. </view>
  23. </view>
  24. <view class="statistics-number ">
  25. <view v-if="level <= 4">
  26. <text>{{ echartsList.onePartnerNum || 0 }}</text>
  27. <text>一级合伙人</text>
  28. </view>
  29. <view v-if="level <= 3">
  30. <text>{{ echartsList.twoPartnerNum || 0 }}</text>
  31. <text>二级合伙人</text>
  32. </view>
  33. <view v-if="level <= 2">
  34. <text>{{ echartsList.threePartnerNum || 0 }}</text>
  35. <text>三级合伙人</text>
  36. </view>
  37. <view v-if="level == 1">
  38. <text>{{ echartsList.fourPartnerNum || 0 }}</text>
  39. <text>四级合伙人</text>
  40. </view>
  41. <!-- <view v-if="level==1">
  42. <text>{{ echartsList.onePartnerNum || 0 }}</text>
  43. <text>一级合伙人</text>
  44. </view>
  45. <view v-if="level<=2">
  46. <text>{{ echartsList.twoPartnerNum || 0 }}</text>
  47. <text>{{level==2?'一级合伙人':'二级合伙人'}}</text>
  48. </view>
  49. <view v-if="level<=3">
  50. <text>{{ echartsList.threePartnerNum || 0 }}</text>
  51. <text>{{level==3?'一级合伙人':level==2?'二级合伙人':'三级合伙人'}}</text>
  52. </view>
  53. <view v-if="level<=4">
  54. <text>{{ echartsList.fourPartnerNum || 0 }}</text>
  55. <text>{{level==4?'一级合伙人':level==3?'二级合伙人':level==2?'三级合伙人':'四级合伙人'}}</text>
  56. </view> -->
  57. <view>
  58. <text>{{ echartsList.workSum || 0 }}</text>
  59. <text>工作室</text>
  60. </view>
  61. <view>
  62. <text>{{ echartsList.deptSum || 0 }}</text>
  63. <text>团队</text>
  64. </view>
  65. <view>
  66. <text>{{ echartsList.deptManSum || 0 }}</text>
  67. <text>代理人</text>
  68. </view>
  69. </view>
  70. <view class="partner-type dis">
  71. <view style="width: 650px;overflow-x: auto;">
  72. <text :class="typeStatistics == val.value ? 'selected' : ''" v-for="val in partnerTypeOption"
  73. :key="val.value" @click="getPartnerType(val.value)">{{ val.lable }}</text>
  74. </view>
  75. </view>
  76. <o-empty v-if="echartsList.countUserNumVoList && echartsList.countUserNumVoList.length == 0" height="20vh" />
  77. <qiun-data-charts v-else type="area" :opts="opts1" :chartData="chartData1" />
  78. </view>
  79. <view class="body-box" v-if="type == 1">
  80. <view class=" dis j-s a-c" style="padding: 10px 10px 0 0;">
  81. <view class="statistics-title">新增人员占比分析</view>
  82. <view class="search-data">
  83. <text v-for="(val, index) in year" :key="index" :class="val.startShow ? 'active' : ''"
  84. @click="onSeachYear(val, index, 2)">{{ val.lable }}</text>
  85. </view>
  86. </view>
  87. <leverStaff @getPartnerType="getPartnerType2"></leverStaff>
  88. <!-- <o-empty v-if="echartsList.countUserNumVoList && echartsList.countUserNumVoList.length==0" height="20vh" /> -->
  89. <view class="charts-box">
  90. <qiun-data-charts type="ring" :opts="{ legend: { position: 'bottom' } }" :eopts="ringOpts" :chartData="chartsDataPie2"
  91. :echartsH5="true" :echartsApp="true" />
  92. </view>
  93. </view>
  94. <view class="body-box" style="padding-bottom: 10px;" v-if="type == 1">
  95. <view class=" dis j-s a-c" style="padding: 10px 10px 0 0;">
  96. <view class="statistics-title">排名</view>
  97. </view>
  98. <leverStaff @getPartnerType="getPartnerType3"></leverStaff>
  99. <view class="teamStatistics ">
  100. <view class="statisticsTitle">
  101. <view>排名</view>
  102. <view>姓名</view>
  103. <view>人数</view>
  104. <view>详情</view>
  105. </view>
  106. <block v-for="(item, index) in directLsit" :key="index">
  107. <view>
  108. <view class="statisticsContent ">
  109. <view>
  110. <image v-if="index == 0" src="/static/icon/paiming1.png" mode=""></image>
  111. <image v-else-if="index == 1" src="/static/icon/paiming2.png" mode=""></image>
  112. <image v-else-if="index == 2" src="/static/icon/paiming3.png" mode=""></image>
  113. <text v-else>{{ index + 1 }}</text>
  114. </view>
  115. <view>{{ item.userName }}</view>
  116. <view>{{ item.deptManNum }}</view>
  117. <view style="color:#739EFF ">查看</view>
  118. </view>
  119. </view>
  120. </block>
  121. <!-- <o-empty v-if="directLsit.length==0" /> -->
  122. </view>
  123. </view>
  124. <view class="body-box" style="margin-top: 100px;" v-if="type == 2">
  125. <view class=" dis j-s a-c" style="padding: 10px 10px 0 0;">
  126. <view class="statistics-title">新增人员汇总统计</view>
  127. <view class="search-data">
  128. <text v-for="(val, index) in year" :key="index" :class="val.startShow ? 'active' : ''"
  129. @click="onSeachYear(val, index, 1)">{{ val.lable }}</text>
  130. </view>
  131. </view>
  132. <view class="statistics-number ">
  133. <view>
  134. <text>{{ echartsList.countSum || 0 }}</text>
  135. <text>新增人员</text>
  136. </view>
  137. <view>
  138. <text>{{ echartsList.deptSum || 0 }}</text>
  139. <text>团队</text>
  140. </view>
  141. <view>
  142. <text>{{ echartsList.deptManSum || 0 }}</text>
  143. <text>代理人</text>
  144. </view>
  145. </view>
  146. <view class="statistics-type">
  147. <text :class="typeStatistics == 1 ? 'selected' : ''" @click="getStatistics(1)">团队</text>
  148. <text :class="typeStatistics == 2 ? 'selected' : ''" @click="getStatistics(2)">代理人</text>
  149. </view>
  150. <o-empty v-if="echartsList.countUserNumVoList && echartsList.countUserNumVoList.length == 0" height="20vh" />
  151. <qiun-data-charts v-else type="area" :opts="opts1" :chartData="chartData1" />
  152. </view>
  153. </view>
  154. </template>
  155. <script>
  156. import {
  157. mapState,
  158. } from "vuex"
  159. import leverStaff from "../components/leverStaff.vue"
  160. export default {
  161. components: {
  162. leverStaff
  163. },
  164. data() {
  165. return {
  166. beginTime:'',
  167. endTime:'',
  168. ringOpts: {
  169. color: [ '#02CDFF','#2D97FF '],
  170. legend: { show: false },
  171. dataLabel: true,
  172. },
  173. chartsDataPie2 :{},
  174. level: '',
  175. type: null,
  176. typeStatistics: 1,
  177. typeStatistics2: 1,
  178. typeStatistics3: 1,
  179. option: {},
  180. supportStaffUrl: '',
  181. headerStyle: {
  182. backgroundColor: 'transparent',
  183. backgroundImage: 'url("/static/beijing (2).png")',
  184. backgroundSize: 'cover',
  185. backgroundPosition: '',
  186. boxShadow: ''
  187. // 其他样式属性...
  188. },
  189. year: [{
  190. lable: '日',
  191. startShow: false
  192. }, {
  193. lable: '周',
  194. startShow: false
  195. }, {
  196. lable: '月',
  197. startShow: false
  198. }],
  199. echartsList: {},
  200. analysisEchartsList: {},
  201. partnerTypeOption: [
  202. {
  203. lable: '一级合伙人',
  204. value: '1'
  205. }, {
  206. lable: '二级合伙人',
  207. value: '2'
  208. }, {
  209. lable: '三级合伙人',
  210. value: '3'
  211. }, {
  212. lable: '四级合伙人',
  213. value: '4'
  214. },
  215. ],
  216. // optsMax:10,
  217. opts1: {
  218. legend: {
  219. show: false // 设置图例不显示
  220. },
  221. yAxis: {
  222. gridType: "dash",
  223. dashLength: 2,
  224. data: [
  225. {
  226. min: 0,
  227. max: 10
  228. }
  229. ]
  230. },
  231. extra: {
  232. area: {
  233. type: "curve",
  234. opacity: 0.2,
  235. addLine: true,
  236. width: 2,
  237. gradient: true,
  238. activeType: "hollow"
  239. }
  240. // line: {
  241. // type: "curve",
  242. // width: 2,
  243. // activeType: "hollow",
  244. // linearType: "custom"
  245. // }
  246. }
  247. },
  248. chartData1: {},
  249. directLsit: []
  250. }
  251. },
  252. computed: {
  253. ...mapState(['userInfo']),
  254. },
  255. onLoad() {
  256. this.level = this.userInfo.sysUser.level
  257. if (this.level == 2) {
  258. this.partnerTypeOption = this.partnerTypeOption.slice(0, -1);
  259. }
  260. if (this.level == 3) {
  261. this.partnerTypeOption = this.partnerTypeOption.slice(0, -2);
  262. }
  263. if (this.level == 4) {
  264. this.partnerTypeOption = this.partnerTypeOption.slice(0, 1);
  265. }
  266. this.$http.get('/sys/qy/wechat/find/picture').then(res => {
  267. this.supportStaffUrl = res.data.supportStaffUrl
  268. })
  269. },
  270. onShow() {
  271. this.type = uni.getStorageSync('type')
  272. // if(this.type ==2){
  273. // this.queryData({type:1})
  274. // }
  275. // else{
  276. // this.queryData({type:1})
  277. // }
  278. this.queryData()
  279. if (this.type == 1) {
  280. this.analysisQueryData()
  281. this.rankingQueryData()
  282. }
  283. },
  284. methods: {
  285. canvasInit(canvas, width, height) {
  286. // 初始化画布
  287. this.canvas2d = canvas;
  288. },
  289. getPartnerType2(type) {
  290. this.typeStatistics2 = type
  291. this.analysisQueryData()
  292. },
  293. getPartnerType3(type) {
  294. this.typeStatistics3 = type
  295. this.rankingQueryData()
  296. },
  297. getPartnerType(type) {
  298. this.typeStatistics = type
  299. this.queryData()
  300. },
  301. getStatistics(type) {
  302. // uni.navigateTo({
  303. // url: "/pages/tools/achievement/achievement"
  304. // })
  305. // this.studioType=type
  306. this.typeStatistics = type
  307. this.queryData()
  308. },
  309. //点击跳转企业微信客服
  310. weChatService() {
  311. uni.share({
  312. provider: "weixin",
  313. openCustomerServiceChat: true,
  314. customerUrl: this.supportStaffUrl, //企业微信地址
  315. corpid: 'wwfe67d19509d43ec5', //企业id
  316. success: (res) => { },
  317. fail: (err) => { }
  318. });
  319. },
  320. onSeachYear(val, index, type) {
  321. this.year.map((value, i) => i === index ? value.startShow = !value.startShow : value.startShow = false);
  322. let now = new Date();
  323. let year = now.getFullYear();
  324. let month = now.getMonth() + 1; // 月份是从0开始的,所以需要加1
  325. let day = now.getDate();
  326. if (index == 0 && val.startShow) {
  327. let theDay = `${year}-${month.toString().padStart(2, '0')}-${day.toString().padStart(2, '0')}`;
  328. this.beginTime=theDay + ' 00:00:01'
  329. this.endTime=theDay + ' 23:59:59'
  330. type == 1?this.queryData():this.analysisQueryData()
  331. }
  332. else if (index == 1 && val.startShow) {
  333. let dayOfWeek = now.getDay();
  334. let firstDayOfWeek = new Date(year, now.getMonth(), day - dayOfWeek + 1);
  335. let lastDayOfWeek = new Date(year, now.getMonth(), day + (7 - dayOfWeek));
  336. let monday = this.formatDate(firstDayOfWeek);
  337. let sunday = this.formatDate(lastDayOfWeek);
  338. this.beginTime=monday + ' 00:00:01'
  339. this.endTime= sunday + ' 23:59:59'
  340. type == 1?this.queryData():this.analysisQueryData()
  341. }
  342. else if (index == 2 && val.startShow) {
  343. this.beginTime= this.getCurrentMonthFirst() + ' 00:00:01'
  344. this.endTime= this.getCurrentMonthLast() + ' 23:59:59'
  345. type == 1?this.queryData():this.analysisQueryData()
  346. }
  347. else {
  348. this.beginTime= ''
  349. this.endTime= ''
  350. type == 1?this.queryData():this.analysisQueryData()
  351. }
  352. },
  353. formatDate(date) {
  354. let year = date.getFullYear();
  355. let month = date.getMonth() + 1;
  356. let day = date.getDate();
  357. month = month < 10 ? '0' + month : month;
  358. day = day < 10 ? '0' + day : day;
  359. return year + '-' + month + '-' + day;
  360. },
  361. getCurrentMonthFirst() {
  362. // 获取当月第一天数据
  363. let date = new Date()
  364. date.setDate(1)
  365. let month = parseInt(date.getMonth() + 1)
  366. let day = date.getDate()
  367. if (month < 10) month = '0' + month
  368. if (day < 10) day = '0' + day
  369. return date.getFullYear() + '-' + month + '-' + day
  370. },
  371. getCurrentMonthLast() {
  372. // 获取当月最后一天数据
  373. let date = new Date()
  374. let year = date.getFullYear()
  375. let month = date.getMonth() + 1
  376. month = month < 10 ? '0' + month : month
  377. let day = new Date(year, month, 0)
  378. return year + '-' + month + '-' + day.getDate()
  379. },
  380. async analysisQueryData() {
  381. let params = {
  382. beginTime: this.beginTime,
  383. endTime: this.endTime,
  384. type: this.typeStatistics2,
  385. }
  386. let res = await this.$http.post('/APPPartner/getPartnerProportion', params);
  387. if (res.code == '200') {
  388. this.chartsDataPie2 = {
  389. "series": [{
  390. "data": [
  391. { name: `新增`,value: res.data.newProportion,labelText:`历史:${res.data.oldProportion}%` },
  392. {name: "历史", value: res.data.oldProportion, labelText:`历史:${res.data.oldProportion}%` }
  393. ]
  394. }]
  395. }
  396. }
  397. },
  398. async rankingQueryData() {
  399. let params = {
  400. type: this.typeStatistics3,
  401. }
  402. let res = await this.$http.get('/APPPartner/getLevelPartner', params);
  403. if (res.code == '200') {
  404. this.directLsit = res.data
  405. }
  406. },
  407. async queryData() {
  408. let params = {
  409. beginTime: this.beginTime,
  410. endTime: this.endTime,
  411. type: this.typeStatistics,
  412. }
  413. let res = {}
  414. if (this.type == 1) {
  415. res = await this.$http.post('/APPPartner/getPartnerCount', params);
  416. }
  417. else {
  418. res = await this.$http.post('/APPPartner/getCountUser', params);
  419. }
  420. if (res.code == '200') {
  421. this.echartsList = res.data
  422. if (res.data.countUserNumVoList && res.data.countUserNumVoList.length > 0) {
  423. let dateList = res.data.countUserNumVoList.map(function (item) {
  424. // return item.time.split(" ")[1] ? item.time.split(" ")[1] + ':00' : item.time.split(" ")[0]
  425. return item.time
  426. });
  427. let valueList = res.data.countUserNumVoList.map(function (item) {
  428. return item.countNum;
  429. });
  430. let rualit = {
  431. categories: dateList,
  432. series: [
  433. {
  434. name: "人数",
  435. // type: "line",
  436. data: valueList
  437. },
  438. ]
  439. };
  440. valueList.sort((a,b) => a-b)
  441. this.opts1.yAxis.data[0].max= valueList[valueList.length - 1];
  442. this.chartData1 = JSON.parse(JSON.stringify(rualit));
  443. }
  444. }
  445. }
  446. }
  447. }
  448. </script>
  449. <style lang="scss" scoped>
  450. .headers {
  451. position: fixed;
  452. top: 0;
  453. left: 0;
  454. height: auto;
  455. width: 100%;
  456. z-index: 999999;
  457. padding: 16px;
  458. padding-top: 40px;
  459. text {
  460. font-size: 18px;
  461. font-weight: 700;
  462. color: #333333;
  463. }
  464. }
  465. .headers-right {
  466. position: absolute;
  467. right: 15px;
  468. display: flex;
  469. align-items: center;
  470. text {
  471. font-size: 13px;
  472. color: #666666;
  473. }
  474. image {
  475. // right: 0;
  476. width: 15px;
  477. height: 15px;
  478. margin-right: 5px;
  479. }
  480. }
  481. .body-box {
  482. background: #ffffff;
  483. margin: 15px
  484. }
  485. .statistics-title {
  486. font-size: 16px;
  487. color: #333333;
  488. }
  489. .statistics-title::before {
  490. content: " ";
  491. display: inline-block;
  492. width: 4px;
  493. height: 12px;
  494. background: linear-gradient(132deg, #2DD9FF 0%, #2D6DFF 100%);
  495. border-radius: 5px 5px 5px 5px;
  496. margin-right: 4px;
  497. margin-top: 2px;
  498. }
  499. .search-data {
  500. color: #666666;
  501. border: 1px solid #EEEEEE;
  502. .active {
  503. color: #FFFFFF;
  504. background: linear-gradient(132deg, #2DD9FF 0%, #2D6DFF 100%);
  505. }
  506. text {
  507. padding: 5px 6px;
  508. border-left: 1px solid #EEEEEE;
  509. }
  510. text:first-child {
  511. border-left: none
  512. }
  513. }
  514. .statistics-number {
  515. margin: 10px 10px 20px 10px;
  516. background: #FBFBFB;
  517. border-radius: 4px 4px 4px 4px;
  518. text-align: center;
  519. padding: 15px 0;
  520. overflow: hidden;
  521. view {
  522. width: 33.33%;
  523. float: left;
  524. }
  525. text {
  526. display: block;
  527. }
  528. text:first-child {
  529. font-size: 25px;
  530. color: #333333;
  531. }
  532. text:last-child {
  533. font-size: 13px;
  534. color: #999999;
  535. }
  536. }
  537. .statistics-type {
  538. text-align: center;
  539. text {
  540. display: inline-block;
  541. width: 80px;
  542. height: 30px;
  543. line-height: 30px;
  544. text-align: center;
  545. font-size: 16px;
  546. color: #666666;
  547. background: #F4F4F4;
  548. }
  549. .selected {
  550. color: #FFFFFF;
  551. background: linear-gradient(132deg, #2DD9FF 0%, #2D6DFF 100%);
  552. }
  553. // text:first-child{
  554. // color: #FFFFFF;
  555. // background: linear-gradient( 132deg, #2DD9FF 0%, #2D6DFF 100%);
  556. // }
  557. }
  558. .partner-type {
  559. margin: 10px;
  560. width: 97%;
  561. overflow: hidden;
  562. white-space: nowrap;
  563. text {
  564. display: inline-block;
  565. border-radius: 14px 14px 14px 14px;
  566. font-size: 14px;
  567. color: #666666;
  568. padding: 1px 10px;
  569. background: #F4F4F4;
  570. margin-right: 8px;
  571. }
  572. .selected {
  573. color: #FFFFFF;
  574. background: linear-gradient(132deg, #2DD9FF 0%, #2D6DFF 100%);
  575. }
  576. }
  577. .teamStatistics {
  578. margin: 10px;
  579. background: #FFFFFF;
  580. // box-shadow: 0px 4px 10px 0px #DAE3F4;
  581. border-radius: 2px 2px 2px 2px;
  582. border: 1px solid #C8D8FF;
  583. }
  584. .statisticsContent {
  585. box-sizing: border-box;
  586. height: 70upx;
  587. text-align: center;
  588. line-height: 70upx;
  589. font-size: 26rpx;
  590. color: #666666;
  591. display: flex;
  592. flex-wrap: nowrap;
  593. justify-content: space-around;
  594. view {
  595. text-align: center;
  596. line-height: 70upx;
  597. width: 25%;
  598. font-size: 12px;
  599. }
  600. image {
  601. display: inline-block;
  602. width: 21px;
  603. height: 21px;
  604. vertical-align: middle;
  605. }
  606. }
  607. .statisticsTitle {
  608. display: flex;
  609. flex-wrap: nowrap;
  610. justify-content: space-around;
  611. height: 70upx;
  612. box-sizing: border-box;
  613. line-height: 70upx;
  614. font-size: 24rpx;
  615. color: #232832;
  616. background: linear-gradient(180deg, #DAE0EE 0%, #E9ECF4 100%);
  617. border-radius: 6px 6px 0 0;
  618. view {
  619. text-align: center;
  620. line-height: 35px;
  621. color: #2D6DFF;
  622. width: 25%;
  623. font-size: 12px;
  624. }
  625. }
  626. .charts-box{
  627. width: 100%;
  628. height: 300px;
  629. }
  630. </style>