index.vue 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538
  1. <template>
  2. <div class="rank-wrap">
  3. <div class="type-list">
  4. <div
  5. v-for="(item, index) in rankTypeList"
  6. :key="index"
  7. :class="{ item: 1, active: item.type === currRankType }"
  8. @click="changeCurrRankType(item.type)"
  9. >
  10. {{ item.label }}
  11. </div>
  12. </div>
  13. <div
  14. v-if="rankList.length"
  15. class="rank-list"
  16. >
  17. <div class="top">
  18. <div
  19. v-for="(item, index) in [rankList[1], rankList[0], rankList[2]]"
  20. :key="index"
  21. :class="{ item: 1, [`rank-${item.rank}`]: 1 }"
  22. >
  23. <div
  24. class="avatar"
  25. @click="
  26. currRankType !== RankTypeEnum.blog &&
  27. router.push({
  28. name: routerName.profile,
  29. params: { userId: item.users[0]?.id },
  30. })
  31. "
  32. >
  33. <Avatar
  34. :size="100"
  35. :avatar="item.users[0]?.avatar"
  36. :living="!!item.live?.live"
  37. ></Avatar>
  38. </div>
  39. <div class="username">{{ item.users[0]?.username }}</div>
  40. <div class="rank">
  41. <i>0{{ item.rank }}</i>
  42. <div
  43. v-if="item.live?.live && currRankType === RankTypeEnum.liveRoom"
  44. class="living"
  45. @click="handleJoin(item.live)"
  46. >
  47. 直播中
  48. </div>
  49. </div>
  50. <div v-if="item.balance && currRankType === RankTypeEnum.wallet">
  51. 钱包:{{ item.balance }}
  52. </div>
  53. </div>
  54. </div>
  55. <div class="top50-list">
  56. <div
  57. v-for="(item, index) in rankList.filter((item, index) => index >= 3)"
  58. :key="index"
  59. class="top50-item"
  60. >
  61. <div class="rank">
  62. <i>{{ item.rank >= 10 ? item.rank : '0' + item.rank }}</i>
  63. </div>
  64. <div
  65. class="left"
  66. @click="
  67. currRankType !== RankTypeEnum.blog &&
  68. router.push({
  69. name: routerName.profile,
  70. params: { userId: item.users[0]?.id },
  71. })
  72. "
  73. >
  74. <img
  75. :src="item.users[0]?.avatar"
  76. class="avatar"
  77. alt=""
  78. />
  79. <div class="username">{{ item.users[0]?.username }}</div>
  80. <div class="wallet">
  81. <div v-if="currRankType === RankTypeEnum.wallet">
  82. (钱包:{{ item.balance }})
  83. </div>
  84. </div>
  85. <div
  86. v-if="item.live?.live && currRankType === RankTypeEnum.liveRoom"
  87. class="living-tag"
  88. @click.stop="handleJoin(item.live)"
  89. >
  90. 直播中
  91. </div>
  92. </div>
  93. <div class="right"></div>
  94. </div>
  95. </div>
  96. </div>
  97. </div>
  98. </template>
  99. <script lang="ts" setup>
  100. import { onMounted, ref } from 'vue';
  101. import { fetchLiveRoomList } from '@/api/liveRoom';
  102. import { fetchBlogUserList, fetchUserList } from '@/api/user';
  103. import { fetchWalletList } from '@/api/wallet';
  104. import { fullLoading } from '@/components/FullLoading';
  105. import {
  106. ILiveRoom,
  107. IUser,
  108. LiveRoomIsShowEnum,
  109. RankTypeEnum,
  110. } from '@/interface';
  111. import router, { routerName } from '@/router';
  112. export interface IRankType {
  113. type: RankTypeEnum;
  114. label: string;
  115. }
  116. const rankTypeList = ref<IRankType[]>([
  117. {
  118. type: RankTypeEnum.liveRoom,
  119. label: '直播榜',
  120. },
  121. {
  122. type: RankTypeEnum.user,
  123. label: '用户榜',
  124. },
  125. {
  126. type: RankTypeEnum.wallet,
  127. label: '土豪榜',
  128. },
  129. {
  130. type: RankTypeEnum.blog,
  131. label: '博客用户',
  132. },
  133. ]);
  134. const mockDataNums = 4;
  135. const currRankType = ref(RankTypeEnum.liveRoom);
  136. const mockRank: {
  137. users: IUser[];
  138. rank: number;
  139. level: number;
  140. score: number;
  141. balance: string;
  142. live?: ILiveRoom;
  143. }[] = [
  144. {
  145. users: [
  146. {
  147. id: -1,
  148. username: '待上榜',
  149. avatar: '',
  150. },
  151. ],
  152. rank: 1,
  153. level: -1,
  154. score: -1,
  155. balance: '0.00',
  156. live: undefined,
  157. },
  158. {
  159. users: [
  160. {
  161. id: -1,
  162. username: '待上榜',
  163. avatar: '',
  164. },
  165. ],
  166. rank: 2,
  167. level: -1,
  168. score: -1,
  169. balance: '0.00',
  170. live: undefined,
  171. },
  172. {
  173. users: [
  174. {
  175. id: -1,
  176. username: '待上榜',
  177. avatar: '',
  178. },
  179. ],
  180. rank: 3,
  181. level: -1,
  182. score: -1,
  183. balance: '0.00',
  184. live: undefined,
  185. },
  186. {
  187. users: [
  188. {
  189. id: -1,
  190. username: '待上榜',
  191. avatar: '',
  192. },
  193. ],
  194. rank: 4,
  195. level: -1,
  196. score: -1,
  197. balance: '0.00',
  198. live: undefined,
  199. },
  200. ];
  201. const rankList = ref(mockRank);
  202. function handleJoin(item) {
  203. router.push({
  204. name: routerName.pull,
  205. params: { roomId: item.live.live_room_id },
  206. });
  207. }
  208. async function getWalletList() {
  209. try {
  210. fullLoading({ loading: true });
  211. const res = await fetchWalletList({});
  212. if (res.code === 200) {
  213. const length = res.data.rows.length;
  214. rankList.value = res.data.rows.map((item, index) => {
  215. return {
  216. users: [item.user],
  217. rank: index + 1,
  218. level: 1,
  219. score: 1,
  220. balance: item.balance,
  221. };
  222. });
  223. if (length < mockDataNums) {
  224. rankList.value.push(...mockRank.slice(length));
  225. }
  226. }
  227. } catch (error) {
  228. console.log(error);
  229. } finally {
  230. fullLoading({ loading: false });
  231. }
  232. }
  233. async function getLiveRoomList() {
  234. try {
  235. fullLoading({ loading: true });
  236. const res = await fetchLiveRoomList({
  237. is_show: LiveRoomIsShowEnum.yes,
  238. orderName: 'updated_at',
  239. orderBy: 'desc',
  240. });
  241. if (res.code === 200) {
  242. const length = res.data.rows.length;
  243. rankList.value = res.data.rows.map((item, index) => {
  244. return {
  245. users: item.users,
  246. live: item,
  247. rank: index + 1,
  248. level: 1,
  249. score: 1,
  250. };
  251. });
  252. if (length < mockDataNums) {
  253. rankList.value.push(...mockRank.slice(length));
  254. }
  255. }
  256. } catch (error) {
  257. console.log(error);
  258. } finally {
  259. fullLoading({ loading: false });
  260. }
  261. }
  262. async function getUserList() {
  263. try {
  264. fullLoading({ loading: true });
  265. const res = await fetchUserList({
  266. orderName: 'updated_at',
  267. orderBy: 'desc',
  268. });
  269. if (res.code === 200) {
  270. const length = res.data.rows.length;
  271. rankList.value = res.data.rows.map((item, index) => {
  272. return {
  273. users: [
  274. {
  275. id: item.id!,
  276. username: item.username!,
  277. avatar: item.avatar!,
  278. },
  279. ],
  280. rank: index + 1,
  281. level: 1,
  282. score: 1,
  283. balance: '',
  284. };
  285. });
  286. if (length < mockDataNums) {
  287. rankList.value.push(...mockRank.slice(length));
  288. }
  289. }
  290. } catch (error) {
  291. console.log(error);
  292. } finally {
  293. fullLoading({ loading: false });
  294. }
  295. }
  296. async function getBlogUserList() {
  297. try {
  298. fullLoading({ loading: true });
  299. const res = await fetchBlogUserList({
  300. orderName: 'updated_at',
  301. orderBy: 'desc',
  302. });
  303. if (res.code === 200) {
  304. const length = res.data.rows.length;
  305. rankList.value = res.data.rows.map((item, index) => {
  306. return {
  307. users: [
  308. {
  309. id: item.id!,
  310. username: item.username!,
  311. avatar: item.avatar!,
  312. },
  313. ],
  314. rank: index + 1,
  315. level: 1,
  316. score: 1,
  317. balance: '',
  318. };
  319. });
  320. if (length < mockDataNums) {
  321. rankList.value.push(...mockRank.slice(length));
  322. }
  323. }
  324. } catch (error) {
  325. console.log(error);
  326. } finally {
  327. fullLoading({ loading: false });
  328. }
  329. }
  330. function changeCurrRankType(type: RankTypeEnum) {
  331. currRankType.value = type;
  332. switch (type) {
  333. case RankTypeEnum.liveRoom:
  334. getLiveRoomList();
  335. break;
  336. case RankTypeEnum.user:
  337. getUserList();
  338. break;
  339. case RankTypeEnum.blog:
  340. getBlogUserList();
  341. break;
  342. case RankTypeEnum.wallet:
  343. getWalletList();
  344. break;
  345. default:
  346. break;
  347. }
  348. }
  349. onMounted(() => {
  350. changeCurrRankType(currRankType.value);
  351. });
  352. </script>
  353. <style lang="scss" scoped>
  354. .rank-wrap {
  355. box-sizing: border-box;
  356. padding-top: 10px;
  357. height: calc(100vh - $header-height);
  358. background-color: #f4f4f4;
  359. .type-list {
  360. display: flex;
  361. align-items: center;
  362. margin: 20px 0;
  363. width: 100%;
  364. .item {
  365. flex: 1;
  366. margin: 0 10px;
  367. height: 40px;
  368. border-radius: 10px;
  369. background-color: $theme-color-gold;
  370. color: white;
  371. text-align: center;
  372. font-weight: bold;
  373. font-size: 20px;
  374. line-height: 40px;
  375. filter: grayscale(1);
  376. cursor: pointer;
  377. &.active {
  378. filter: grayscale(0);
  379. }
  380. }
  381. }
  382. .rank-list {
  383. width: 100%;
  384. .living-tag {
  385. display: inline-block;
  386. margin: 0 auto;
  387. padding: 2px 5px;
  388. width: 40px;
  389. border: 1px solid $theme-color-gold;
  390. border-radius: 10px;
  391. color: $theme-color-gold;
  392. text-align: center;
  393. font-size: 12px;
  394. line-height: 1.2;
  395. cursor: pointer;
  396. }
  397. .top {
  398. display: flex;
  399. align-items: flex-end;
  400. justify-content: center;
  401. margin-top: 100px;
  402. width: 100%;
  403. .item {
  404. position: relative;
  405. margin: 0 20px;
  406. width: 200px;
  407. height: 180px;
  408. border-radius: 15px;
  409. background-color: white;
  410. text-align: center;
  411. &.rank-1 {
  412. height: 200px;
  413. border-color: #ff6744;
  414. color: #ff6744;
  415. .rank {
  416. margin-top: 20px;
  417. }
  418. .avatar-wrap {
  419. .avatar {
  420. border: 2px solid #ff6744;
  421. }
  422. }
  423. }
  424. &.rank-2 {
  425. border-color: #44d6ff;
  426. color: #44d6ff;
  427. .avatar-wrap {
  428. .avatar {
  429. border: 2px solid #44d6ff;
  430. }
  431. }
  432. }
  433. &.rank-3 {
  434. border-color: #ffb200;
  435. color: #ffb200;
  436. .avatar-wrap {
  437. .avatar {
  438. border: 2px solid #ffb200;
  439. }
  440. }
  441. }
  442. .avatar {
  443. margin-top: -50px;
  444. display: inline-block;
  445. cursor: pointer;
  446. }
  447. .username {
  448. margin-bottom: 10px;
  449. font-size: 22px;
  450. }
  451. .rank {
  452. position: relative;
  453. display: inline-block;
  454. padding: 0px 20px;
  455. border: 1px solid;
  456. border-radius: 20px;
  457. font-size: 20px;
  458. .living {
  459. position: absolute;
  460. bottom: 0;
  461. left: 50%;
  462. transform: translate(-50%, 130%);
  463. @extend .living-tag;
  464. }
  465. }
  466. }
  467. }
  468. .top50-list {
  469. margin-top: 20px;
  470. border-radius: 10px;
  471. background-color: white;
  472. .top50-item {
  473. display: flex;
  474. align-items: center;
  475. padding: 0 10px;
  476. height: 40px;
  477. color: #666;
  478. &:nth-child(2n) {
  479. background-color: #fafbfc;
  480. }
  481. .rank {
  482. box-sizing: border-box;
  483. margin-right: 20px;
  484. width: 80px;
  485. border-radius: 40px;
  486. background-color: #84f9da;
  487. color: white;
  488. text-align: center;
  489. font-size: 20px;
  490. }
  491. .left {
  492. display: flex;
  493. align-items: center;
  494. font-size: 12px;
  495. cursor: pointer;
  496. .avatar {
  497. margin-right: 10px;
  498. width: 28px;
  499. height: 28px;
  500. border-radius: 50%;
  501. }
  502. .username {
  503. width: 100px;
  504. @extend %singleEllipsis;
  505. }
  506. .wallet {
  507. margin-left: 4px;
  508. }
  509. }
  510. }
  511. }
  512. }
  513. }
  514. </style>