shuisheng před 1 rokem
rodič
revize
6bd2943a6d

+ 8 - 0
src/components/Avatar/index.vue

@@ -6,6 +6,7 @@
     <div class="cycle-wrap">
       <div
         class="avatar"
+        :class="{ border }"
         :style="{ backgroundImage: `url(${avatar})` }"
       ></div>
       <template v-if="living">
@@ -24,11 +25,13 @@ withDefaults(
     avatar: string;
     size: number;
     living?: boolean;
+    border?: boolean;
   }>(),
   {
     avatar: '',
     size: 100,
     living: false,
+    border: false,
   }
 );
 </script>
@@ -52,12 +55,17 @@ withDefaults(
     height: var(--width);
     .avatar {
       display: inline-block;
+      box-sizing: border-box;
       margin: 0 auto;
       width: var(--width);
       height: var(--width);
       border-radius: 50%;
+      cursor: pointer;
 
       @extend %containBg;
+      &.border {
+        border: 1px solid $theme-color-gold;
+      }
     }
     .cycle {
       position: absolute;

+ 5 - 6
src/components/LoginModal/index.vue

@@ -79,10 +79,10 @@
               tab="注册"
             >
               <n-form
-                ref="loginFormRefRef"
+                ref="loginFormRef"
                 label-placement="left"
                 size="large"
-                :model="loginFormRef"
+                :model="loginForm"
                 :rules="loginRules"
               >
                 <n-form-item path="id">
@@ -182,7 +182,6 @@ const loginForm = ref({
   password: '',
 });
 const loginFormRef = ref(null);
-const loginFormRefRef = ref(null);
 const currentTab = ref('pwdlogin'); // pwdlogin
 const loopTimer = ref();
 const emits = defineEmits(['close']);
@@ -206,14 +205,14 @@ const handleLogin = async () => {
     loginForm.value.username.length < 3 ||
     loginForm.value.username.length > 12
   ) {
-    window.$message.warning('用户名长度要求3-12!');
+    window.$message.warning('用户名长度要求3-12!');
     return;
   }
   if (
     loginForm.value.password.length < 6 ||
     loginForm.value.password.length > 18
   ) {
-    window.$message.warning('密码长度要求6-18!');
+    window.$message.warning('密码长度要求6-18!');
     return;
   }
   let token = null;
@@ -231,7 +230,7 @@ const handleLogin = async () => {
 function handleUserRegister(e) {
   e.preventDefault();
   // @ts-ignore
-  loginFormRefRef.value.validate(async (errors) => {
+  loginFormRef.value.validate(async (errors) => {
     if (!errors) {
       const res = await fetchUserRegister({
         username: loginForm.value.username,

+ 2 - 2
src/layout/pc/head/index.vue

@@ -376,14 +376,14 @@
                 class="item"
                 @click.prevent="
                   router.push({
-                    name: routerName.profile,
+                    name: routerName.my,
                     params: {
                       userId: userStore.userInfo.id,
                     },
                   })
                 "
               >
-                <div class="txt">{{ t('layout.profile') }}</div>
+                <div class="txt">{{ t('layout.my') }}</div>
               </a>
               <a
                 class="item"

+ 1 - 1
src/locales/en/layout.ts

@@ -23,7 +23,7 @@ export default nameSpaceWrap('layout', {
   startLive: 'Start Live',
   login: 'Login',
   logout: 'Logout',
-  profile: 'Profile',
+  my: 'My',
   resource: 'Resource',
   libraries: 'Official libraries',
   rank: 'Rank',

+ 1 - 1
src/locales/zh/layout.ts

@@ -23,7 +23,7 @@ export default nameSpaceWrap('layout', {
   startLive: '我要开播',
   login: '登录',
   logout: '退出',
-  profile: '个人信息',
+  my: '个人信息',
   resource: '资源',
   libraries: '官方库',
   rank: '排行榜',

+ 14 - 8
src/router/index.ts

@@ -16,7 +16,7 @@ export const mobileRouterName = {
   h5Room: 'h5Room',
   h5Area: 'h5Area',
   h5Rank: 'h5Rank',
-  h5Profile: 'h5Profile',
+  h5My: 'h5My',
   ...commonRouterName,
 };
 
@@ -44,7 +44,8 @@ export const routerName = {
   pushStreamDifferent: 'pushStreamDifferent',
   notFound: 'notFound',
   group: 'group',
-  profile: 'profile',
+  my: 'my',
+  user: 'user',
   download: 'download',
   downloadLive: 'downloadLive',
   downloadRemoteDesktop: 'downloadRemoteDesktop',
@@ -125,9 +126,14 @@ export const defaultRoutes: RouteRecordRaw[] = [
         component: () => import('@/views/shop/index.vue'),
       },
       {
-        name: routerName.profile,
-        path: '/profile/:userId',
-        component: () => import('@/views/profile/index.vue'),
+        name: routerName.my,
+        path: '/my',
+        component: () => import('@/views/my/index.vue'),
+      },
+      {
+        name: routerName.user,
+        path: '/user/:id',
+        component: () => import('@/views/user/index.vue'),
       },
       {
         name: routerName.downloadRemoteDesktop,
@@ -219,9 +225,9 @@ export const defaultRoutes: RouteRecordRaw[] = [
         component: () => import('@/views/h5/rank/index.vue'),
       },
       {
-        name: mobileRouterName.h5Profile,
-        path: 'profile',
-        component: () => import('@/views/h5/profile/index.vue'),
+        name: mobileRouterName.h5My,
+        path: 'my',
+        component: () => import('@/views/h5/my/index.vue'),
       },
     ],
   },

+ 1 - 1
src/store/app/index.ts

@@ -90,7 +90,7 @@ export const useAppStore = defineStore('app', {
       navList: [
         { routeName: mobileRouterName.h5, name: '频道' },
         { routeName: mobileRouterName.h5Rank, name: '排行' },
-        { routeName: mobileRouterName.h5Profile, name: '我的' },
+        { routeName: mobileRouterName.h5My, name: '我的' },
       ],
       allTrack: [],
       liveLine: LiveLineEnum.hls,

+ 0 - 0
src/views/h5/profile/index.vue → src/views/h5/my/index.vue


+ 278 - 0
src/views/my/index.vue

@@ -0,0 +1,278 @@
+<template>
+  <div class="my-wrap">
+    <div class="id">用户id:{{ userStore.userInfo?.id }}</div>
+    <div class="avatar">
+      <span class="txt">用户头像:</span>
+      <Avatar
+        :avatar="userStore.userInfo?.avatar"
+        :size="30"
+        :border="!userStore.userInfo?.avatar?.length"
+      ></Avatar>
+    </div>
+    <div class="username">用户昵称:{{ userStore.userInfo?.username }}</div>
+    <div class="username">
+      用户角色:{{
+        userStore.userInfo?.roles?.map((item) => item.role_name).join(',')
+      }}
+    </div>
+    <br />
+    <div class="pull-url">
+      <span
+        v-if="!userStore.userInfo?.live_rooms?.length"
+        class="link"
+        @click="openLiveRoom"
+      >
+        未开通
+      </span>
+      <div v-else>
+        <div>
+          直播间地址:
+          <a
+            :href="getLiveRoomPageUrl(userStore.userInfo?.live_rooms?.[0]?.id!)"
+            class="link"
+            target="_blank"
+          >
+            {{ getLiveRoomPageUrl(userStore.userInfo?.live_rooms?.[0]?.id!) }}
+          </a>
+        </div>
+        <div>直播间名称:{{ userStore.userInfo?.live_rooms?.[0]?.name }}</div>
+        <div>
+          直播间简介:{{
+            userStore.userInfo?.live_rooms?.[0]?.desc || '暂无简介'
+          }}
+        </div>
+        <div>
+          直播间分区:{{
+            userStore.userInfo?.live_rooms?.[0]?.areas?.[0]?.name || '暂无分区'
+          }}
+        </div>
+        <div
+          v-if="
+            userStore.userInfo?.auths?.find(
+              (v) => v.auth_value === DEFAULT_AUTH_INFO.LIVE_PUSH.auth_value
+            )
+          "
+          class="url-wrap"
+          v-loading="updateKeyLoading"
+        >
+          <div
+            class="link"
+            @click="handleUpdateKey"
+          >
+            更新地址
+          </div>
+          <div
+            class="cdn"
+            v-if="
+              userStore.userInfo?.auths?.find(
+                (v) =>
+                  v.auth_value === DEFAULT_AUTH_INFO.LIVE_PULL_SVIP.auth_value
+              )
+            "
+          >
+            <div>
+              <span>
+                RTMP推流地址(CDN):{{
+                  userStore.userInfo?.live_rooms?.[0]?.cdn_push_rtmp_url!
+                }},
+              </span>
+              <span
+                class="link"
+                @click="
+                  handleCopy(
+                    userStore.userInfo?.live_rooms?.[0]?.cdn_push_rtmp_url!
+                  )
+                "
+              >
+                复制
+              </span>
+            </div>
+            <div>
+              <span>
+                OBS服务器(CDN):{{
+                  userStore.userInfo?.live_rooms?.[0]?.cdn_push_obs_server!
+                }},
+              </span>
+              <span
+                class="link"
+                @click="
+                  handleCopy(
+                    userStore.userInfo?.live_rooms?.[0]?.cdn_push_obs_server!
+                  )
+                "
+              >
+                复制
+              </span>
+            </div>
+            <div>
+              <span>
+                OBS推流码(CDN):{{
+                  userStore.userInfo?.live_rooms?.[0]?.cdn_push_obs_stream_key!
+                }},
+              </span>
+              <span
+                class="link"
+                @click="
+                  handleCopy(
+                    userStore.userInfo?.live_rooms?.[0]
+                      ?.cdn_push_obs_stream_key!
+                  )
+                "
+              >
+                复制
+              </span>
+            </div>
+          </div>
+
+          <div class="srs">
+            <div>
+              <span>
+                RTMP推流地址:{{
+                  userStore.userInfo?.live_rooms?.[0]?.push_rtmp_url!
+                }},
+              </span>
+              <span
+                class="link"
+                @click="
+                  handleCopy(
+                    userStore.userInfo?.live_rooms?.[0]?.push_rtmp_url!
+                  )
+                "
+              >
+                复制
+              </span>
+            </div>
+            <div>
+              <span
+                >OBS服务器:{{
+                  userStore.userInfo?.live_rooms?.[0]?.push_obs_server!
+                }},</span
+              >
+              <span
+                class="link"
+                @click="
+                  handleCopy(
+                    userStore.userInfo?.live_rooms?.[0]?.push_obs_server!
+                  )
+                "
+              >
+                复制
+              </span>
+            </div>
+            <div>
+              <span
+                >OBS推流码:{{
+                  userStore.userInfo?.live_rooms?.[0]?.push_obs_stream_key!
+                }},</span
+              >
+              <span
+                class="link"
+                @click="
+                  handleCopy(
+                    userStore.userInfo?.live_rooms?.[0]?.push_obs_stream_key!
+                  )
+                "
+              >
+                复制
+              </span>
+            </div>
+          </div>
+        </div>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script lang="ts" setup>
+import { copyToClipBoard, openToTarget } from 'billd-utils';
+import { ref } from 'vue';
+import { useRouter } from 'vue-router';
+
+import { fetchUpdateLiveRoomKey } from '@/api/liveRoom';
+import { DEFAULT_AUTH_INFO } from '@/constant';
+import { loginTip } from '@/hooks/use-login';
+import { routerName } from '@/router';
+import { useUserStore } from '@/store/user';
+import { LiveRoomTypeEnum } from '@/types/ILiveRoom';
+import { getLiveRoomPageUrl } from '@/utils';
+
+const userStore = useUserStore();
+const router = useRouter();
+
+const updateKeyLoading = ref(false);
+
+function handleCopy(url: string) {
+  copyToClipBoard(url);
+  window.$message.success('复制成功!');
+}
+
+function openLiveRoom() {
+  if (!loginTip()) {
+    return;
+  }
+  const url = router.resolve({
+    name: routerName.push,
+    query: { liveType: LiveRoomTypeEnum.srs },
+  });
+  openToTarget(url.href);
+}
+
+async function handleUpdateKey() {
+  try {
+    updateKeyLoading.value = true;
+    const res = await fetchUpdateLiveRoomKey();
+    if (res.code === 200 && userStore.userInfo?.live_rooms?.[0]) {
+      userStore.userInfo.live_rooms[0].push_obs_server =
+        res.data.srsPushRes.push_obs_server;
+      userStore.userInfo.live_rooms[0].push_obs_stream_key =
+        res.data.srsPushRes.push_obs_stream_key;
+      userStore.userInfo.live_rooms[0].push_rtmp_url =
+        res.data.srsPushRes.push_rtmp_url;
+      userStore.userInfo.live_rooms[0].push_srt_url =
+        res.data.srsPushRes.push_srt_url;
+      userStore.userInfo.live_rooms[0].push_webrtc_url =
+        res.data.srsPushRes.push_webrtc_url;
+      userStore.userInfo.live_rooms[0].cdn_push_obs_server =
+        res.data.srsPushRes.push_obs_server;
+      userStore.userInfo.live_rooms[0].cdn_push_obs_stream_key =
+        res.data.cdnPushRes.push_obs_stream_key;
+      userStore.userInfo.live_rooms[0].cdn_push_rtmp_url =
+        res.data.cdnPushRes.push_rtmp_url;
+      userStore.userInfo.live_rooms[0].cdn_push_srt_url =
+        res.data.cdnPushRes.push_srt_url;
+      userStore.userInfo.live_rooms[0].cdn_push_webrtc_url =
+        res.data.cdnPushRes.push_webrtc_url;
+    }
+  } catch (error) {
+    console.error(error);
+  } finally {
+    updateKeyLoading.value = false;
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+.my-wrap {
+  position: relative;
+  padding: 10px;
+  .link {
+    color: $theme-color-gold;
+    text-decoration: none;
+    cursor: pointer;
+  }
+  .avatar {
+    display: flex;
+    align-items: center;
+    .txt {
+      margin-right: 10px;
+    }
+  }
+  .url-wrap {
+    position: relative;
+    margin-top: 10px;
+    .cdn {
+      margin-bottom: 10px;
+    }
+  }
+}
+</style>

+ 0 - 292
src/views/profile/index.vue

@@ -1,292 +0,0 @@
-<template>
-  <div
-    class="profile-wrap"
-    v-loading="getUserLoading"
-  >
-    <div class="uid">用户id:{{ userInfo?.id }}</div>
-    <div class="avatar">
-      <span class="txt">用户头像:</span>
-      <Avatar
-        :avatar="userInfo?.avatar"
-        :size="30"
-      ></Avatar>
-    </div>
-    <div class="username">用户昵称:{{ userInfo?.username }}</div>
-    <div
-      class="username"
-      v-if="userStore.userInfo"
-    >
-      用户角色:{{ userInfo?.roles?.map((item) => item.role_name).join(',') }}
-    </div>
-    <br />
-    <div class="pull-url">
-      <span
-        v-if="
-          !userInfo?.live_rooms?.length &&
-          userStore.userInfo?.id === userInfo?.id
-        "
-        class="link"
-        @click="openLiveRoom"
-      >
-        未开通
-      </span>
-      <span v-else-if="!userInfo?.live_rooms?.length">
-        该用户未开通直播间
-      </span>
-      <div v-else>
-        <div>
-          直播间地址:
-          <a
-            :href="getLiveRoomPageUrl(userInfo?.live_rooms?.[0]?.id!)"
-            class="link"
-            target="_blank"
-          >
-            {{ getLiveRoomPageUrl(userInfo?.live_rooms?.[0]?.id!) }}
-          </a>
-        </div>
-        <div>直播间名称:{{ userInfo?.live_rooms?.[0]?.name }}</div>
-        <div>
-          直播间简介:{{ userInfo?.live_rooms?.[0]?.desc || '暂无简介' }}
-        </div>
-        <div>
-          直播间分区:{{
-            userInfo.live_rooms[0]?.areas?.[0]?.name || '暂无分区'
-          }}
-        </div>
-        <div
-          v-if="
-            userStore.userInfo?.id === userInfo.id &&
-            userStore.auths?.find(
-              (v) => v.auth_value === DEFAULT_AUTH_INFO.LIVE_PUSH.auth_value
-            )
-          "
-          class="url-wrap"
-          v-loading="updateKeyLoading"
-        >
-          <div
-            class="link"
-            @click="handleUpdateKey"
-          >
-            更新地址
-          </div>
-          <div
-            class="cdn"
-            v-if="
-              userStore.userInfo?.auths?.find(
-                (v) =>
-                  v.auth_value === DEFAULT_AUTH_INFO.LIVE_PULL_SVIP.auth_value
-              )
-            "
-          >
-            <div>
-              <span>
-                RTMP推流地址(CDN):{{ liveRoomInfo?.cdn_push_rtmp_url! }},
-              </span>
-              <span
-                class="link"
-                @click="handleCopy(liveRoomInfo?.cdn_push_rtmp_url!)"
-              >
-                复制
-              </span>
-            </div>
-            <div>
-              <span>
-                OBS服务器(CDN):{{ liveRoomInfo?.cdn_push_obs_server! }},
-              </span>
-              <span
-                class="link"
-                @click="handleCopy(liveRoomInfo?.cdn_push_obs_server!)"
-              >
-                复制
-              </span>
-            </div>
-            <div>
-              <span>
-                OBS推流码(CDN):{{ liveRoomInfo?.cdn_push_obs_stream_key! }},
-              </span>
-              <span
-                class="link"
-                @click="handleCopy(liveRoomInfo?.cdn_push_obs_stream_key!)"
-              >
-                复制
-              </span>
-            </div>
-          </div>
-
-          <div class="srs">
-            <div>
-              <span> RTMP推流地址:{{ liveRoomInfo?.push_rtmp_url! }}, </span>
-              <span
-                class="link"
-                @click="handleCopy(liveRoomInfo?.push_rtmp_url!)"
-              >
-                复制
-              </span>
-            </div>
-            <div>
-              <span>OBS服务器:{{ liveRoomInfo?.push_obs_server! }},</span>
-              <span
-                class="link"
-                @click="handleCopy(liveRoomInfo?.push_obs_server!)"
-              >
-                复制
-              </span>
-            </div>
-            <div>
-              <span>OBS推流码:{{ liveRoomInfo?.push_obs_stream_key! }},</span>
-              <span
-                class="link"
-                @click="handleCopy(liveRoomInfo?.push_obs_stream_key!)"
-              >
-                复制
-              </span>
-            </div>
-          </div>
-        </div>
-      </div>
-    </div>
-  </div>
-</template>
-
-<script lang="ts" setup>
-import { copyToClipBoard, openToTarget } from 'billd-utils';
-import { ref, watch, watchEffect } from 'vue';
-import { useRoute, useRouter } from 'vue-router';
-
-import { fetchUpdateLiveRoomKey } from '@/api/liveRoom';
-import { fetchFindUser } from '@/api/user';
-import { DEFAULT_AUTH_INFO } from '@/constant';
-import { loginTip } from '@/hooks/use-login';
-import { routerName } from '@/router';
-import { useUserStore } from '@/store/user';
-import { ILiveRoom, LiveRoomTypeEnum } from '@/types/ILiveRoom';
-import { IUser } from '@/types/IUser';
-import { getLiveRoomPageUrl } from '@/utils';
-
-const userStore = useUserStore();
-const route = useRoute();
-const router = useRouter();
-
-const liveRoomInfo = ref<ILiveRoom>();
-const userId = ref(-1);
-const userInfo = ref<IUser>();
-const getUserLoading = ref(false);
-const updateKeyLoading = ref(false);
-
-watchEffect(() => {
-  if (route.params.userId) {
-    userId.value = Number(route.params.userId as string);
-    handleUserInfo();
-  }
-});
-
-watch(
-  () => userStore.userInfo,
-  (newval) => {
-    if (newval) {
-      liveRoomInfo.value = newval.live_rooms?.[0];
-    }
-  },
-  { immediate: true }
-);
-
-function handleReplaceCDNUrl(url: string) {
-  const reg = /pushtype=([0-9]+)/g;
-  console.log(url.replace(reg, 'pushtype=3'));
-  return url.replace(reg, `pushtype=${LiveRoomTypeEnum.tencent_css}`);
-}
-
-function handleReplaceRtmpUrl(url: string) {
-  const reg = /pushtype=([0-9]+)/g;
-  console.log(url.replace(reg, 'pushtype=3'));
-  return url.replace(reg, `pushtype=${LiveRoomTypeEnum.obs}`);
-}
-
-async function handleUserInfo() {
-  try {
-    getUserLoading.value = true;
-    const res = await fetchFindUser(userId.value);
-    if (res.code === 200) {
-      userInfo.value = res.data;
-    }
-  } catch (error) {
-    console.error(error);
-  } finally {
-    getUserLoading.value = false;
-  }
-}
-
-function handleCopy(url: string) {
-  copyToClipBoard(url);
-  window.$message.success('复制成功!');
-}
-
-function openLiveRoom() {
-  if (!loginTip()) {
-    return;
-  }
-  const url = router.resolve({
-    name: routerName.push,
-    query: { liveType: LiveRoomTypeEnum.srs },
-  });
-  openToTarget(url.href);
-}
-
-async function handleUpdateKey() {
-  try {
-    updateKeyLoading.value = true;
-    const res = await fetchUpdateLiveRoomKey();
-    if (res.code === 200) {
-      if (liveRoomInfo.value) {
-        liveRoomInfo.value.push_obs_server =
-          res.data.srsPushRes.push_obs_server;
-        liveRoomInfo.value.push_obs_stream_key =
-          res.data.srsPushRes.push_obs_stream_key;
-        liveRoomInfo.value.push_rtmp_url = res.data.srsPushRes.push_rtmp_url;
-        liveRoomInfo.value.push_srt_url = res.data.srsPushRes.push_srt_url;
-        liveRoomInfo.value.push_webrtc_url =
-          res.data.srsPushRes.push_webrtc_url;
-        liveRoomInfo.value.cdn_push_obs_server =
-          res.data.srsPushRes.push_obs_server;
-        liveRoomInfo.value.cdn_push_obs_stream_key =
-          res.data.cdnPushRes.push_obs_stream_key;
-        liveRoomInfo.value.cdn_push_rtmp_url =
-          res.data.cdnPushRes.push_rtmp_url;
-        liveRoomInfo.value.cdn_push_srt_url = res.data.cdnPushRes.push_srt_url;
-        liveRoomInfo.value.cdn_push_webrtc_url =
-          res.data.cdnPushRes.push_webrtc_url;
-      }
-    }
-  } catch (error) {
-    console.error(error);
-  } finally {
-    updateKeyLoading.value = false;
-  }
-}
-</script>
-
-<style lang="scss" scoped>
-.profile-wrap {
-  position: relative;
-  padding: 10px;
-  .link {
-    color: $theme-color-gold;
-    text-decoration: none;
-    cursor: pointer;
-  }
-  .avatar {
-    display: flex;
-    align-items: center;
-    .txt {
-      margin-right: 10px;
-    }
-  }
-  .url-wrap {
-    position: relative;
-    margin-top: 10px;
-    .cdn {
-      margin-bottom: 10px;
-    }
-  }
-}
-</style>

+ 2 - 2
src/views/pull/index.vue

@@ -30,7 +30,7 @@
             }"
             @click="
               router.push({
-                name: routerName.profile,
+                name: routerName.my,
                 params: { userId: anchorInfo?.id },
               })
             "
@@ -707,7 +707,7 @@ function handleRestoreSpeakingUser({ socketId, userId }) {
 
 function jumpProfile(userId: number) {
   const url = router.resolve({
-    name: routerName.profile,
+    name: routerName.my,
     params: { userId },
   });
   openToTarget(url.href);

+ 14 - 1
src/views/push/index.vue

@@ -724,6 +724,19 @@ watch(
   }
 );
 
+watch(
+  () => route.query.roomId,
+  (newval) => {
+    if (newval) {
+      handleSendGetLiveUser(Number(newval));
+    }
+  },
+  {
+    deep: true,
+    immediate: true,
+  }
+);
+
 function handleSendDanmu() {
   sendDanmu();
 }
@@ -884,7 +897,6 @@ onMounted(() => {
   initUserMedia();
   initCanvas();
   handleCache();
-  handleSendGetLiveUser(Number(roomId.value));
 });
 
 onUnmounted(() => {
@@ -909,6 +921,7 @@ onUnmounted(() => {
 });
 
 function handleSendGetLiveUser(liveRoomId: number) {
+  clearInterval(loopGetLiveUserTimer.value);
   async function main() {
     const res = await fetchLiveRoomOnlineUser({ live_room_id: liveRoomId });
     if (res.code === 200) {

+ 18 - 10
src/views/rank/index.vue

@@ -24,17 +24,14 @@
           <div
             class="avatar"
             @click="
-              currRankType !== RankTypeEnum.blog &&
-                router.push({
-                  name: routerName.profile,
-                  params: { userId: item.users[0]?.id },
-                })
+              currRankType !== RankTypeEnum.blog && handleJump(item.users[0])
             "
           >
             <Avatar
               :size="100"
               :avatar="item.users[0]?.avatar"
               :living="!!item.live?.live"
+              :border="!item.users[0]?.avatar?.length"
             ></Avatar>
           </div>
           <div class="username">{{ item.users[0]?.username }}</div>
@@ -77,11 +74,7 @@
           <div
             class="left"
             @click="
-              currRankType !== RankTypeEnum.blog &&
-                router.push({
-                  name: routerName.profile,
-                  params: { userId: item.users[0]?.id },
-                })
+              currRankType !== RankTypeEnum.blog && handleJump(item.users[0])
             "
           >
             <img
@@ -133,9 +126,11 @@ import { fetchWalletList } from '@/api/wallet';
 import { fullLoading } from '@/components/FullLoading';
 import { RankTypeEnum } from '@/interface';
 import router, { routerName } from '@/router';
+import { useUserStore } from '@/store/user';
 import { ILiveRoom, LiveRoomIsShowEnum } from '@/types/ILiveRoom';
 import { formatMoney } from '@/utils';
 
+const userStore = useUserStore();
 export interface IRankType {
   type: RankTypeEnum;
   label: string;
@@ -240,6 +235,19 @@ const mockRank: {
 ];
 const rankList = ref(mockRank);
 
+function handleJump(item) {
+  if (userStore.userInfo?.id === item.id) {
+    router.push({
+      name: routerName.my,
+    });
+  } else {
+    router.push({
+      name: routerName.user,
+      params: { id: item.id },
+    });
+  }
+}
+
 function handleJoin(item) {
   router.push({
     name: routerName.pull,

+ 140 - 0
src/views/user/index.vue

@@ -0,0 +1,140 @@
+<template>
+  <div
+    class="profile-wrap"
+    v-loading="getUserLoading"
+  >
+    <div class="uid">用户id:{{ userInfo?.id }}</div>
+    <div class="avatar">
+      <span class="txt">用户头像:</span>
+      <Avatar
+        :avatar="userInfo?.avatar"
+        :size="30"
+        :border="!userInfo?.avatar?.length"
+      ></Avatar>
+    </div>
+    <div class="username">用户昵称:{{ userInfo?.username }}</div>
+    <div
+      class="username"
+      v-if="userStore.userInfo"
+    >
+      用户角色:{{ userInfo?.roles?.map((item) => item.role_name).join(',') }}
+    </div>
+    <br />
+    <div class="pull-url">
+      <span
+        v-if="
+          !userInfo?.live_rooms?.length &&
+          userStore.userInfo?.id === userInfo?.id
+        "
+        class="link"
+        @click="openLiveRoom"
+      >
+        未开通
+      </span>
+      <span v-else-if="!userInfo?.live_rooms?.length">
+        该用户未开通直播间
+      </span>
+      <div v-else>
+        <div>
+          直播间地址:
+          <a
+            :href="getLiveRoomPageUrl(userInfo?.live_rooms?.[0]?.id!)"
+            class="link"
+            target="_blank"
+          >
+            {{ getLiveRoomPageUrl(userInfo?.live_rooms?.[0]?.id!) }}
+          </a>
+        </div>
+        <div>直播间名称:{{ userInfo?.live_rooms?.[0]?.name }}</div>
+        <div>
+          直播间简介:{{ userInfo?.live_rooms?.[0]?.desc || '暂无简介' }}
+        </div>
+        <div>
+          直播间分区:{{
+            userInfo.live_rooms[0]?.areas?.[0]?.name || '暂无分区'
+          }}
+        </div>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script lang="ts" setup>
+import { openToTarget } from 'billd-utils';
+import { ref, watchEffect } from 'vue';
+import { useRoute, useRouter } from 'vue-router';
+
+import { fetchFindUser } from '@/api/user';
+import { loginTip } from '@/hooks/use-login';
+import { routerName } from '@/router';
+import { useUserStore } from '@/store/user';
+import { LiveRoomTypeEnum } from '@/types/ILiveRoom';
+import { IUser } from '@/types/IUser';
+import { getLiveRoomPageUrl } from '@/utils';
+
+const userStore = useUserStore();
+const route = useRoute();
+const router = useRouter();
+
+const userId = ref(-1);
+const userInfo = ref<IUser>();
+const getUserLoading = ref(false);
+
+watchEffect(() => {
+  if (route.params.id) {
+    userId.value = Number(route.params.id as string);
+    handleUserInfo();
+  }
+});
+
+async function handleUserInfo() {
+  try {
+    getUserLoading.value = true;
+    const res = await fetchFindUser(userId.value);
+    if (res.code === 200) {
+      userInfo.value = res.data;
+    }
+  } catch (error) {
+    console.error(error);
+  } finally {
+    getUserLoading.value = false;
+  }
+}
+
+function openLiveRoom() {
+  if (!loginTip()) {
+    return;
+  }
+  const url = router.resolve({
+    name: routerName.push,
+    query: { liveType: LiveRoomTypeEnum.srs },
+  });
+  openToTarget(url.href);
+}
+</script>
+
+<style lang="scss" scoped>
+.profile-wrap {
+  position: relative;
+  padding: 10px;
+  .link {
+    color: $theme-color-gold;
+    text-decoration: none;
+    cursor: pointer;
+  }
+  .avatar {
+    display: flex;
+    align-items: center;
+    .txt {
+      margin-right: 10px;
+    }
+  }
+  .url-wrap {
+    position: relative;
+    margin-top: 10px;
+    .cdn {
+      margin-bottom: 10px;
+    }
+  }
+}
+</style>

+ 12 - 3
src/views/wallet/index.vue

@@ -38,9 +38,10 @@
 </template>
 
 <script lang="ts" setup>
-import { onMounted, onUnmounted, ref } from 'vue';
+import { onMounted, ref } from 'vue';
 import { useI18n } from 'vue-i18n';
 
+import { fetchMyWallet } from '@/api/wallet';
 import { fetchWalletRecordMyList } from '@/api/walletRecord';
 import { fullLoading } from '@/components/FullLoading';
 import {
@@ -84,12 +85,20 @@ const typeMap = {
   [WalletRecordEnum.signin]: '签到',
 };
 
-onUnmounted(() => {});
-
 onMounted(() => {
+  updateMyWallet();
   getPayList();
 });
 
+async function updateMyWallet() {
+  const res = await fetchMyWallet();
+  if (res.code === 200) {
+    if (userStore.userInfo?.wallet?.balance !== undefined) {
+      userStore.userInfo.wallet.balance = res.data.balance;
+    }
+  }
+}
+
 async function getPayList() {
   try {
     fullLoading({ loading: true });