xiongzhu před 3 roky
rodič
revize
35d6219e82

binární
src/assets/icon_balance_type_01.png


binární
src/assets/icon_balance_type_02.png


binární
src/assets/icon_balance_type_03.png


binární
src/assets/icon_pay_wallet.png


+ 25 - 30
src/components/ProductInfo.vue

@@ -21,44 +21,39 @@
                     <div class="name">明日可得(元)</div>
                 </div>
             </div>
-
         </div>
     </div>
 </template>
 
-<script lang="ts">
-import { defineComponent, computed } from 'vue'
+<script setup>
+import { computed } from 'vue'
 import { useRouter } from 'vue-router'
-export default defineComponent({
-    props: {
-        info: {
-            type: Object,
-            default: () => {
-                return {}
-            }
-        },
-        list: {
-            type: Boolean,
-            default: false
-        }
-    },
-    setup(props) {
-        const category = computed(() => {
-            return props.info.category || {}
-        })
 
-        const router = useRouter()
-        const goDetail = () => {
-            router.push({
-                path: '/productDetail',
-                query: {
-                    id: props.info.id
-                }
-            })
+const props = defineProps({
+    info: {
+        type: Object,
+        default: () => {
+            return {}
         }
-        return { category, goDetail }
+    },
+    list: {
+        type: Boolean,
+        default: false
     }
 })
+const category = computed(() => {
+    return props.info.category || {}
+})
+
+const router = useRouter()
+const goDetail = () => {
+    router.push({
+        path: '/productDetail',
+        query: {
+            id: props.info.id
+        }
+    })
+}
 </script>
 
 <style lang="less" scoped>
@@ -90,7 +85,7 @@ export default defineComponent({
             font-size: 10px;
             color: #392d19;
             line-height: 16px;
-            background: var(--ion-color-step-0)66;
+            background: var(--ion-color-step-0) 66;
             border-radius: 2px;
             padding: 0 2px;
         }

+ 9 - 2
src/locales/zh.json

@@ -53,7 +53,13 @@
             "balance": "余额支付"
         },
         "payNow": "立即支付",
-        "totalPayment": "实际支付"
+        "totalPayment": "实际支付",
+        "total": "合计",
+        "payInfo": "支付信息",
+        "buyNow": "立即购买",
+        "walletPay": "钱包支付",
+        "processing": "处理中",
+        "createSuccess": "订单创建成功"
     },
     "balance": {
         "symbol": "¥",
@@ -86,7 +92,8 @@
     },
     "user": {
         "wallet": "我的钱包",
-        "profile": "编辑资料"
+        "profile": "编辑资料",
+        "notLogin": "用户未登录,是否立即登录?"
     },
     "product": {
         "detail": "商品详情",

+ 1 - 1
src/styles/theme/variables.less

@@ -10,7 +10,7 @@ http://ionicframework.com/docs/theming/ */
 	--ion-text-color-rgb: 0,0,0;
 
     --ion-color-step-0: #ffffff;
-	--ion-color-step-50: #f2f2f2;
+	--ion-color-step-50: #F5F7FA;
 	--ion-color-step-100: #e6e6e6;
 	--ion-color-step-150: #d9d9d9;
 	--ion-color-step-200: #cccccc;

+ 1 - 1
src/utils/toast.js

@@ -69,7 +69,7 @@ Toast.loading = async function (options) {
     loadingInstance = loading
     loading.present()
 }
-Toast.dismiss = async () => {
+Toast.dismiss = Toast.clear = async () => {
     if (toastInstance) {
         toastInstance.dismiss()
     }

+ 1 - 1
src/views/HomePage.vue

@@ -300,7 +300,7 @@ const getStatus = info => {
 }
 
 :deep(.van-cell) {
-    --van-cell-background-color: var(--ion-background-color);
+    --van-cell-background: var(--ion-background-color);
     --van-cell-horizontal-padding: 20px;
     --van-cell-text-color: var(--ion-color-step-800);
     .f();

+ 154 - 16
src/views/ProductDetailPage.vue

@@ -37,10 +37,10 @@
                         </div>
                     </div>
 
-                    <div class="creator" v-if="user.id">
+                    <div class="creator" v-if="info.user && info.user.id">
                         <div class="text1">产品持有人:</div>
-                        <van-image width="20" height="20" radius="4" :src="user.avatar"></van-image>
-                        <div class="text2">{{ user.nickname }}</div>
+                        <van-image width="20" height="20" radius="4" :src="info.user.avatar"></van-image>
+                        <div class="text2">{{ info.user.nickname }}</div>
                     </div>
                 </div>
             </div>
@@ -64,26 +64,59 @@
         <ion-footer v-if="info.status === 'IN_STOCK'">
             <ion-toolbar>
                 <div class="footer">
-                    <van-button type="primary" block>立即购买</van-button>
+                    <van-button type="primary" block @click="onPay">立即购买</van-button>
                 </div>
             </ion-toolbar>
         </ion-footer>
+        <ion-modal
+            :is-open="showPayModal"
+            class="pay-modal"
+            :initial-breakpoint="breakpoint"
+            :breakpoints="[0, breakpoint]"
+            @didDismiss="showPayModal = false"
+        >
+            <ion-content :style="{ height: `${breakpoint * 100}%` }">
+                <div class="head">
+                    <div class="title">{{ $t('order.payInfo') }}</div>
+                    <div class="close" @click="showWithdrawModal = false">
+                        <img src="@/assets/icon_close.svg" />
+                    </div>
+                </div>
+                <div class="price-box">
+                    <div class="label">{{ $t('order.total') }}({{ $t('balance.unit') }})</div>
+                    <div class="value">{{ info.currentPrice }}</div>
+                </div>
+                <div class="divider"></div>
+                <div class="pay-item">
+                    <img src="@/assets/icon_pay_wallet.png" class="icon" />
+                    <div class="label">{{ $t('order.walletPay') }}</div>
+                    <van-checkbox name="wallet" v-model="payMethod" @click.stop />
+                </div>
+                <div class="footer">
+                    <van-button type="primary" block @click="pay">{{ $t('order.buyNow') }}</van-button>
+                </div>
+            </ion-content>
+        </ion-modal>
     </ion-page>
 </template>
 
 <script setup>
 import { Swiper, SwiperSlide } from 'swiper/vue'
 import 'swiper/swiper.min.css'
-import { ref, getCurrentInstance, onMounted, computed } from 'vue'
-import { useRoute } from 'vue-router'
+import { ref, onMounted, computed } from 'vue'
+import { useRoute, useRouter } from 'vue-router'
+import { useWindowSize } from '@vueuse/core'
+import toast from '@/utils/toast'
+import { http } from '@/plugins/http'
+import { useI18n } from 'vue-i18n'
+import { IonButton, alertController } from '@ionic/vue'
+import { useUserStore } from '@/stores/user'
+import { mapState } from 'pinia'
 
-const {
-    appContext: {
-        config: { globalProperties: global }
-    }
-} = getCurrentInstance()
 const route = useRoute()
-
+const router = useRouter()
+const userState = useUserStore()
+const { t } = useI18n()
 const info = ref({
     pic: []
 })
@@ -91,12 +124,9 @@ const info = ref({
 const category = computed(() => {
     return info.value.category || {}
 })
-const user = computed(() => {
-    return info.value.user || {}
-})
 
 function getDetail() {
-    global.$http.get('/product/get/' + route.query.id).then(res => {
+    http.get('/product/get/' + route.query.id).then(res => {
         info.value = res
     })
 }
@@ -104,6 +134,41 @@ function getDetail() {
 onMounted(() => {
     getDetail()
 })
+
+const showPayModal = ref(false)
+const { height: windowHeight } = useWindowSize()
+const breakpoint = computed(() => {
+    return 450 / windowHeight.value
+})
+const payMethod = ref('wallet')
+const onPay = () => {
+    console.log(userState.user)
+    if (!userState.user) {
+        router.push({ name: 'login' })
+    } else {
+        showPayModal.value = true
+    }
+}
+const pay = () => {
+    showPayModal.value = false
+    toast.loading(t('order.processing'))
+    http.post('/order/createOrder', {
+        productId: info.value.id
+    })
+        .then(res => {
+            toast.clear()
+            router.push({
+                name: 'orderDetail',
+                query: {
+                    id: res.id
+                }
+            })
+        })
+        .catch(e => {
+            console.log(e)
+            toast.error(e.error)
+        })
+}
 </script>
 
 <style lang="less" scoped>
@@ -223,4 +288,77 @@ ion-footer {
     --van-button-border-width: 0;
     --van-button-primary-background: linear-gradient(135deg, #d700ff 0%, #3e22ff 100%);
 }
+.pay-modal {
+    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;
+            }
+        }
+    }
+    .price-box {
+        background: #f5f7fa;
+        text-align: center;
+        margin: 16px;
+        padding: 20px 0;
+        border-radius: 4px;
+        .label {
+            color: var(--ion-color-step-400);
+            font-size: 14px;
+            line-height: 24px;
+        }
+        .value {
+            line-height: 30px;
+            font-size: 30px;
+            margin-top: 6px;
+            font-weight: bold;
+        }
+    }
+    .footer {
+        position: absolute;
+        bottom: 0;
+        left: 0;
+        right: 0;
+        padding: 9px 27px;
+    }
+    .divider {
+        margin: 0 16px;
+        height: 1px;
+        background: var(--ion-color-step-50);
+    }
+    .pay-item {
+        .f();
+        height: 48px;
+        margin-top: 12px;
+        padding: 0 16px;
+        .icon {
+            width: 24px;
+            height: 24px;
+        }
+        .label {
+            margin-left: 10px;
+            font-size: 14px;
+            font-weight: bold;
+            flex: 1;
+        }
+    }
+    :deep(.van-checkbox__icon--checked .van-icon) {
+        background: linear-gradient(135deg, #a108ff 0%, #5c7cff 100%);
+        border-color: var(--ion-color-step-0);
+    }
+}
 </style>

+ 5 - 1
src/views/WalletPage.vue

@@ -109,6 +109,7 @@
     </ion-page>
 </template>
 <script>
+import { useWindowSize } from '@vueuse/core'
 export default {
     data() {
         return {
@@ -124,7 +125,7 @@ export default {
             withdrawAmount: null,
             withdrawFeeRate: 0.08,
             withdrawFeeLowRate: 0.01,
-            breakpoint: Number((450 / window.innerHeight).toFixed(2))
+            windowSize: useWindowSize()
         }
     },
     created() {
@@ -157,6 +158,9 @@ export default {
                 fee: fee.toFixed(2),
                 realReceipt: (amount - fee).toFixed(2)
             }
+        },
+        breakpoint() {
+            return Number((450 / this.windowSize.height).toFixed(2))
         }
     },
     methods: {