更新:增加买书确认订单页面
This commit is contained in:
63
api/modules/order.ts
Normal file
63
api/modules/order.ts
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
// api/modules/order.ts
|
||||||
|
import { mainClient } from '@/api/clients/main'
|
||||||
|
import type { IApiResponse } from '@/api/types'
|
||||||
|
import type {
|
||||||
|
ICreateOrderParams,
|
||||||
|
IGooglePayVerifyParams,
|
||||||
|
ICreateOrderResponse
|
||||||
|
} from '@/types/order'
|
||||||
|
import type { IUserInfo } from '@/types/user'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 订单相关 API
|
||||||
|
*/
|
||||||
|
export const orderApi = {
|
||||||
|
/**
|
||||||
|
* 创建订单
|
||||||
|
* @param data 订单数据
|
||||||
|
*/
|
||||||
|
async createOrder(data: ICreateOrderParams) {
|
||||||
|
const res = await mainClient.request<IApiResponse<ICreateOrderResponse>>({
|
||||||
|
url: 'bookAbroad/order/placeOrder',
|
||||||
|
method: 'POST',
|
||||||
|
data
|
||||||
|
})
|
||||||
|
return res
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 验证 Google Pay 支付
|
||||||
|
* @param params 支付验证参数
|
||||||
|
*/
|
||||||
|
async verifyGooglePay(params: IGooglePayVerifyParams) {
|
||||||
|
const res = await mainClient.request<IApiResponse>({
|
||||||
|
url: 'pay/googlepay/googleVerify',
|
||||||
|
method: 'POST',
|
||||||
|
data: params
|
||||||
|
})
|
||||||
|
return res
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取用户信息(包含虚拟币余额)
|
||||||
|
*/
|
||||||
|
async getUserInfo() {
|
||||||
|
const res = await mainClient.request<IApiResponse<{ user: IUserInfo }>>({
|
||||||
|
url: 'common/user/getUserInfo',
|
||||||
|
method: 'POST'
|
||||||
|
})
|
||||||
|
return res
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 刷新用户信息
|
||||||
|
* @param userId 用户ID
|
||||||
|
*/
|
||||||
|
async refreshUserInfo(userId: number) {
|
||||||
|
const res = await mainClient.request<IApiResponse<{ user: IUserInfo }>>({
|
||||||
|
url: `book/user/info/${userId}`,
|
||||||
|
method: 'POST'
|
||||||
|
})
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -75,11 +75,11 @@ const displayStats = computed(() => {
|
|||||||
if (!props.showStats) return ''
|
if (!props.showStats) return ''
|
||||||
|
|
||||||
if (props.book.readCount && props.book.readCount > 0) {
|
if (props.book.readCount && props.book.readCount > 0) {
|
||||||
return `${props.book.readCount}${t('home.readingCount')}`
|
return `${props.book.readCount}${t('bookHome.readingCount')}`
|
||||||
}
|
}
|
||||||
|
|
||||||
if (props.book.buyCount && props.book.buyCount > 0) {
|
if (props.book.buyCount && props.book.buyCount > 0) {
|
||||||
return `${props.book.buyCount}${t('home.purchased')}`
|
return `${props.book.buyCount}${t('bookHome.purchased')}`
|
||||||
}
|
}
|
||||||
|
|
||||||
return ''
|
return ''
|
||||||
|
|||||||
@@ -231,6 +231,30 @@
|
|||||||
"language": "Book language",
|
"language": "Book language",
|
||||||
"readAudio": "Loading audio..."
|
"readAudio": "Loading audio..."
|
||||||
},
|
},
|
||||||
|
"bookOrder": {
|
||||||
|
"title": "Order Confirmation",
|
||||||
|
"bookInfo": "Book Information",
|
||||||
|
"amount": "Amount",
|
||||||
|
"paymentMethod": "Payment Method",
|
||||||
|
"googlePay": "Google Pay",
|
||||||
|
"virtualCoin": "Virtual Coin",
|
||||||
|
"balance": "Balance",
|
||||||
|
"confirm": "Confirm Order",
|
||||||
|
"creating": "Creating order...",
|
||||||
|
"processing": "Processing payment...",
|
||||||
|
"paymentSuccess": "Payment successful",
|
||||||
|
"paymentFailed": "Payment failed",
|
||||||
|
"paymentCancelled": "Payment cancelled",
|
||||||
|
"insufficientBalance": "Insufficient virtual coin balance",
|
||||||
|
"googlePayNotAvailable": "Google Pay not available",
|
||||||
|
"productNotFound": "Product not found",
|
||||||
|
"orderCreateFailed": "Failed to create order",
|
||||||
|
"verificationFailed": "Payment verification failed",
|
||||||
|
"pleaseWait": "Please wait...",
|
||||||
|
"doNotRepeat": "Please do not submit repeatedly",
|
||||||
|
"notMuch": "Insufficient balance",
|
||||||
|
"orderTitle": "Order Confirmation"
|
||||||
|
},
|
||||||
"bookDetails": {
|
"bookDetails": {
|
||||||
"title": "Book Details",
|
"title": "Book Details",
|
||||||
"title_comment": "Reviews",
|
"title_comment": "Reviews",
|
||||||
@@ -257,7 +281,7 @@
|
|||||||
"deleteText": "Delete this comment?",
|
"deleteText": "Delete this comment?",
|
||||||
"deleteSuccess": "Deleted"
|
"deleteSuccess": "Deleted"
|
||||||
},
|
},
|
||||||
"home": {
|
"bookHome": {
|
||||||
"block1": "My Books",
|
"block1": "My Books",
|
||||||
"block2": "Recommended",
|
"block2": "Recommended",
|
||||||
"more": "More",
|
"more": "More",
|
||||||
@@ -275,7 +299,7 @@
|
|||||||
"workOrder": {
|
"workOrder": {
|
||||||
"submit_success": "Submitted successfully"
|
"submit_success": "Submitted successfully"
|
||||||
},
|
},
|
||||||
"course": {
|
"courseHome": {
|
||||||
"title": "Course",
|
"title": "Course",
|
||||||
"watchHistory": "Watch History",
|
"watchHistory": "Watch History",
|
||||||
"tryListen": "Try Listening",
|
"tryListen": "Try Listening",
|
||||||
|
|||||||
@@ -258,7 +258,31 @@
|
|||||||
"deleteText": "确定删除此评论吗?",
|
"deleteText": "确定删除此评论吗?",
|
||||||
"deleteSuccess": "删除成功"
|
"deleteSuccess": "删除成功"
|
||||||
},
|
},
|
||||||
"home": {
|
"bookOrder": {
|
||||||
|
"title": "订单确认",
|
||||||
|
"bookInfo": "图书信息",
|
||||||
|
"amount": "金额",
|
||||||
|
"paymentMethod": "支付方式",
|
||||||
|
"googlePay": "Google Pay",
|
||||||
|
"virtualCoin": "虚拟币",
|
||||||
|
"balance": "余额",
|
||||||
|
"confirm": "确认下单",
|
||||||
|
"creating": "创建订单中...",
|
||||||
|
"processing": "支付处理中...",
|
||||||
|
"paymentSuccess": "支付成功",
|
||||||
|
"paymentFailed": "支付失败",
|
||||||
|
"paymentCancelled": "支付已取消",
|
||||||
|
"insufficientBalance": "虚拟币余额不足",
|
||||||
|
"googlePayNotAvailable": "Google Pay 不可用",
|
||||||
|
"productNotFound": "商品未找到",
|
||||||
|
"orderCreateFailed": "订单创建失败",
|
||||||
|
"verificationFailed": "支付验证失败",
|
||||||
|
"pleaseWait": "请稍候...",
|
||||||
|
"doNotRepeat": "请勿重复提交",
|
||||||
|
"notMuch": "虚拟币余额不足",
|
||||||
|
"orderTitle": "订单确认"
|
||||||
|
},
|
||||||
|
"bookHome": {
|
||||||
"block1": "我的书单",
|
"block1": "我的书单",
|
||||||
"block2": "推荐图书",
|
"block2": "推荐图书",
|
||||||
"more": "更多",
|
"more": "更多",
|
||||||
@@ -276,7 +300,7 @@
|
|||||||
"workOrder": {
|
"workOrder": {
|
||||||
"submit_success": "提交成功"
|
"submit_success": "提交成功"
|
||||||
},
|
},
|
||||||
"course": {
|
"courseHome": {
|
||||||
"title": "课程",
|
"title": "课程",
|
||||||
"watchHistory": "观看记录",
|
"watchHistory": "观看记录",
|
||||||
"tryListen": "精彩试听",
|
"tryListen": "精彩试听",
|
||||||
|
|||||||
14
pages.json
14
pages.json
@@ -5,12 +5,6 @@
|
|||||||
"style": {
|
"style": {
|
||||||
"navigationBarTitleText": "%index.title%"
|
"navigationBarTitleText": "%index.title%"
|
||||||
}
|
}
|
||||||
}, {
|
|
||||||
"path": "pages/component/component",
|
|
||||||
"style": {
|
|
||||||
"navigationBarTitleText": "%index.component%",
|
|
||||||
"enablePullDownRefresh": false
|
|
||||||
}
|
|
||||||
}, {
|
}, {
|
||||||
"path": "pages/login/login",
|
"path": "pages/login/login",
|
||||||
"style": {
|
"style": {
|
||||||
@@ -107,7 +101,7 @@
|
|||||||
"path": "pages/book/search",
|
"path": "pages/book/search",
|
||||||
"style": {
|
"style": {
|
||||||
"navigationStyle": "custom",
|
"navigationStyle": "custom",
|
||||||
"navigationBarTitleText": "%home.searchPlaceholder%"
|
"navigationBarTitleText": "%bookHome.searchPlaceholder%"
|
||||||
}
|
}
|
||||||
}, {
|
}, {
|
||||||
"path": "pages/book/listen/index",
|
"path": "pages/book/listen/index",
|
||||||
@@ -121,6 +115,12 @@
|
|||||||
"navigationStyle": "custom",
|
"navigationStyle": "custom",
|
||||||
"navigationBarTitleText": "%listen.title%"
|
"navigationBarTitleText": "%listen.title%"
|
||||||
}
|
}
|
||||||
|
}, {
|
||||||
|
"path": "pages/book/order",
|
||||||
|
"style": {
|
||||||
|
"navigationStyle": "custom",
|
||||||
|
"navigationBarTitleText": "%order.orderTitle%"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"tabBar": {
|
"tabBar": {
|
||||||
|
|||||||
@@ -18,17 +18,17 @@
|
|||||||
<view class="stats">
|
<view class="stats">
|
||||||
<view class="stat-item">
|
<view class="stat-item">
|
||||||
<image src="@/static/icon/icon_look_c.png" mode="aspectFit" />
|
<image src="@/static/icon/icon_look_c.png" mode="aspectFit" />
|
||||||
<text>{{ readCount }}{{ $t('home.readingCount') }}</text>
|
<text>{{ readCount }}{{ $t('bookHome.readingCount') }}</text>
|
||||||
</view>
|
</view>
|
||||||
<view class="divider" />
|
<view class="divider" />
|
||||||
<view class="stat-item">
|
<view class="stat-item">
|
||||||
<image src="@/static/icon/icon_listen_c.png" mode="aspectFit" />
|
<image src="@/static/icon/icon_listen_c.png" mode="aspectFit" />
|
||||||
<text>{{ listenCount }}{{ $t('home.listenCount') }}</text>
|
<text>{{ listenCount }}{{ $t('bookHome.listenCount') }}</text>
|
||||||
</view>
|
</view>
|
||||||
<view class="divider" />
|
<view class="divider" />
|
||||||
<view class="stat-item">
|
<view class="stat-item">
|
||||||
<image src="@/static/icon/icon_bug_c.png" mode="aspectFit" />
|
<image src="@/static/icon/icon_bug_c.png" mode="aspectFit" />
|
||||||
<text>{{ buyCount }}{{ $t('home.purchased') }}</text>
|
<text>{{ buyCount }}{{ $t('bookHome.purchased') }}</text>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
light
|
light
|
||||||
clearable
|
clearable
|
||||||
class="search-bar"
|
class="search-bar"
|
||||||
:placeholder="$t('home.searchPlaceholder')"
|
:placeholder="$t('bookHome.searchPlaceholder')"
|
||||||
@search="handleSearch"
|
@search="handleSearch"
|
||||||
/>
|
/>
|
||||||
<view class="icon-hua">
|
<view class="icon-hua">
|
||||||
@@ -25,13 +25,13 @@
|
|||||||
<view class="mine-block">
|
<view class="mine-block">
|
||||||
<!-- 我的书单 -->
|
<!-- 我的书单 -->
|
||||||
<view class="mine-1">
|
<view class="mine-1">
|
||||||
<text class="mine-title">{{ $t('home.block1') }}</text>
|
<text class="mine-title">{{ $t('bookHome.block1') }}</text>
|
||||||
<view
|
<view
|
||||||
v-if="myBooksList.length > 0"
|
v-if="myBooksList.length > 0"
|
||||||
class="mine-more"
|
class="mine-more"
|
||||||
@click="handleMoreClick"
|
@click="handleMoreClick"
|
||||||
>
|
>
|
||||||
{{ $t('home.more') }}
|
{{ $t('bookHome.more') }}
|
||||||
<image src="@/static/icon/icon_right.png" />
|
<image src="@/static/icon/icon_right.png" />
|
||||||
</view>
|
</view>
|
||||||
<view v-if="myBooksList.length > 0" class="mine-1-list">
|
<view v-if="myBooksList.length > 0" class="mine-1-list">
|
||||||
@@ -50,7 +50,7 @@
|
|||||||
|
|
||||||
<!-- 推荐图书 -->
|
<!-- 推荐图书 -->
|
||||||
<view class="mine-2">
|
<view class="mine-2">
|
||||||
<text class="mine-title">{{ $t('home.block2') }}</text>
|
<text class="mine-title">{{ $t('bookHome.block2') }}</text>
|
||||||
<swiper
|
<swiper
|
||||||
v-if="recommendBooksList.length > 0"
|
v-if="recommendBooksList.length > 0"
|
||||||
autoplay
|
autoplay
|
||||||
@@ -73,7 +73,7 @@
|
|||||||
|
|
||||||
<!-- 活动图书模块 -->
|
<!-- 活动图书模块 -->
|
||||||
<view v-if="showActivity" class="activity-block">
|
<view v-if="showActivity" class="activity-block">
|
||||||
<text class="activity-title">{{ $t('home.activityTitle') }}</text>
|
<text class="activity-title">{{ $t('bookHome.activityTitle') }}</text>
|
||||||
<scroll-view class="scroll-view" scroll-x :show-scrollbar="false">
|
<scroll-view class="scroll-view" scroll-x :show-scrollbar="false">
|
||||||
<view class="activity-label-list">
|
<view class="activity-label-list">
|
||||||
<view
|
<view
|
||||||
@@ -377,11 +377,11 @@ const formatPrice = (book: IBookWithStats): string => {
|
|||||||
*/
|
*/
|
||||||
const formatStats = (book: IBookWithStats): string => {
|
const formatStats = (book: IBookWithStats): string => {
|
||||||
if (book.readCount && book.readCount > 0) {
|
if (book.readCount && book.readCount > 0) {
|
||||||
return `${book.readCount}${t('home.readingCount')}`
|
return `${book.readCount}${t('bookHome.readingCount')}`
|
||||||
}
|
}
|
||||||
|
|
||||||
if (book.buyCount && book.buyCount > 0) {
|
if (book.buyCount && book.buyCount > 0) {
|
||||||
return `${book.buyCount}${t('home.purchased')}`
|
return `${book.buyCount}${t('bookHome.purchased')}`
|
||||||
}
|
}
|
||||||
|
|
||||||
return ''
|
return ''
|
||||||
|
|||||||
@@ -0,0 +1,721 @@
|
|||||||
|
<template>
|
||||||
|
<view class="order-page">
|
||||||
|
<!-- 导航栏 -->
|
||||||
|
<nav-bar :title="$t('bookOrder.orderTitle')"></nav-bar>
|
||||||
|
|
||||||
|
<!-- 图书信息区域 -->
|
||||||
|
<view class="order-block">
|
||||||
|
<view class="order-info">
|
||||||
|
<image :src="bookInfo.images" class="order-img" mode="aspectFill"></image>
|
||||||
|
<text class="order-name">{{ bookInfo.name }}</text>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<view class="order-price">
|
||||||
|
<text class="order-title">{{ $t('bookOrder.amount') }}</text>
|
||||||
|
<view v-if="paymentMethod === '5'" class="price-display">
|
||||||
|
<image src="/static/icon/currency.png" class="coin-img"></image>
|
||||||
|
<text class="coin-text">{{ displayPrice }} NZD</text>
|
||||||
|
</view>
|
||||||
|
<view v-if="paymentMethod === '4'" class="price-display">
|
||||||
|
<image src="/static/icon/coin.png" class="coin-img"></image>
|
||||||
|
<text class="coin-text">{{ displayPrice }}</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<!-- 支付方式选择区域 -->
|
||||||
|
<view class="order-type">
|
||||||
|
<text class="order-title">{{ $t('bookOrder.paymentMethod') }}</text>
|
||||||
|
<radio-group @change="handlePaymentChange" class="radio-group">
|
||||||
|
<label
|
||||||
|
v-for="(item, index) in paymentOptions"
|
||||||
|
:key="index"
|
||||||
|
class="type-label"
|
||||||
|
>
|
||||||
|
<view class="type-view">
|
||||||
|
<radio
|
||||||
|
:value="item.value"
|
||||||
|
:checked="paymentMethod === item.value"
|
||||||
|
color="#54a966"
|
||||||
|
></radio>
|
||||||
|
<text>
|
||||||
|
{{ item.name }}
|
||||||
|
<text v-if="item.value === '4'" class="balance-text">
|
||||||
|
({{ $t('bookOrder.balance') }}{{ userCoinBalance }})
|
||||||
|
</text>
|
||||||
|
</text>
|
||||||
|
</view>
|
||||||
|
</label>
|
||||||
|
</radio-group>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<!-- 底部确认按钮 -->
|
||||||
|
<view class="order-btn">
|
||||||
|
<view class="btn-spacer"></view>
|
||||||
|
<button
|
||||||
|
class="confirm-btn"
|
||||||
|
:disabled="isSubmitting"
|
||||||
|
@click="handleConfirmOrder"
|
||||||
|
>
|
||||||
|
{{ $t('bookOrder.confirm') }}
|
||||||
|
</button>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { ref, computed, onMounted } from 'vue'
|
||||||
|
import { onLoad, onShow, onUnload } from '@dcloudio/uni-app'
|
||||||
|
import { useI18n } from 'vue-i18n'
|
||||||
|
import { useUserStore } from '@/stores/user'
|
||||||
|
import { storeToRefs } from 'pinia'
|
||||||
|
import { orderApi } from '@/api/modules/order'
|
||||||
|
import { bookApi } from '@/api/modules/book'
|
||||||
|
import type { IBookDetail } from '@/types/book'
|
||||||
|
import type { IPaymentOption } from '@/types/order'
|
||||||
|
|
||||||
|
const { t } = useI18n()
|
||||||
|
const userStore = useUserStore()
|
||||||
|
const { userInfo } = storeToRefs(userStore)
|
||||||
|
|
||||||
|
// 页面参数
|
||||||
|
const bookId = ref(0)
|
||||||
|
|
||||||
|
// 图书信息
|
||||||
|
const bookInfo = ref<IBookDetail>({
|
||||||
|
id: 0,
|
||||||
|
name: '',
|
||||||
|
images: '',
|
||||||
|
author: { authorName: '', introduction: '' },
|
||||||
|
priceData: { dictType: '', dictValue: '' },
|
||||||
|
abroadPrice: 0,
|
||||||
|
isBuy: false,
|
||||||
|
freeChapterCount: 0
|
||||||
|
})
|
||||||
|
|
||||||
|
// 支付相关
|
||||||
|
const paymentMethod = ref<'4' | '5'>('5') // 默认 Google Pay
|
||||||
|
const paymentOptions = ref<IPaymentOption[]>([])
|
||||||
|
const userCoinBalance = ref(0)
|
||||||
|
const orderSn = ref('')
|
||||||
|
const isSubmitting = ref(false)
|
||||||
|
|
||||||
|
// Google Pay 相关
|
||||||
|
const googlePayConnected = ref(false)
|
||||||
|
let googlePayPlugin: any = null
|
||||||
|
|
||||||
|
// 计算显示价格
|
||||||
|
const displayPrice = computed(() => {
|
||||||
|
if (paymentMethod.value === '4') {
|
||||||
|
// 虚拟币价格
|
||||||
|
return (bookInfo.value.abroadPrice || 0) * 10
|
||||||
|
} else {
|
||||||
|
// Google Pay 价格
|
||||||
|
return bookInfo.value.priceData?.dictValue || '0'
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 页面加载
|
||||||
|
*/
|
||||||
|
onLoad((options: any) => {
|
||||||
|
if (options.id) {
|
||||||
|
bookId.value = Number(options.id)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 初始化支付方式
|
||||||
|
initPaymentOptions()
|
||||||
|
|
||||||
|
// 初始化 Google Pay
|
||||||
|
initGooglePay()
|
||||||
|
|
||||||
|
// 加载图书信息
|
||||||
|
loadBookInfo()
|
||||||
|
})
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 页面显示
|
||||||
|
*/
|
||||||
|
onShow(() => {
|
||||||
|
// 刷新用户信息
|
||||||
|
loadUserInfo()
|
||||||
|
})
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 页面卸载
|
||||||
|
*/
|
||||||
|
onUnload(() => {
|
||||||
|
// 清理资源
|
||||||
|
uni.hideLoading()
|
||||||
|
})
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 初始化支付方式列表
|
||||||
|
*/
|
||||||
|
function initPaymentOptions() {
|
||||||
|
const platform = uni.getSystemInfoSync().platform
|
||||||
|
|
||||||
|
if (platform === 'android') {
|
||||||
|
// Android 平台显示 Google Pay
|
||||||
|
paymentOptions.value = [
|
||||||
|
{ value: '5', name: t('bookOrder.googlePay') }
|
||||||
|
]
|
||||||
|
paymentMethod.value = '5'
|
||||||
|
} else {
|
||||||
|
// iOS 平台暂不支持支付
|
||||||
|
paymentOptions.value = []
|
||||||
|
paymentMethod.value = '5'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 初始化 Google Pay 插件
|
||||||
|
*/
|
||||||
|
function initGooglePay() {
|
||||||
|
// #ifdef APP-PLUS
|
||||||
|
try {
|
||||||
|
googlePayPlugin = uni.requireNativePlugin('sn-googlepay5')
|
||||||
|
if (googlePayPlugin) {
|
||||||
|
googlePayPlugin.init({}, (result: any) => {
|
||||||
|
console.log('[Google Pay] Init result:', result)
|
||||||
|
if (result.code === 0) {
|
||||||
|
googlePayConnected.value = true
|
||||||
|
console.log('[Google Pay] Connected successfully')
|
||||||
|
} else {
|
||||||
|
googlePayConnected.value = false
|
||||||
|
console.log('[Google Pay] Connection failed')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('[Google Pay] Init error:', error)
|
||||||
|
googlePayConnected.value = false
|
||||||
|
}
|
||||||
|
// #endif
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 加载图书信息
|
||||||
|
*/
|
||||||
|
async function loadBookInfo() {
|
||||||
|
try {
|
||||||
|
uni.showLoading({ title: t('common.loading') })
|
||||||
|
|
||||||
|
const res = await bookApi.getBookInfo(bookId.value)
|
||||||
|
|
||||||
|
uni.hideLoading()
|
||||||
|
|
||||||
|
if (res.bookInfo) {
|
||||||
|
bookInfo.value = res.bookInfo
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
uni.hideLoading()
|
||||||
|
console.error('[Order] Load book info error:', error)
|
||||||
|
uni.showToast({
|
||||||
|
title: t('common.networkError'),
|
||||||
|
icon: 'none'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 加载用户信息
|
||||||
|
*/
|
||||||
|
async function loadUserInfo() {
|
||||||
|
if (!userInfo.value.id) return
|
||||||
|
|
||||||
|
try {
|
||||||
|
const res = await orderApi.getUserInfo()
|
||||||
|
if (res.result) {
|
||||||
|
userCoinBalance.value = res.result.peanutCoin || 0
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('[Order] Load user info error:', error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 切换支付方式
|
||||||
|
*/
|
||||||
|
function handlePaymentChange(e: any) {
|
||||||
|
paymentMethod.value = e.detail.value
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 确认下单
|
||||||
|
*/
|
||||||
|
async function handleConfirmOrder() {
|
||||||
|
// 防止重复提交
|
||||||
|
if (isSubmitting.value) {
|
||||||
|
uni.showToast({
|
||||||
|
title: t('bookOrder.doNotRepeat'),
|
||||||
|
icon: 'none'
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 验证订单
|
||||||
|
if (!validateOrder()) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
isSubmitting.value = true
|
||||||
|
|
||||||
|
try {
|
||||||
|
// 创建订单
|
||||||
|
await createOrder()
|
||||||
|
} catch (error) {
|
||||||
|
isSubmitting.value = false
|
||||||
|
console.error('[Order] Confirm order error:', error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 验证订单
|
||||||
|
*/
|
||||||
|
function validateOrder(): boolean {
|
||||||
|
// 检查是否登录
|
||||||
|
if (!userInfo.value.id) {
|
||||||
|
uni.showToast({
|
||||||
|
title: t('login.agreeFirst'),
|
||||||
|
icon: 'none'
|
||||||
|
})
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// 虚拟币支付时检查余额
|
||||||
|
if (paymentMethod.value === '4') {
|
||||||
|
const coinPrice = (bookInfo.value.abroadPrice || 0) * 10
|
||||||
|
if (userCoinBalance.value < coinPrice) {
|
||||||
|
uni.showToast({
|
||||||
|
title: t('bookOrder.insufficientBalance'),
|
||||||
|
icon: 'none'
|
||||||
|
})
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建订单
|
||||||
|
*/
|
||||||
|
async function createOrder() {
|
||||||
|
try {
|
||||||
|
uni.showLoading({ title: t('bookOrder.creating') })
|
||||||
|
|
||||||
|
const res = await orderApi.createOrder({
|
||||||
|
paymentMethod: paymentMethod.value,
|
||||||
|
orderMoney: displayPrice.value,
|
||||||
|
abroadBookId: bookId.value,
|
||||||
|
orderType: 'abroadBook'
|
||||||
|
})
|
||||||
|
|
||||||
|
uni.hideLoading()
|
||||||
|
|
||||||
|
if (res.code === 0 && res.orderSn) {
|
||||||
|
orderSn.value = res.orderSn
|
||||||
|
|
||||||
|
// 根据支付方式执行相应流程
|
||||||
|
if (paymentMethod.value === '4') {
|
||||||
|
// 虚拟币支付
|
||||||
|
await processVirtualCoinPayment()
|
||||||
|
} else if (paymentMethod.value === '5') {
|
||||||
|
// Google Pay 支付
|
||||||
|
await processGooglePayment()
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
throw new Error(res.msg || t('bookOrder.orderCreateFailed'))
|
||||||
|
}
|
||||||
|
} catch (error: any) {
|
||||||
|
uni.hideLoading()
|
||||||
|
isSubmitting.value = false
|
||||||
|
uni.showToast({
|
||||||
|
title: error.message || t('bookOrder.orderCreateFailed'),
|
||||||
|
icon: 'none'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 处理虚拟币支付
|
||||||
|
*/
|
||||||
|
async function processVirtualCoinPayment() {
|
||||||
|
try {
|
||||||
|
// 虚拟币支付在订单创建时已完成
|
||||||
|
// 刷新用户信息
|
||||||
|
await refreshUserInfo()
|
||||||
|
|
||||||
|
// 显示支付成功
|
||||||
|
uni.showToast({
|
||||||
|
title: t('bookOrder.paymentSuccess'),
|
||||||
|
icon: 'success'
|
||||||
|
})
|
||||||
|
|
||||||
|
// 延迟跳转
|
||||||
|
setTimeout(() => {
|
||||||
|
navigateToBookDetail()
|
||||||
|
}, 1000)
|
||||||
|
} catch (error) {
|
||||||
|
isSubmitting.value = false
|
||||||
|
console.error('[Order] Virtual coin payment error:', error)
|
||||||
|
uni.showToast({
|
||||||
|
title: t('bookOrder.paymentFailed'),
|
||||||
|
icon: 'none'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 处理 Google Pay 支付
|
||||||
|
*/
|
||||||
|
async function processGooglePayment() {
|
||||||
|
try {
|
||||||
|
// 检查 Google Pay 连接状态
|
||||||
|
if (!googlePayConnected.value) {
|
||||||
|
throw new Error(t('bookOrder.googlePayNotAvailable'))
|
||||||
|
}
|
||||||
|
|
||||||
|
uni.showLoading({ title: t('bookOrder.processing') })
|
||||||
|
|
||||||
|
// 1. 查询商品 SKU
|
||||||
|
const skuList = await queryGooglePaySku()
|
||||||
|
|
||||||
|
if (skuList.length === 0) {
|
||||||
|
throw new Error(t('bookOrder.productNotFound'))
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. 调起 Google Pay 支付
|
||||||
|
const paymentResult = await initiateGooglePayment()
|
||||||
|
|
||||||
|
// 3. 消费购买凭证
|
||||||
|
await consumeGooglePayPurchase(paymentResult.purchaseToken)
|
||||||
|
|
||||||
|
// 4. 后端验证支付
|
||||||
|
await verifyGooglePayment(paymentResult)
|
||||||
|
|
||||||
|
// 5. 支付成功处理
|
||||||
|
await handlePaymentSuccess()
|
||||||
|
|
||||||
|
} catch (error: any) {
|
||||||
|
uni.hideLoading()
|
||||||
|
isSubmitting.value = false
|
||||||
|
|
||||||
|
console.error('[Order] Google Pay payment error:', error)
|
||||||
|
|
||||||
|
uni.showToast({
|
||||||
|
title: error.message || t('bookOrder.paymentFailed'),
|
||||||
|
icon: 'none',
|
||||||
|
duration: 2000
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询 Google Pay SKU
|
||||||
|
*/
|
||||||
|
function queryGooglePaySku(): Promise<any[]> {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
if (!googlePayPlugin) {
|
||||||
|
reject(new Error(t('bookOrder.googlePayNotAvailable')))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const productId = bookInfo.value.priceData?.dictType
|
||||||
|
if (!productId) {
|
||||||
|
reject(new Error(t('bookOrder.productNotFound')))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
googlePayPlugin.querySku(
|
||||||
|
{ inapp: [productId] },
|
||||||
|
(result: any) => {
|
||||||
|
console.log('[Google Pay] Query SKU result:', result)
|
||||||
|
|
||||||
|
if (result.code === 0 && result.list && result.list.length > 0) {
|
||||||
|
resolve(result.list)
|
||||||
|
} else {
|
||||||
|
reject(new Error(t('bookOrder.productNotFound')))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 调起 Google Pay 支付
|
||||||
|
*/
|
||||||
|
function initiateGooglePayment(): Promise<{ purchaseToken: string; productId: string }> {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
if (!googlePayPlugin) {
|
||||||
|
reject(new Error(t('bookOrder.googlePayNotAvailable')))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const productId = bookInfo.value.priceData?.dictType
|
||||||
|
|
||||||
|
googlePayPlugin.payAll(
|
||||||
|
{
|
||||||
|
accountId: orderSn.value,
|
||||||
|
productId: productId
|
||||||
|
},
|
||||||
|
(result: any) => {
|
||||||
|
console.log('[Google Pay] Payment result:', result)
|
||||||
|
|
||||||
|
if (result.code === 0 && result.data && result.data.length > 0) {
|
||||||
|
const purchaseToken = result.data[0].original.purchaseToken
|
||||||
|
resolve({ purchaseToken, productId })
|
||||||
|
} else {
|
||||||
|
// 支付失败或取消
|
||||||
|
reject(new Error(t('bookOrder.paymentCancelled')))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 消费 Google Pay 购买凭证
|
||||||
|
*/
|
||||||
|
function consumeGooglePayPurchase(purchaseToken: string): Promise<void> {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
if (!googlePayPlugin) {
|
||||||
|
reject(new Error(t('bookOrder.googlePayNotAvailable')))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
googlePayPlugin.consume(
|
||||||
|
{ purchaseToken },
|
||||||
|
(result: any) => {
|
||||||
|
console.log('[Google Pay] Consume result:', result)
|
||||||
|
|
||||||
|
if (result.code === 0) {
|
||||||
|
resolve()
|
||||||
|
} else {
|
||||||
|
reject(new Error(t('bookOrder.verificationFailed')))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 验证 Google Pay 支付
|
||||||
|
*/
|
||||||
|
async function verifyGooglePayment(paymentResult: { purchaseToken: string; productId: string }) {
|
||||||
|
try {
|
||||||
|
const res = await orderApi.verifyGooglePay({
|
||||||
|
purchaseToken: paymentResult.purchaseToken,
|
||||||
|
orderSn: orderSn.value,
|
||||||
|
productId: paymentResult.productId
|
||||||
|
})
|
||||||
|
|
||||||
|
if (res.code !== 0) {
|
||||||
|
throw new Error(res.msg || t('bookOrder.verificationFailed'))
|
||||||
|
}
|
||||||
|
} catch (error: any) {
|
||||||
|
throw new Error(error.message || t('bookOrder.verificationFailed'))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 支付成功处理
|
||||||
|
*/
|
||||||
|
async function handlePaymentSuccess() {
|
||||||
|
try {
|
||||||
|
// 刷新用户信息
|
||||||
|
await refreshUserInfo()
|
||||||
|
|
||||||
|
uni.hideLoading()
|
||||||
|
|
||||||
|
// 显示支付成功
|
||||||
|
uni.showToast({
|
||||||
|
title: t('bookOrder.paymentSuccess'),
|
||||||
|
icon: 'success'
|
||||||
|
})
|
||||||
|
|
||||||
|
// 延迟跳转
|
||||||
|
setTimeout(() => {
|
||||||
|
navigateToBookDetail()
|
||||||
|
}, 1000)
|
||||||
|
} catch (error) {
|
||||||
|
console.error('[Order] Payment success handler error:', error)
|
||||||
|
// 即使刷新用户信息失败,也跳转到详情页
|
||||||
|
setTimeout(() => {
|
||||||
|
navigateToBookDetail()
|
||||||
|
}, 1000)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 刷新用户信息
|
||||||
|
*/
|
||||||
|
async function refreshUserInfo() {
|
||||||
|
if (!userInfo.value.id) return
|
||||||
|
|
||||||
|
try {
|
||||||
|
const res = await orderApi.refreshUserInfo(userInfo.value.id)
|
||||||
|
if (res.code === 0 && res.user) {
|
||||||
|
userStore.setUserInfo(res.user)
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('[Order] Refresh user info error:', error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 跳转到图书详情页
|
||||||
|
*/
|
||||||
|
function navigateToBookDetail() {
|
||||||
|
uni.navigateTo({
|
||||||
|
url: `/pages/book/detail?id=${bookId.value}&page=order`
|
||||||
|
})
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.order-page {
|
||||||
|
min-height: 100vh;
|
||||||
|
background: #f7faf9;
|
||||||
|
}
|
||||||
|
|
||||||
|
.order-block {
|
||||||
|
margin: 20rpx;
|
||||||
|
padding: 30rpx;
|
||||||
|
background: #fff;
|
||||||
|
border-radius: 15rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.order-info {
|
||||||
|
margin-top: 20rpx;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
.order-img {
|
||||||
|
width: 180rpx;
|
||||||
|
height: 240rpx;
|
||||||
|
border-radius: 10rpx;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.order-name {
|
||||||
|
flex: 1;
|
||||||
|
color: #333;
|
||||||
|
font-size: 36rpx;
|
||||||
|
padding-left: 40rpx;
|
||||||
|
line-height: 44rpx;
|
||||||
|
max-height: 88rpx;
|
||||||
|
overflow: hidden;
|
||||||
|
display: -webkit-box;
|
||||||
|
-webkit-line-clamp: 2;
|
||||||
|
-webkit-box-orient: vertical;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.order-price {
|
||||||
|
padding-top: 40rpx;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
|
||||||
|
.price-display {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.coin-img {
|
||||||
|
width: 40rpx;
|
||||||
|
height: 40rpx;
|
||||||
|
margin-right: 10rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.coin-text {
|
||||||
|
font-size: 38rpx;
|
||||||
|
color: #ff4703;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.order-type {
|
||||||
|
background: #fff;
|
||||||
|
border-radius: 15rpx;
|
||||||
|
margin: 20rpx;
|
||||||
|
padding: 30rpx;
|
||||||
|
|
||||||
|
.radio-group {
|
||||||
|
margin-top: 30rpx;
|
||||||
|
padding-bottom: 10rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.type-label {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
margin-top: 10rpx;
|
||||||
|
|
||||||
|
.type-view {
|
||||||
|
width: 100%;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
line-height: 30rpx;
|
||||||
|
|
||||||
|
radio {
|
||||||
|
transform: scale(0.95);
|
||||||
|
}
|
||||||
|
|
||||||
|
text {
|
||||||
|
font-size: 30rpx;
|
||||||
|
padding-left: 5rpx;
|
||||||
|
color: #333;
|
||||||
|
|
||||||
|
.balance-text {
|
||||||
|
padding-left: 10rpx;
|
||||||
|
color: #54a966;
|
||||||
|
font-weight: normal;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.order-title {
|
||||||
|
font-size: 34rpx;
|
||||||
|
line-height: 50rpx;
|
||||||
|
padding-bottom: 10rpx;
|
||||||
|
color: #333;
|
||||||
|
}
|
||||||
|
|
||||||
|
.order-btn {
|
||||||
|
width: 100%;
|
||||||
|
height: 110rpx;
|
||||||
|
background: #fff;
|
||||||
|
position: fixed;
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
padding: 0 20rpx;
|
||||||
|
box-shadow: 0 -2rpx 10rpx rgba(0, 0, 0, 0.05);
|
||||||
|
|
||||||
|
.btn-spacer {
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.confirm-btn {
|
||||||
|
margin: 20rpx 0;
|
||||||
|
padding: 0 35rpx;
|
||||||
|
height: 70rpx;
|
||||||
|
line-height: 70rpx;
|
||||||
|
background-color: #ff4703;
|
||||||
|
color: #fff;
|
||||||
|
font-size: 30rpx;
|
||||||
|
border-radius: 10rpx;
|
||||||
|
border: none;
|
||||||
|
|
||||||
|
&[disabled] {
|
||||||
|
opacity: 0.6;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|||||||
@@ -158,11 +158,11 @@ const formatPrice = (book: IBookWithStats): string => {
|
|||||||
*/
|
*/
|
||||||
const formatStats = (book: IBookWithStats): string => {
|
const formatStats = (book: IBookWithStats): string => {
|
||||||
if (book.readCount && book.readCount > 0) {
|
if (book.readCount && book.readCount > 0) {
|
||||||
return `${book.readCount}${t('home.readingCount')}`
|
return `${book.readCount}${t('bookHome.readingCount')}`
|
||||||
}
|
}
|
||||||
|
|
||||||
if (book.buyCount && book.buyCount > 0) {
|
if (book.buyCount && book.buyCount > 0) {
|
||||||
return `${book.buyCount}${t('home.purchased')}`
|
return `${book.buyCount}${t('bookHome.purchased')}`
|
||||||
}
|
}
|
||||||
|
|
||||||
return ''
|
return ''
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
light
|
light
|
||||||
clearable
|
clearable
|
||||||
class="search-bar"
|
class="search-bar"
|
||||||
:placeholder="$t('course.searchPlaceholder')"
|
:placeholder="$t('courseHome.searchPlaceholder')"
|
||||||
@search="handleSearch"
|
@search="handleSearch"
|
||||||
/>
|
/>
|
||||||
<view class="icon-hua">
|
<view class="icon-hua">
|
||||||
@@ -64,7 +64,7 @@
|
|||||||
<view class="learnBox" v-if="learnList.length > 0">
|
<view class="learnBox" v-if="learnList.length > 0">
|
||||||
<view class="titleBox flexbox">
|
<view class="titleBox flexbox">
|
||||||
<image src="../../static/course/learing.png" mode="aspectFit"></image>
|
<image src="../../static/course/learing.png" mode="aspectFit"></image>
|
||||||
<text>{{ $t('course.watchHistory') }}</text>
|
<text>{{ $t('courseHome.watchHistory') }}</text>
|
||||||
</view>
|
</view>
|
||||||
<view class="learn flexbox">
|
<view class="learn flexbox">
|
||||||
<view
|
<view
|
||||||
@@ -120,7 +120,7 @@
|
|||||||
<view class="learnBox" v-if="tryListenList.length > 0">
|
<view class="learnBox" v-if="tryListenList.length > 0">
|
||||||
<view class="titleBox flexbox">
|
<view class="titleBox flexbox">
|
||||||
<image src="../../static/course/try_listen.png" mode="aspectFit"></image>
|
<image src="../../static/course/try_listen.png" mode="aspectFit"></image>
|
||||||
<text>{{ $t('course.tryListen') }}</text>
|
<text>{{ $t('courseHome.tryListen') }}</text>
|
||||||
</view>
|
</view>
|
||||||
<view class="learn flexbox shiting">
|
<view class="learn flexbox shiting">
|
||||||
<view
|
<view
|
||||||
@@ -143,14 +143,14 @@
|
|||||||
{{ item.title }}
|
{{ item.title }}
|
||||||
</view>
|
</view>
|
||||||
<view class="buybtn">
|
<view class="buybtn">
|
||||||
<span>{{ $t('course.buy') }}</span>
|
<span>{{ $t('courseHome.buy') }}</span>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
<view class="moreBox shiting">
|
<view class="moreBox shiting">
|
||||||
<text @click="onPageJump('/pages/course/tryListen', 1, $t('course.tryListen'))"
|
<text @click="onPageJump('/pages/course/tryListen', 1, $t('courseHome.tryListen'))"
|
||||||
>{{ $t('course.moreTryListen') }}</text
|
>{{ $t('courseHome.moreTryListen') }}</text
|
||||||
>
|
>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
|
|||||||
67
types/order.d.ts
vendored
Normal file
67
types/order.d.ts
vendored
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
// types/order.d.ts
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 订单创建参数接口
|
||||||
|
*/
|
||||||
|
export interface ICreateOrderParams {
|
||||||
|
paymentMethod: '4' | '5' // 支付方式: 4-虚拟币, 5-Google Pay
|
||||||
|
orderMoney: number | string // 订单金额
|
||||||
|
abroadBookId: number // 图书ID
|
||||||
|
orderType: 'abroadBook' // 订单类型
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Google Pay 验证参数接口
|
||||||
|
*/
|
||||||
|
export interface IGooglePayVerifyParams {
|
||||||
|
purchaseToken: string // 购买凭证
|
||||||
|
orderSn: string // 订单号
|
||||||
|
productId: string // 产品ID
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 订单创建响应接口
|
||||||
|
*/
|
||||||
|
export interface ICreateOrderResponse {
|
||||||
|
code: number
|
||||||
|
orderSn: string // 订单号
|
||||||
|
msg?: string
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Google Pay SKU 信息接口
|
||||||
|
*/
|
||||||
|
export interface IGooglePaySku {
|
||||||
|
productId: string
|
||||||
|
type: string
|
||||||
|
price: string
|
||||||
|
price_amount_micros: number
|
||||||
|
price_currency_code: string
|
||||||
|
title: string
|
||||||
|
description: string
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Google Pay 支付结果接口
|
||||||
|
*/
|
||||||
|
export interface IGooglePayResult {
|
||||||
|
code: number
|
||||||
|
data?: Array<{
|
||||||
|
original: {
|
||||||
|
purchaseToken: string
|
||||||
|
orderId: string
|
||||||
|
packageName: string
|
||||||
|
productId: string
|
||||||
|
purchaseTime: number
|
||||||
|
purchaseState: number
|
||||||
|
}
|
||||||
|
}>
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 支付方式选项接口
|
||||||
|
*/
|
||||||
|
export interface IPaymentOption {
|
||||||
|
value: '4' | '5'
|
||||||
|
name: string
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user