ranking.vue 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660
  1. <template>
  2. <view class="ranking">
  3. <custom-nav :title="pageTitle"></custom-nav>
  4. <view class="content">
  5. <view class="top_container">
  6. <view class="day-title">
  7. <text @tap="switchDay(0)" :class="day === 0 ? 'active' : ''">总榜单</text>
  8. <text @tap="switchDay(1)" :class="day === 1 ? 'active' : ''">昨日榜单</text>
  9. </view>
  10. </view>
  11. <view class="my_rank_container">
  12. <view class="my_rank" v-if="userServerInfo">
  13. <text class="num">{{ userServerInfo.rank }}</text>
  14. <image :src="avatarUrl" mode="" class="userImg"></image>
  15. <text class="name">{{ nickName }}</text>
  16. <text class="score">{{ userServerInfo.score }}</text>
  17. </view>
  18. </view>
  19. <view class="list_container">
  20. <view class="type-title" v-if="typeList.length > 0">
  21. <text v-for="(item, index) in typeList" :key="index" @tap="switchType(index)" :class="type === index ? 'active' : ''">{{ item }}</text>
  22. </view>
  23. <view class="rank_list_fixed_title">
  24. <view class="text1">排名</view>
  25. <view class="text3">
  26. <view class="text5">头像</view>
  27. <view class="text6">昵称</view>
  28. </view>
  29. <view class="text4">学分</view>
  30. </view>
  31. <view class="list">
  32. <scroll-view
  33. v-if="scrollview"
  34. show-scrollbar="true"
  35. :scroll-top="scrollTop"
  36. scroll-with-animation="true"
  37. :scroll-y="true"
  38. :style="{ height: scrollViewHeight + 'px' }"
  39. @scrolltolower="scrolltolower"
  40. @scrolltoupper="scrolltoTop"
  41. >
  42. <ranking-item
  43. v-for="(item, index) in list"
  44. :key="item.id"
  45. :index="item.rank || index + 1"
  46. :item="item"
  47. :rank="user.rank"
  48. :type="type"
  49. :bg="user.id === item.id && userServerInfo.type !== 3 && day === 0 && type + 1 === userServerInfo.type"
  50. ></ranking-item>
  51. <custom-reach-bottom v-if="nomore || list.length" :nomore="nomore"></custom-reach-bottom>
  52. </scroll-view>
  53. </view>
  54. </view>
  55. <view class="share_btn">
  56. <!-- <button open-type="share">点我晒一晒排名</button> -->
  57. <button @click="toShare">点我晒一晒排名</button>
  58. </view>
  59. </view>
  60. <page-toast :is-show="is_float" :is-close="false">
  61. <view class="toast_container shangsheng_toast" @click="is_float = 0">
  62. <image class="bg" src="https://api.jiuweiyun.cn/public/uploads/icon/toast9.png"></image>
  63. <view class="text">
  64. <view>上升了</view>
  65. <view>{{ is_float }}名</view>
  66. </view>
  67. </view>
  68. </page-toast>
  69. </view>
  70. </template>
  71. <script>
  72. import rankingItem from '../../components/ranking-item.vue';
  73. import { api_todayPerson, api_todayCrown, api_todayTeam, api_todayWar, api_yesterdayPerson, api_yesterdayCrown, api_yesterdayTeam, api_yesterdayWar } from '../../api.js';
  74. var rank_prev_scroll = 0,
  75. prev_flag = true,
  76. location_flag = false,
  77. load_prev_scrolltop = 0;
  78. let ONE_H = 70;
  79. let PAGE_SIZE = 20;
  80. export default {
  81. onShareAppMessage: function(res) {
  82. uni.showLoading({ title: '加载中', mask: true }); //显示loading
  83. if (res.from === 'button') {
  84. return {
  85. title: '我的排名',
  86. path: `/pages/crownshare/crownshare?top=${JSON.stringify(this.list.slice(0, 3))}&list=${JSON.stringify(this.shareList)}&season=${this.userServerInfo.season}`
  87. };
  88. }
  89. return {
  90. title: '大卫博士商学院卖货争霸',
  91. path: '/pages/index/index'
  92. };
  93. },
  94. components: {
  95. rankingItem
  96. },
  97. data() {
  98. return {
  99. pageTitle: '排行榜',
  100. typeList: [], //个人/批发商/团队/服务 导航栏显示内容
  101. day: 0, //今日/昨日
  102. type: 0, //个人/批发商/团队/服务
  103. page: 1, //
  104. list: [],
  105. user: {}, //用户当前排名和浮动情况
  106. scrollViewHeight: 0, //scrollview 高
  107. requesting: false, //是否正在请求
  108. nomore: false, //没得更多了
  109. apis: [
  110. //用二维数组来表示 今日昨日一共八个 api
  111. [api_todayPerson, api_todayTeam, api_todayCrown, api_todayWar],
  112. [api_yesterdayPerson, api_yesterdayTeam, api_yesterdayCrown, api_yesterdayWar]
  113. ],
  114. scrollview: true, // 显示隐藏 scrollvew 解决切换后 scrolltop 不回到顶部的BUG
  115. shareList: [], //批发商分享列表
  116. scrollTop: 0, //设置竖向滚动条位置,
  117. is_float: 0,
  118. rankData: [],
  119. isClickLocation: false,
  120. avatarUrl: '',
  121. nickName: ''
  122. };
  123. },
  124. computed: {
  125. userWeixinInfo() {
  126. //用户微信信息
  127. return this.$store.state.userWeixinInfo;
  128. },
  129. userServerInfo() {
  130. //用户信息
  131. return this.$store.state.userServerInfo;
  132. },
  133. showFiexed() {
  134. //是否在屏幕下方显示显示个人信息
  135. return this.userServerInfo.type === this.type + 1 && this.userServerInfo.type !== 3 && this.day === 0;
  136. }
  137. },
  138. methods: {
  139. toShare() {
  140. uni.navigateTo({
  141. url: '../share/share'
  142. });
  143. },
  144. scrolltoTop() {
  145. if (this.isClickLocation) {
  146. let _this = this;
  147. this.getPageData(
  148. () => {
  149. _this.isClickLocation = false;
  150. _this.scrollTop = 0;
  151. _this.page = 1;
  152. },
  153. 0,
  154. 1
  155. );
  156. }
  157. },
  158. // 快速定位到我的位置
  159. locationMe(my) {
  160. this.isClickLocation = true;
  161. let max_one_screen_len = Math.ceil(this.scrollViewHeight / ONE_H);
  162. let toscroll;
  163. if (my % PAGE_SIZE < max_one_screen_len && my % PAGE_SIZE > 0) {
  164. toscroll = 0;
  165. } else if (my % PAGE_SIZE > PAGE_SIZE - max_one_screen_len || my % PAGE_SIZE === 0) {
  166. toscroll = (PAGE_SIZE - max_one_screen_len) * ONE_H;
  167. } else {
  168. toscroll = ((my % PAGE_SIZE) - 1) * ONE_H;
  169. }
  170. let you_page = Math.ceil(my / PAGE_SIZE);
  171. // 如果我的排名小于第一页的个数
  172. if (my < PAGE_SIZE) {
  173. this.scrollTop = toscroll;
  174. } else {
  175. if (!this.rankData.some(a => a.page === you_page)) {
  176. this.page = you_page;
  177. location_flag = true;
  178. let _this = this;
  179. this.getPageData(() => {
  180. // 计算出向下滚动距离
  181. if (toscroll > 0) {
  182. _this.scrollTop = toscroll;
  183. }
  184. }, 0);
  185. }
  186. }
  187. },
  188. switchDay(day) {
  189. //切换天
  190. this.day = day;
  191. this.switched();
  192. },
  193. switchType(index) {
  194. //切换类型
  195. this.type = index;
  196. this.switched();
  197. },
  198. getPageData(cb, isMy = 1, page) {
  199. page = page ? page : this.page;
  200. this.requesting = true;
  201. uni.showLoading({ title: '加载中', mask: true });
  202. this.$ajax.get(`${this.apis[this.day][this.type]}?page=${page}&season=${this.userServerInfo.season}`).then(
  203. ([, { data: res }]) => {
  204. res.data.list.length < 20 ? (this.nomore = true) : ''; //如果返回的数据长度小于20,说明没得更多了
  205. this.requesting = false;
  206. if (isMy !== 1) {
  207. this.rankData = [];
  208. }
  209. this.rankData.push({
  210. page: page,
  211. data: res.data.list
  212. });
  213. this.rankData.sort((a, b) => a.page - b.page);
  214. cb && cb(res.data);
  215. uni.hideLoading();
  216. },
  217. () => {
  218. uni.hideLoading();
  219. this.requesting = false;
  220. }
  221. );
  222. },
  223. switched() {
  224. //切换数据
  225. uni.showLoading({ title: '加载中', mask: true }); //显示loading
  226. this.scrollViewHeight = 0; //将 scrollview 变为高变为零
  227. this.scrollview = false; // 隐藏 scrollvew 解决切换后 scrolltop 不回到顶部的BUG
  228. this.page = 1; //恢复页码
  229. this.nomore = false; //恢复没得更多了
  230. this.isClickLocation = false;
  231. this.scrollTop = 0;
  232. this.rankData = [];
  233. let _this = this;
  234. this.getPageData(data => {
  235. _this.scrollview = true; // 显示 scrollvew 解决切换后 scrolltop 不回到顶部的BUG
  236. data.per_data ? (_this.user = data.per_data) : ''; //是否有用户排名信息传过来,有就赋给 user
  237. _this.$scrollViewHeight('.list'); //设置页面内 scroll view 的高度
  238. if (_this.userServerInfo.type === 2 && _this.type === 1 && _this.day === 0) {
  239. //如果是批发商点击了批发商榜
  240. _this.makeCrownShareList();
  241. } else {
  242. _this.$hideLoading(); //异步操作结束,停止 loading
  243. }
  244. });
  245. },
  246. scrolltolower() {
  247. //下拉 scroll view 触底函数
  248. if (this.userServerInfo.type === 1 && this.type === 1) {
  249. //普通客户查看批发商榜时不会触发
  250. return;
  251. }
  252. if (!this.requesting && !this.nomore) {
  253. //防抖
  254. this.page = this.rankData[this.rankData.length - 1].page + 1;
  255. this.getPageData();
  256. }
  257. },
  258. async makeCrownShareList() {
  259. //生成批发商分享页面的列表数据
  260. const user = Object.assign(
  261. {
  262. //生成用户信息
  263. name: this.userServerInfo.name,
  264. avatar: this.userWeixinInfo.avatarUrl,
  265. self: true
  266. },
  267. this.user
  268. );
  269. const rank = start => {
  270. this.shareList.forEach((e, i) => {
  271. e.rank = i + start;
  272. });
  273. };
  274. if (this.user.rank < 5) {
  275. //前四名的处理方式
  276. this.shareList = this.list.slice(0, 4);
  277. this.shareList.splice(this.user.rank - 1, 1, user);
  278. rank(1); //为分享数组里面的对象添加排名
  279. this.$hideLoading(); //异步操作结束,停止 loading
  280. } else if (this.user.rank > 4 && this.user.rank < 20) {
  281. //5 - 19 名的处理方式
  282. this.shareList = this.list.slice(this.user.rank - 3, this.user.rank + 1);
  283. this.shareList.splice(2, 1, user);
  284. rank(this.user.rank - 2); //为分享数组里面的对象添加排名
  285. this.$hideLoading(); //异步操作结束,停止 loading
  286. } else if (this.user.rank === 20) {
  287. //第 20 名的处理方式
  288. this.shareList = this.list.slice(17, 19);
  289. this.$ajax.get(`${api_todayCrown}?page=2&season=${this.userServerInfo.season}`).then(([, { data: res }]) => {
  290. this.shareList.push(user);
  291. this.shareList.push(res.data.list[0]);
  292. rank(this.user.rank - 2); //为分享数组里面的对象添加排名
  293. this.$hideLoading(); //异步操作结束,停止 loading
  294. });
  295. } else {
  296. this.$hideLoading();
  297. if (this.user.rank) {
  298. const page = Math.floor(this.user.rank / 20) + 1; //自己排名所处的页数(第几页)
  299. const index = this.user.rank % 20; //自己在自己那页的下标(第几个)
  300. const [, { data: res1 }] = await this.$ajax.get(`${api_todayCrown}?page=${page - 1}&season=${this.userServerInfo.season}`);
  301. const [, { data: res2 }] = await this.$ajax.get(`${api_todayCrown}?page=${page}&season=${this.userServerInfo.season}`);
  302. const [, { data: res3 }] = await this.$ajax.get(`${api_todayCrown}?page=${page + 1}&season=${this.userServerInfo.season}`);
  303. const totalList = [...res1.data.list, ...res2.data.list, ...res3.data.list];
  304. this.shareList = totalList.slice(20 + index - 3, 20 + index + 1);
  305. this.shareList.splice(2, 1, user);
  306. rank(this.user.rank - 2); //为分享数组里面的对象添加排名
  307. this.$hideLoading(); //异步操作结束,停止 loading
  308. }
  309. }
  310. }
  311. },
  312. created() {
  313. this.avatarUrl = this.userServerInfo.avatar
  314. this.nickName = this.userServerInfo.name
  315. uni.showLoading({ title: '加载中', mask: true }); //显示loading
  316. if (this.userServerInfo.type == 1) {
  317. //根据用户类型生成要展示的数据列表
  318. this.typeList = ['个人排行榜'];
  319. this.apis = [
  320. //用二维数组来表示 今日昨日一共八个 api
  321. [api_todayPerson, api_todayTeam],
  322. [api_yesterdayPerson, api_yesterdayTeam]
  323. ];
  324. } else if (this.userServerInfo.type == 2) {
  325. this.typeList = ['个人排行榜', '团队排行榜'];
  326. } else if (this.userServerInfo.type == 3) {
  327. this.typeList = ['个人排行榜', '团队排行榜'];
  328. }
  329. this.$scrollViewHeight('.list'); //设置页面内 scroll view 的高度
  330. let _this = this;
  331. this.getPageData(data => {
  332. _this.$hideLoading(); //异步操作结束,停止 loading
  333. data.per_data ? (_this.user = data.per_data) : ''; //是否有用户排名信息传过来,有就赋给 user
  334. _this.is_float = (data.per_data && data.per_data.float) || 0;
  335. });
  336. },
  337. watch: {
  338. rankData: {
  339. handler(a, b) {
  340. if (a.length > 0) {
  341. this.list = [];
  342. a.forEach(item => {
  343. this.list = this.list.concat(item.data);
  344. });
  345. }
  346. },
  347. deep: true
  348. }
  349. }
  350. };
  351. </script>
  352. <style lang="scss" scoped>
  353. .ranking {
  354. @include page();
  355. .shangsheng_toast {
  356. width: 750rpx;
  357. height: 811rpx;
  358. .text {
  359. color: #e46b00;
  360. font-size: 60rpx;
  361. position: absolute;
  362. width: 200rpx;
  363. left: 50%;
  364. margin-left: -100rpx;
  365. bottom: 227rpx;
  366. text-align: center;
  367. line-height: 90rpx;
  368. }
  369. }
  370. .content {
  371. border-top: $custom-nav-borderbot-height solid $custom-nav-borderbot-color;
  372. display: flex;
  373. flex-direction: column;
  374. background-color: #f2f4f5;
  375. .top_container {
  376. width: 100%;
  377. height: 265rpx;
  378. background-image: url(../../static/new/rank_bg.png);
  379. background-repeat: no-repeat;
  380. background-size: 100% 100%;
  381. .day-title {
  382. width: 100%;
  383. display: flex;
  384. justify-content: space-between;
  385. align-items: center;
  386. box-sizing: border-box;
  387. padding: 0 50rpx;
  388. margin: 34rpx 0 28rpx 0;
  389. text {
  390. height: 64rpx;
  391. width: 300rpx;
  392. line-height: 64rpx;
  393. text-align: center;
  394. box-sizing: border-box;
  395. border: 2rpx solid #ffffff;
  396. font-size: 36rpx;
  397. color: #ffffff;
  398. border-radius: 64rpx;
  399. &.active {
  400. color: #fa6342;
  401. background-color: #ffffff;
  402. }
  403. }
  404. }
  405. }
  406. .my_rank_container {
  407. width: 100%;
  408. padding: 0 30rpx;
  409. position: relative;
  410. height: 40rpx;
  411. margin-bottom: 30rpx;
  412. .my_rank {
  413. height: 120rpx;
  414. position: absolute;
  415. top: -80rpx;
  416. left: 30rpx;
  417. right: 30rpx;
  418. background-color: #ffffff;
  419. border-radius: 10rpx;
  420. box-sizing: border-box;
  421. padding: 0 42rpx;
  422. display: flex;
  423. justify-content: space-between;
  424. align-items: center;
  425. .num {
  426. color: #2a2a2a;
  427. font-size: 40rpx;
  428. }
  429. .userImg {
  430. width: 64rpx;
  431. height: 64rpx;
  432. border-radius: 50%;
  433. }
  434. .name {
  435. font-size: 28rpx;
  436. color: #2a2a2a;
  437. }
  438. .score {
  439. color: #fa6342;
  440. font-size: 28rpx;
  441. }
  442. }
  443. }
  444. .share_btn {
  445. margin-top: 15rpx;
  446. padding: 0 30rpx;
  447. button {
  448. width: 100%;
  449. height: 76rpx;
  450. border: 2rpx solid #ffffff;
  451. border-radius: 24rpx;
  452. padding: 0;
  453. background: #fa6342;
  454. line-height: 76rpx;
  455. text-align: center;
  456. font-size: 28rpx;
  457. color: #ffffff;
  458. border-radius: 76rpx;
  459. }
  460. }
  461. .title-bar {
  462. height: 4rpx;
  463. width: 100%;
  464. background: #dedede;
  465. position: relative;
  466. .title-drog {
  467. width: 50%;
  468. height: 100%;
  469. background: #fa6342;
  470. position: absolute;
  471. top: 0;
  472. left: 0;
  473. &::after {
  474. content: '';
  475. display: block;
  476. width: 0;
  477. height: 0;
  478. border-style: solid;
  479. border-width: 8rpx 12rpx;
  480. border-color: transparent transparent red transparent;
  481. transform: translate(175.5rpx, -100%);
  482. }
  483. }
  484. }
  485. image {
  486. display: block;
  487. width: 100%;
  488. height: 240rpx;
  489. }
  490. .type-title {
  491. height: 83rpx;
  492. width: 100%;
  493. display: flex;
  494. justify-content: space-around;
  495. text {
  496. height: 83rpx;
  497. flex: 1;
  498. color: #999999;
  499. font-size: 36rpx;
  500. line-height: 83rpx;
  501. text-align: center;
  502. box-sizing: border-box;
  503. position: relative;
  504. border: 2rpx solid #ffffff;
  505. font-weight: 500;
  506. &.active {
  507. background-color: #ffffff;
  508. color: #fa6342;
  509. }
  510. }
  511. }
  512. .list_container {
  513. margin: 0 30rpx;
  514. flex: 1;
  515. display: flex;
  516. justify-content: space-between;
  517. flex-direction: column;
  518. box-shadow: 0 0 21rpx 3rpx rgba(255, 90, 11, 0.2);
  519. }
  520. .rank_list_fixed_title {
  521. width: 100%;
  522. height: 64rpx;
  523. line-height: 64rpx;
  524. color: #666666;
  525. font-size: 32rpx;
  526. padding: 0 30rpx;
  527. box-sizing: border-box;
  528. display: flex;
  529. justify-content: space-between;
  530. align-items: center;
  531. .text1 {
  532. width: 76rpx;
  533. }
  534. .text3 {
  535. width: calc(100% - 206rpx);
  536. display: flex;
  537. justify-content: space-between;
  538. align-items: center;
  539. margin-left: 40rpx;
  540. }
  541. .text4 {
  542. width: 130rpx;
  543. text-align: center;
  544. }
  545. .text5 {
  546. width: 64rpx;
  547. text-align: center;
  548. }
  549. .text6 {
  550. width: calc(100% - 104rpx);
  551. // text-align: center;
  552. text-align: left !important;
  553. }
  554. }
  555. .list {
  556. flex: 1;
  557. height: calc(100% - 91rpx - 64rpx);
  558. }
  559. .fiexed {
  560. height: 100rpx;
  561. bottom: 0;
  562. background: #fa6342;
  563. display: flex;
  564. padding: 0 30rpx;
  565. .left {
  566. height: 100%;
  567. width: 136rpx;
  568. display: flex;
  569. flex-direction: column;
  570. align-items: center;
  571. justify-content: center;
  572. text {
  573. color: #ffffff;
  574. font-size: 26rpx;
  575. &.rank {
  576. font-size: 32rpx;
  577. }
  578. }
  579. }
  580. .center {
  581. width: 380rpx;
  582. margin-left: 10rpx;
  583. height: 100%;
  584. display: flex;
  585. align-items: center;
  586. color: #ffffff;
  587. position: relative;
  588. image {
  589. width: 64rpx;
  590. height: 64rpx;
  591. border-radius: 50%;
  592. &.hat {
  593. position: absolute;
  594. top: 6rpx;
  595. left: -5rpx;
  596. width: 72rpx;
  597. height: 88rpx;
  598. }
  599. }
  600. text {
  601. margin-left: 30rpx;
  602. font-size: 24rpx;
  603. }
  604. }
  605. .right {
  606. flex: 1;
  607. display: flex;
  608. align-items: center;
  609. color: #ffffff;
  610. button {
  611. width: 146rpx;
  612. height: 48rpx;
  613. border: 2rpx solid #ffffff;
  614. border-radius: 24rpx;
  615. padding: 0;
  616. background: transparent;
  617. line-height: 48rpx;
  618. text-align: center;
  619. font-size: 24rpx;
  620. color: #ffffff;
  621. }
  622. .score {
  623. width: 130rpx;
  624. height: 100%;
  625. display: flex;
  626. align-items: center;
  627. color: #fa6342;
  628. image {
  629. width: 30rpx;
  630. height: 30rpx;
  631. }
  632. text {
  633. font-size: 24rpx;
  634. margin-left: 10rpx;
  635. }
  636. }
  637. .float {
  638. flex: 1;
  639. display: flex;
  640. align-items: center;
  641. image {
  642. width: 24rpx;
  643. height: 30rpx;
  644. }
  645. text {
  646. margin-left: 10rpx;
  647. font-size: 24rpx;
  648. }
  649. }
  650. }
  651. }
  652. }
  653. }
  654. </style>