index.vue 27 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045
  1. <template>
  2. <view class="uni-app">
  3. <view class="status-bar" />
  4. <view class="main-container">
  5. <view class="header linear-gradient">
  6. <view class="header-title">
  7. 首页
  8. </view>
  9. <!-- #ifndef MP-WEIXIN -->
  10. <view class="avatar-box">
  11. <wk-avatar :name="userInfo.realname" :avatar="userInfo.img" :size="12" class="avatar" />
  12. </view>
  13. <!-- #endif -->
  14. </view>
  15. <view
  16. v-if="showTopFilter"
  17. class="filter-sticky">
  18. <view class="title">
  19. 仪表盘
  20. </view>
  21. <view class="filter-box user" @click="handleOpenFilter('userOrDept')">
  22. <text class="text">
  23. {{ filterDataTypeLabel }}
  24. </text>
  25. <text class="icon" />
  26. </view>
  27. <view class="filter-box time" @click="handleOpenFilter('time')">
  28. <text class="text">
  29. {{ filterTimeLabel }}
  30. </text>
  31. <text class="icon" />
  32. </view>
  33. </view>
  34. <wk-scroll-view
  35. :scroll-top="scrollTop"
  36. :show-empty="false"
  37. :load-more="false"
  38. :status="listStatus"
  39. class="container"
  40. @refresh="handleRefresh"
  41. @scroll="handleScrollFn">
  42. <view class="quick-wrapper">
  43. <view class="bg linear-gradient" />
  44. <view class="quick-list">
  45. <view
  46. v-for="item in quickList"
  47. :key="item.type"
  48. class="quick-list-item"
  49. @click="handleNavigateTo(item)">
  50. <image :src="$static(item.img)" class="img" />
  51. <text class="text">
  52. {{ item.label }}
  53. </text>
  54. </view>
  55. <view
  56. v-for="i in (4 - quickList.length)"
  57. :key="i"
  58. class="quick-list-item hidden" />
  59. </view>
  60. </view>
  61. <view class="common-section">
  62. <view class="section-header">
  63. <view class="left">
  64. 常用功能
  65. </view>
  66. <view class="filter-box" @click="handleToggleConfigPopup">
  67. <text class="text">
  68. 配置
  69. </text>
  70. <image :src="$static('images/icon/config.png')" class="pic" />
  71. </view>
  72. </view>
  73. <view class="common-list">
  74. <view
  75. v-for="item in commonList"
  76. :key="item.type"
  77. class="common-list-item"
  78. @click="handleNavigateTo(item)">
  79. <image :src="$static(item.icon)" class="img" />
  80. <text class="text">
  81. {{ item.label }}
  82. </text>
  83. </view>
  84. <template v-if="commonList.length % 4 !== 0">
  85. <view
  86. v-for="i in (4 - commonList.length % 4)"
  87. :key="i"
  88. class="common-list-item hidden" />
  89. </template>
  90. </view>
  91. </view>
  92. <view class="panel-section">
  93. <!-- @touchmove="handleTouchMove" -->
  94. <view class="section-header">
  95. <view class="left">
  96. 仪表盘
  97. </view>
  98. <view class="filter-box user" @click="handleOpenFilter('userOrDept')">
  99. <text class="text">
  100. {{ filterDataTypeLabel }}
  101. </text>
  102. <text class="icon" />
  103. </view>
  104. <view class="filter-box time" @click="handleOpenFilter('time')">
  105. <text class="text">
  106. {{ filterTimeLabel }}
  107. </text>
  108. <text class="icon" />
  109. </view>
  110. </view>
  111. <view class="section-item scroll-view-hook">
  112. <view class="section-title">
  113. <view class="left">
  114. <image :src="$static('images/home/icon_sales.png')" class="icon" />
  115. <text class="text">
  116. 销售简报
  117. </text>
  118. </view>
  119. </view>
  120. <view class="report-list">
  121. <view
  122. v-for="(item, index) in reportList"
  123. :key="index"
  124. class="report-list-item"
  125. @click="handleReportTo(item)">
  126. <view class="text">
  127. {{ item.label }}
  128. </view>
  129. <view class="num">
  130. {{ item.unit || '' }}{{ item.num }}
  131. </view>
  132. </view>
  133. </view>
  134. </view>
  135. <view class="section-item">
  136. <view class="section-title">
  137. <view class="left">
  138. <image :src="$static('images/home/icon_statis.png')" class="icon" />
  139. <text class="text">
  140. 合同金额目标及完成情况
  141. </text>
  142. </view>
  143. </view>
  144. <chart-contract :params="filterData" />
  145. </view>
  146. <view class="section-item">
  147. <view class="section-title">
  148. <view class="left">
  149. <image :src="$static('images/home/icon_statis.png')" class="icon" />
  150. <text class="text">
  151. 回款金额目标及完成情况
  152. </text>
  153. </view>
  154. </view>
  155. <chart-refund :params="filterData" />
  156. </view>
  157. <view class="section-item">
  158. <view class="section-title">
  159. <view class="left">
  160. <image :src="$static('images/home/icon_slices.png')" class="icon" />
  161. <text class="text">
  162. 业绩指标完成率({{ performanceText }})
  163. </text>
  164. </view>
  165. <!-- <wk-drop
  166. v-model="performanceVal"
  167. :list="performanceOptions"
  168. @change="handlePerformanceChange" /> -->
  169. <view class="drop-control" @click="handleOpenDrop('performance')">
  170. <view class="drop-label">
  171. {{ performanceText }}
  172. </view>
  173. <view ref="icon" class="drop-icon">
  174. <text class="wk wk-arrow-right icon" />
  175. </view>
  176. </view>
  177. </view>
  178. <chart-performance ref="performance" :params="filterData" />
  179. </view>
  180. <view class="section-item rank">
  181. <view class="section-title">
  182. <view class="left">
  183. <image :src="$static('images/home/icon_ranking.png')" class="icon" />
  184. <text class="text">
  185. 排行榜
  186. </text>
  187. </view>
  188. <view class="right">
  189. <!-- <wk-drop
  190. v-model="rankVal"
  191. :list="rankOptions"
  192. @change="handleRankChange" /> -->
  193. <view class="drop-control" @click="handleOpenDrop('rank')">
  194. <view class="drop-label">
  195. {{ rankText }}
  196. </view>
  197. <view ref="icon" class="drop-icon">
  198. <text class="wk wk-arrow-right icon" />
  199. </view>
  200. </view>
  201. </view>
  202. </view>
  203. <chart-ranking ref="rank" :params="filterData" />
  204. </view>
  205. </view>
  206. </wk-scroll-view>
  207. </view>
  208. <wk-tabbar v-model="footerIndex" :list="mixinFooterNav" />
  209. <uni-popup ref="popup" :mask-click="false" type="dialog">
  210. <wk-popup-expiration />
  211. </uni-popup>
  212. <uni-popup
  213. ref="popupBottom"
  214. radius="10rpx 10rpx 0 0"
  215. type="bottom">
  216. <wk-action-sheet
  217. :list="configPopupList"
  218. label="label"
  219. @select="handleSelectConfig" />
  220. </uni-popup>
  221. <uni-popup
  222. ref="filterPopup"
  223. :mask-click="filterPopupMaskFlag"
  224. radius="20rpx 20rpx 0 0"
  225. type="bottom"
  226. @mask-close="filterMaskClick">
  227. <workbench-filter
  228. ref="workbenchFilter"
  229. :filter-data="filterObj"
  230. :default-tab="filterDefaultTab"
  231. @popup-change="childPopupChange"
  232. @change="handleChangeFilter"
  233. @close="handleCloseFilter" />
  234. </uni-popup>
  235. <!-- 小程序scroll-view中fixed定位有问题 -->
  236. <uni-popup
  237. ref="dropPopup"
  238. radius="10rpx 10rpx 0 0"
  239. type="bottom">
  240. <view class="filter-popup">
  241. <view class="popup-header">
  242. <view class="text">
  243. 筛选
  244. </view>
  245. <text class="wk wk-close icon" @click="handleCloseDrop" />
  246. </view>
  247. <view class="popup-content">
  248. <view class="list">
  249. <view
  250. v-for="item in dropList"
  251. :key="item.value"
  252. :class="{active: dropVal === item.value}"
  253. class="list-item"
  254. @click="handleDropSelect(item)">
  255. <text class="text">
  256. {{ item.label }}
  257. </text>
  258. <text v-show="dropVal === item.value" class="wk wk-check icon" />
  259. </view>
  260. </view>
  261. </view>
  262. </view>
  263. </uni-popup>
  264. </view>
  265. </template>
  266. <script>
  267. import {
  268. crmInstrumentQueryBulletin
  269. } from 'API/crm/work'
  270. import WorkbenchFilter from '@/components/base/workbench-filter.vue'
  271. import ChartContract from './components/chartContract'
  272. import ChartRefund from './components/chartRefund'
  273. import ChartPerformance from './components/chartPerformance'
  274. import ChartRanking from './components/chartRanking'
  275. import tabbar from '@/mixins/tabbar.js'
  276. import { getQuickList, getCommonNavList, timeOptions } from '@/utils/data.js'
  277. import { deepCopy } from '@/utils/lib.js'
  278. import { DEFAULT_NAV_CONFIG } from '@/config.js'
  279. import {
  280. mapGetters
  281. } from 'vuex'
  282. export default {
  283. name: 'HomeIndex',
  284. components: {
  285. WorkbenchFilter,
  286. ChartContract,
  287. ChartRefund,
  288. ChartPerformance,
  289. ChartRanking
  290. },
  291. mixins: [tabbar],
  292. data() {
  293. return {
  294. reportList: [
  295. {
  296. label: '新增客户',
  297. key: 'customerCount',
  298. num: 0,
  299. type: 'customer'
  300. },
  301. {
  302. label: '新增联系人',
  303. key: 'contactsCount',
  304. num: 0,
  305. type: 'contacts'
  306. },
  307. {
  308. label: '新增商机',
  309. key: 'businessCount',
  310. num: 0,
  311. type: 'business'
  312. },
  313. {
  314. label: '新增合同',
  315. key: 'contractCount',
  316. num: 0,
  317. type: 'contract'
  318. },
  319. {
  320. label: '合同金额',
  321. key: 'contractMoney',
  322. num: 0,
  323. unit: '¥',
  324. type: 'contract_money'
  325. },
  326. {
  327. label: '商机金额',
  328. key: 'businessMoney',
  329. num: 0,
  330. unit: '¥',
  331. type: 'business_money'
  332. },
  333. {
  334. label: '回款金额',
  335. key: 'receivablesMoney',
  336. num: 0,
  337. unit: '¥',
  338. type: 'receivables_money'
  339. },
  340. {
  341. label: '新增跟进记录',
  342. key: 'recordCount',
  343. num: 0,
  344. type: 'record'
  345. },
  346. ],
  347. performanceVal: 1,
  348. performanceOptions: [
  349. { label: '回款金额', value: 2 },
  350. { label: '合同金额', value: 1 }
  351. ],
  352. rankVal: 1,
  353. rankOptions: [
  354. { label: '合同金额', value: 1 },
  355. { label: '回款金额', value: 2 },
  356. { label: '合同数', value: 3 },
  357. { label: '新增客户', value: 4 },
  358. { label: '新增联系人', value: 5 },
  359. { label: '新增跟进记录', value: 8 }
  360. ],
  361. dropVal: null,
  362. dropType: '',
  363. dropList: [],
  364. filterData: {
  365. dateFilter: 'month',
  366. dataType: 2
  367. },
  368. filterObj: null,
  369. filterDefaultTab: 'userOrDept',
  370. loading: false,
  371. filterPopupMaskFlag: true,
  372. configPopupList: [
  373. { label: '快速入口设置', url: '/pages/home/quickConfig' },
  374. { label: '常用功能设置', url: '/pages/home/commonConfig' }
  375. ],
  376. filterDataTypeOptions: [
  377. { label: '仅本人', value: 1 },
  378. { label: '本人及下属', value: 2 },
  379. { label: '仅本部门', value: 3 },
  380. { label: '本部门及下属部门', value: 4 },
  381. { label: '自定义', value: 0 }
  382. ],
  383. scrollMin: 0, // 显示顶部filter距离阀值
  384. showTopFilter: false,
  385. oldScrollTop: 0,
  386. scrollTop: 0,
  387. listStatus: '',
  388. mousePageY: 0
  389. }
  390. },
  391. computed: {
  392. ...mapGetters({
  393. userInfo: 'user/userInfo',
  394. showExpiration: 'user/showExpiration',
  395. navConfig: 'user/navConfig'
  396. }),
  397. quickList() {
  398. const config = this.$isEmpty(this.navConfig) ? {} : this.navConfig
  399. const arr = this.$isEmpty(config.quick) ? DEFAULT_NAV_CONFIG.quick : config.quick
  400. return getQuickList(arr)
  401. },
  402. commonList() {
  403. const config = this.$isEmpty(this.navConfig) ? {} : this.navConfig
  404. const arr = this.$isEmpty(config.common) ? DEFAULT_NAV_CONFIG.common : config.common
  405. return getCommonNavList(arr)
  406. },
  407. // 筛选范围label
  408. filterDataTypeLabel() {
  409. const dataType = this.filterData.dataType || null
  410. if (!dataType || dataType === -1) {
  411. // const data = this.filterObj.userOrDeptData
  412. // const flag = data.type === 1
  413. // return flag ? data.data[0].name : data.data[0].realname
  414. return '自定义'
  415. } else {
  416. const findRes = this.filterDataTypeOptions.find(o => o.value === dataType)
  417. if (findRes) {
  418. return findRes.label
  419. }
  420. }
  421. return ''
  422. },
  423. // 筛选时间label
  424. filterTimeLabel() {
  425. const type = this.filterData.dateFilter
  426. if (!type || type === -1 || type === 'custom') {
  427. // const startTime = this.filterObj.startTime.replace(/-/g, '.')
  428. // const endTime = this.filterObj.endTime.replace(/-/g, '.')
  429. const startTime = this.filterObj.startDate
  430. const endTime = this.filterObj.endDate
  431. return `${startTime}~${endTime}`
  432. } else {
  433. const findRes = timeOptions.find(o => o.value === type)
  434. if (findRes) {
  435. return findRes.label
  436. }
  437. }
  438. return ''
  439. },
  440. hasToken() {
  441. return !!(uni.getStorageSync('token') || null)
  442. },
  443. performanceText() {
  444. return this.performanceOptions.find(o => o.value === this.performanceVal).label
  445. },
  446. rankText() {
  447. return this.rankOptions.find(o => o.value === this.rankVal).label
  448. }
  449. },
  450. watch: {
  451. showExpiration: {
  452. handler() {
  453. if (this.showExpiration) {
  454. this.$nextTick(function() {
  455. this.$refs.popup.open()
  456. })
  457. }
  458. },
  459. immediate: true,
  460. deep: true
  461. }
  462. },
  463. onBackPress(evt) {
  464. if (evt.from === 'backbutton' && this.showFilter) {
  465. this.showFilter = !this.showFilter
  466. return true // 返回值为 true 时,表示不执行默认的返回
  467. }
  468. return false
  469. },
  470. mounted() {
  471. if (this.hasToken) {
  472. const cache = uni.getStorageSync('homeFilterConfig') || null
  473. if (cache) {
  474. this.filterObj = cache.obj
  475. this.filterData = cache.data
  476. }
  477. this.getData()
  478. this.handlePerformanceChange(this.performanceVal)
  479. this.handleRankChange(this.rankVal)
  480. } else {
  481. this.$Router.reLaunch('/pages/login/index')
  482. }
  483. this.$nextTick(function() {
  484. this.setScrollMin()
  485. })
  486. },
  487. methods: {
  488. // handleTouchMove(e) {
  489. // // console.log('www move', e)
  490. // const targetId = e.target.id
  491. // if (!targetId.endsWith('Chart')) return
  492. // const pageY = e.touches[0].pageY
  493. // this.scrollTop = this.oldScrollTop
  494. // this.$nextTick(() => {
  495. // this.scrollTop = this.oldScrollTop + ((this.mousePageY - pageY) * 3)
  496. // this.mousePageY = e.touches[0].pageY
  497. // })
  498. // },
  499. handleRefresh() {
  500. this.listStatus = 'loading'
  501. this.getData()
  502. this.filterData = deepCopy(this.filterData)
  503. this.handlePerformanceChange(this.performanceVal)
  504. // this.handleRankChange(this.rankVal)
  505. },
  506. getData() {
  507. if (this.loading) return
  508. this.loading = true
  509. crmInstrumentQueryBulletin(this.filterData).then(res => {
  510. this.loading = false
  511. let obj = res[6] || null
  512. if (!obj) return
  513. this.reportList.forEach(item => {
  514. item.num = obj[item.key] || 0
  515. })
  516. this.listStatus = 'noMore'
  517. }).catch(() => {
  518. this.loading = false
  519. })
  520. },
  521. /**
  522. * 设置滚动距离阀值
  523. */
  524. setScrollMin() {
  525. const that = this
  526. const query = uni.createSelectorQuery().in(this)
  527. query.select('.scroll-view-hook')
  528. .boundingClientRect(data => {
  529. that.scrollMin = data.top - uni.upx2px(88)
  530. }).exec()
  531. },
  532. /**
  533. * 滚动回调
  534. * @param {Object} evt
  535. */
  536. handleScrollFn(evt) {
  537. this.oldScrollTop = evt.detail.scrollTop
  538. // console.log('oldScrollTop', this.oldScrollTop)
  539. const flag = this.oldScrollTop >= this.scrollMin
  540. if (flag !== this.showTopFilter) {
  541. this.showTopFilter = flag
  542. // const step = (flag ? 1 : -1) * uni.upx2px(88)
  543. // this.scrollTop = this.oldScrollTop + step
  544. // console.log('-----', step, this.oldScrollTop)
  545. // this.scrollTop = this.oldScrollTop
  546. // this.$nextTick(() => {
  547. // this.scrollTop = this.oldScrollTop + step
  548. // })
  549. }
  550. },
  551. /**
  552. * 筛选
  553. */
  554. handleOpenFilter(tab) {
  555. this.filterDefaultTab = tab
  556. this.$refs.filterPopup.open()
  557. },
  558. handleCloseFilter() {
  559. this.$refs.filterPopup.close()
  560. },
  561. filterMaskClick() {
  562. if (!this.filterPopupMaskFlag) {
  563. this.$refs.workbenchFilter.closeChildPopup()
  564. }
  565. },
  566. childPopupChange(flag) {
  567. this.filterPopupMaskFlag = !flag
  568. },
  569. handleChangeFilter(filterObj, data) {
  570. console.info('handleChangeFilter: ', filterObj, data)
  571. this.filterObj = filterObj
  572. this.filterData = filterObj
  573. // uni.setStorageSync('homeFilterConfig', {
  574. // obj: filterObj,
  575. // data: data
  576. // })
  577. this.getData()
  578. this.handlePerformanceChange(this.performanceVal)
  579. this.handleRankChange(this.rankVal)
  580. },
  581. handleToggleConfigPopup(type) {
  582. this.$refs.popupBottom.open()
  583. },
  584. handleSelectConfig(index, item, next) {
  585. next()
  586. this.$Router.navigateTo(item.url)
  587. },
  588. handleOpenDrop(type) {
  589. this.dropType = type
  590. this.dropVal = this[`${type}Val`]
  591. this.dropList = deepCopy(this[`${type}Options`])
  592. this.$refs.dropPopup.open()
  593. },
  594. handleCloseDrop() {
  595. this.$refs.dropPopup.close()
  596. },
  597. handleDropSelect(item) {
  598. this.dropVal = item.value
  599. this[`${this.dropType}Val`] = item.value
  600. this.handleCloseDrop()
  601. if (this.dropType === 'performance') {
  602. this.handlePerformanceChange(this.dropVal)
  603. } else if (this.dropType === 'rank') {
  604. this.handleRankChange(this.dropVal)
  605. }
  606. this.dropType = ''
  607. this.dropVal = null
  608. },
  609. /**
  610. * 跳转
  611. */
  612. handleNavigateTo(item) {
  613. if (item.auth && !this.$auth(item.auth)) {
  614. this.$toast('权限不足')
  615. return
  616. }
  617. this.$Router.navigateTo({
  618. url: item.url,
  619. query: item.query || {}
  620. })
  621. },
  622. handleReportTo(item) {
  623. if (item.type !== 'record') {
  624. this.$Router.navigateTo({
  625. url: '/pages_crm/homeReport/report',
  626. query: {
  627. module: item.type,
  628. ...this.filterData
  629. }
  630. })
  631. } else {
  632. this.$Router.navigateTo({
  633. url: '/pages_crm/homeReport/recordCountList',
  634. query: this.filterData
  635. })
  636. }
  637. },
  638. handlePerformanceChange(val) {
  639. this.$nextTick(() => {
  640. this.$refs.performance.getData(val)
  641. })
  642. },
  643. handleRankChange(val) {
  644. this.$nextTick(() => {
  645. this.$refs.rank.getData(val)
  646. })
  647. }
  648. }
  649. }
  650. </script>
  651. <style scoped lang="scss">
  652. .main-container {
  653. position: relative;
  654. .header {
  655. width: 100%;
  656. height: 88rpx;
  657. padding: 0 32rpx;
  658. @include left;
  659. .header-title {
  660. flex: 1;
  661. font-size: 34rpx;
  662. color: white;
  663. }
  664. .avatar-box {
  665. width: 64rpx;
  666. height: 64rpx;
  667. .avatar {
  668. width: 100%;
  669. height: 100%;
  670. }
  671. }
  672. }
  673. .filter-sticky {
  674. position: relative;
  675. z-index: 1;
  676. width: 100%;
  677. box-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.1);
  678. background-color: white;
  679. padding: 15rpx 20rpx;
  680. @include left;
  681. .title {
  682. flex: 1;
  683. font-size: 30rpx;
  684. font-weight: bold;
  685. color: $dark;
  686. }
  687. .filter-box {
  688. @include center;
  689. &.user {
  690. margin-right: 15rpx;
  691. }
  692. .icon {
  693. width: 0;
  694. height: 0;
  695. border-left: 10rpx solid transparent;
  696. border-right: 10rpx solid transparent;
  697. border-top: 10rpx solid $gray;
  698. margin-left: 10rpx;
  699. }
  700. .text {
  701. font-size: 24rpx;
  702. }
  703. }
  704. }
  705. .container {
  706. flex: 1;
  707. overflow: hidden;
  708. .quick-wrapper {
  709. position: relative;
  710. width: 100%;
  711. padding: 10rpx 20rpx 0;
  712. .bg {
  713. position: absolute;
  714. top: 0;
  715. left: 0;
  716. width: 100%;
  717. height: 128rpx;
  718. }
  719. .quick-list {
  720. position: relative;
  721. width: 100%;
  722. height: 188rpx;
  723. box-shadow: 0px 6rpx 50rpx rgba(148, 153, 181, 0.38);
  724. border-radius: 24rpx;
  725. background: #FFFFFF;
  726. padding: 0 32rpx;
  727. display: flex;
  728. align-items: center;
  729. justify-content: space-between;
  730. .quick-list-item {
  731. width: 20%;
  732. flex-direction: column;
  733. padding: 20rpx 0;
  734. @include center;
  735. &.hidden {
  736. visibility: hidden;
  737. }
  738. .img {
  739. width: 64rpx;
  740. height: 64rpx;
  741. }
  742. .text {
  743. font-size: 24rpx;
  744. margin-top: 10rpx;
  745. }
  746. }
  747. }
  748. }
  749. .section-header {
  750. margin-top: 30rpx;
  751. margin-bottom: 20rpx;
  752. @include left;
  753. .left {
  754. flex: 1;
  755. font-size: 30rpx;
  756. font-weight: bold;
  757. color: $dark;
  758. }
  759. .filter-box {
  760. background-color: white;
  761. padding: 10rpx 15rpx;
  762. border-radius: 12rpx;
  763. @include center;
  764. &.user {
  765. margin-right: 15rpx;
  766. }
  767. .pic {
  768. width: 32rpx;
  769. height: 32rpx;
  770. margin-left: 15rpx;
  771. }
  772. .icon {
  773. width: 0;
  774. height: 0;
  775. border-left: 10rpx solid transparent;
  776. border-right: 10rpx solid transparent;
  777. border-top: 10rpx solid $gray;
  778. margin-left: 10rpx;
  779. }
  780. .text {
  781. font-size: 24rpx;
  782. }
  783. }
  784. }
  785. .common-section {
  786. padding: 0 20rpx;
  787. overflow: hidden;
  788. .common-list {
  789. width: 100%;
  790. display: flex;
  791. justify-content: space-between;
  792. flex-wrap: wrap;
  793. .common-list-item {
  794. width: 164rpx;
  795. height: 144rpx;
  796. background-color: white;
  797. box-shadow: 0px 3rpx 9rpx rgba(210, 212, 220, 0.77);
  798. border-radius: 16rpx;
  799. margin-bottom: 12rpx;
  800. flex-direction: column;
  801. @include center;
  802. &.hidden {
  803. visibility: hidden;
  804. }
  805. .img {
  806. width: 60rpx;
  807. height: 60rpx;
  808. }
  809. .text {
  810. font-size: 24rpx;
  811. margin-top: 10rpx;
  812. }
  813. }
  814. }
  815. }
  816. .panel-section {
  817. padding: 0 20rpx;
  818. overflow: hidden;
  819. .section-header {
  820. margin-top: 20rpx;
  821. }
  822. .section-item {
  823. width: 100%;
  824. background-color: white;
  825. border: 1rpx solid $border-color;
  826. border-top: 4rpx solid $theme-color;
  827. border-radius: 4rpx;
  828. padding: 25rpx 20rpx;
  829. margin-bottom: 15rpx;
  830. .section-title {
  831. width: 100%;
  832. @include left;
  833. .left {
  834. flex: 1;
  835. .icon {
  836. width: 40rpx;
  837. height: 40rpx;
  838. vertical-align: middle;
  839. margin-right: 10rpx;
  840. }
  841. .text {
  842. font-size: 28rpx;
  843. font-weight: bold;
  844. color: #212121;
  845. vertical-align: middle;
  846. }
  847. }
  848. }
  849. &.rank {
  850. padding-bottom: 15rpx;
  851. }
  852. }
  853. .report-list {
  854. width: 100%;
  855. display: flex;
  856. align-items: center;
  857. justify-content: space-between;
  858. flex-wrap: wrap;
  859. margin-bottom: 10rpx;
  860. .report-list-item {
  861. width: 48.5%;
  862. height: 120rpx;
  863. flex-direction: column;
  864. background-color: #EEF0F4;
  865. border-radius: 6rpx;
  866. padding: 0 24rpx;
  867. margin-top: 15rpx;
  868. @include center;
  869. .text {
  870. width: 100%;
  871. font-size: $wk-font-base;
  872. color: $gray;
  873. }
  874. .num {
  875. width: 100%;
  876. font-size: $wk-font-large;
  877. font-weight: bold;
  878. }
  879. }
  880. }
  881. }
  882. }
  883. }
  884. .drop-control {
  885. font-size: 26rpx;
  886. background-color: #F5F5F5;
  887. border-radius: 4rpx;
  888. padding: 8rpx 15rpx;
  889. @include left;
  890. .drop-label {
  891. color: $gray;
  892. margin-right: 15rpx;
  893. line-height: 1;
  894. }
  895. .drop-icon {
  896. will-change: transform;
  897. transition: all ease .2s;
  898. @include center;
  899. .icon {
  900. line-height: 1;
  901. font-size: 24rpx;
  902. transform: rotate(90deg);
  903. }
  904. &.active {
  905. transform: rotate(180deg);
  906. }
  907. }
  908. }
  909. .filter-popup {
  910. padding: 10rpx 36rpx 20rpx;
  911. .popup-header {
  912. position: relative;
  913. @include center;
  914. .text {
  915. font-size: $wk-font-large;
  916. }
  917. .icon {
  918. position: absolute;
  919. left: 0;
  920. top: 50%;
  921. transform: translateY(-50%);
  922. color: $gray;
  923. font-size: $wk-font-medium;
  924. }
  925. }
  926. .popup-content {
  927. width: 100%;
  928. min-height: 500rpx;
  929. max-height: 700rpx;
  930. overflow: auto;
  931. margin-top: 38rpx;
  932. .list {
  933. width: 100%;
  934. .list-item {
  935. color: $dark;
  936. font-size: $wk-font-base;
  937. border-bottom: 1rpx solid $border-color;
  938. padding: 22rpx 0;
  939. @include left;
  940. .text {
  941. flex: 1;
  942. }
  943. .icon {
  944. font-size: $wk-font-medium;
  945. color: inherit;
  946. line-height: 1;
  947. }
  948. &.active {
  949. color: $theme-color;
  950. }
  951. }
  952. }
  953. }
  954. }
  955. </style>