index.vue 11 KB

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