Browse Source

feat: 重构优化支付相关

shuisheng 1 year ago
parent
commit
514f945634

+ 13 - 0
src/api/signin.ts

@@ -0,0 +1,13 @@
+import { ISignin } from '@/interface';
+import request from '@/utils/request';
+
+export function fetchCreateSignin(data: ISignin) {
+  return request.post('/signin/create', data);
+}
+export function fetchTodayIsSignin({ liveRoomId }) {
+  return request.get('/signin/today_is_signin', {
+    params: {
+      live_room_id: liveRoomId,
+    },
+  });
+}

+ 8 - 0
src/api/walletRecord.ts

@@ -0,0 +1,8 @@
+import { IPaging, IWalletRecord } from '@/interface';
+import request from '@/utils/request';
+
+export function fetchWalletRecordMyList(params) {
+  return request.get<IPaging<IWalletRecord>>('/wallet_record/my_list', {
+    params,
+  });
+}

BIN
src/assets/img/data.png


BIN
src/assets/img/rank.png


+ 0 - 0
src/assets/img/pay.png → src/assets/img/wallet.png


+ 11 - 3
src/components/QrPay/index.vue

@@ -1,7 +1,10 @@
 <template>
   <div class="qr-pay-wrap">
-    <div class="money">金额:{{ props.money.toFixed(2) }}元</div>
-    <div class="qrcode-wrap">
+    <div class="money">金额:{{ formatMoney(props.money * 100) }}元</div>
+    <div
+      class="qrcode-wrap"
+      v-loading="loading"
+    >
       <img
         v-if="aliPayBase64 !== ''"
         class="qrcode"
@@ -67,7 +70,7 @@ import { onMounted, onUnmounted, ref } from 'vue';
 import { fetchAliPay, fetchAliPayStatus } from '@/api/order';
 import { PayStatusEnum } from '@/interface';
 import { useUserStore } from '@/store/user';
-import { formatDownTime } from '@/utils';
+import { formatDownTime, formatMoney } from '@/utils';
 
 const userStore = useUserStore();
 const aliPayBase64 = ref('');
@@ -75,6 +78,7 @@ const payStatusTimer = ref();
 const downTimer = ref();
 const downTimeStart = ref();
 const downTimeEnd = ref();
+const loading = ref(false);
 const isExpired = ref(false);
 
 const currentPayStatus = ref(PayStatusEnum.wait);
@@ -128,6 +132,8 @@ function handleDownTime() {
 }
 
 async function handleStartPay() {
+  loading.value = true;
+  aliPayBase64.value = '';
   isExpired.value = false;
   currentPayStatus.value = PayStatusEnum.wait;
   clearInterval(payStatusTimer.value);
@@ -150,6 +156,8 @@ async function handleStartPay() {
     }
   } catch (error) {
     console.log(error);
+  } finally {
+    loading.value = false;
   }
 }
 

+ 5 - 3
src/hooks/use-pull.ts

@@ -24,7 +24,8 @@ export function usePull(roomId: string) {
   const appStore = useAppStore();
   const localStream = ref<MediaStream>();
   const danmuStr = ref('');
-  const msgIsFile = ref<WsMessageMsgIsFileEnum>(WsMessageMsgIsFileEnum.no);
+  const msgIsFile = ref(WsMessageMsgIsFileEnum.no);
+  const danmuMsgType = ref<DanmuMsgTypeEnum>(DanmuMsgTypeEnum.danmu);
   const autoplayVal = ref(false);
   const videoLoading = ref(false);
   const isPlaying = ref(false);
@@ -439,7 +440,7 @@ export function usePull(roomId: string) {
     const messageData: WsMessageType['data'] = {
       socket_id: '',
       msg: danmuStr.value,
-      msgType: DanmuMsgTypeEnum.danmu,
+      msgType: danmuMsgType.value,
       live_room_id: Number(roomId),
       msgIsFile: msgIsFile.value,
       send_msg_time: +new Date(),
@@ -450,7 +451,7 @@ export function usePull(roomId: string) {
       msgType: WsMsgTypeEnum.message,
       data: messageData,
     });
-    // damuList.value.push(danmu);
+
     danmuStr.value = '';
   }
 
@@ -464,6 +465,7 @@ export function usePull(roomId: string) {
     keydownDanmu,
     sendDanmu,
     addVideo,
+    danmuMsgType,
     isPlaying,
     msgIsFile,
     mySocketId,

+ 1 - 1
src/hooks/use-websocket.ts

@@ -668,7 +668,7 @@ export const useWebsocket = () => {
         live_room_id: data.data.live_room_id,
         request_id: data.request_id,
         socket_id: data.socket_id,
-        msgType: DanmuMsgTypeEnum.danmu,
+        msgType: data.data.msgType,
         msg: data.data.msg,
         userInfo: data.user_info,
         msgIsFile: data.data.msgIsFile,

+ 43 - 0
src/interface.ts

@@ -136,6 +136,22 @@ export interface IGiftRecord {
   deleted_at?: string;
 }
 
+export interface ISignin {
+  id?: number;
+  user_id?: number;
+  live_room_id?: number;
+  nums?: number;
+
+  /** 用户信息 */
+  user?: IUser;
+  /** 直播间信息 */
+  live_room?: ILiveRoom;
+
+  created_at?: string;
+  updated_at?: string;
+  deleted_at?: string;
+}
+
 export enum LiveLineEnum {
   rtc = 'rtc',
   hls = 'hls',
@@ -246,6 +262,32 @@ export interface ILiveConfig {
   deleted_at?: string;
 }
 
+export enum WalletRecordEnum {
+  reward,
+  recharge,
+  signin,
+}
+
+export enum WalletRecordAmountStatusEnum {
+  add,
+  del,
+}
+
+export interface IWalletRecord {
+  id?: number;
+  user_id?: number;
+  order_id?: number;
+  type?: WalletRecordEnum;
+  name?: string;
+  amount?: number;
+  amount_status?: WalletRecordAmountStatusEnum;
+  remark?: string;
+
+  created_at?: string;
+  updated_at?: string;
+  deleted_at?: string;
+}
+
 export interface IOrder {
   id?: number;
   /** 用户信息 */
@@ -459,6 +501,7 @@ export enum DanmuMsgTypeEnum {
   userLeaved,
   system,
   redbag,
+  reward,
 }
 
 export interface IUpdateJoinInfo {

+ 74 - 32
src/layout/pc/head/index.vue

@@ -3,7 +3,6 @@
     <div class="head">
       <div class="left">
         <div
-          v-if="MODULE_CONFIG_SWITCH.logo"
           class="logo-wrap"
           @click="router.push('/')"
         >
@@ -13,7 +12,6 @@
         <div class="nav">
           <a
             class="item"
-            v-if="MODULE_CONFIG_SWITCH.home"
             :class="{
               active: router.currentRoute.value.path === '/',
             }"
@@ -23,7 +21,6 @@
             首页
           </a>
           <a
-            v-if="MODULE_CONFIG_SWITCH.area"
             class="item"
             :class="{
               active: router.currentRoute.value.name === routerName.area,
@@ -33,7 +30,6 @@
             分区
           </a>
           <a
-            v-if="MODULE_CONFIG_SWITCH.shop"
             class="item"
             :class="{
               active: router.currentRoute.value.name === routerName.shop,
@@ -46,7 +42,6 @@
             class="item"
             :href="COMMON_URL.admin"
             @click.prevent="openToTarget(COMMON_URL.admin)"
-            v-if="MODULE_CONFIG_SWITCH.admin"
           >
             直播后台
           </a>
@@ -54,7 +49,6 @@
             class="item"
             :href="COMMON_URL.mobileApk"
             @click.prevent="openToTarget(COMMON_URL.mobileApk)"
-            v-if="MODULE_CONFIG_SWITCH.appdownload"
           >
             App下载
             <div class="badge">
@@ -74,10 +68,7 @@
         </div>
       </div>
       <div class="right">
-        <Dropdown
-          class="doc"
-          v-if="MODULE_CONFIG_SWITCH.appdownload"
-        >
+        <Dropdown class="doc">
           <template #btn>
             <div class="btn">
               文档<VPIconChevronDown class="icon"></VPIconChevronDown>
@@ -121,10 +112,7 @@
           </template>
         </Dropdown>
 
-        <Dropdown
-          class="ecosystem"
-          v-if="MODULE_CONFIG_SWITCH.ecosystem"
-        >
+        <Dropdown class="ecosystem">
           <template #btn>
             <div class="btn">
               生态系统<VPIconChevronDown class="icon"></VPIconChevronDown>
@@ -165,10 +153,7 @@
           </template>
         </Dropdown>
 
-        <Dropdown
-          class="about"
-          v-if="MODULE_CONFIG_SWITCH.about"
-        >
+        <Dropdown class="about">
           <template #btn>
             <div class="btn">
               关于<VPIconChevronDown class="icon"></VPIconChevronDown>
@@ -198,7 +183,6 @@
         </Dropdown>
 
         <a
-          v-if="MODULE_CONFIG_SWITCH.sponsors"
           class="sponsors"
           :class="{
             active: router.currentRoute.value.name === routerName.sponsors,
@@ -209,7 +193,21 @@
           赞助
         </a>
         <a
-          v-if="MODULE_CONFIG_SWITCH.privatizationDeployment"
+          class="signin"
+          :class="{
+            active:
+              router.currentRoute.value.name ===
+              routerName.privatizationDeployment,
+          }"
+          @click="handleSignin"
+        >
+          签到
+          <div
+            class="red-dot"
+            v-if="appStore.showSigninRedDot"
+          ></div>
+        </a>
+        <a
           class="privatizationDeployment"
           :class="{
             active:
@@ -228,7 +226,6 @@
         </a>
 
         <a
-          v-if="MODULE_CONFIG_SWITCH.github"
           class="github"
           target="_blank"
           href="https://github.com/galaxy-s10/billd-live"
@@ -239,31 +236,25 @@
           />
         </a>
 
-        <Dropdown
-          class="start-live"
-          v-if="MODULE_CONFIG_SWITCH.startLive"
-        >
+        <Dropdown class="start-live">
           <template #btn>
             <div class="btn">我要开播</div>
           </template>
           <template #list>
             <div class="list">
               <a
-                v-if="MODULE_CONFIG_SWITCH.startLiveSRS"
                 class="item"
                 @click.prevent="handleStartLive(LiveRoomTypeEnum.user_srs)"
               >
                 <div class="txt">srs开播</div>
               </a>
               <a
-                v-if="MODULE_CONFIG_SWITCH.startLiveWebRTC"
                 class="item"
                 @click.prevent="handleStartLive(LiveRoomTypeEnum.user_wertc)"
               >
                 <div class="txt">webrtc开播</div>
               </a>
               <a
-                v-if="MODULE_CONFIG_SWITCH.startLiveWebMSR"
                 class="item"
                 @click.prevent="handleStartLive(LiveRoomTypeEnum.user_msr)"
               >
@@ -320,13 +311,14 @@
 
 <script lang="ts" setup>
 import { openToTarget, windowReload } from 'billd-utils';
-import { onMounted, ref } from 'vue';
+import { onMounted, ref, watch } from 'vue';
 import { useRouter } from 'vue-router';
 
+import { fetchCreateSignin, fetchTodayIsSignin } from '@/api/signin';
 import Dropdown from '@/components/Dropdown/index.vue';
 import VPIconChevronDown from '@/components/icons/VPIconChevronDown.vue';
 import VPIconExternalLink from '@/components/icons/VPIconExternalLink.vue';
-import { COMMON_URL, MODULE_CONFIG_SWITCH } from '@/constant';
+import { COMMON_URL } from '@/constant';
 import { loginTip } from '@/hooks/use-login';
 import { routerName } from '@/router';
 import { useAppStore } from '@/store/app';
@@ -342,18 +334,22 @@ const about = ref([
   {
     label: '常见问题',
     routerName: routerName.faq,
+    url: '',
   },
   {
     label: '团队',
     routerName: routerName.team,
+    url: '',
   },
   {
     label: '官方群',
     routerName: routerName.group,
+    url: '',
   },
   {
     label: '版本发布',
     routerName: routerName.release,
+    url: '',
   },
 ]);
 const resource = ref([
@@ -405,6 +401,40 @@ const plugins = ref([
   },
 ]);
 
+watch(
+  () => userStore.userInfo?.id,
+  (newval) => {
+    if (newval) {
+      initSigninStatus();
+    }
+  },
+  {
+    immediate: true,
+  }
+);
+
+async function handleSignin() {
+  const res = await fetchCreateSignin({});
+  if (res.code === 200) {
+    appStore.showSigninRedDot = false;
+    // eslint-disable-next-line
+    window.$message.success(`签到成功!已连续签到${res.data.nums}天`);
+  }
+}
+
+async function initSigninStatus() {
+  const res = await fetchTodayIsSignin({
+    liveRoomId: appStore.liveRoomInfo?.id,
+  });
+  if (res.code === 200) {
+    if (res.data) {
+      appStore.showSigninRedDot = false;
+    } else {
+      appStore.showSigninRedDot = true;
+    }
+  }
+}
+
 function handleLogout() {
   userStore.logout();
   setTimeout(() => {
@@ -476,6 +506,15 @@ function handleStartLive(key: LiveRoomTypeEnum) {
         @include minFont(10);
       }
     }
+    .red-dot {
+      position: absolute;
+      top: -5px;
+      right: -5px;
+      width: 6px;
+      height: 6px;
+      border-radius: 50%;
+      background-color: red;
+    }
     .hr {
       width: 100%;
       height: 1px;
@@ -599,12 +638,14 @@ function handleStartLive(key: LiveRoomTypeEnum) {
 
       .github,
       .sponsors,
-      .privatizationDeployment {
+      .privatizationDeployment,
+      .signin {
         display: flex;
         align-items: center;
         margin-right: 20px;
         color: black;
         text-decoration: none;
+        cursor: pointer;
         &:hover {
           color: $theme-color-gold;
         }
@@ -612,7 +653,8 @@ function handleStartLive(key: LiveRoomTypeEnum) {
           margin-right: 5px;
         }
       }
-      .privatizationDeployment {
+      .privatizationDeployment,
+      .signin {
         position: relative;
       }
 

+ 16 - 9
src/layout/pc/sidebar/index.vue

@@ -1,7 +1,6 @@
 <template>
   <aside class="sidebar-wrap">
     <div
-      v-if="MODULE_CONFIG_SWITCH.sidebarRank"
       class="item"
       @click="router.push({ name: routerName.rank })"
     >
@@ -9,7 +8,6 @@
       <div class="txt">排行榜</div>
     </div>
     <div
-      v-if="MODULE_CONFIG_SWITCH.sidebarShop"
       class="item"
       @click="router.push({ name: routerName.shop })"
     >
@@ -17,18 +15,23 @@
       <div class="txt">商店</div>
     </div>
     <div
-      v-if="MODULE_CONFIG_SWITCH.sidebarOrder"
       class="item"
       @click="router.push({ name: routerName.order })"
     >
-      <div class="ico pay"></div>
-      <div class="txt">订单</div>
+      <div class="ico data"></div>
+      <div class="txt">全站充值</div>
+    </div>
+    <div
+      class="item"
+      @click="router.push({ name: routerName.wallet })"
+    >
+      <div class="ico wallet"></div>
+      <div class="txt">我的收支</div>
     </div>
   </aside>
 </template>
 
 <script lang="ts" setup>
-import { MODULE_CONFIG_SWITCH } from '@/constant';
 import router, { routerName } from '@/router';
 </script>
 
@@ -39,7 +42,7 @@ import router, { routerName } from '@/router';
   right: 0;
   z-index: 10;
   padding: 15px 10px;
-  width: 50px;
+  width: 60px;
   border-radius: 20px 0 0 20px;
   background-color: white;
   box-shadow: 0 0 20px 1px rgba($theme-color-gold, 0.15);
@@ -58,14 +61,18 @@ import router, { routerName } from '@/router';
       opacity: 0.9;
 
       @extend %containBg;
+
       &.rank {
         @include setBackground('@/assets/img/rank.png');
       }
       &.shop {
         @include setBackground('@/assets/img/shop.png');
       }
-      &.pay {
-        @include setBackground('@/assets/img/pay.png');
+      &.wallet {
+        @include setBackground('@/assets/img/wallet.png');
+      }
+      &.data {
+        @include setBackground('@/assets/img/data.png');
       }
     }
     .txt {

+ 6 - 0
src/router/index.ts

@@ -30,6 +30,7 @@ export const routerName = {
   privatizationDeployment: 'privatizationDeployment',
   support: 'support',
   order: 'order',
+  wallet: 'wallet',
   shop: 'shop',
   link: 'link',
   ad: 'ad',
@@ -141,6 +142,11 @@ export const defaultRoutes: RouteRecordRaw[] = [
         path: '/order',
         component: () => import('@/views/order/index.vue'),
       },
+      {
+        name: routerName.wallet,
+        path: '/wallet',
+        component: () => import('@/views/wallet/index.vue'),
+      },
       {
         name: routerName.ad,
         path: '/ad',

+ 2 - 0
src/store/app/index.ts

@@ -42,6 +42,7 @@ export type AppRootState = {
   showLoginModal: boolean;
   disableSpeaking: Map<number, { exp: number; label: string }>;
   pkStream?: MediaStream;
+  showSigninRedDot: boolean;
 };
 
 export const useAppStore = defineStore('app', {
@@ -60,6 +61,7 @@ export const useAppStore = defineStore('app', {
       liveRoomInfo: undefined,
       showLoginModal: false,
       disableSpeaking: new Map(),
+      showSigninRedDot: false,
     };
   },
   actions: {

+ 1 - 0
src/views/order/index.vue

@@ -41,6 +41,7 @@
         </div>
         <div class="time">{{ item.send_pay_date || '-' }}</div>
       </div>
+      <div v-if="!payList.length">暂无数据</div>
     </div>
   </div>
 </template>

+ 76 - 21
src/views/pull/index.vue

@@ -38,7 +38,13 @@
             "
           ></div>
           <div class="detail">
-            <div class="top">{{ anchorInfo?.username }}</div>
+            <div class="top">
+              <div class="name">{{ anchorInfo?.username }}</div>
+              <div class="follow">
+                <div class="f-left">+关注</div>
+                <div class="f-right">666</div>
+              </div>
+            </div>
             <div class="bottom">
               <span>{{ appStore.liveRoomInfo?.desc }}</span>
               <span v-if="NODE_ENV === 'development'">
@@ -62,14 +68,18 @@
           class="other"
           @click="handlePk"
         >
-          <div class="top">在线人数:{{ liveUserList.length }}</div>
+          <div class="top">
+            <div class="item">666人看过</div>
+            <div class="item">666点赞</div>
+            <div class="item">当前在线:{{ liveUserList.length }}人</div>
+          </div>
           <div class="bottom">
             <n-popover
               placement="bottom"
               trigger="hover"
             >
               <template #trigger>
-                <div class="tag">收到礼物</div>
+                <div class="tag">礼物成就</div>
               </template>
               <div class="popover-list">
                 <template v-if="giftGroupList.length">
@@ -85,9 +95,10 @@
                     <div class="nums">x{{ item.nums }}</div>
                   </div>
                 </template>
-                <span v-else>暂未收到礼物</span>
+                <span v-else>暂</span>
               </div>
             </n-popover>
+            <div class="tag">人气榜</div>
           </div>
         </div>
       </div>
@@ -135,7 +146,7 @@
           v-for="(item, index) in giftGoodsList"
           :key="index"
           class="item"
-          @click="handlePay({ goodsId: item.id })"
+          @click="handlePay(item)"
         >
           <div
             class="ico"
@@ -212,6 +223,14 @@
           :key="index"
           class="item"
         >
+          <template v-if="item.msgType === DanmuMsgTypeEnum.reward">
+            <div class="reward">
+              <span>[{{ formatTimeHour(item.send_msg_time) }}]</span>
+              <span>
+                {{ item.userInfo?.username }} 打赏了{{ item.msg }}!
+              </span>
+            </div>
+          </template>
           <template v-if="item.msgType === DanmuMsgTypeEnum.danmu">
             <span class="time">[{{ formatTimeHour(item.send_msg_time) }}]</span>
             <span class="name">
@@ -445,6 +464,7 @@ const {
   keydownDanmu,
   sendDanmu,
   handlePlay,
+  danmuMsgType,
   msgIsFile,
   mySocketId,
   videoHeight,
@@ -723,6 +743,7 @@ async function uploadChange() {
         file: fileList[0],
       });
       if (res?.resultUrl) {
+        danmuMsgType.value = DanmuMsgTypeEnum.danmu;
         danmuStr.value = res.resultUrl || '错误图片';
         sendDanmu();
       }
@@ -738,14 +759,17 @@ async function uploadChange() {
   }
 }
 
-async function handlePay({ goodsId }) {
+async function handlePay(item: IGoods) {
   const res = await fetchGiftRecordCreate({
-    goodsId,
+    goodsId: item.id!,
     goodsNums: 1,
     liveRoomId: Number(roomId.value),
   });
   if (res.code === 200) {
     window.$message.success('打赏成功!');
+    danmuMsgType.value = DanmuMsgTypeEnum.reward;
+    danmuStr.value = item.name || '';
+    sendDanmu();
   }
   userStore.updateMyWallet();
   getGiftGroupList();
@@ -776,10 +800,6 @@ async function getGoodsList() {
 }
 
 function handleRecharge() {
-  if (!MODULE_CONFIG_SWITCH.pay) {
-    window.$message.info('敬请期待!');
-    return;
-  }
   if (!loginTip()) return;
   showRecharge.value = true;
 }
@@ -868,7 +888,7 @@ function handleScrollTop() {
     overflow: hidden;
     box-sizing: border-box;
     width: $w-1000;
-    height: 100%;
+    height: 740px;
     border-radius: 6px;
     background-color: $theme-color-papayawhip;
     color: #61666d;
@@ -878,7 +898,7 @@ function handleScrollTop() {
       justify-content: space-between;
       box-sizing: border-box;
       padding: 10px 20px;
-      height: 70px;
+      height: 80px;
       color: #18191c;
 
       .info {
@@ -897,7 +917,32 @@ function handleScrollTop() {
         }
         .detail {
           .top {
+            display: flex;
             margin-bottom: 10px;
+            .follow {
+              display: flex;
+              align-items: center;
+              margin-left: 10px;
+              height: 20px;
+              border-radius: 12px;
+              background-color: $theme-color-gold;
+              font-size: 12px;
+              .f-left {
+                display: flex;
+                align-items: center;
+                padding: 0 10px;
+                color: white;
+                cursor: pointer;
+              }
+              .f-right {
+                display: flex;
+                align-items: center;
+                padding: 0 10px;
+                height: 100%;
+                border-radius: 0 12px 12px 0;
+                background-color: #e3e5e7;
+              }
+            }
           }
           .bottom {
             font-size: 14px;
@@ -915,12 +960,17 @@ function handleScrollTop() {
         justify-content: center;
         font-size: 14px;
         .top {
+          display: flex;
           margin-bottom: 10px;
+          .item {
+            margin-right: 10px;
+          }
         }
         .bottom {
           font-size: 12px;
           .tag {
             display: inline-block;
+            margin-right: 10px;
             padding: 4px 10px;
             border-radius: 10px;
             background-color: $theme-color-gold;
@@ -1035,8 +1085,7 @@ function handleScrollTop() {
       align-items: center;
       justify-content: space-around;
       box-sizing: border-box;
-      margin: 5px 0;
-      height: 100px;
+      padding: 5px 0;
       > :last-child {
         position: absolute;
       }
@@ -1044,10 +1093,9 @@ function handleScrollTop() {
         display: flex;
         align-items: center;
         flex-direction: column;
-        justify-content: center;
         box-sizing: border-box;
-        width: 100px;
-        height: 100px;
+        width: 90px;
+        height: 88px;
         text-align: center;
         cursor: pointer;
         &:hover {
@@ -1056,8 +1104,9 @@ function handleScrollTop() {
 
         .ico {
           position: relative;
-          width: 45px;
-          height: 45px;
+          width: 40px;
+          height: 40px;
+          margin-top: 12px;
           background-position: center center;
           background-size: cover;
           background-repeat: no-repeat;
@@ -1099,6 +1148,7 @@ function handleScrollTop() {
     display: inline-block;
     box-sizing: border-box;
     width: $w-250;
+    height: 740px;
     border-radius: 6px;
     background-color: $theme-color-papayawhip;
     color: #9499a0;
@@ -1106,7 +1156,7 @@ function handleScrollTop() {
       display: flex;
       align-items: center;
       justify-content: space-evenly;
-      padding: 5px 0;
+      height: 27px;
       font-size: 12px;
     }
     .user-list {
@@ -1156,6 +1206,10 @@ function handleScrollTop() {
         white-space: normal;
         word-wrap: break-word;
         font-size: 13px;
+        .reward {
+          color: $theme-color-gold;
+          font-weight: bold;
+        }
 
         .name,
         .time {
@@ -1279,6 +1333,7 @@ function handleScrollTop() {
         margin-left: auto;
         padding: 4px;
         width: 70px;
+        height: 24px;
         border-radius: 4px;
         background-color: $theme-color-gold;
         color: white;

+ 4 - 1
src/views/pull/recharge/index.vue

@@ -33,7 +33,7 @@
 
       <QrPayCpt
         v-if="showQrPay"
-        :money="money"
+        :money="goodsInfo.money"
         :goods-id="goodsInfo.goodsId"
         :live-room-id="goodsInfo.liveRoomId"
       ></QrPayCpt>
@@ -55,6 +55,7 @@ const money = ref(1);
 
 const showQrPay = ref(false);
 const goodsInfo = reactive({
+  money: 0,
   goodsId: -1,
   liveRoomId: -1,
 });
@@ -90,7 +91,9 @@ async function startPay() {
   const res = await fetchFindByTypeGoods(GoodsTypeEnum.recharge);
   if (res.code === 200) {
     showQrPay.value = false;
+    console.log(money.value, '-----');
     nextTick(() => {
+      goodsInfo.money = money.value;
       goodsInfo.goodsId = res.data.id!;
       showQrPay.value = true;
     });

+ 4 - 3
src/views/rank/index.vue

@@ -49,7 +49,7 @@
             </div>
           </div>
           <div v-if="item.balance && currRankType === RankTypeEnum.wallet">
-            钱包:{{ item.balance }}
+            钱包:{{ formatMoney(item.balance) }}
           </div>
         </div>
       </div>
@@ -80,7 +80,7 @@
             <div class="username">{{ item.users[0]?.username }}</div>
             <div class="wallet">
               <div v-if="currRankType === RankTypeEnum.wallet">
-                (钱包:{{ item.balance }})
+                (钱包:{{ formatMoney(item.balance) }}
               </div>
             </div>
             <div
@@ -109,6 +109,7 @@ import { RankTypeEnum } from '@/interface';
 import router, { routerName } from '@/router';
 import { ILiveRoom, LiveRoomIsShowEnum } from '@/types/ILiveRoom';
 import { IUser } from '@/types/IUser';
+import { formatMoney } from '@/utils';
 
 export interface IRankType {
   type: RankTypeEnum;
@@ -143,7 +144,7 @@ const mockRank: {
   rank: number;
   level: number;
   score: number;
-  balance: string;
+  balance: number;
   live?: ILiveRoom;
 }[] = [
   {

+ 5 - 9
src/views/shop/index.vue

@@ -38,12 +38,12 @@
           <div class="info">100%好评</div>
           <div class="desc">{{ item.desc }}</div>
           <div class="price-wrap">
-            <span class="price">¥{{ item.price }}</span>
+            <span class="price">¥{{ formatMoney(item.price) }}</span>
             <del
               v-if="item.price !== item.original_price"
               class="original-price"
             >
-              {{ item.original_price }}
+              {{ formatMoney(item.original_price) }}
             </del>
           </div>
         </div>
@@ -64,16 +64,16 @@ import { useRoute } from 'vue-router';
 
 import { fetchGoodsList } from '@/api/goods';
 import QrPayCpt from '@/components/QrPay/index.vue';
-import { MODULE_CONFIG_SWITCH } from '@/constant';
 import { GoodsTypeEnum, IGoods } from '@/interface';
 import router from '@/router';
+import { formatMoney } from '@/utils';
 
 const route = useRoute();
 const list = ref<IGoods[]>([]);
 const loading = ref(false);
 const showQrPay = ref(false);
 const goodsInfo = reactive({
-  money: '0.00',
+  money: 0,
   goodsId: -1,
   liveRoomId: -1,
 });
@@ -121,11 +121,7 @@ function changeTab(type: GoodsTypeEnum) {
 }
 
 function startPay(item: IGoods) {
-  if (!MODULE_CONFIG_SWITCH.pay) {
-    window.$message.info('敬请期待!');
-    return;
-  }
-  if (Number(item.price) === 0) {
+  if (item.price! <= 0) {
     window.$message.info('该商品是免费的,不需要购买!');
     return;
   }

+ 144 - 0
src/views/wallet/index.vue

@@ -0,0 +1,144 @@
+<template>
+  <div class="order-wrap">
+    <h2 class="title">
+      我的钱包:<span class="val">{{
+        formatMoney(userStore.userInfo?.wallet?.balance)
+      }}</span>
+      元
+    </h2>
+    <div class="list">
+      <div class="head-wrap">
+        <div
+          v-for="(item, index) in headList"
+          :key="index"
+          class="head"
+        >
+          <div>{{ item.label }}</div>
+        </div>
+      </div>
+      <div
+        v-for="(item, index) in walletRecordList"
+        :key="index"
+        class="item"
+      >
+        <div>{{ item.created_at }}</div>
+        <div>{{ item.order_id || '无' }}</div>
+        <div>{{ typeMap[item.type!] }}</div>
+        <div>{{ item.name }}</div>
+        <div>
+          <span>{{
+            item.amount_status === WalletRecordAmountStatusEnum.add ? '+' : '-'
+          }}</span>
+          <span>{{ formatMoney(item.amount) }}元</span>
+        </div>
+      </div>
+      <div v-if="!walletRecordList.length">暂无数据</div>
+    </div>
+  </div>
+</template>
+
+<script lang="ts" setup>
+import { onMounted, onUnmounted, ref } from 'vue';
+
+import { fetchWalletRecordMyList } from '@/api/walletRecord';
+import { fullLoading } from '@/components/FullLoading';
+import {
+  IWalletRecord,
+  WalletRecordAmountStatusEnum,
+  WalletRecordEnum,
+} from '@/interface';
+import { useUserStore } from '@/store/user';
+import { formatMoney } from '@/utils';
+
+const userStore = useUserStore();
+const walletRecordList = ref<IWalletRecord[]>([]);
+
+const headList = ref([
+  {
+    label: '创建时间',
+    key: 'created_at',
+  },
+  {
+    label: '订单id',
+    key: 'order_id',
+  },
+  {
+    label: '类型',
+    key: 'type',
+  },
+  {
+    label: '名称',
+    key: 'name',
+  },
+  {
+    label: '金额',
+    key: 'amount',
+  },
+]);
+
+const typeMap = {
+  [WalletRecordEnum.recharge]: '充值',
+  [WalletRecordEnum.reward]: '打赏',
+  [WalletRecordEnum.signin]: '签到',
+};
+
+onUnmounted(() => {});
+
+onMounted(() => {
+  getPayList();
+});
+
+async function getPayList() {
+  try {
+    fullLoading({ loading: true });
+    const res = await fetchWalletRecordMyList({});
+    if (res.code === 200) {
+      walletRecordList.value = res.data.rows;
+    }
+  } catch (error) {
+    console.log(error);
+  } finally {
+    fullLoading({ loading: false });
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+.order-wrap {
+  padding: 0px 30px 0;
+  .title {
+    text-align: center;
+    .val {
+      color: $theme-color-gold;
+    }
+  }
+  .list {
+    text-align: center;
+
+    .head-wrap {
+      display: flex;
+      align-items: center;
+      .head {
+        flex: 1;
+        box-sizing: border-box;
+        margin-bottom: 5px;
+      }
+    }
+    .item {
+      display: flex;
+      align-items: center;
+      height: 40px;
+      color: #666;
+      > div {
+        display: flex;
+        align-items: center;
+        flex: 1;
+        justify-content: center;
+      }
+      &:nth-child(2n) {
+        background-color: #fafbfc;
+      }
+    }
+  }
+}
+</style>