xiongzhu 3 سال پیش
والد
کامیت
76a641ff11

BIN
src/assets/bg_distribution.png


+ 17 - 0
src/assets/icon_balance.svg

@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg width="32px" height="32px" viewBox="0 0 32 32" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
+    <title>icon-tixianchenggong</title>
+    <g id="页面-1" stroke="none" stroke-width="1" fill-rule="evenodd">
+        <g id="交易明细" transform="translate(-16.000000, -290.000000)" fill-rule="nonzero">
+            <g id="编组备份-7" transform="translate(0.000000, 274.000000)">
+                <g id="编组-6" transform="translate(16.000000, 10.000000)">
+                    <g id="编组-18" transform="translate(0.000000, 6.000000)">
+                        <path d="M2,7 L2,25 C2,25.5522847 2.44771525,26 3,26 L29,26 C29.5522847,26 30,25.5522847 30,25 L30,7 C30,6.44771525 29.5522847,6 29,6 L3,6 C2.44771525,6 2,6.44771525 2,7 Z" id="路径"></path>
+                        <polygon id="路径" fill="#FFFFFF" points="2 10 30 10 30 14 2 14"></polygon>
+                        <polygon id="路径" fill="#FFFFFF" points="5 18 13 18 13 20 5 20"></polygon>
+                    </g>
+                </g>
+            </g>
+        </g>
+    </g>
+</svg>

BIN
src/assets/icon_balance_type_01.png


BIN
src/assets/icon_balance_type_02.png


BIN
src/assets/icon_balance_type_03.png


+ 15 - 0
src/assets/icon_close.svg

@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg width="24px" height="24px" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
+    <title>icon_close</title>
+    <g id="页面-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
+        <g id="提现" transform="translate(-335.000000, -348.000000)">
+            <g id="编组-22备份" transform="translate(0.000000, 332.000000)">
+                <g id="icon/close" transform="translate(335.000000, 16.000000)">
+                    <circle id="椭圆形" fill="#F5F7FA" cx="12" cy="12" r="12"></circle>
+                    <line x1="9" y1="9" x2="15" y2="15" id="直线" stroke="#939599" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"></line>
+                    <line x1="15" y1="9" x2="9" y2="15" id="直线" stroke="#939599" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"></line>
+                </g>
+            </g>
+        </g>
+    </g>
+</svg>

+ 7 - 8
src/components/Record.vue

@@ -38,28 +38,27 @@
     </div>
 </template>
 <script>
-import { mapState } from 'pinia';
-import { useUserStore } from '@/stores/user';
-import { withdrawStatus } from '../status';
+import { mapState } from 'pinia'
+import { useUserStore } from '@/stores/user'
+import { withdrawStatus } from '../status'
 export default {
-    name: 'record',
     props: {
         info: {
             type: Object,
             default: () => {
-                return {};
+                return {}
             }
         }
     },
     data() {
         return {
             withdrawStatus
-        };
+        }
     },
     computed: {
-        ...mapState(userUserStore, ['user'])
+        ...mapState(useUserStore, ['user'])
     }
-};
+}
 </script>
 <style lang="less" scoped>
 .record {

+ 7 - 7
src/components/RecordOrder.vue

@@ -26,16 +26,16 @@
     </div>
 </template>
 <script>
-import { mapState } from 'pinia';
-import { useUserStore } from '@/stores/user';
-import { commissionStatus } from '../status';
+import { mapState } from 'pinia'
+import { useUserStore } from '@/stores/user'
+import { commissionStatus } from '../status'
 export default {
     name: 'orderInfo',
     props: {
         info: {
             type: Object,
             default: () => {
-                return {};
+                return {}
             }
         },
         status: {
@@ -46,12 +46,12 @@ export default {
     data() {
         return {
             commissionStatus
-        };
+        }
     },
     computed: {
-        ...mapState(userUserStore, ['user'])
+        ...mapState(useUserStore, ['user'])
     }
-};
+}
 </script>
 <style lang="less" scoped>
 .orderInfo {

+ 26 - 2
src/locales/zh.json

@@ -1,7 +1,13 @@
 {
     "cancel": "取消",
     "login": "登录",
+    "title": {
+        "balanceRecord": "交易明细",
+        "distribution": "收益中心"
+    },
     "common": {
+        "cancel": "取消",
+        "confirm": "确定",
         "pullRefresh": "下拉刷新",
         "loadFinish": "加载完成",
         "home": "首页",
@@ -48,11 +54,29 @@
     "balance": {
         "symbol": "¥",
         "balance": "账户余额",
-        "record": "交易明细",
         "chooseAmount": "选择金额",
         "inputCustomAmount": "请输入自定义金额",
         "withdraw": "提现",
-        "recharge": "充值"
+        "recharge": "充值",
+        "totalWithdraw": "累计提现",
+        "record": {
+            "pay": "支付",
+            "receipt": "收款",
+            "recharge": "充值",
+            "withdraw": "提现"
+        },
+        "withdrawModalTitle": "申请提现",
+        "confirmWithdraw": "确认提现",
+        "withdrawAmount": "提现金额",
+        "availableWidthdrawAmount": "可提现金额",
+        "withdrawInputTip": "请输入提现金额",
+        "withdrawAmountError": "请输入正确的提现金额",
+        "withdrawing": "提现中",
+        "withdrawSuccess": "提现成功",
+        "withdrawFeeTip0": "注: 购买总流水的1/3手续费是",
+        "withdrawFeeTip1": ",超出部分手续费",
+        "withdrawFee": "提现手续费",
+        "realReceipt": "实际到账"
     },
     "user": {
         "wallet": "我的钱包",

+ 8 - 0
src/main.js

@@ -10,6 +10,9 @@ import Vant from 'vant'
 import { ConfigProvider } from 'vant'
 import { useDark } from '@vueuse/core'
 import toast from '@/utils/toast'
+import setDefaultOptions from 'date-fns/setDefaultOptions'
+import zhCN from 'date-fns/locale/zh-CN'
+import enUS from 'date-fns/locale/en-US'
 
 import 'normalize.css/normalize.css'
 
@@ -61,3 +64,8 @@ dark.value = false
 router.isReady().then(() => {
     app.mount('#app')
 })
+if (navigator.language === 'zh-CN') {
+    setDefaultOptions({ locale: zhCN })
+} else {
+    setDefaultOptions({ locale: enUS })
+}

+ 5 - 0
src/router/index.js

@@ -104,6 +104,11 @@ const router = createRouter({
             path: '/changeText',
             name: 'changeText',
             component: () => import('@/views/ChangeTextPage.vue')
+        },
+        {
+            path: '/distribution',
+            name: 'distribution',
+            component: () => import('@/views/DistributionPage.vue')
         }
     ]
 })

+ 9 - 1
src/styles/main.less

@@ -29,7 +29,15 @@ ion-toast.error-toast {
 ion-toolbar {
     --border-style: none;
 }
-
+ion-refresher {
+    --color: var(--ion-color-step-400);
+}
+ion-button {
+    --border-radius: 4px;
+}
+.refresher-pulling-icon {
+    color: var(--ion-color-step-400) !important;
+}
 .van-button--primary {
     background: linear-gradient(135deg, #a108ff 0%, #5c7cff 100%);
     border-width: 0;

+ 153 - 26
src/views/BalanceRecordPage.vue

@@ -5,25 +5,51 @@
                 <ion-buttons slot="start">
                     <ion-back-button default-href="#" @click="$router.back()"></ion-back-button>
                 </ion-buttons>
-                <ion-title>{{ $t('order.my') }}</ion-title>
+                <ion-title>{{ $t('title.balanceRecord') }}</ion-title>
             </ion-toolbar>
         </ion-header>
         <ion-content>
-            <van-pull-refresh v-model="refreshing" @refresh="refresh">
-                <van-list v-model="loading" :finished="finished" finished-text="没有更多了" @load="loadmore">
-                    <van-cell
-                        v-for="item in records"
-                        :key="item.id"
-                        :title="item.amount"
-                        :value="item.createdAt.substr(0, 16)"
-                    />
-                    <van-empty v-if="finished && records.length === 0"></van-empty>
-                </van-list>
-            </van-pull-refresh>
+            <ion-refresher slot="fixed" @ionRefresh="refresh">
+                <ion-refresher-content></ion-refresher-content>
+            </ion-refresher>
+            <ion-item class="header" sticky>
+                <div class="date" @click="showPicker = true">
+                    {{ yearMonth }}
+                    <ion-icon :icon="caretDownOutline"></ion-icon>
+                </div>
+                <div class="total">{{ $t('balance.totalWithdraw') }}{{ $t('balance.symbol') }}{{ totalWithDraw }}</div>
+            </ion-item>
+            <van-list v-model="loading" :finished="finished" finished-text="没有更多了" @load="loadmore">
+                <ion-item class="record-item" v-for="item in records" :key="item.id" :class="item.remark.split('.')">
+                    <ion-icon :src="balanceIcon"></ion-icon>
+                    <ion-label>
+                        <h3>{{ $t(item.remark) }}</h3>
+                        <p>{{ item.createdAt.substr(5, 11) }}</p>
+                    </ion-label>
+                    <ion-label slot="end" class="amount">
+                        {{ item.amount >= 0 ? '+' : '' }}{{ item.amount }}
+                    </ion-label>
+                </ion-item>
+
+                <van-empty v-if="finished && records.length === 0"></van-empty>
+            </van-list>
         </ion-content>
+        <ion-modal id="picker" :is-open="showPicker" @didDismiss="showPicker = false">
+            <ion-datetime
+                v-model="date"
+                presentation="month-year"
+                :cancel-text="$t('common.cancel')"
+                :done-text="$t('common.confirm')"
+                :show-default-buttons="true"
+                @ionChange="confirmPicker"
+            ></ion-datetime>
+        </ion-modal>
     </ion-page>
 </template>
 <script>
+import balanceIcon from '@/assets/icon_balance.svg'
+import { caretDownOutline } from 'ionicons/icons'
+import { format, formatISO, parseISO, startOfMonth, endOfMonth } from 'date-fns'
 export default {
     data() {
         return {
@@ -31,31 +57,132 @@ export default {
             refreshing: true,
             loading: false,
             finished: false,
-            records: []
+            records: [],
+            balanceIcon,
+            caretDownOutline,
+            showPicker: false,
+            date: formatISO(new Date())
+        }
+    },
+    created() {
+        this.getData()
+    },
+    computed: {
+        yearMonth() {
+            return format(parseISO(this.date, new Date()), 'yyyy MMM')
+        },
+        totalWithDraw() {
+            return -this.records.filter(i => i.remark === 'balance.record.withdraw').reduce((a, b) => a + b.amount, 0)
         }
     },
     methods: {
-        refresh() {
+        refresh(event) {
             this.loading = true
             this.page = 0
-            this.getBalance()
-            this.getData()
+            this.finished = false
+            this.getData(event)
         },
         loadmore() {
             this.page++
             this.getData()
         },
-        getData() {
-            return this.$http.get('/user/balanceRecord', { page: this.page, size: 10 }).then(res => {
-                if (res.number === 0) {
-                    this.records = []
-                }
-                this.records = this.records.concat(res.content)
-                this.refreshing = false
-                this.loading = false
-                this.finished = res.last
-            })
+        getData(e) {
+            const date = parseISO(this.date, new Date())
+            return this.$http
+                .get('/user/balanceRecord', {
+                    page: this.page,
+                    size: 10000,
+                    start: format(startOfMonth(date), 'yyyy-MM-dd HH:mm:ss'),
+                    end: format(endOfMonth(date), 'yyyy-MM-dd HH:mm:ss')
+                })
+                .then(res => {
+                    if (res.number === 0) {
+                        this.records = []
+                    }
+                    this.records = this.records.concat(res.content)
+                    this.refreshing = false
+                    this.loading = false
+                    this.finished = res.last
+                    if (e) {
+                        e.target.complete()
+                    }
+                })
+        },
+        confirmPicker(e) {
+            this.date = e.detail.value
+            this.getData()
         }
     }
 }
 </script>
+<style lang="less" scoped>
+.header {
+    --border-style: none;
+    .date {
+        width: 104px;
+        height: 32px;
+        background: var(--ion-color-step-0);
+        border-radius: 4px;
+        font-size: 12px;
+        .f();
+        justify-content: center;
+        ion-icon {
+            margin-left: 6px;
+        }
+    }
+    .total {
+        flex-grow: 1;
+        text-align: right;
+        font-size: 12px;
+        color: var(--ion-color-step-400);
+        padding-right: 6px;
+    }
+}
+.record-item {
+    --background: var(--ion-color-step-0);
+    --border-color: var(--ion-color-step-100);
+    ion-icon {
+        width: 32px;
+        height: 32px;
+    }
+    ion-label {
+        margin-left: 10px;
+    }
+    .amount {
+        font-weight: bold;
+    }
+    ion-icon {
+        fill: #59b12c;
+    }
+    &.recharge,
+    &.receipt {
+        ion-icon {
+            fill: #477bff;
+        }
+        .amount {
+            color: #477bff;
+        }
+    }
+    &.withdraw {
+        h3 {
+            color: #ff7f1f;
+        }
+        ion-icon {
+            fill: #ff7f1f;
+        }
+        .amount {
+            color: #ff7f1f;
+        }
+    }
+}
+ion-modal#picker {
+    --width: fit-content;
+    --min-width: calc(100vw - 80px);
+    --height: fit-content;
+    --border-radius: 6px;
+    --box-shadow: 0 28px 48px rgba(0, 0, 0, 0.4);
+}
+ion-datetime {
+    color: var(--ion-text-color);
+}
+</style>

+ 148 - 0
src/views/CommissionPage.vue

@@ -0,0 +1,148 @@
+<template>
+    <div class="commission">
+        <div class="commission-value">
+            <div class="value">
+                <span>{{ commission.total }}</span>
+                <span>元</span>
+            </div>
+            <div class="sub">累计佣金</div>
+        </div>
+
+        <van-cell-group>
+            <van-cell
+                title="可提现佣金"
+                :value="commission.available + '元'"
+                title-class="cell-title"
+                value-class="cell-value"
+            />
+        </van-cell-group>
+        <van-cell-group>
+            <van-cell title="已申请佣金" value="0.00元" title-class="cell-title" value-class="cell-value" />
+            <van-cell title="待打款佣金" value="0.00元" title-class="cell-title" value-class="cell-value" />
+            <van-cell title="无效佣金" value="0.00元" title-class="cell-title" value-class="cell-value" />
+            <van-cell
+                title="成功提现佣金"
+                :value="commission.withdraw + '元'"
+                title-class="cell-title"
+                value-class="cell-value"
+            />
+        </van-cell-group>
+        <van-cell-group>
+            <van-cell
+                title="待收货佣金"
+                :value="commission.notChecked + '元'"
+                title-class="cell-title"
+                value-class="cell-value"
+            />
+            <van-cell
+                title="未结算佣金"
+                :value="commission.notChecked + '元'"
+                title-class="cell-title"
+                value-class="cell-value"
+            />
+        </van-cell-group>
+
+        <div class="tips">
+            <div class="tips-title">用户须知</div>
+
+            <div class="tips-content">
+                买家确认收货后,立即获得分销佣金
+                <br />注意:可用佣金满 <span>1元</span>后才能申请提现
+            </div>
+        </div>
+    </div>
+</template>
+<script>
+import { mapState } from 'pinia'
+import { useUserStore } from '@/stores/user'
+export default {
+    name: 'commissionPage',
+    data() {
+        return {
+            commission: {}
+        }
+    },
+    computed: {
+        ...mapState(useUserStore, ['user'])
+    },
+    mounted() {
+        this.$http.get('/commission/detail').then(res => {
+            this.commission = res
+        })
+    }
+}
+</script>
+<style lang="less" scoped>
+.commission {
+    background: rgba(242, 244, 245, 1);
+    padding: 15px;
+    box-sizing: border-box;
+}
+
+.commission-value {
+    height: 110px;
+    background: rgba(255, 143, 0, 1);
+    border-radius: 4px;
+    display: flex;
+    flex-direction: column;
+    align-items: center;
+    justify-content: center;
+    color: #fff;
+    font-size: 12px;
+    line-height: 17px;
+
+    .value {
+        span {
+            &:first-child {
+                font-size: 24px;
+                font-weight: bold;
+            }
+
+            &:last-child {
+                margin-left: 4px;
+            }
+        }
+    }
+
+    .sub {
+        margin-top: 7px;
+    }
+}
+.cell-title {
+    font-size: 14px;
+    font-weight: bold;
+    color: #000000;
+}
+.cell-value {
+    font-size: 16px;
+    color: #000;
+}
+
+.van-cell {
+    line-height: 40px;
+}
+.van-cell-group {
+    border-radius: 2px;
+    overflow: hidden;
+    margin-top: 10px;
+}
+
+.tips {
+    margin-top: 15px;
+
+    .tips-title {
+        font-size: 14px;
+        color: rgba(0, 0, 0, 1);
+        line-height: 20px;
+    }
+
+    .tips-content {
+        margin-top: 6px;
+        font-size: 13px;
+        color: rgba(102, 102, 102, 1);
+        span {
+            color: #ff8f00;
+        }
+    }
+}
+</style>

+ 162 - 0
src/views/CommissionRecord.vue

@@ -0,0 +1,162 @@
+<template>
+    <div class="list">
+        <div class="top">
+            <van-tabs
+                v-model="chooseTab"
+                title-active-color="#FF7900"
+                :line-height="2"
+                title-inactive-color="#000000"
+                @click="tabClick"
+            >
+                <van-tab :title="item" v-for="(item, index) in tabList" :key="index"></van-tab>
+            </van-tabs>
+        </div>
+        <van-pull-refresh v-model="refreshing" @refresh="onRefresh" success-text="刷新成功">
+            <div class="content">
+                <van-list v-model="loading" :finished="finished" finished-text="没有更多了" @load="onLoad">
+                    <div class="order-list">
+                        <record v-for="(item, index) in list" :info="item" :key="index"></record>
+                        <!-- <record></record>
+             <record></record> -->
+                    </div>
+                </van-list>
+            </div>
+        </van-pull-refresh>
+    </div>
+</template>
+<script>
+import { mapState } from 'pinia'
+import { useUserStore } from '@/stores/user'
+import record from '@/components/Record.vue'
+export default {
+    name: 'CommissionRecord',
+    data() {
+        return {
+            chooseTab: 0,
+            priceDirection: 0,
+            list: [],
+            refreshing: false,
+            loading: false,
+            finished: false,
+            tabList: ['全部', '待审核', '待打款', '已打款', '无效'],
+            status: ['', 'PENDING', 'WAIT_TRANSFER', 'TRANSFERRED', 'CANCELED'],
+            page: 0,
+            size: 20
+        }
+    },
+    computed: {
+        ...mapState(useUserStore, ['user'])
+    },
+    created() {
+        this.onLoad()
+    },
+    methods: {
+        onRefresh() {
+            this.page = 0
+            this.refreshing = true
+            this.loading = false
+            this.finished = false
+            this.getData().then(_ => {
+                this.refreshing = false
+            })
+        },
+        onLoad() {
+            this.refreshing = false
+            this.loading = true
+            this.finished = false
+            this.getData().then(_ => {
+                this.refreshing = false
+            })
+        },
+        tabClick(name, title) {
+            this.page = 0
+            this.list = []
+            this.loading = false
+            this.isLoading = false
+            this.finished = false
+        },
+        getData() {
+            var data = {
+                page: this.page,
+                size: 20
+            }
+            if (this.status[this.chooseTab]) {
+                data.query = {
+                    status: this.status[this.chooseTab],
+                    userId: this.user.id
+                }
+            } else {
+                data.query = {
+                    userId: this.user.id
+                }
+            }
+            return this.$http
+                .post('/withdrawApply/all', data)
+                .then(res => {
+                    if (res.first) {
+                        this.list = []
+                    }
+                    this.list = this.list.concat(res.content)
+                    this.loading = false
+                    if (res.last) {
+                        this.finished = true
+                    } else {
+                        this.page++
+                    }
+                })
+                .catch(e => {})
+        }
+    },
+    components: {
+        record
+    }
+}
+</script>
+<style lang="less" scoped>
+.list {
+    background-color: #f2f4f5;
+}
+.top {
+    position: sticky;
+    top: 0;
+    z-index: 20;
+}
+.content {
+    min-height: 100vh;
+    position: relative;
+}
+.tab-title {
+    display: flex;
+    align-items: center;
+    justify-content: center;
+
+    img {
+        width: 24px;
+        height: 24px;
+    }
+
+    .img-list {
+        display: flex;
+        flex-direction: column;
+        align-items: center;
+        justify-content: center;
+        margin-left: 4px;
+
+        img {
+            width: 8px;
+            height: 5px;
+
+            &:last-child {
+                margin-top: 2px;
+            }
+        }
+    }
+}
+.order-list {
+    padding: 15px 14px;
+
+    .order-info {
+        margin-bottom: 15px;
+    }
+}
+</style>

+ 52 - 0
src/views/CommissionRecordList.vue

@@ -0,0 +1,52 @@
+<template>
+    <div class="list">
+        <record-order
+            v-for="(item, index) in list"
+            :key="index"
+            :info="item"
+            :status="status"
+            :auditAmount="auditAmount"
+            :amount="amount"
+        ></record-order>
+        <!-- <record-order></record-order> -->
+    </div>
+</template>
+<script>
+import { mapState } from 'pinia'
+import { useUserStore } from '@/stores/user'
+import recordOrder from '@/components/RecordOrder.vue'
+export default {
+    name: 'commissionRecordListPage',
+    data() {
+        return {
+            list: [],
+            status: '',
+            amount: 0,
+            auditAmount: 0
+        }
+    },
+    computed: {
+        ...mapState(useUserStore, ['user'])
+    },
+    mounted() {
+        this.$http.post('/withdrawApply/detail/' + this.$route.query.id).then(res => {
+            this.list = res.commissionOrders
+            this.status = res.status
+            if (res.amount) {
+                this.amount = res.amount
+            }
+            if (res.auditAmount) {
+                this.auditAmount = res.auditAmount
+            }
+        })
+    },
+    components: {
+        recordOrder
+    }
+}
+</script>
+<style lang="less" scoped>
+.list {
+    padding: 15px;
+}
+</style>

+ 300 - 0
src/views/DistributionPage.vue

@@ -0,0 +1,300 @@
+<template>
+    <ion-page>
+        <ion-header>
+            <ion-toolbar>
+                <ion-buttons slot="start">
+                    <ion-back-button default-href="#" @click="$router.back()"></ion-back-button>
+                </ion-buttons>
+                <ion-title>{{ $t('title.distribution') }}</ion-title>
+            </ion-toolbar>
+        </ion-header>
+        <ion-content>
+            <div class="distibution">
+                <div class="info">
+                    <div class="left">
+                        <div class="text1">{{ user.nickname }}</div>
+                        <div class="text2" v-if="commission.superior">推荐人:{{ commission.superior }}</div>
+                    </div>
+
+                    <div class="right">
+                        <img
+                            src="../../assets/fenxiao_icon_erweima.png"
+                            @click="goNext('extension')"
+                            class="qrcode-img"
+                            alt=""
+                        />
+                        <div class="qrcode-text">推广二维码</div>
+                    </div>
+                </div>
+
+                <div class="content">
+                    <div class="item">
+                        <div class="left">
+                            <div class="text1">
+                                <span>{{ commission.withdraw }}</span>
+                                <span>元</span>
+                            </div>
+                            <div class="text2">成功提现佣金</div>
+                        </div>
+
+                        <van-button
+                            class="button1"
+                            round
+                            @click="goNext('commissionRecord')"
+                            style="font-weight: bold; border: 0"
+                        >
+                            查看明细
+                        </van-button>
+                    </div>
+
+                    <div class="item">
+                        <div class="left">
+                            <div class="text1">
+                                <span>{{ commission.available }}</span>
+                                <span>元</span>
+                            </div>
+                            <div class="text2">可提现佣金</div>
+                        </div>
+
+                        <van-button type="primary" round @click="withdrawApply">立即提现 </van-button>
+                    </div>
+                </div>
+
+                <div class="menu-list">
+                    <div class="menu-item" @click="goNext('commission')">
+                        <img src="../../assets/fenxiao_icon_yongjin.png" alt />
+                        <div class="right">
+                            <div class="text1">分销佣金</div>
+                            <div class="text2">{{ commission.total }} 元</div>
+                        </div>
+                    </div>
+
+                    <div class="menu-item" @click="goNext('distributionOrder')">
+                        <img src="../../assets/fenxiao_icon_dingdan.png" alt />
+                        <div class="right">
+                            <div class="text1">分销订单</div>
+                            <div class="text2">{{ commission.orderCount }} 笔</div>
+                        </div>
+                    </div>
+                </div>
+
+                <van-cell-group :border="false" class="menu-list2">
+                    <van-cell
+                        title="我的下线"
+                        title-class="menu-title"
+                        @click="goNext('subordinate')"
+                        :value="commission.juniorCount + '人'"
+                        is-link
+                    >
+                        <img src="../../assets/fenxiao_list_icon_yeji.png" class="menu-img" slot="icon" alt />
+                    </van-cell>
+                    <van-cell title="业绩统计" title-class="menu-title" @click="goNext('statistics')" is-link>
+                        <img src="../../assets/fenxiao_list_icon_xiaxian.png" class="menu-img" slot="icon" alt />
+                    </van-cell>
+                    <!-- <van-cell title="佣金排名" title-class="menu-title" is-link>
+        <img src="../../assets/fenxiao_list_icon_paiming.png" class="menu-img" slot="icon" alt />
+      </van-cell> -->
+                </van-cell-group>
+            </div>
+        </ion-content>
+    </ion-page>
+</template>
+<script>
+import { mapState } from 'pinia'
+import { useUserStore } from '@/stores/user'
+export default {
+    data() {
+        return {
+            commission: {},
+            show: false,
+            url: ''
+        }
+    },
+    computed: {
+        ...mapState(useUserStore, ['user'])
+    },
+    mounted() {
+        this.getInfo()
+    },
+    methods: {
+        withdrawApply() {
+            this.$http
+                .post('/withdrawApply/apply')
+                .then(res => {
+                    this.$dialog
+                        .alert({
+                            message: '提现申请提交成功'
+                        })
+                        .then(() => {
+                            this.getInfo()
+                        })
+                })
+                .catch(e => {
+                    return this.$toast(e.error)
+                })
+        },
+        getInfo() {
+            this.$http.get('/commission/overview').then(res => {
+                this.commission = res
+            })
+        }
+    }
+}
+</script>
+<style lang="less" scoped>
+.distibution {
+    background: linear-gradient(180deg, rgba(255, 143, 0, 1) 0%, rgba(255, 143, 0, 0) 190px);
+    min-height: 100%;
+}
+
+.info {
+    display: flex;
+    justify-content: space-between;
+    padding: 22px 15px 20px;
+    align-items: center;
+
+    .right {
+        display: flex;
+        flex-direction: column;
+        align-items: center;
+    }
+    .qrcode-img {
+        width: 34px;
+        height: 34px;
+    }
+    .qrcode-text {
+        font-size: 12px;
+        color: rgba(255, 255, 255, 1);
+        line-height: 17px;
+        margin-top: 4px;
+    }
+
+    .left {
+        .text1 {
+            font-size: 21px;
+            font-weight: bold;
+            color: rgba(255, 255, 255, 1);
+            line-height: 29px;
+        }
+        .text2 {
+            font-size: 12px;
+            font-weight: bold;
+            color: rgba(255, 255, 255, 1);
+            line-height: 17px;
+            margin-top: 5px;
+        }
+    }
+}
+
+.content {
+    background: rgba(255, 255, 255, 1);
+    box-shadow: 0px 4px 8px 0px rgba(0, 0, 0, 0.04);
+    border-radius: 4px;
+    margin: 0 15px;
+    padding: 0 30px;
+
+    .item {
+        height: 100px;
+        display: flex;
+        align-items: center;
+        justify-content: space-between;
+        .left {
+            .text1 {
+                span {
+                    font-size: 12px;
+                    font-weight: bold;
+                    color: rgba(51, 51, 51, 1);
+                    line-height: 17px;
+                    &:first-child {
+                        font-size: 24px;
+                    }
+                }
+            }
+
+            .text2 {
+                font-size: 12px;
+                color: rgba(128, 128, 128, 1);
+                line-height: 17px;
+                margin-top: 5px;
+            }
+        }
+
+        .van-button {
+            width: 88px;
+            height: 36px;
+            line-height: 36px;
+            font-size: 13px;
+        }
+
+        .button1 {
+            background: rgba(255, 143, 0, 0.12);
+            color: #ff8f00;
+            border-color: rgba(255, 143, 0, 0.12);
+        }
+
+        &:not(:last-child) {
+            border-bottom: 1px solid #f2f4f5;
+        }
+    }
+}
+
+.menu-list {
+    display: flex;
+    padding: 25px 15px 15px;
+    justify-content: space-between;
+    .menu-item {
+        display: flex;
+        align-items: center;
+        width: calc((100% - 15px) / 2);
+        height: 80px;
+        background: rgba(255, 255, 255, 1);
+        box-shadow: 0px 4px 8px 0px rgba(0, 0, 0, 0.04);
+        border-radius: 4px;
+        justify-content: center;
+        img {
+            width: 44px;
+            height: 44px;
+        }
+
+        .right {
+            margin-left: 10px;
+            .text1 {
+                font-size: 16px;
+                font-weight: bold;
+                color: rgba(51, 51, 51, 1);
+                line-height: 22px;
+            }
+            .text2 {
+                font-size: 14px;
+                color: rgba(142, 142, 147, 1);
+                line-height: 20px;
+                margin-top: 2px;
+            }
+        }
+    }
+}
+
+.menu-list2 {
+    .menu-img {
+        width: 24px;
+        height: 24px;
+        margin-right: 10px;
+    }
+
+    .menu-title {
+        font-size: 14px;
+        color: rgba(0, 0, 0, 1);
+    }
+
+    .menu-not-val {
+        font-size: 13px;
+        color: rgba(255, 143, 0, 1);
+    }
+
+    .van-cell {
+        line-height: 40px;
+        display: flex;
+        align-items: center;
+    }
+}
+</style>

+ 2 - 2
src/views/MinePage.vue

@@ -64,7 +64,7 @@
             </div>
 
             <van-cell-group class="menu" :border="false">
-                <van-cell title="我的收益" value="有新的收益" is-link>
+                <van-cell title="我的收益" value="有新的收益" is-link :to="{ name: 'distribution' }">
                     <template #icon>
                         <img class="menu-icon" src="../assets/info_icon_shoyi.png" alt="" />
                     </template>
@@ -93,7 +93,7 @@
                     </template>
                 </van-cell>
 
-                <van-cell title="设置" is-link @click="goSetting">
+                <van-cell title="设置" is-link :to="{ name: 'setting' }">
                     <template #icon>
                         <img class="menu-icon" src="../assets/info_icon_shezhi.png" alt="" />
                     </template>

+ 225 - 15
src/views/WalletPage.vue

@@ -1,5 +1,5 @@
 <template>
-    <ion-page>
+    <ion-page class="wallet-page">
         <ion-header>
             <ion-toolbar>
                 <ion-buttons slot="start">
@@ -15,9 +15,9 @@
                     >{{ balance.balance }}
                 </div>
                 <div class="label">{{ $t('balance.balance') }}</div>
-                <div class="btn-record">
+                <div class="btn-record" @click="$router.push({ name: 'balanceRecord' })">
                     <img src="../assets/double_arrow_left.png" class="arrow" />
-                    <div>{{ $t('balance.record') }}</div>
+                    <div>{{ $t('title.balanceRecord') }}</div>
                     <img src="../assets/double_arrow_right.png" class="arrow" />
                 </div>
             </div>
@@ -28,11 +28,11 @@
                         class="amount-item"
                         v-for="item in amountOptions"
                         :key="item"
-                        :class="{ active: amount === item }"
-                        @click="amount = item"
+                        :class="{ active: rechargeAmount === item }"
+                        @click="rechargeAmount = item"
                     >
-                        <span class="sym">{{ $t('balance.symbol') }}</span
-                        >{{ item }}
+                        <span class="sym">{{ $t('balance.symbol') }}</span>
+                        {{ item }}
                     </div>
                     <div class="input-wrapper">
                         <span class="sym">{{ $t('balance.symbol') }}</span>
@@ -51,11 +51,61 @@
         <ion-footer class="ion-no-border">
             <ion-toolbar>
                 <div class="bottom-buttons">
-                    <ion-button color="light">{{ $t('balance.withdraw') }}</ion-button>
-                    <ion-button>{{ $t('balance.recharge') }}</ion-button>
+                    <ion-button class="btn-withdraw" @click="showWithdrawModal = true">{{
+                        $t('balance.withdraw')
+                    }}</ion-button>
+                    <ion-button class="btn-recharge" @click="confirmRecharge">{{ $t('balance.recharge') }}</ion-button>
                 </div>
             </ion-toolbar>
         </ion-footer>
+        <ion-modal
+            id="modal-withdraw"
+            :is-open="showWithdrawModal"
+            :initial-breakpoint="breakpoint"
+            :breakpoints="[0, breakpoint]"
+            @didDismiss="showWithdrawModal = false"
+        >
+            <ion-content :style="{ height: `${breakpoint * 100}%` }">
+                <div>
+                    <div class="head">
+                        <div class="title">{{ $t('balance.withdrawModalTitle') }}</div>
+                        <div class="close" @click="showWithdrawModal = false">
+                            <img src="@/assets/icon_close.svg" />
+                        </div>
+                    </div>
+                    <div class="label">{{ $t('balance.withdrawAmount') }}</div>
+                    <div class="desc">
+                        {{ $t('balance.availableWidthdrawAmount') }}{{ $t('balance.symbol') }}{{ balance.balance }}
+                    </div>
+                    <div class="input-wrapper">
+                        <span class="sym">{{ $t('balance.symbol') }}</span>
+                        <ion-input
+                            v-model="withdrawAmount"
+                            :placeholder="$t('balance.withdrawInputTip')"
+                            inputmode="decimal"
+                            :size="36"
+                            clearInput
+                        ></ion-input>
+                    </div>
+                    <div class="item">
+                        <div class="item-label">{{ $t('balance.withdrawFee') }}</div>
+                        <div class="value">{{ fee.fee }}</div>
+                    </div>
+                    <div class="item">
+                        <div class="item-label">{{ $t('balance.realReceipt') }}</div>
+                        <div class="value">{{ fee.realReceipt }}</div>
+                    </div>
+                    <div class="tip">
+                        {{ $t('balance.withdrawFeeTip0') }}<span class="orange">{{ withdrawFeeRate * 100 + '%' }}</span
+                        >{{ $t('balance.withdrawFeeTip1')
+                        }}<span class="orange">{{ withdrawFeeLowRate * 100 + '%' }}</span>
+                    </div>
+                    <div class="footer">
+                        <ion-button expand="block" @click="withdraw">{{ $t('balance.confirmWithdraw') }}</ion-button>
+                    </div>
+                </div>
+            </ion-content>
+        </ion-modal>
     </ion-page>
 </template>
 <script>
@@ -63,17 +113,51 @@ export default {
     data() {
         return {
             balance: {
-                balance: 0
+                balance: 0,
+                feeFreeAllowances: 0
             },
             showRecharge: false,
-            rechargeAmount: 999,
+            rechargeAmount: 100,
             amountOptions: [100, 200, 300, 600, 800, 1000],
-            amount: 100,
-            customAmount: null
+            customAmount: null,
+            showWithdrawModal: false,
+            withdrawAmount: null,
+            withdrawFeeRate: 0.08,
+            withdrawFeeLowRate: 0.01,
+            breakpoint: Number((450 / window.innerHeight).toFixed(2))
         }
     },
     created() {
         this.getBalance()
+        this.$http.get('/sysConfig/get/withdraw_fee_rate').then(res => {
+            this.withdrawFeeRate = Number(res.value)
+        })
+        this.$http.get('/sysConfig/get/withdraw_fee_low_rate').then(res => {
+            this.withdrawFeeLowRate = Number(res.value)
+        })
+    },
+    computed: {
+        fee() {
+            const amount = Number(this.withdrawAmount)
+            if (!amount || this.withdrawAmount <= 0 || this.withdrawAmount > this.balance.balance) {
+                return {
+                    fee: '-',
+                    realReceipt: '-'
+                }
+            }
+            let fee
+            if (amount <= this.balance.feeFreeAllowances) {
+                fee = this.withdrawFeeLowRate * amount
+            } else {
+                fee =
+                    this.withdrawFeeRate * (amount - this.balance.feeFreeAllowances) +
+                    this.withdrawFeeLowRate * this.balance.feeFreeAllowances
+            }
+            return {
+                fee: fee.toFixed(2),
+                realReceipt: (amount - fee).toFixed(2)
+            }
+        }
     },
     methods: {
         getBalance() {
@@ -88,11 +172,32 @@ export default {
                 this.$toast.success('充值成功')
                 this.getBalance()
             })
+        },
+        withdraw() {
+            const amount = Number(this.withdrawAmount)
+            if (!amount || this.withdrawAmount <= 0 || this.withdrawAmount > this.balance.balance) {
+                this.$toast.error(this.$t('balance.withdrawAmountError'))
+                return
+            }
+            this.$toast.loading(this.$t('balance.withdrawing'))
+            this.$http
+                .post('/withdrawApply/apply', { amount })
+                .then(res => {
+                    this.$toast.success(this.$t('balance.withdrawSuccess'))
+                    this.getBalance()
+                    this.showWithdrawModal = false
+                })
+                .catch(e => {
+                    this.$toast.error(e.error)
+                })
         }
     }
 }
 </script>
 <style lang="less" scoped>
+:deep(.wallet-page) {
+    --ion-color-primary: #477bff;
+}
 .wallet-page {
     background-color: white;
     display: flex;
@@ -202,13 +307,118 @@ export default {
         }
     }
 }
-ion-footer {
-    background: var(--ion-item-background);
+:deep(ion-footer ion-toolbar) {
+    --background: var(--ion-color-step-0);
 }
 .bottom-buttons {
+    padding: 0 16px;
     .f();
     ion-button {
         flex-grow: 1;
     }
 }
+
+ion-button.btn-withdraw {
+    height: 38px;
+    --background: none;
+    --background-hover: rgba(var(--ion-color-light-contrast-rgb), 0.04);
+    --background-activated: rgba(var(--ion-color-light-contrast-rgb), 0.04);
+    --background-focused: rgba(var(--ion-color-light-contrast-rgb), 0.04);
+    --border-color: var(--ion-color-step-400);
+    --border-style: solid;
+    --border-width: 1px;
+    --color: var(--ion-color-step-400);
+    --border-radius: 4px;
+}
+ion-button.btn-recharge {
+    height: 38px;
+    margin-left: 20px;
+    --border-radius: 4px;
+}
+ion-modal#modal-withdraw {
+    --ion-color-primary: #477bff;
+    ion-content {
+        --background: var(--ion-color-step-0);
+    }
+    .head {
+        .f();
+        padding-left: 16px;
+        border-bottom: 1px solid var(--ion-color-step-50);
+        font-size: 14px;
+        .title {
+            flex-grow: 1;
+            color: var(--ion-color-text);
+            padding: 16px 0 10px 0;
+        }
+        .close {
+            padding: 16px 16px 10px 0;
+            img {
+                width: 24px;
+                height: 24px;
+            }
+        }
+    }
+    .label {
+        margin: 20px 0 0 16px;
+        font-size: 14px;
+        font-weight: bold;
+        line-height: 24px;
+    }
+    .desc {
+        margin: 2px 0 0 16px;
+        color: var(--ion-color-step-400);
+        font-size: 13px;
+        line-height: 22px;
+    }
+    .input-wrapper {
+        .f();
+        align-items: baseline;
+        margin: 12px 16px 0 16px;
+        background: var(--ion-color-step-50);
+        border-radius: 6px;
+        padding-left: 16px;
+        .sym {
+            font-size: 17px;
+            font-weight: bold;
+            margin-right: 10px;
+        }
+        ion-input {
+            font-size: 26px;
+            font-weight: bold;
+            --placeholder-font-weight: 400;
+            --placeholder-color: var(--ion-color-step-400);
+            ::-webkit-input-placeholder {
+                font-size: 18px;
+            }
+        }
+    }
+    .item {
+        .f();
+        height: 54px;
+        border-bottom: 1px solid var(--ion-color-step-50);
+        margin: 0 16px;
+        color: var(--ion-color-step-400);
+        font-size: 14px;
+        .item-label {
+            flex-grow: 1;
+        }
+    }
+    .tip {
+        margin-top: 14px;
+        padding: 0 16px;
+        line-height: 18px;
+        color: var(--ion-color-step-400);
+        font-size: 13px;
+        .orange {
+            color: #ff7f1f;
+        }
+    }
+    .footer {
+        position: absolute;
+        bottom: 0;
+        left: 0;
+        right: 0;
+        padding: 9px 27px;
+    }
+}
 </style>