index.vue 11 KB

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