AI销管
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

811 lines
20 KiB

  1. <template>
  2. <view class="pages">
  3. <!-- 筛选框 -->
  4. <view class="boxtittabs">
  5. <view class="items" @tap="screenShow = true">{{ showTimeText }}
  6. <u-icon name="arrow-down" size="24" style="padding-left: 12rpx"></u-icon>
  7. </view>
  8. <view class="items" @tap="showSelect('companyList')">{{ showBeText }}
  9. <u-icon name="arrow-down" size="24" style="padding-left: 12rpx"></u-icon>
  10. </view>
  11. <view class="items" @tap="showSelect('houseList')">{{ showBeText1 }}
  12. <u-icon name="arrow-down" size="24" style="padding-left: 12rpx"></u-icon>
  13. </view>
  14. </view>
  15. <!-- 编辑指标 -->
  16. <view class="edit" v-if="CHECKAUTHORITY('biEditTarget')">
  17. <view class="edits" @click="toEdit">
  18. 编辑指标
  19. </view>
  20. </view>
  21. <!-- 待处理 -->
  22. <view class="grop">
  23. <view class="title">
  24. <image class="title-icon" src="https://static.quhouse.com/bc2ec951ad9a47e5bf58f2829926e143.png"
  25. mode="" />
  26. 转写消费
  27. </view>
  28. <view class="grid5">
  29. <block v-for="(item,index) in stayPendingProcessingArr">
  30. <view :key="index" class="real" v-if="item.show">
  31. <view class="realnum">{{item.data || 0}}</view>
  32. <view class="realtext">{{ item.title }}</view>
  33. </view>
  34. </block>
  35. </view>
  36. </view>
  37. <!-- 接待简报 -->
  38. <view class="grop">
  39. <view class="title">
  40. <image class="title-icon" src="https://static.quhouse.com/bc2ec951ad9a47e5bf58f2829926e143.png"
  41. mode="" />
  42. 接待简报
  43. </view>
  44. <view class="grid4">
  45. <block v-for="(item,index) in ReceptionBriefingArr">
  46. <view :key="index" class="real" v-if="item.show">
  47. <view class="realnum">{{item.data || 0}}{{ item.unit }}</view>
  48. <view class="realtext">{{ item.title }}</view>
  49. </view>
  50. </block>
  51. </view>
  52. </view>
  53. <!-- 排名柱状图 -->
  54. <block v-for="(item, index) in IndexRankingArr">
  55. <view class="grop" :key="index" v-if="item.show">
  56. <view class="titles">
  57. <view class="lside">
  58. {{item.title}}排名(top10)
  59. </view>
  60. <view class="rside">
  61. <view class="rside-item" :class="{active: item.isShowCity}" @click="checkCity(item, '按项目')">
  62. 按项目
  63. </view>
  64. <view class="rside-item" :class="{active: !item.isShowCity}" @click="checkCity(item, '按城市')">
  65. 按城市
  66. </view>
  67. </view>
  68. </view>
  69. <view class="echarts">
  70. <template v-if="item.type">
  71. <template v-if="item.isShowCity">
  72. <qiun-data-charts :type="item.type" :chartData="item.lineOptsect" :opts="item.lineOpts"
  73. background="none" :ontouch="true" :canvasId="item.canvasId" :canvas2d="true" />
  74. </template>
  75. <template v-else>
  76. <qiun-data-charts :type="item.type" :chartData="item.lineOptsect1" :opts="item.lineOpts"
  77. background="none" :ontouch="true" :canvasId="item.canvasId1" :canvas2d="true" />
  78. </template>
  79. </template>
  80. <template v-else>
  81. <view class="empty">
  82. <view
  83. style="width: 100%;height: 300rpx;display: flex;flex-direction: column;justify-content: center;align-items: center;">
  84. <view style="width: 100%;text-align: center;">
  85. <image style="width: 220rpx;height: 200rpx;"
  86. src="https://static.quhouse.com/zhikong_xcx_img/nodatalist.png" mode="">
  87. </image>
  88. </view>
  89. <view style="text-align: center;width: 100%;margin-top: 20rpx;color: #999999;">暂无数据
  90. </view>
  91. </view>
  92. </view>
  93. </template>
  94. </view>
  95. </view>
  96. </block>
  97. <!-- 趋势折线图 -->
  98. <block v-for="(item, index) in IndicatorTrendsArr">
  99. <view class="grop" :key="index" v-if="item.show">
  100. <view class="titles">
  101. <view class="lside">
  102. {{item.title}}趋势
  103. </view>
  104. </view>
  105. <view class="echarts">
  106. <template v-if="item.lineOptsect">
  107. <qiun-data-charts :type="item.type" :chartData="item.lineOptsect" :opts="item.lineOpts"
  108. background="none" :ontouch="true" :canvasId="item.canvasId" :canvas2d="true" />
  109. </template>
  110. <template v-else>
  111. <view class="empty">
  112. <view
  113. style="width: 100%;height: 300rpx;display: flex;flex-direction: column;justify-content: center;align-items: center;">
  114. <view style="width: 100%;text-align: center;">
  115. <image style="width: 220rpx;height: 200rpx;"
  116. src="https://static.quhouse.com/zhikong_xcx_img/nodatalist.png" mode="">
  117. </image>
  118. </view>
  119. <view style="text-align: center;width: 100%;margin-top: 20rpx;color: #999999;">暂无数据
  120. </view>
  121. </view>
  122. </view>
  123. </template>
  124. </view>
  125. </view>
  126. </block>
  127. <!-- 分布饼图 -->
  128. <block v-for="(item, index) in IndicatorDistributionArr">
  129. <view class="grop" :key="index" v-if="item.show">
  130. <view class="titles">
  131. <view class="lside">
  132. {{item.title}}分布
  133. </view>
  134. </view>
  135. <view class="echarts">
  136. <template v-if="item.type">
  137. <qiun-data-charts :type="item.type" :chartData="item.lineOptsect" :opts="item.lineOpts"
  138. background="none" :ontouch="true" :canvasId="item.canvasId" :canvas2d="true" />
  139. </template>
  140. <template v-else>
  141. <view class="empty">
  142. <view
  143. style="width: 100%;height: 300rpx;display: flex;flex-direction: column;justify-content: center;align-items: center;">
  144. <view style="width: 100%;text-align: center;">
  145. <image style="width: 220rpx;height: 200rpx;"
  146. src="https://static.quhouse.com/zhikong_xcx_img/nodatalist.png" mode="">
  147. </image>
  148. </view>
  149. <view style="text-align: center;width: 100%;margin-top: 20rpx;color: #999999;">暂无数据
  150. </view>
  151. </view>
  152. </view>
  153. </template>
  154. </view>
  155. </view>
  156. </block>
  157. <!-- 更多筛选 -->
  158. <u-popup v-model="screenShow" mode="bottom" height="400">
  159. <view class="screen">
  160. <view class="boxtittab">
  161. <view class="tabbox">
  162. <view :class="{ activecllasscet: params.dateType == 0 }" @click="tabtimetap(0, '今天')">今天</view>
  163. </view>
  164. <view class="tabbox">
  165. <view :class="{ activecllasscet: params.dateType == 1 }" @click="tabtimetap(1, '近七天')">近七天
  166. </view>
  167. </view>
  168. <view class="tabbox">
  169. <view :class="{ activecllasscet: params.dateType == 2 }" @click="tabtimetap(2, '近30天')">近30天
  170. </view>
  171. </view>
  172. <view class="tabbox">
  173. <view :class="{ activecllasscet: params.dateType == null }" @click="tabtimetap(null, '自定义')">自定义
  174. </view>
  175. </view>
  176. </view>
  177. </view>
  178. </u-popup>
  179. <!-- 日期选择器 -->
  180. <u-calendar v-model="totalTimeShow" mode="range" @change="totalTimeChange"></u-calendar>
  181. <!-- 项目&公司 -->
  182. <u-select :mask-close-able="false" label-name="templateName" value-name="id" v-model="showTemplate"
  183. mode="single-column" :list="templateList" @cancel="templateCancel" @confirm="templateConfirm"></u-select>
  184. </view>
  185. </template>
  186. <script>
  187. const config = require("@/config");
  188. import * as allArrList from './arr.js'
  189. export default {
  190. data() {
  191. return {
  192. showTimeText: '近七天', // 展示文字
  193. showBeText: '公司', //
  194. showBeText1: '项目', //
  195. showTemplate: false,
  196. screenShow: false, // 日期选择器
  197. totalTimeShow: false, // 日期选择器
  198. templateList: [], // 销讲业务
  199. houseList: [], // 项目列表
  200. companyList: [], // 项目列表
  201. stayPendingProcessingArr: allArrList.stayPendingProcessingArr, // 待处理
  202. ReceptionBriefingArr: allArrList.ReceptionBriefingArr, // 接待简报
  203. IndexRankingArr: allArrList.IndexRankingArr, // 排名
  204. IndicatorTrendsArr: allArrList.IndicatorTrendsArr, // 排名
  205. IndicatorDistributionArr: allArrList.IndicatorDistributionArr, // 排名
  206. params: {
  207. staDate: '', //开启时间
  208. endDate: '', // 结束时间
  209. houseId: '', // 楼盘
  210. orgCode: '', // 公司code
  211. dateType: 1, // 自定义时间 今天0 近七天1 30天2
  212. },
  213. needFormatArr: ['stayPendingProcessingArr', 'ReceptionBriefingArr', 'IndexRankingArr',
  214. 'IndicatorTrendsArr', 'IndicatorDistributionArr'
  215. ], // 需要格式化的数组
  216. publicId: '', // 标识区别选择的是公司还是项目
  217. publicOpts: {
  218. color: ["#1890FF", "#91CB74", "#FAC858", "#EE6666", "#73C0DE", "#3CA272", "#FC8452", "#9A60B4",
  219. "#ea7ccc"
  220. ],
  221. padding: [15, 15, 0, 5],
  222. enableScroll: true,
  223. legend: {},
  224. xAxis: {
  225. rotateLabel: true,
  226. rotateAngle: 90,
  227. fontSize: 10,
  228. itemCount: 4,
  229. },
  230. yAxis: {
  231. gridType: "dash",
  232. },
  233. extra: {
  234. line: {
  235. type: "straight",
  236. width: 2,
  237. activeType: "hollow"
  238. }
  239. }
  240. }
  241. };
  242. },
  243. onLoad() {
  244. this.getHouse()
  245. this.getCompany()
  246. this.initPage()
  247. },
  248. onPullDownRefresh() {
  249. this.initPage()
  250. setTimeout(() => {
  251. uni.stopPullDownRefresh()
  252. }, 2000)
  253. },
  254. methods: {
  255. // 字典
  256. biDictionary() {
  257. this.$u.get('/customer/biDict').then(res => {
  258. if (res) {
  259. this.needFormatArr.forEach((item, index) => {
  260. this[item] = this[item].map(it => {
  261. return {
  262. ...it,
  263. indexType: index
  264. }
  265. })
  266. let arr1 = res.filter(arr => arr.indexType == index)
  267. arr1.map(ie => {
  268. let objs = this[item].findIndex(obj => {
  269. return obj.title == ie.indexName && obj.indexType == ie
  270. .indexType
  271. }) || 0
  272. this[item][objs].id = ie.id || ''
  273. })
  274. })
  275. this.getFindBiByAccountId()
  276. }
  277. })
  278. },
  279. // 回显
  280. getFindBiByAccountId() {
  281. this.$u.get('/customer/findBiByAccountId').then(res => {
  282. if (res) {
  283. let arr = [...res.index1.split(','), ...res.index2.split(','), ...res.index3.split(','),
  284. ...res.index4.split(','), ...res.index5.split(',')
  285. ]
  286. this.needFormatArr.forEach(item => {
  287. this[item].forEach(items => {
  288. let obj = arr.find(obj => obj == items.id)
  289. if (obj) items.show = true
  290. else items.show = false
  291. })
  292. })
  293. }
  294. })
  295. },
  296. async initPage() {
  297. await this.biDictionary()
  298. await this.bishowIndex1()
  299. await this.bishowIndex2()
  300. this.$nextTick(() => {
  301. this.bishowIndex3()
  302. this.bishowIndex4()
  303. this.bishowIndex5()
  304. })
  305. },
  306. checkCity(item, name) {
  307. if (name == '按项目') {
  308. item.isShowCity = true
  309. } else {
  310. item.isShowCity = false
  311. }
  312. this.$forceUpdate()
  313. },
  314. bishowIndex1() {
  315. this.$u.post('/customer/bishowIndex1', this.params).then(res => {
  316. if (res) {
  317. this.stayPendingProcessingArr.forEach(item => {
  318. item.data = res[item.id] || 0
  319. })
  320. }
  321. })
  322. },
  323. bishowIndex2() {
  324. this.$u.post('/customer/bishowIndex2', this.params).then(res => {
  325. if (res) {
  326. this.ReceptionBriefingArr.forEach(item => {
  327. item.data = res[item.id] || 0
  328. })
  329. }
  330. })
  331. },
  332. bishowIndex3() {
  333. this.$u.post('/customer/bishowIndex3', this.params).then(res => {
  334. if (res) {
  335. this.IndexRankingArr.forEach(item => {
  336. if (res[item.id] && res[item.id].data.length > 0) {
  337. // 按项目
  338. item.canvasId = `IndexRankingArr${item.id}`
  339. item.lineOptsect = {
  340. categories: res[item.id].data.map(itme => {
  341. return itme.name
  342. }),
  343. series: [{
  344. name: item.title,
  345. data: JSON.parse(JSON.stringify(res[item.id].data)),
  346. }]
  347. }
  348. item.type = 'column'
  349. item.lineOpts = this.publicOpts
  350. item.lineOpts.legend = {
  351. show: false
  352. }
  353. // 按城市
  354. item.canvasId1 = `IndexRankingArrs${item.id}`
  355. item.lineOptsect1 = {
  356. categories: res[item.id].data2.map(itme => {
  357. return itme.name
  358. }),
  359. series: [{
  360. name: item.title,
  361. data: JSON.parse(JSON.stringify(res[item.id].data2))
  362. }]
  363. }
  364. this.$forceUpdate()
  365. } else {
  366. item.lineOptsect = null
  367. this.$forceUpdate()
  368. }
  369. })
  370. }
  371. })
  372. },
  373. bishowIndex5() {
  374. this.$u.post('/customer/bishowIndex5', this.params).then(res => {
  375. if (res) {
  376. this.IndicatorDistributionArr.forEach(item => {
  377. if (res[item.id]) {
  378. item.type = 'pie'
  379. item.canvasId = `IndicatorDistributionArrs${item.id}`
  380. item.lineOptsect = {
  381. series: [{
  382. data: JSON.parse(JSON.stringify(res[item.id]))
  383. }]
  384. }
  385. item.lineOpts = {
  386. color: ["#1890FF", "#91CB74", "#FAC858", "#EE6666", "#73C0DE",
  387. "#3CA272", "#FC8452", "#9A60B4", "#ea7ccc"
  388. ],
  389. padding: [20, 20, 20, 20],
  390. enableScroll: false,
  391. extra: {
  392. pie: {
  393. activeOpacity: 0.5,
  394. activeRadius: 10,
  395. offsetAngle: 0.5,
  396. labelWidth: 15,
  397. border: false,
  398. borderWidth: 3,
  399. borderColor: "#FFFFFF"
  400. },
  401. markLine: {
  402. labelOffsetX: 10,
  403. labelOffsetY: 10,
  404. }
  405. },
  406. }
  407. // '无效原因'
  408. if (item.id == 55) {
  409. item.lineOpts.legend = {
  410. show: false
  411. }
  412. }
  413. this.$forceUpdate()
  414. } else {
  415. item.lineOptsect = null
  416. this.$forceUpdate()
  417. }
  418. })
  419. }
  420. })
  421. },
  422. bishowIndex4() {
  423. this.$u.post('/customer/bishowIndex4', this.params).then(res => {
  424. if (res) {
  425. this.IndicatorTrendsArr.forEach(item => {
  426. if (res[item.id]) {
  427. item.canvasId = `IndicatorTrendsArr${item.id}`
  428. item.lineOptsect = {
  429. categories: [],
  430. series: [{
  431. name: item.title,
  432. data: []
  433. }]
  434. }
  435. item.type = 'line'
  436. item.lineOpts = this.publicOpts
  437. res[item.id].forEach(itme => {
  438. item.lineOptsect.categories.push(itme.statDate.split(' ')[0])
  439. item.lineOptsect.series[0].data.push(itme[item.params] || 0)
  440. })
  441. this.$forceUpdate()
  442. } else {
  443. item.lineOptsect = null
  444. this.$forceUpdate()
  445. }
  446. })
  447. }
  448. })
  449. },
  450. toEdit() {
  451. uni.navigateTo({
  452. url: '/pages/center/RuleEditing/RuleEditing'
  453. })
  454. },
  455. showSelect(params) {
  456. this.publicId = params
  457. this.templateList = this[params]
  458. this.showTemplate = true
  459. },
  460. // 获取项目
  461. getHouse() {
  462. uni.request({
  463. url: config.service.getUser,
  464. method: "GET",
  465. header: {
  466. 'content-type': 'application/json',
  467. 'Authorization': 'Bearer ' + uni.getStorageSync('weapp_session_login_data').token
  468. },
  469. success: (res) => {
  470. this.houseList = res.data.data.houseList.map(item => {
  471. return {
  472. id: item.id,
  473. templateName: item.propertyName,
  474. }
  475. })
  476. }
  477. })
  478. },
  479. // 获取公司
  480. getCompany() {
  481. this.$u.post('/customer/getMyOrg').then(res => {
  482. if (res) {
  483. this.companyList = res.map(item => {
  484. return {
  485. id: item.orgCode,
  486. templateName: item.name
  487. }
  488. })
  489. }
  490. })
  491. },
  492. //时间切换
  493. tabtimetap(index, text) {
  494. this.params.dateType = index;
  495. if (index == null) {
  496. this.totalTimeShow = true;
  497. this.screenShow = false
  498. } else {
  499. this.screenShow = false
  500. this.showTimeText = text
  501. this.params.endDate = ''
  502. this.params.staDate = ''
  503. this.initPage()
  504. }
  505. },
  506. //自定义时间
  507. totalTimeChange(e) {
  508. this.screenShow = false
  509. this.showTimeText = `${e.startDate}-${e.endDate}`
  510. this.params.dateType = null;
  511. this.params.endDate = e.endDate
  512. this.params.staDate = e.startDate
  513. this.initPage()
  514. },
  515. //
  516. templateCancel() {
  517. this.showTemplate = false;
  518. },
  519. //
  520. templateConfirm(e) {
  521. this.showTemplate = false;
  522. if (this.publicId == 'houseList') {
  523. this.showBeText1 = e[0].label
  524. this.params.houseId = e[0].value
  525. } else {
  526. this.showBeText = e[0].label
  527. this.params.orgCode = e[0].value
  528. }
  529. this.initPage()
  530. },
  531. },
  532. }
  533. </script>
  534. <style lang="scss" scoped>
  535. .pages {
  536. padding: 0 0 20rpx 0;
  537. width: 100vw;
  538. min-height: 100vh;
  539. background: #f2f2f2;
  540. display: flex;
  541. flex-direction: column;
  542. .boxtittabs {
  543. width: 100%;
  544. height: 92rpx;
  545. background: #FFFFFF;
  546. display: flex;
  547. align-items: center;
  548. position: sticky;
  549. top: var(--window-top);
  550. .items {
  551. padding: 0 24rpx;
  552. width: 50%;
  553. height: 100%;
  554. display: flex;
  555. align-items: center;
  556. justify-content: center;
  557. overflow: hidden;
  558. white-space: nowrap;
  559. text-overflow: ellipsis;
  560. }
  561. }
  562. .screen {
  563. //时间切换的样式
  564. .boxtittab {
  565. width: 100%;
  566. height: 100%;
  567. background: #FFFFFF;
  568. display: flex;
  569. flex-direction: column;
  570. border: none;
  571. .tabbox {
  572. flex: 1;
  573. height: 100%;
  574. text-align: center;
  575. line-height: 92rpx;
  576. color: #666666;
  577. font-size: 28rpx;
  578. font-weight: 400;
  579. display: flex;
  580. justify-content: center;
  581. .activecllasscet {
  582. width: 96rpx;
  583. color: #2671E2;
  584. font-weight: 600;
  585. border-bottom: 4rpx solid #2671E2;
  586. }
  587. }
  588. }
  589. }
  590. .edit {
  591. margin: 20rpx 0 0 0;
  592. padding: 0 20rpx;
  593. width: 100%;
  594. display: flex;
  595. align-items: center;
  596. justify-content: flex-end;
  597. .edits {
  598. padding: 10rpx 20rpx;
  599. background: #1890FF;
  600. color: #fff;
  601. border-radius: 16rpx;
  602. font-size: 32rpx;
  603. }
  604. }
  605. .grop {
  606. margin: 20rpx 0 0 0;
  607. padding: 20rpx;
  608. width: 100%;
  609. background: #fff;
  610. .title {
  611. height: 42rpx;
  612. font-size: 30rpx;
  613. font-family: PingFangSC-Semibold, PingFang SC;
  614. font-weight: 600;
  615. color: #333333;
  616. line-height: 42rpx;
  617. margin-bottom: 24rpx;
  618. display: flex;
  619. align-items: center;
  620. .title-icon {
  621. width: 12rpx;
  622. height: 20rpx;
  623. margin-right: 18rpx;
  624. }
  625. }
  626. .titles {
  627. width: 100%;
  628. display: flex;
  629. .lside {
  630. flex-grow: 1;
  631. height: 42rpx;
  632. font-size: 30rpx;
  633. font-family: PingFangSC-Semibold, PingFang SC;
  634. font-weight: 600;
  635. color: #333333;
  636. line-height: 42rpx;
  637. margin-bottom: 24rpx;
  638. display: flex;
  639. align-items: center;
  640. }
  641. .rside {
  642. flex-shrink: 0;
  643. display: flex;
  644. align-items: center;
  645. .rside-item {
  646. margin: 0 10rpx 0 0;
  647. &.active {
  648. color: #1890FF;
  649. }
  650. }
  651. }
  652. }
  653. .grid5 {
  654. padding: 20rpx 0;
  655. grid-row-gap: 20rpx;
  656. .real {
  657. width: 100%;
  658. height: 100%;
  659. .realnum {
  660. width: 100%;
  661. text-align: center;
  662. height: 50rpx;
  663. font-size: 36rpx;
  664. font-family: SourceHanSansCN-Medium, SourceHanSansCN;
  665. font-weight: bold;
  666. color: #333333;
  667. line-height: 50rpx;
  668. .qushi-icon {
  669. width: 28rpx;
  670. height: 14rpx;
  671. margin-left: 2rpx;
  672. }
  673. }
  674. .realtext {
  675. width: 100%;
  676. text-align: center;
  677. margin-top: 8rpx;
  678. height: 32rpx;
  679. font-size: 24rpx;
  680. font-family: PingFangSC-Regular, PingFang SC;
  681. font-weight: 400;
  682. color: #666666;
  683. line-height: 32rpx;
  684. }
  685. }
  686. }
  687. .grid4 {
  688. padding: 20rpx 0;
  689. grid-row-gap: 20rpx;
  690. .real {
  691. width: 100%;
  692. height: 100%;
  693. .realnum {
  694. width: 100%;
  695. text-align: center;
  696. height: 50rpx;
  697. font-size: 36rpx;
  698. font-family: SourceHanSansCN-Medium, SourceHanSansCN;
  699. font-weight: bold;
  700. color: #333333;
  701. line-height: 50rpx;
  702. .qushi-icon {
  703. width: 28rpx;
  704. height: 14rpx;
  705. margin-left: 2rpx;
  706. }
  707. }
  708. .realtext {
  709. width: 100%;
  710. text-align: center;
  711. margin-top: 8rpx;
  712. height: 32rpx;
  713. font-size: 24rpx;
  714. font-family: PingFangSC-Regular, PingFang SC;
  715. font-weight: 400;
  716. color: #666666;
  717. line-height: 32rpx;
  718. }
  719. }
  720. }
  721. }
  722. .grid5 {
  723. display: grid;
  724. grid-template-columns: repeat(5, 1fr);
  725. }
  726. .grid4 {
  727. display: grid;
  728. grid-template-columns: repeat(4, 1fr);
  729. }
  730. }
  731. </style>