panhui пре 3 година
родитељ
комит
eef1bcc2f2

+ 25 - 0
src/api/index.ts

@@ -134,3 +134,28 @@ export function fetchMembershipRenew<T>(planId: string | number) {
         }
     })
 }
+
+export function fetchUserBalance<T>() {
+    return get<T>({
+        url: '/userBalance/get'
+    })
+}
+
+export function fetchUserBalanceRecords<T>() {
+    return get<Array<T>>({
+        url: '/userBalance/records/get'
+    })
+}
+
+export function fetchWithdraw<T>(data: any) {
+    return post<Array<T>>({
+        url: '/userBalance/withdraw',
+        data: data
+    })
+}
+
+export function fetchCommissionRecords<T>() {
+    return get<Array<T>>({
+        url: '/commission/records/get'
+    })
+}

BIN
src/assets/empty-dark.png


BIN
src/assets/empty.png


BIN
src/assets/icon-jiangli.png


BIN
src/assets/icon-tixian.png


BIN
src/assets/png-shouyi-bg.png


+ 0 - 8
src/components/common/AccountPannel.vue

@@ -1,8 +0,0 @@
-<template>
-    <div>
-
-    </div>
-</template>
-
-<script setup lang="ts">
-</script>

+ 256 - 0
src/components/common/BalancePannel.vue

@@ -0,0 +1,256 @@
+<template>
+    <div class="px-5 py-3">
+        <div class="money rounded-[12px] overflow-hidden">
+            <img src="@/assets/png-shouyi-bg.png" alt="" class="money-bg" />
+            <div class="money-box flex">
+                <div class="money-left flex-1 flex flex-col px-4">
+                    <div class="text1 text-xs">账户余额</div>
+                    <div class="text2 text-4xl mb-5 alimamaShuHeiTi">¥{{ balance }}</div>
+                    <n-button
+                        class="self-start"
+                        @click="showWithdraw = true"
+                        type="primary"
+                        size="small"
+                        icon-placement="right"
+                        quaternary
+                        round
+                    >
+                        去提现
+                        <template #icon>
+                            <n-icon size="18">
+                                <ChevronRight />
+                            </n-icon>
+                        </template>
+                    </n-button>
+                </div>
+                <!-- <div class="money-right px-5 py-2 border rounded-[8px] mr-[19px] flex flex-col items-center">
+                    <div class="text1 flex items-center text-xs">
+                        我的邀请
+                        <n-icon size="18">
+                            <ChevronRight />
+                        </n-icon>
+                    </div>
+                    <div class="text2 text-xl alimamaShuHeiTi">21</div>
+                </div> -->
+
+                <div class="commission flex items-center text-xs" @click="goCommission">
+                    邀请记录<n-icon size="18">
+                        <ChevronRight />
+                    </n-icon>
+                </div>
+            </div>
+        </div>
+
+        <div class="list">
+            <div class="title flex justify-between py-4">
+                <span class="alimamaShuHeiTi text-base">收支明细</span>
+
+                <!-- <n-button size="small">
+                    2023年4月
+                    <n-icon size="18">
+                        <ChevronDown />
+                    </n-icon>
+                </n-button> -->
+            </div>
+
+            <div
+                class="record-info flex items-center py-4 bg-gray-100 px-3 rounded-[8px] dark:bg-[#20223C]"
+                v-for="(item, index) in records"
+                :key="index"
+            >
+                <img class="w-[36px]" :src="item.type === 'COMMISSION' ? commissionImg : withdrawImg" alt="" />
+                <div class="text px-[12px] flex-1">
+                    <div class="text-sm">{{ item.remark }}</div>
+                    <div class="text-xs text-[#797A8A] mt-[2px]">{{ item.createdAt }}</div>
+                </div>
+                <div
+                    class="num text-lg alimamaShuHeiTi"
+                    :class="{ 'text-[#7C3AED] dark:text-[#FFF671]': item.type === 'COMMISSION' }"
+                >
+                    {{ item.type === 'COMMISSION' ? '+' : '-' }} {{ item.amount }}
+                </div>
+            </div>
+
+            <div class="empty py-6" v-if="!recordLoading && records.length === 0">
+                <img class="w-3/5 block mx-[auto]" :src="isDark ? emptyDarkImg : emptyImg" alt="" />
+                <div class="text-sm text-[#939599] text-center py-3">暂无信息</div>
+            </div>
+        </div>
+
+        <n-modal v-model:show="showCommission" class="max-w-md" transform-origin="center">
+            <n-card
+                :border="false"
+                title="我的邀请"
+                class="!rounded-xl commission-card"
+                content-style="padding:0;overflow:auto"
+            >
+                <commission-pannel></commission-pannel>
+            </n-card>
+        </n-modal>
+
+        <n-modal v-model:show="showWithdraw" class="max-w-md !w-[90%]" transform-origin="center">
+            <n-card
+                :border="false"
+                title="余额提现"
+                class="!rounded-xl"
+                content-style="padding:10px 20px;overflow:auto"
+                header-style="padding:10px 20px"
+            >
+                <div>
+                    <div class="text-sm font-bold">提现金额</div>
+                    <div class="text-xs text-[#C8C9CC] mt-[2px]">全部可提现 ¥{{ balance }}</div>
+                </div>
+                <div class="withdraw flex items-center mt-2">
+                    <n-input-number class="flex-1" v-model:value="withdrawValue" :show-button="false">
+                        <template #prefix> ¥ </template>
+                    </n-input-number>
+                    <n-button
+                        class="!ml-[10px]"
+                        secondary
+                        type="primary"
+                        @click="withdrawValue = balance"
+                        round
+                        size="small"
+                        >全部</n-button
+                    >
+                </div>
+
+                <div class="px-6 mt-20">
+                    <n-button
+                        type="primary"
+                        :loading="loading"
+                        block
+                        round
+                        size="large"
+                        :disabled="!canWithdraw"
+                        @click="withdraw"
+                        >确认提现</n-button
+                    >
+                </div>
+            </n-card>
+        </n-modal>
+    </div>
+</template>
+
+<script setup lang="ts">
+import { ref, computed } from 'vue'
+import { NButton, NIcon, NModal, NCard, NInputNumber, useMessage } from 'naive-ui'
+import { ChevronRight, ChevronDown } from '@vicons/tabler'
+import { fetchUserBalance, fetchUserBalanceRecords, fetchWithdraw } from '@/api'
+import withdrawImg from '@/assets/icon-tixian.png'
+import commissionImg from '@/assets/icon-jiangli.png'
+import { useBasicLayout } from '@/hooks/useBasicLayout'
+import { useRouter } from 'vue-router'
+import { CommissionPannel } from '@/components/common'
+import emptyImg from '@/assets/empty.png'
+import emptyDarkImg from '@/assets/empty-dark.png'
+import { useTheme } from '@/hooks/useTheme'
+
+const balance = ref(0)
+getBanlance()
+function getBanlance() {
+    fetchUserBalance().then((res: any) => {
+        balance.value = res.balance
+    })                                              
+}
+
+const recordLoading = ref(true)
+const records = ref([])
+fetchUserBalanceRecords().then((res: any) => {
+    records.value = res
+    recordLoading.value = false
+})
+const { isMobile } = useBasicLayout()
+const showCommission = ref(false)
+const router = useRouter()
+function goCommission() {
+    if (isMobile.value) {
+        router.push('/commission')
+    } else {
+        showCommission.value = true
+    }
+}
+
+const showWithdraw = ref(false)
+const withdrawValue = ref(0)
+const canWithdraw = computed(() => {
+    return Number(withdrawValue.value) > 0
+})
+
+const message = useMessage()
+const loading = ref(false)
+function withdraw() {
+    loading.value = true
+    fetchWithdraw({
+        amount: withdrawValue.value
+    })
+        .then(res => {
+            message.success('提现成功')
+            getBanlance()
+            showWithdraw.value = false
+        })
+        .catch(e => {
+            message.error(e.message)
+        })
+        .finally(() => {
+            loading.value = false
+        })
+}
+
+const { isDark } = useTheme()
+</script>
+
+<style lang="less" scoped>
+.money {
+    position: relative;
+    color: #fff;
+
+    .money-bg {
+        display: block;
+        height: 144px;
+        width: 100%;
+    }
+    .money-box {
+        position: absolute;
+        top: 0;
+        left: 0;
+        right: 0;
+        bottom: 0;
+        .f();
+
+        .money-left {
+            flex-grow: 1;
+        }
+
+        .n-button {
+            background-color: #fff;
+        }
+
+        .money-right {
+            border-color: #ffffff30;
+            background: linear-gradient(180deg, #6d43ff 0%, rgba(109, 67, 255, 0.3) 100%);
+        }
+    }
+}
+
+.list {
+    color: var(--n-text-color);
+}
+.record-info + .record-info {
+    margin-top: 16px;
+}
+
+.commission {
+    padding: 4px 6px 4px 15px;
+    background: #6033ff;
+    box-shadow: -2px 2px 4px 0px #9f83ff;
+    border-radius: 0px 12px 0px 12px;
+    position: absolute;
+    top: 0;
+    right: 0;
+}
+.commission-card {
+    max-height: 80vh;
+    min-height: 50vh;
+}
+</style>

+ 54 - 0
src/components/common/CommissionPannel.vue

@@ -0,0 +1,54 @@
+<template>
+    <div class="px-5 py-3">
+        <div
+            class="info flex items-center py-4 bg-gray-100 px-3 rounded-[8px] dark:bg-[#20223C]"
+            v-for="(item, index) in list"
+            :key="index"
+        >
+            <img class="w-[36px]" src="https://cdn.raex.vip/image/2023-04-14-16-53-17zrXKWdyk.png" alt="" />
+
+            <div class="flex-1 px-[12px]">
+                <div class="text-sm">{{ item.name }}</div>
+                <!-- <div class="text-xs text-[#797A8A] mt-[2px]">加入时间:{{ formatTime(item.createdAt) }}</div> -->
+            </div>
+
+            <div class="text-xs flex flex-col items-end">
+                <div>+{{ item.amount }}</div>
+                <div class="mt-[2px]">总收益</div>
+            </div>
+        </div>
+
+        <div class="empty py-6" v-if="!loading && list.length === 0">
+            <img class="w-3/5 block mx-[auto]" :src="isDark ? emptyDarkImg : emptyImg" alt="" />
+            <div class="text-sm text-[#939599] text-center py-3">暂无信息</div>
+        </div>
+    </div>
+</template>
+
+<script setup lang="ts">
+import { ref } from 'vue'
+import { fetchCommissionRecords } from '@/api'
+import { format } from 'date-fns'
+import emptyImg from '@/assets/empty.png'
+import emptyDarkImg from '@/assets/empty-dark.png'
+import { useTheme } from '@/hooks/useTheme'
+
+const { isDark } = useTheme()
+
+const list = ref([])
+const loading = ref(true)
+fetchCommissionRecords().then((res: any) => {
+    list.value = res
+    loading.value = false
+})
+
+function formatTime(str: any) {
+    return format(new Date(str), 'yyyy-MM-dd HH:mm')
+}
+</script>
+
+<style lang="less" scoped>
+.info + .info {
+    margin-top: 16px;
+}
+</style>

+ 4 - 2
src/components/common/index.ts

@@ -9,7 +9,8 @@ import PromptStore from './PromptStore.vue'
 import LoginForm from './LoginForm.vue'
 import MinePannel from './minePannel.vue'
 import VipPannel from './VipPannel.vue'
-import AccountPannel from './AccountPannel.vue'
+import BalancePannel from './BalancePannel.vue'
+import CommissionPannel from './CommissionPannel.vue'
 import VipModal from './VipModal.vue'
 import RuleContent from './RuleContent.vue'
 
@@ -25,7 +26,8 @@ export {
     LoginForm,
     MinePannel,
     VipPannel,
-    AccountPannel,
+    BalancePannel,
+    CommissionPannel,
     VipModal,
     RuleContent
 }

+ 28 - 5
src/components/common/minePannel.vue

@@ -19,10 +19,10 @@
                     </div>
                 </n-col>
                 <n-col :span="12">
-                    <div class="share-btn">
+                    <div class="share-btn" @click="goBalance">
                         <div class="share-text">
                             <div class="text1">我的收益</div>
-                            <div class="text2">余额:0.00</div>
+                            <div class="text2">余额:{{ balance }}</div>
                         </div>
                         <img src="@/assets/png-shouyi.png" alt="" />
                     </div>
@@ -37,16 +37,24 @@
         </div>
 
         <share v-model:show="showShareModal" />
+
+        <n-modal v-model:show="showBalance" class="max-w-md" transform-origin="center">
+            <n-card :border="false" title="我的收益" class="!rounded-xl balance" content-style="padding:0;overflow:auto">
+                <balance-pannel></balance-pannel>
+            </n-card>
+        </n-modal>
     </div>
 </template>
 
 <script setup lang="ts">
-import { UserAvatar, VipCard, Share } from '@/components/common'
+import { UserAvatar, VipCard, Share, BalancePannel } from '@/components/common'
 import { NCard, NRow, NCol, useMessage, NButton, useDialog, NModal } from 'naive-ui'
 import { useRouter } from 'vue-router'
 import { ref } from 'vue'
 import { useUserStore } from '@/store'
 import { emitter } from '@/plugins'
+import { fetchUserBalance } from '@/api'
+import { useBasicLayout } from '@/hooks/useBasicLayout'
 
 const router = useRouter()
 const message = useMessage()
@@ -74,9 +82,20 @@ function logout() {
     })
 }
 
-function goAccount() {
-    router.push('/account')
+const { isMobile } = useBasicLayout()
+const showBalance = ref(false)
+function goBalance() {
+    if (isMobile.value) {
+        router.push('/balance')
+    } else {
+        showBalance.value = true
+    }
 }
+
+const balance = ref(0)
+fetchUserBalance().then((res: any) => {
+    balance.value = res.balance
+})
 </script>
 
 <style lang="less" scoped>
@@ -153,4 +172,8 @@ function goAccount() {
         }
     }
 }
+
+.balance {
+    max-height: 80vh;
+}
 </style>

+ 8 - 3
src/router/index.ts

@@ -83,9 +83,14 @@ const routes: RouteRecordRaw[] = [
         component: () => import('@/views/page/RuleView.vue')
     },
     {
-        path: '/account',
-        name: 'account',
-        component: () => import('@/views/page/AccountView.vue')
+        path: '/balance',
+        name: 'balance',
+        component: () => import('@/views/page/BalanceView.vue')
+    },
+    {
+        path: '/commission',
+        name: 'commission',
+        component: () => import('@/views/page/CommissionView.vue')
     },
 
     {

+ 0 - 1
src/store/modules/auth/index.ts

@@ -51,7 +51,6 @@ export const useAuthStore = defineStore('auth-store', {
 
         async phoneLogin(phone: string | number, code: string | number, invitor?: string | number) {
             const data = await fetchPhoneLogin<any>(phone, code, invitor)
-            console.log(data)
             this.setToken(data.access_token)
         }
     }

+ 10 - 3
src/views/page/AccountView.vue → src/views/page/BalanceView.vue

@@ -1,13 +1,13 @@
 <template>
     <div class="page">
-        <n-page-header title="我的收益" @back="handleBack"> </n-page-header>
+        <n-page-header class="head bg-white dark:bg-black" title="我的收益" @back="handleBack"> </n-page-header>
 
-        <account-pannel></account-pannel>
+        <balance-pannel></balance-pannel>
     </div>
 </template>
 
 <script setup lang="ts">
-import { AccountPannel } from '@/components/common'
+import { BalancePannel } from '@/components/common'
 import { NCard, NEl, NPageHeader, NRow, NCol, NGrid, NGridItem, NButton, NIcon } from 'naive-ui'
 import { useRouter } from 'vue-router'
 
@@ -29,4 +29,11 @@ function handleBack() {
         }
     }
 }
+
+.head {
+    // background-color: #fff;
+    position: sticky;
+    top: 0;
+    z-index: 20;
+}
 </style>

+ 39 - 0
src/views/page/CommissionView.vue

@@ -0,0 +1,39 @@
+<template>
+    <div class="page">
+        <n-page-header class="head bg-white dark:bg-black" title="邀请人数" @back="handleBack"> </n-page-header>
+
+        <commission-pannel></commission-pannel>
+    </div>
+</template>
+
+<script setup lang="ts">
+import { CommissionPannel } from '@/components/common'
+import { NCard, NEl, NPageHeader, NRow, NCol, NGrid, NGridItem, NButton, NIcon } from 'naive-ui'
+import { useRouter } from 'vue-router'
+
+const router = useRouter()
+function handleBack() {
+    router.back()
+}
+</script>
+
+<style lang="less" scoped>
+:deep(.n-page-header) {
+    height: 50px;
+    padding: 0 22px;
+    .n-page-header__main {
+        flex-grow: 1;
+        .n-page-header__title {
+            flex-grow: 1;
+            text-align: center;
+        }
+    }
+}
+
+.head {
+    // background-color: #fff;
+    position: sticky;
+    top: 0;
+    z-index: 20;
+}
+</style>