AI销管
選択できるのは25トピックまでです。 トピックは、先頭が英数字で、英数字とダッシュ('-')を使用した35文字以内のものにしてください。
 
 
 
 

750 行
18 KiB

  1. <template>
  2. <view class="pages">
  3. <view class="boxtittab">
  4. <view class="tabbox">
  5. <view :class="{ activecllasscet: activeTotal == 4 }" @click="tabtimetap(4)">近七天</view>
  6. </view>
  7. <view class="tabbox">
  8. <view :class="{ activecllasscet: activeTotal == 5 }" @click="tabtimetap(5)">近15天</view>
  9. </view>
  10. <view class="tabbox">
  11. <view :class="{ activecllasscet: activeTotal == 6 }" @click="tabtimetap(6)">近30天</view>
  12. </view>
  13. <view class="tabbox">
  14. <view :class="{ activecllasscet: activeTotal == 3 }" @click="tabtimetap(3)">自定义</view>
  15. </view>
  16. </view>
  17. <view class="container">
  18. <scroll-view class="lside" scroll-y="true">
  19. <view class="lside-scrollbox">
  20. <block v-for="(data, index) in lsideList">
  21. <view class="lside-scrollbox-items" @tap="chooseLside(data, index)"
  22. :class="{active: index === lsideListIndex}" :key="index">
  23. {{ data.title }}
  24. </view>
  25. </block>
  26. </view>
  27. </scroll-view>
  28. <scroll-view class="rside" scroll-y="true">
  29. <view class="rside-scrollbox">
  30. <!-- 接待量 -->
  31. <template v-if="lsideListIndex === 0">
  32. <view class="single">
  33. <view class="title">
  34. <view class="title1">接待量(TOP10)</view>
  35. </view>
  36. <view class="hejisan">
  37. <view class="sanbox1">
  38. <view class="text1-2">{{newTeam1||0}}</view>
  39. <view class="text1-1">项目</view>
  40. </view>
  41. <view class="sanbox1">
  42. <view class="text1-2">{{newAvg1||0}}</view>
  43. <view class="text1-1">均值</view>
  44. </view>
  45. </view>
  46. <block v-for="(item,index) in newlisttabinfo1">
  47. <view class="box">
  48. <view class="box-lside">
  49. <template v-if="index < 2">
  50. <image class="img"
  51. :src="'../../../static/images/ranking/ranking'+ (index+1) +'.png'"
  52. mode=""></image>
  53. </template>
  54. <template v-else>
  55. <view class="ranking">{{ index + 1 }}</view>
  56. </template>
  57. </view>
  58. <view class="box-rside">
  59. <view class="box-top">
  60. <view class="percent-name">{{item.name}}</view>
  61. <view class="percent-zxl">{{ !item.zxl ? 0 : item.zxl}}</view>
  62. </view>
  63. <view class="percent-box">
  64. <view class="percent" :style="'width:'+ getPercent(item.zxl,1) + '%'">
  65. </view>
  66. </view>
  67. </view>
  68. </view>
  69. </block>
  70. </view>
  71. </template>
  72. <!-- 接待时长 -->
  73. <template v-if="lsideListIndex === 1">
  74. <view class="single">
  75. <view class="title">
  76. <view class="title1">接待时长(TOP10)</view>
  77. </view>
  78. <view class="hejisan">
  79. <view class="sanbox1">
  80. <view class="text1-2">{{newTeam2||0}}</view>
  81. <view class="text1-1">项目</view>
  82. </view>
  83. <view class="sanbox1">
  84. <view class="text1-2">{{newAvg2||0}}</view>
  85. <view class="text1-1">均值</view>
  86. </view>
  87. </view>
  88. <block v-for="(item,index) in newlisttabinfo2">
  89. <view class="box">
  90. <view class="box-lside">
  91. <template v-if="index < 2">
  92. <image class="img"
  93. :src="'../../../static/images/ranking/ranking'+ (index+1) +'.png'"
  94. mode=""></image>
  95. </template>
  96. <template v-else>
  97. <view class="ranking">{{ index + 1 }}</view>
  98. </template>
  99. </view>
  100. <view class="box-rside">
  101. <view class="box-top">
  102. <view class="percent-name">{{item.name}}</view>
  103. <view class="percent-zxl">{{ !item.zxl ? 0 : item.zxl}}</view>
  104. </view>
  105. <view class="percent-box">
  106. <view class="percent" :style="'width:'+ getPercent(item.zxl,2) + '%'">
  107. </view>
  108. </view>
  109. </view>
  110. </view>
  111. </block>
  112. </view>
  113. </template>
  114. <!-- 销讲执行排名 -->
  115. <template v-if="lsideListIndex === 2">
  116. <view class="single">
  117. <view class="title">
  118. <view class="title1" style="flex: 1;">销讲执行排名(TOP10)</view>
  119. </view>
  120. <view class="hejisan">
  121. <view class="sanbox1">
  122. <view class="text1-2">{{newTeam3||0}}</view>
  123. <view class="text1-1">项目</view>
  124. </view>
  125. <view class="sanbox1">
  126. <view class="text1-2">{{newAvg3||0}}%</view>
  127. <view class="text1-1">均值</view>
  128. </view>
  129. </view>
  130. <block v-for="(item,index) in newlisttabinfo3">
  131. <view class="box">
  132. <view class="box-lside">
  133. <template v-if="index < 2">
  134. <image class="img"
  135. :src="'../../../static/images/ranking/ranking'+ (index+1) +'.png'"
  136. mode=""></image>
  137. </template>
  138. <template v-else>
  139. <view class="ranking">{{ index + 1 }}</view>
  140. </template>
  141. </view>
  142. <view class="box-rside">
  143. <view class="box-top">
  144. <view class="percent-name">{{item.name}}</view>
  145. <view class="percent-zxl">{{ !item.zxl ? 0 : item.zxl}}</view>
  146. </view>
  147. <view class="percent-box">
  148. <view class="percent" :style="'width:'+ getPercent1(item.zxl) + '%'">
  149. </view>
  150. </view>
  151. </view>
  152. </view>
  153. </block>
  154. </view>
  155. </template>
  156. <!-- 顾问执行排名 -->
  157. <template v-if="lsideListIndex === 3">
  158. <view class="single">
  159. <view class="title">
  160. <view class="title1" style="flex: 1;">顾问执行排名(TOP10)</view>
  161. </view>
  162. <block v-for="(item,index) in newlisttabinfo4">
  163. <view class="box">
  164. <view class="box-lside">
  165. <template v-if="index < 2">
  166. <image class="img"
  167. :src="'../../../static/images/ranking/ranking'+ (index+1) +'.png'"
  168. mode=""></image>
  169. </template>
  170. <template v-else>
  171. <view class="ranking">{{ index + 1 }}</view>
  172. </template>
  173. </view>
  174. <view class="box-rside">
  175. <view class="box-top">
  176. <view class="percent-name">{{item.name}}</view>
  177. <view class="percent-zxl">{{ !item.zxl ? 0 : item.zxl}}</view>
  178. </view>
  179. <view class="percent-box">
  180. <view class="percent" :style="'width:'+ getPercent1(item.zxl) + '%'">
  181. </view>
  182. </view>
  183. </view>
  184. </view>
  185. </block>
  186. </view>
  187. </template>
  188. <template v-if="lsideListIndex === 4">
  189. <view class="single">
  190. <view class="title" style="padding-right: 30rpx;">
  191. <view class="title1" style="flex: 1;">销讲能力</view>
  192. <view class="title2" style="flex: 1;justify-content: flex-end;" @click="staffShow=true">
  193. <view class="title2-che" style="width: auto;">{{staff.label}}
  194. <image class="righttochoose" src="@/static/images/down.png" mode="">
  195. </image>
  196. </view>
  197. </view>
  198. </view>
  199. <view class="uchaserbox" v-if="emptyCharData">
  200. <qiun-data-charts type="radar" :chartData="chartData" :canvas2d="true"
  201. canvasId="wangxiaohuaerlingeryilingwuyib88" background="none" :loadingType="0"
  202. :opts="opts" />
  203. </view>
  204. <view class="uchaserbox" v-else>
  205. <u-empty mode="data"></u-empty>
  206. </view>
  207. </view>
  208. </template>
  209. </view>
  210. </scroll-view>
  211. </view>
  212. <!-- 日期选择器 -->
  213. <u-calendar v-model="totalTimeShow" mode="range" @change="totalTimeChange"></u-calendar>
  214. <!-- 选择项目 -->
  215. <u-select v-model="staffShow" :list="staffList" @confirm="staffSelectCallback" :default-value='selindex'>
  216. </u-select>
  217. <!-- 加载组件 -->
  218. <u-loadings v-model="LOADING"></u-loadings>
  219. </view>
  220. </template>
  221. <script>
  222. var app = getApp();
  223. var util = require("../../../utils/util.js");
  224. var config = require("../../../config");
  225. export default {
  226. data() {
  227. return {
  228. activeTotal: 4, // 时间选择下标
  229. // 日期选择器
  230. totalTimeShow: false, // 日期选择器
  231. lastStartDate: '', // 开始时间
  232. lastEndDate: '', // 结束时间
  233. // 项目选择器
  234. staffShow: false, // 展示项目选择器
  235. staffList: [], // 可选项目列表
  236. staff: {
  237. value: '',
  238. label: '',
  239. }, // 选择的项目数据
  240. houseId: '', // 项目id
  241. lsideList: [{
  242. title: '接待量',
  243. method: 'receptionCountList',
  244. methodParams: "1,groupComparisonReception",
  245. },
  246. {
  247. title: '接待时长',
  248. method: 'receptionCountList',
  249. methodParams: "2,groupComparisonReceptionTime"
  250. },
  251. {
  252. title: '销讲排名',
  253. method: 'receptionCountList',
  254. methodParams: "3,groupComparisonTalkRank"
  255. },
  256. {
  257. title: '顾问排名',
  258. method: 'receptionCountList',
  259. methodParams: "4,groupComparisonTalkRankByConsultant"
  260. },
  261. {
  262. title: '销讲能力',
  263. method: 'getPowerList',
  264. methodParams: ''
  265. },
  266. ],
  267. lsideListIndex: 0, // 默认选中下标
  268. // 右侧存放数据变量
  269. newlisttabinfo1: [{
  270. name: '接待量',
  271. zxl: '0'
  272. },
  273. {
  274. name: '平均执行率',
  275. zxl: '0'
  276. },
  277. {
  278. name: '接待客户',
  279. zxl: '0'
  280. },
  281. ], // 接待量
  282. // 接待量
  283. newTeam1: '',
  284. newAvg1: '',
  285. newlisttabinfo2: [{
  286. name: '接待量',
  287. zxl: '0'
  288. },
  289. {
  290. name: '平均执行率',
  291. zxl: '0'
  292. },
  293. {
  294. name: '接待客户',
  295. zxl: '0'
  296. },
  297. ], // 接待时长
  298. // 接待时长
  299. newTeam2: '',
  300. newAvg2: '',
  301. newlisttabinfo3: [{
  302. name: '接待量',
  303. zxl: '0'
  304. },
  305. {
  306. name: '平均执行率',
  307. zxl: '0'
  308. },
  309. {
  310. name: '接待客户',
  311. zxl: '0'
  312. },
  313. ], // 销讲排名
  314. // 销讲排名
  315. newTeam3: '',
  316. newAvg3: '',
  317. newlisttabinfo4: [{
  318. name: '接待量',
  319. zxl: '0'
  320. },
  321. {
  322. name: '平均执行率',
  323. zxl: '0'
  324. },
  325. {
  326. name: '接待客户',
  327. zxl: '0'
  328. },
  329. ], // 顾问排名
  330. // 顾问排名
  331. newTeam4: '',
  332. newAvg4: '',
  333. chartData: {
  334. categories: [],
  335. series: []
  336. }, // 销讲能力
  337. };
  338. },
  339. onLoad() {
  340. this.LOADING = true
  341. uni.$on('updateGroup', (data) => {
  342. this.houseId = data.arr.join(',')
  343. // 获取销奖能力
  344. this.getPowerList()
  345. })
  346. this.getSectionList()
  347. },
  348. onPullDownRefresh() {},
  349. methods: {
  350. // 获取部门列表
  351. getSectionList() {
  352. this.$u.post('/user/getHouseByToken', )
  353. .then(res => {
  354. // console.log(res)
  355. this.staffList = []
  356. res.map((item, index) => {
  357. let obj = {}
  358. obj.value = item.id
  359. obj.label = item.propertyName
  360. this.staffList.push(obj)
  361. })
  362. this.houseId = this.staffList[0].value
  363. this.staff = this.staffList[0]
  364. this.getdata()
  365. })
  366. },
  367. // 获取数据
  368. getdata() {
  369. let params = this.lsideList[this.lsideListIndex].methodParams.split(',')
  370. this[this.lsideList[this.lsideListIndex].method](params[0], params[1])
  371. },
  372. // 转换百分比
  373. getPercent(num, type) {
  374. if (this.newlisttabinfo1 && this.newlisttabinfo1.length && type == 1) {
  375. let index0 = this.newlisttabinfo1[0]
  376. let percent = num / (index0.zxl) * 100
  377. return percent.toFixed(2)
  378. } else if (this.newlisttabinfo2 && this.newlisttabinfo2.length && type == 2) {
  379. let index0 = this.newlisttabinfo2[0]
  380. let percent = num / (index0.zxl) * 100
  381. return percent.toFixed(2)
  382. } else if (this.newlisttabinfo3 && this.newlisttabinfo3.length && type == 3) {
  383. let index0 = this.newlisttabinfo3[0]
  384. let percent = num / (index0.zxl) * 100
  385. return percent.toFixed(2)
  386. } else {
  387. return 0
  388. }
  389. },
  390. // 取数值
  391. getPercent1(num) {
  392. console.log(num)
  393. return num || 0
  394. },
  395. // 接待时长
  396. receptionCountList(index, url) {
  397. this.$u.post(`/cusLvStatistics/${url}`, {
  398. timeType: this.lastEndDate ? null : this.activeTotal + '',
  399. lastEndDate: this.lastEndDate,
  400. lastStartDate: this.lastStartDate
  401. })
  402. .then(res => {
  403. this.LOADING = false
  404. // console.log(res)
  405. let result = res.result
  406. this['newTeam' + index] = res.avg[0]
  407. this['newAvg' + index] = res.avg[1]
  408. this['newlisttabinfo' + index] = []
  409. // 当选择全部时
  410. let arr = []
  411. // 当两个都选择的时候
  412. result.map(item => {
  413. let obj = {}
  414. obj.name = item.houseName
  415. obj.zxl = item.data
  416. arr.push(obj)
  417. })
  418. arr = this.dealData(arr)
  419. this['newlisttabinfo' + index] = arr
  420. }).catch(() => {
  421. this.LOADING = false
  422. })
  423. },
  424. // 获取销奖能力
  425. getPowerList() {
  426. this.chartData = {
  427. categories: [],
  428. series: []
  429. }
  430. this.$u.post('/cusLvStatistics/groupComparisonMarketingAbility', {
  431. houseIds: this.houseId,
  432. timeType: this.lastEndDate ? null : this.activeTotal + '',
  433. lastEndDate: this.lastEndDate,
  434. lastStartDate: this.lastStartDate
  435. })
  436. .then(res => {
  437. this.LOADING = false
  438. let allobj = {
  439. categories: [],
  440. series: []
  441. }
  442. if (res.result.length != 0) {
  443. res.result.map((item, index) => {
  444. let obj = {
  445. name: item.length > 0 ? item[0].houseName : '',
  446. data: []
  447. }
  448. item.map(item1 => {
  449. if (index == 0) {
  450. allobj.categories.push(item1.name)
  451. }
  452. obj.data.push(item1.avgExecutionRate)
  453. })
  454. allobj.series.push(obj)
  455. })
  456. this.chartData = allobj
  457. this.$forceUpdate()
  458. this.emptyCharData = true;
  459. } else {
  460. this.emptyCharData = false;
  461. }
  462. }).catch(e => {
  463. this.LOADING = false
  464. })
  465. },
  466. //时间切换
  467. tabtimetap(index) {
  468. this.activeTotal = index;
  469. if (index == 3) {
  470. this.totalTimeShow = true;
  471. } else {
  472. this.lastEndDate = ''
  473. this.lastStartDate = ''
  474. this.getdata()
  475. }
  476. },
  477. //自定义时间
  478. totalTimeChange(e) {
  479. console.log(e.startDate, e.endDate)
  480. this.activeTotal = 3;
  481. this.lastEndDate = e.endDate
  482. this.lastStartDate = e.startDate
  483. this.getdata()
  484. },
  485. // 定义一个公共方法对数据进行处理
  486. dealData(arr) {
  487. // 获取最大值
  488. let num = Math.max.apply(Math, arr.map(function(o) {
  489. return o.zxl
  490. })) //结果:3
  491. if (num > 100) {
  492. // 获取最大值的下标
  493. arr.map(item => {
  494. item.zxl1 = Math.floor(item.zxl / num * 100)
  495. })
  496. return arr
  497. } else {
  498. arr.map(item => {
  499. item.zxl1 = item.zxl
  500. })
  501. return arr
  502. }
  503. },
  504. // 选择项目后更新数据
  505. staffSelectCallback(e) {
  506. this.staff = e[0]
  507. this.houseId = e[0].value
  508. this.getPowerList()
  509. },
  510. // 左侧菜单选中
  511. chooseLside(data, index) {
  512. this.lsideListIndex = index
  513. this.getdata()
  514. },
  515. },
  516. };
  517. </script>
  518. <style lang="scss" scoped>
  519. .pages {
  520. width: 100%;
  521. height: 100vh;
  522. display: flex;
  523. flex-direction: column;
  524. background: #F8F8F8;
  525. .boxtittab {}
  526. .container {
  527. padding: 16rpx 0;
  528. width: 100%;
  529. height: calc(100% - 92rpx);
  530. display: grid;
  531. grid-template-columns: 160rpx 1fr;
  532. .lside {
  533. width: 100%;
  534. height: 100%;
  535. background: #F6F7FB;
  536. .lside-scrollbox {
  537. width: 100%;
  538. display: flex;
  539. flex-direction: column;
  540. .lside-scrollbox-items {
  541. width: 100%;
  542. height: 72rpx;
  543. display: flex;
  544. justify-content: center;
  545. align-items: center;
  546. font-size: 24rpx;
  547. font-family: PingFangSC-Regular, PingFang SC;
  548. font-weight: 400;
  549. color: #666666;
  550. overflow: hidden;
  551. text-overflow: ellipsis;
  552. white-space: nowrap;
  553. &.active {
  554. font-weight: 600;
  555. color: #2671E2;
  556. background: #FFFFFF;
  557. }
  558. }
  559. }
  560. }
  561. }
  562. .rside {
  563. width: 100%;
  564. height: 100%;
  565. .rside-scrollbox {
  566. width: 100%;
  567. min-height: 100%;
  568. background: #fff;
  569. display: flex;
  570. flex-direction: column;
  571. .single {
  572. width: 100%;
  573. display: flex;
  574. flex-direction: column;
  575. .hejisan {
  576. margin: 0 auto 28rpx;
  577. width: 542rpx;
  578. height: 120rpx;
  579. display: flex;
  580. background: #F6F7FB;
  581. border-radius: 8rpx;
  582. .sanbox1 {
  583. position: relative;
  584. flex-grow: 1;
  585. display: flex;
  586. flex-direction: column;
  587. justify-content: center;
  588. align-items: center;
  589. &:last-child::after {
  590. content: '';
  591. position: absolute;
  592. left: 0;
  593. top: 50%;
  594. transform: translateY(-50%);
  595. width: 1rpx;
  596. height: 80rpx;
  597. background: #E0E0E0;
  598. }
  599. }
  600. .text1-1 {
  601. font-size: 24rpx;
  602. font-family: PingFangSC-Regular, PingFang SC;
  603. font-weight: 400;
  604. color: #333333;
  605. line-height: 32rpx;
  606. }
  607. .text1-2 {
  608. color: #333333;
  609. font-size: 40rpx;
  610. line-height: 46rpx;
  611. font-family: PingFangSC-Regular, PingFang SC;
  612. margin-bottom: 10rpx;
  613. }
  614. }
  615. .uchaserbox {
  616. width: 100%;
  617. height: 470rpx;
  618. }
  619. .box {
  620. margin: 0 0 28rpx;
  621. padding: 0 24rpx;
  622. width: 100%;
  623. display: flex;
  624. .box-lside {
  625. margin: 0 24rpx 0 0;
  626. flex-shrink: 0;
  627. display: flex;
  628. justify-content: center;
  629. align-items: center;
  630. .img {
  631. width: 42rpx;
  632. height: 44rpx;
  633. }
  634. .ranking {
  635. width: 42rpx;
  636. height: 44rpx;
  637. font-size: 24rpx;
  638. font-family: SFPro-SemiboldItalic, SFPro;
  639. font-weight: normal;
  640. color: #8A8D9F;
  641. }
  642. }
  643. .box-rside {
  644. flex-grow: 1;
  645. .box-top {
  646. margin-bottom: 14rpx;
  647. width: 470rpx;
  648. display: flex;
  649. .percent-name {
  650. flex-grow: 1;
  651. width: calc(100% - 42rpx);
  652. overflow: hidden;
  653. white-space: nowrap;
  654. text-overflow: ellipsis;
  655. }
  656. .percent-zxl {
  657. flex-shrink: 0;
  658. }
  659. }
  660. .percent-box {
  661. width: 100%;
  662. height: 30rpx;
  663. .percent {
  664. height: 100%;
  665. background: #F1F3FF;
  666. border-radius: 15px;
  667. }
  668. }
  669. }
  670. }
  671. }
  672. }
  673. }
  674. }
  675. </style>