- 修改 ArticleController.java - 更新 application.yml 配置 - 更新 frontend/.env.production 环境配置 - 添加 single_uniapp22miao 小程序模块 - 添加 logs 目录
1100 lines
28 KiB
Vue
1100 lines
28 KiB
Vue
<template>
|
||
<view class="confirm-page">
|
||
<!-- 自定义导航栏 -->
|
||
<view class="custom-navbar">
|
||
<view class="nav-back" @click="goBack">
|
||
<text class="back-icon">‹</text>
|
||
</view>
|
||
<text class="nav-title">提交订单</text>
|
||
<view class="nav-placeholder"></view>
|
||
</view>
|
||
|
||
<!-- 主内容区 -->
|
||
<view class="main-content">
|
||
<!-- 收货地址 -->
|
||
<view class="section-card address-section" @click="onAddress">
|
||
<view class="section-header">
|
||
<text class="section-title">收货地址</text>
|
||
</view>
|
||
<view class="address-row">
|
||
<view v-if="addressInfo.id" class="address-content">
|
||
<view class="address-info">
|
||
<text class="receiver-name">{{ addressInfo.realName }}</text>
|
||
<text class="receiver-phone">{{ addressInfo.phone }}</text>
|
||
</view>
|
||
<view class="address-detail-row">
|
||
<!-- <text v-if="addressInfo.isDefault" class="default-tag">[默认]</text> -->
|
||
<text class="address-detail">{{ fullAddress }}</text>
|
||
</view>
|
||
</view>
|
||
<view v-else class="no-address">
|
||
<text>设置收货地址</text>
|
||
</view>
|
||
<!-- <view class="arrow-icon">
|
||
<text class="iconfont icon-jiantou">›</text>
|
||
</view> -->
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 商品信息 -->
|
||
<view class="section-card goods-section">
|
||
<view class="section-header">
|
||
<text class="section-title-bold">共计商品</text>
|
||
</view>
|
||
<view v-for="(item, index) in cartInfo" :key="index" class="goods-item">
|
||
<image :src="item.image" class="goods-image" mode="aspectFill" />
|
||
<view class="goods-info">
|
||
<text class="goods-name">{{ item.name || item.storeName }}</text>
|
||
<!-- <view class="goods-tags">
|
||
<text class="goods-tag">积分购买兑换</text>
|
||
</view> -->
|
||
<view class="goods-bottom">
|
||
<text class="goods-points">{{ item.points || item.integral }}积分</text>
|
||
<text class="goods-quantity">x {{ item.quantity || item.cartNum }}</text>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 使用积分 -->
|
||
<view class="section-card points-section" @click="toggleUseIntegral">
|
||
<view class="option-row">
|
||
<text class="option-label">使用积分</text>
|
||
<view class="option-value">
|
||
<text class="points-text">约为积分{{ totalIntegral }}</text>
|
||
<view class="checkbox" :class="{ checked: useIntegral }">
|
||
<text v-if="useIntegral" class="check-icon">✓</text>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 快递费用 -->
|
||
<view class="section-card express-section">
|
||
<view class="option-row">
|
||
<text class="option-label">快递费用</text>
|
||
<text class="express-free">免运费</text>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 商品数量 -->
|
||
<view class="section-card quantity-section">
|
||
<view class="option-row">
|
||
<text class="option-label">商品数量</text>
|
||
<text class="quantity-value">{{ orderProNum }}</text>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 底部提交栏 -->
|
||
<view class="submit-bar safe-area-inset-bottom">
|
||
<view class="total-section">
|
||
<text class="total-label">合计</text>
|
||
<view class="total-price-row">
|
||
<text class="total-price">{{ formatNumber(totalIntegral) }}积分</text>
|
||
<text class="balance-text">余额: {{ formatNumber(userIntegral) }}积分</text>
|
||
</view>
|
||
</view>
|
||
<view
|
||
class="submit-btn"
|
||
:class="{ disabled: submitting || !canSubmit }"
|
||
@click="SubOrder"
|
||
>
|
||
<text v-if="submitting">提交中...</text>
|
||
<text v-else>立即兑换</text>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</template>
|
||
|
||
<script>
|
||
import {
|
||
getCartList,
|
||
preOrderApi,
|
||
orderCreate,
|
||
orderPay,
|
||
loadPreOrderApi
|
||
} from '@/api/order.js'
|
||
import {
|
||
getAddressDetail,
|
||
getAddressDefault,
|
||
getAddressList,
|
||
getUserInfo
|
||
} from '@/api/user.js'
|
||
import { getProductDetail } from '@/api/store.js'
|
||
import { mapGetters } from "vuex"
|
||
import { toLogin } from '@/libs/login.js'
|
||
|
||
export default {
|
||
data() {
|
||
return {
|
||
// 页面来源
|
||
from: '',
|
||
// 商品ID
|
||
goodsId: 0,
|
||
// 购物车ID列表(从URL参数获取)
|
||
cartIds: '',
|
||
// 商品数量
|
||
quantity: 1,
|
||
// 商品列表
|
||
cartInfo: [],
|
||
// 商品总数
|
||
orderProNum: 0,
|
||
// 地址信息
|
||
addressInfo: {},
|
||
// 地址ID
|
||
addressId: 0,
|
||
// 地址变更ID(从地址选择页返回)
|
||
addressChangeId: 0,
|
||
// 用户积分余额
|
||
userIntegral: 0,
|
||
// 是否使用积分
|
||
useIntegral: true,
|
||
// 最大数量
|
||
maxQuantity: 50,
|
||
// 备注信息
|
||
mark: '',
|
||
// 提交中
|
||
submitting: false,
|
||
// 预下单订单号
|
||
preOrderNo: '',
|
||
// 支付渠道
|
||
payChannel: ''
|
||
}
|
||
},
|
||
|
||
computed: {
|
||
...mapGetters(['isLogin', 'userInfo']),
|
||
|
||
// 完整地址
|
||
fullAddress() {
|
||
if (!this.addressInfo.id) return ''
|
||
return `${this.addressInfo.province || ''}${this.addressInfo.city || ''}${this.addressInfo.district || ''}${this.addressInfo.detail || ''}`
|
||
},
|
||
|
||
// 总积分
|
||
totalIntegral() {
|
||
return this.cartInfo.reduce((sum, item) => {
|
||
const points = item.points || item.integral || 0
|
||
const num = item.quantity || item.cartNum || 1
|
||
return sum + points * num
|
||
}, 0)
|
||
},
|
||
|
||
// 是否可以提交
|
||
canSubmit() {
|
||
return this.addressInfo.id &&
|
||
this.cartInfo.length > 0 &&
|
||
this.userIntegral >= this.totalIntegral
|
||
}
|
||
},
|
||
|
||
watch: {
|
||
isLogin: {
|
||
handler: function(newV, oldV) {
|
||
if (newV) {
|
||
this.initPage()
|
||
}
|
||
},
|
||
deep: true
|
||
}
|
||
},
|
||
|
||
onLoad(options) {
|
||
// 设置支付渠道
|
||
// #ifdef H5
|
||
this.payChannel = this.$wechat && this.$wechat.isWeixin() ? 'public' : 'weixinh5'
|
||
// #endif
|
||
// #ifdef MP
|
||
this.payChannel = 'routine'
|
||
// #endif
|
||
// #ifdef APP-PLUS
|
||
this.payChannel = 'weixinAppAndroid'
|
||
// #endif
|
||
|
||
this.from = options.from || ''
|
||
this.goodsId = options.id || 0
|
||
this.cartIds = options.cartIds || '' // 获取购物车ID列表
|
||
this.quantity = parseInt(options.quantity) || 1
|
||
this.addressChangeId = options.addressId || 0
|
||
|
||
if (this.isLogin) {
|
||
this.initPage()
|
||
} else {
|
||
toLogin()
|
||
}
|
||
},
|
||
|
||
onShow() {
|
||
// 从地址选择页返回时更新地址
|
||
uni.$on('bindSelectAddress', (res) => {
|
||
if (res && res.addressId) {
|
||
this.addressId = res.addressId
|
||
this.getAddressInfo()
|
||
}
|
||
uni.$off('bindSelectAddress')
|
||
})
|
||
|
||
// 兼容 storage 方式
|
||
const selectedAddress = uni.getStorageSync('selected_address')
|
||
if (selectedAddress) {
|
||
this.addressInfo = selectedAddress
|
||
this.addressId = selectedAddress.id
|
||
uni.removeStorageSync('selected_address')
|
||
}
|
||
},
|
||
|
||
methods: {
|
||
// 返回上一页
|
||
goBack() {
|
||
uni.navigateBack()
|
||
},
|
||
|
||
// 格式化数字(添加千分位)
|
||
formatNumber(num) {
|
||
if (!num && num !== 0) return '0'
|
||
return num.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ',')
|
||
},
|
||
|
||
// 初始化页面
|
||
async initPage() {
|
||
// 加载商品数据
|
||
await this.loadGoodsData()
|
||
// 获取用户积分余额
|
||
this.getUserIntegral()
|
||
// 获取地址信息
|
||
if (this.addressChangeId) {
|
||
this.addressId = this.addressChangeId
|
||
this.getAddressInfo()
|
||
} else {
|
||
this.getDefaultAddress()
|
||
}
|
||
},
|
||
|
||
// 获取用户积分余额(从用户信息中获取)
|
||
async getUserIntegral() {
|
||
try {
|
||
// 优先从 vuex store 获取
|
||
if (this.userInfo && this.userInfo.integral !== undefined) {
|
||
this.userIntegral = this.userInfo.integral || 0
|
||
}
|
||
|
||
// 刷新用户信息获取最新积分
|
||
const res = await getUserInfo()
|
||
if (res.data) {
|
||
// 更新 vuex store
|
||
this.$store.commit('UPDATE_USERINFO', res.data)
|
||
this.userIntegral = res.data.integral || 0
|
||
}
|
||
} catch (error) {
|
||
console.error('获取用户积分失败:', error)
|
||
// 降级处理:尝试从本地存储获取
|
||
const userInfoCache = uni.getStorageSync('USER_INFO')
|
||
if (userInfoCache) {
|
||
const info = typeof userInfoCache === 'string' ? JSON.parse(userInfoCache) : userInfoCache
|
||
if (info && info.integral !== undefined) {
|
||
this.userIntegral = info.integral || 0
|
||
}
|
||
}
|
||
}
|
||
},
|
||
|
||
// 加载商品数据
|
||
async loadGoodsData() {
|
||
if (this.from === 'cart') {
|
||
// 从购物车来,读取选中的商品
|
||
await this.loadCartItems()
|
||
} else {
|
||
// 单个商品购买(包括有goodsId或有buy_now_goods缓存的情况)
|
||
await this.loadSingleItem()
|
||
}
|
||
},
|
||
|
||
// 加载购物车商品
|
||
async loadCartItems() {
|
||
// 解析选中的购物车ID列表
|
||
const selectedIds = this.cartIds ? this.cartIds.split(',').map(id => parseInt(id)) : []
|
||
console.log('选中的购物车ID:', selectedIds)
|
||
|
||
if (selectedIds.length === 0) {
|
||
// 尝试从缓存读取
|
||
const checkoutItems = uni.getStorageSync('checkout_items')
|
||
if (checkoutItems) {
|
||
this.parseCartItems(checkoutItems)
|
||
return
|
||
}
|
||
this.showTips('请选择商品')
|
||
setTimeout(() => uni.navigateBack(), 1500)
|
||
return
|
||
}
|
||
|
||
try {
|
||
uni.showLoading({ title: '加载中...' })
|
||
|
||
// 从API获取购物车列表
|
||
const res = await getCartList({
|
||
page: 1,
|
||
limit: 50,
|
||
isValid: true
|
||
})
|
||
|
||
console.log('购物车列表响应:', res)
|
||
|
||
if (res.data && res.data.list) {
|
||
const allItems = res.data.list || []
|
||
// 筛选出选中的商品
|
||
const selectedItems = allItems.filter(item => selectedIds.includes(item.id))
|
||
console.log('筛选后的商品:', selectedItems)
|
||
|
||
if (selectedItems.length > 0) {
|
||
this.parseCartItems(selectedItems)
|
||
} else {
|
||
this.showTips('未找到选中的商品')
|
||
setTimeout(() => uni.navigateBack(), 1500)
|
||
}
|
||
} else {
|
||
this.showTips('获取购物车失败')
|
||
}
|
||
} catch (error) {
|
||
console.error('加载购物车商品失败:', error)
|
||
this.showTips('加载商品失败')
|
||
} finally {
|
||
uni.hideLoading()
|
||
}
|
||
},
|
||
|
||
// 解析购物车商品数据
|
||
parseCartItems(items) {
|
||
const itemList = typeof items === 'string' ? JSON.parse(items) : items
|
||
this.cartInfo = itemList.map(item => {
|
||
// 积分字段优先级:vipPrice > price > integral > points
|
||
const pointsValue = item.vipPrice || item.price || item.integral || item.points || 0
|
||
return {
|
||
id: item.id,
|
||
goodsId: item.productId || item.goodsId || item.id,
|
||
name: item.storeName || item.name,
|
||
image: item.image || item.pic,
|
||
points: pointsValue,
|
||
integral: pointsValue,
|
||
quantity: item.cartNum || item.quantity || 1,
|
||
cartNum: item.cartNum || item.quantity || 1,
|
||
attrValueId: item.productAttrUnique || item.attrValueId || item.unique || ''
|
||
}
|
||
})
|
||
|
||
// 计算商品总数
|
||
this.orderProNum = this.cartInfo.reduce((sum, item) => {
|
||
return sum + (item.quantity || item.cartNum || 1)
|
||
}, 0)
|
||
|
||
console.log('解析后的商品列表:', this.cartInfo)
|
||
console.log('商品总数:', this.orderProNum)
|
||
},
|
||
|
||
// 加载单个商品
|
||
async loadSingleItem() {
|
||
// 从详情页传递的商品信息
|
||
const goodsInfo = uni.getStorageSync('buy_now_goods')
|
||
if (goodsInfo) {
|
||
try {
|
||
const goods = typeof goodsInfo === 'string' ? JSON.parse(goodsInfo) : goodsInfo
|
||
let attrValueId = goods.attrValueId || goods.unique || goods.productAttrUnique || ''
|
||
|
||
// 如果没有规格信息,获取商品默认规格
|
||
if (!attrValueId && (goods.id || this.goodsId)) {
|
||
attrValueId = await this.getDefaultAttrValueId(goods.id || this.goodsId)
|
||
}
|
||
|
||
this.cartInfo = [{
|
||
id: goods.id || this.goodsId,
|
||
goodsId: goods.id || this.goodsId,
|
||
name: goods.name || goods.storeName,
|
||
image: goods.image || goods.pic,
|
||
points: goods.points || goods.integral,
|
||
integral: goods.integral || goods.points,
|
||
quantity: this.quantity,
|
||
cartNum: this.quantity,
|
||
attrValueId: attrValueId
|
||
}]
|
||
this.orderProNum = this.quantity
|
||
// 使用后删除缓存
|
||
uni.removeStorageSync('buy_now_goods')
|
||
} catch (error) {
|
||
console.error('解析商品信息失败:', error)
|
||
this.showTips('商品信息加载失败')
|
||
}
|
||
} else if (this.goodsId) {
|
||
// 只有商品ID,需要获取商品详情
|
||
await this.fetchGoodsDetailAndSetCart()
|
||
} else {
|
||
// 没有商品信息,提示错误
|
||
this.showTips('请选择要购买的商品')
|
||
setTimeout(() => {
|
||
uni.navigateBack()
|
||
}, 1500)
|
||
}
|
||
},
|
||
|
||
// 获取商品默认规格ID
|
||
async getDefaultAttrValueId(productId) {
|
||
try {
|
||
const res = await getProductDetail(productId, 1)
|
||
if (res.data && res.data.productValue) {
|
||
const productValue = res.data.productValue
|
||
// 找到第一个有库存的规格
|
||
for (let key in productValue) {
|
||
if (productValue[key].stock > 0) {
|
||
return productValue[key].id || ''
|
||
}
|
||
}
|
||
// 如果都没库存,返回第一个规格
|
||
const firstKey = Object.keys(productValue)[0]
|
||
if (firstKey && productValue[firstKey]) {
|
||
return productValue[firstKey].id || ''
|
||
}
|
||
}
|
||
} catch (error) {
|
||
console.error('获取商品规格失败:', error)
|
||
}
|
||
return ''
|
||
},
|
||
|
||
// 获取商品详情并设置购物车
|
||
async fetchGoodsDetailAndSetCart() {
|
||
try {
|
||
uni.showLoading({ title: '加载中...' })
|
||
const res = await getProductDetail(this.goodsId, 1)
|
||
uni.hideLoading()
|
||
|
||
if (res.data && res.data.productInfo) {
|
||
const productInfo = res.data.productInfo
|
||
const productValue = res.data.productValue || {}
|
||
|
||
// 获取默认规格
|
||
let attrValueId = ''
|
||
let price = productInfo.price
|
||
let image = productInfo.image
|
||
|
||
for (let key in productValue) {
|
||
if (productValue[key].stock > 0) {
|
||
attrValueId = productValue[key].id || ''
|
||
price = productValue[key].price || price
|
||
image = productValue[key].image || image
|
||
break
|
||
}
|
||
}
|
||
|
||
// 如果没找到有库存的,用第一个
|
||
if (!attrValueId) {
|
||
const firstKey = Object.keys(productValue)[0]
|
||
if (firstKey && productValue[firstKey]) {
|
||
attrValueId = productValue[firstKey].id || ''
|
||
price = productValue[firstKey].price || price
|
||
}
|
||
}
|
||
|
||
this.cartInfo = [{
|
||
id: this.goodsId,
|
||
goodsId: this.goodsId,
|
||
name: productInfo.storeName,
|
||
image: image,
|
||
points: price,
|
||
integral: price,
|
||
quantity: this.quantity,
|
||
cartNum: this.quantity,
|
||
attrValueId: attrValueId
|
||
}]
|
||
this.orderProNum = this.quantity
|
||
} else {
|
||
throw new Error('商品信息不存在')
|
||
}
|
||
} catch (error) {
|
||
uni.hideLoading()
|
||
console.error('获取商品详情失败:', error)
|
||
this.showTips('商品信息加载失败')
|
||
setTimeout(() => {
|
||
uni.navigateBack()
|
||
}, 1500)
|
||
}
|
||
},
|
||
|
||
// 获取默认地址
|
||
async getDefaultAddress() {
|
||
try {
|
||
const res = await getAddressDefault()
|
||
if (res.data && res.data.id) {
|
||
this.addressInfo = res.data
|
||
this.addressId = res.data.id
|
||
} else {
|
||
// 如果没有默认地址,尝试获取地址列表中的第一个
|
||
const listRes = await getAddressList()
|
||
if (listRes.data && listRes.data.length > 0) {
|
||
const firstAddr = listRes.data[0]
|
||
this.addressInfo = firstAddr
|
||
this.addressId = firstAddr.id
|
||
}
|
||
}
|
||
} catch (error) {
|
||
console.error('获取默认地址失败:', error)
|
||
}
|
||
},
|
||
|
||
// 根据地址ID获取地址信息
|
||
async getAddressInfo() {
|
||
if (!this.addressId) return
|
||
try {
|
||
const res = await getAddressDetail(this.addressId)
|
||
if (res.data) {
|
||
this.addressInfo = res.data
|
||
}
|
||
} catch (error) {
|
||
console.error('获取地址详情失败:', error)
|
||
}
|
||
},
|
||
|
||
// 跳转选择地址
|
||
onAddress() {
|
||
uni.navigateTo({
|
||
url: '/pages/sub-pages/address/index?from=integral&cartId=' + (this.goodsId || '')
|
||
})
|
||
},
|
||
|
||
// 切换使用积分
|
||
toggleUseIntegral() {
|
||
this.useIntegral = !this.useIntegral
|
||
},
|
||
|
||
// 提交订单(参考 order_confirm 的 SubOrder 方法)
|
||
SubOrder() {
|
||
let that = this
|
||
|
||
// 验证收货地址
|
||
if (!that.addressId && !that.addressInfo.id) {
|
||
return that.showTips('请选择收货地址')
|
||
}
|
||
|
||
// 验证商品
|
||
if (that.cartInfo.length === 0) {
|
||
return that.showTips('请选择商品')
|
||
}
|
||
|
||
// 验证积分余额
|
||
if (that.userIntegral < that.totalIntegral) {
|
||
return that.showTips('积分余额不足')
|
||
}
|
||
|
||
// 防止重复提交
|
||
if (that.submitting) return
|
||
|
||
// 开始创建订单
|
||
that.createOrder()
|
||
},
|
||
|
||
// 创建订单(参考 order_confirm 使用 @api/order.js 接口)
|
||
async createOrder() {
|
||
this.submitting = true
|
||
uni.showLoading({ title: '提交中...', mask: true })
|
||
|
||
try {
|
||
// 第一步:创建预下单
|
||
const preOrderData = {
|
||
preOrderType: 'buyNow',
|
||
orderDetails: this.cartInfo.map(item => ({
|
||
productId: item.goodsId || item.id,
|
||
attrValueId: item.attrValueId || '',
|
||
productNum: item.quantity || item.cartNum || 1
|
||
}))
|
||
}
|
||
|
||
// 如果是从购物车来的,使用购物车ID
|
||
if (this.from === 'cart' && this.cartIds) {
|
||
preOrderData.preOrderType = 'shoppingCart'
|
||
preOrderData.orderDetails = this.cartInfo.map(item => ({
|
||
shoppingCartId: item.id,
|
||
productId: item.goodsId || item.id,
|
||
attrValueId: item.attrValueId || '',
|
||
productNum: item.quantity || item.cartNum || 1
|
||
}))
|
||
}
|
||
|
||
console.log('预下单数据:', preOrderData)
|
||
|
||
const preOrderRes = await preOrderApi(preOrderData)
|
||
console.log('预下单响应:', preOrderRes)
|
||
|
||
if (!preOrderRes.data || !preOrderRes.data.preOrderNo) {
|
||
throw new Error(preOrderRes.msg || '预下单失败')
|
||
}
|
||
|
||
this.preOrderNo = preOrderRes.data.preOrderNo
|
||
|
||
// 第二步:创建订单
|
||
const orderData = {
|
||
preOrderNo: this.preOrderNo,
|
||
addressId: this.addressId || this.addressInfo.id,
|
||
couponId: 0,
|
||
useIntegral: this.useIntegral, // 使用积分
|
||
mark: this.mark,
|
||
shippingType: 1, // 1=快递配送
|
||
storeId: 0
|
||
}
|
||
|
||
console.log('创建订单数据:', orderData)
|
||
|
||
const orderRes = await orderCreate(orderData)
|
||
console.log('创建订单响应:', orderRes)
|
||
|
||
if (!orderRes.data || !orderRes.data.orderNo) {
|
||
throw new Error(orderRes.msg || '创建订单失败')
|
||
}
|
||
|
||
const orderNo = orderRes.data.orderNo
|
||
|
||
// 第三步:使用积分支付(余额支付方式)
|
||
await this.payWithIntegral(orderNo)
|
||
|
||
} catch (error) {
|
||
uni.hideLoading()
|
||
console.error('创建订单失败:', error)
|
||
this.showTips(error.message || error.msg || '提交失败,请重试')
|
||
this.submitting = false
|
||
}
|
||
},
|
||
|
||
// 使用积分支付
|
||
async payWithIntegral(orderNo) {
|
||
try {
|
||
const payData = {
|
||
orderNo: orderNo,
|
||
payChannel: this.payChannel || 'public',
|
||
payType: 'yue', // 余额支付(积分支付)
|
||
scene: 0
|
||
}
|
||
|
||
console.log('支付数据:', payData)
|
||
|
||
const payRes = await orderPay(payData)
|
||
console.log('支付响应:', payRes)
|
||
|
||
uni.hideLoading()
|
||
|
||
// 清除购物车缓存
|
||
if (this.from === 'cart') {
|
||
uni.removeStorageSync('checkout_items')
|
||
}
|
||
uni.removeStorageSync('buy_now_goods')
|
||
|
||
// 判断支付结果
|
||
if (payRes.data && payRes.data.payType === 'yue') {
|
||
// 余额/积分支付成功
|
||
uni.showToast({
|
||
title: '兑换成功',
|
||
icon: 'success'
|
||
})
|
||
|
||
// 跳转到订单详情或订单列表
|
||
setTimeout(() => {
|
||
uni.redirectTo({
|
||
url: `/pages/integral/orders?status=-99`
|
||
})
|
||
}, 1500)
|
||
} else {
|
||
throw new Error(payRes.msg || '支付失败')
|
||
}
|
||
|
||
} catch (error) {
|
||
uni.hideLoading()
|
||
console.error('支付失败:', error)
|
||
this.showTips(error.message || error.msg || '支付失败,请重试')
|
||
} finally {
|
||
this.submitting = false
|
||
}
|
||
},
|
||
|
||
// 显示提示
|
||
showTips(title) {
|
||
if (this.$util && this.$util.Tips) {
|
||
return this.$util.Tips({ title: title })
|
||
} else {
|
||
uni.showToast({
|
||
title: title,
|
||
icon: 'none'
|
||
})
|
||
}
|
||
}
|
||
}
|
||
}
|
||
</script>
|
||
|
||
<style lang="scss" scoped>
|
||
// 主题色变量
|
||
$primary-color: #F54900;
|
||
$text-primary: #0A0A0A;
|
||
$text-secondary: #4A5565;
|
||
$text-tertiary: #6A7282;
|
||
$text-muted: #99A1AF;
|
||
$bg-color: #F9FAFB;
|
||
$card-bg: #FFFFFF;
|
||
$border-color: rgba(0, 0, 0, 0.1);
|
||
|
||
.confirm-page {
|
||
min-height: 100vh;
|
||
background-color: $card-bg;
|
||
display: flex;
|
||
flex-direction: column;
|
||
}
|
||
|
||
// 自定义导航栏
|
||
.custom-navbar {
|
||
background-color: $card-bg;
|
||
height: 112rpx;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
padding: 0 32rpx;
|
||
border-bottom: 1rpx solid $border-color;
|
||
flex-shrink: 0;
|
||
}
|
||
|
||
.nav-back {
|
||
width: 72rpx;
|
||
height: 64rpx;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
border-radius: 16rpx;
|
||
|
||
.back-icon {
|
||
font-size: 56rpx;
|
||
color: $text-primary;
|
||
font-weight: 300;
|
||
line-height: 1;
|
||
}
|
||
}
|
||
|
||
.nav-title {
|
||
flex: 1;
|
||
font-size: 32rpx;
|
||
color: $text-primary;
|
||
font-weight: 400;
|
||
text-align: center;
|
||
}
|
||
|
||
.nav-placeholder {
|
||
width: 72rpx;
|
||
}
|
||
|
||
// 主内容区
|
||
.main-content {
|
||
flex: 1;
|
||
background-color: $bg-color;
|
||
padding: 0 32rpx;
|
||
padding-bottom: 180rpx;
|
||
}
|
||
|
||
// 卡片通用样式
|
||
.section-card {
|
||
margin-top: 24rpx;
|
||
padding: 32rpx;
|
||
background-color: $card-bg;
|
||
border-radius: 20rpx;
|
||
|
||
&:first-child {
|
||
margin-top: 24rpx;
|
||
}
|
||
}
|
||
|
||
.section-header {
|
||
margin-bottom: 0;
|
||
}
|
||
|
||
.section-title {
|
||
font-size: 32rpx;
|
||
font-weight: 400;
|
||
color: $text-primary;
|
||
}
|
||
|
||
.section-title-bold {
|
||
font-size: 36rpx;
|
||
font-weight: 500;
|
||
color: $text-primary;
|
||
}
|
||
|
||
// 收货地址
|
||
.address-section {
|
||
padding: 32rpx;
|
||
}
|
||
|
||
.address-row {
|
||
display: flex;
|
||
align-items: flex-start;
|
||
margin-top: 24rpx;
|
||
}
|
||
|
||
.address-content {
|
||
flex: 1;
|
||
}
|
||
|
||
.address-info {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 24rpx;
|
||
margin-bottom: 8rpx;
|
||
|
||
.receiver-name {
|
||
font-size: 30rpx;
|
||
font-weight: 500;
|
||
color: $text-primary;
|
||
}
|
||
|
||
.receiver-phone {
|
||
font-size: 28rpx;
|
||
color: $text-secondary;
|
||
}
|
||
}
|
||
|
||
.address-detail-row {
|
||
display: flex;
|
||
align-items: flex-start;
|
||
|
||
.default-tag {
|
||
font-size: 24rpx;
|
||
color: $primary-color;
|
||
margin-right: 12rpx;
|
||
flex-shrink: 0;
|
||
}
|
||
}
|
||
|
||
.address-detail {
|
||
font-size: 28rpx;
|
||
color: $text-secondary;
|
||
line-height: 1.5;
|
||
}
|
||
|
||
.no-address {
|
||
flex: 1;
|
||
|
||
text {
|
||
font-size: 28rpx;
|
||
color: $text-tertiary;
|
||
}
|
||
}
|
||
|
||
.arrow-icon {
|
||
width: 40rpx;
|
||
height: 40rpx;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
margin-top: 8rpx;
|
||
|
||
.iconfont, .icon-jiantou {
|
||
font-size: 36rpx;
|
||
color: $text-tertiary;
|
||
font-weight: 300;
|
||
}
|
||
}
|
||
|
||
// 商品信息
|
||
.goods-section {
|
||
padding: 32rpx;
|
||
}
|
||
|
||
.goods-item {
|
||
display: flex;
|
||
gap: 24rpx;
|
||
margin-top: 24rpx;
|
||
|
||
&:first-child {
|
||
margin-top: 24rpx;
|
||
}
|
||
}
|
||
|
||
.goods-image {
|
||
width: 160rpx;
|
||
height: 160rpx;
|
||
border-radius: 8rpx;
|
||
background-color: #F5F5F5;
|
||
flex-shrink: 0;
|
||
}
|
||
|
||
.goods-info {
|
||
flex: 1;
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: 8rpx;
|
||
min-height: 160rpx;
|
||
}
|
||
|
||
.goods-name {
|
||
font-size: 28rpx;
|
||
color: $text-primary;
|
||
font-weight: 500;
|
||
line-height: 1.4;
|
||
display: -webkit-box;
|
||
-webkit-box-orient: vertical;
|
||
-webkit-line-clamp: 1;
|
||
line-clamp: 1;
|
||
overflow: hidden;
|
||
}
|
||
|
||
.goods-tags {
|
||
margin-top: 0;
|
||
}
|
||
|
||
.goods-tag {
|
||
font-size: 28rpx;
|
||
color: $text-tertiary;
|
||
}
|
||
|
||
.goods-bottom {
|
||
display: flex;
|
||
justify-content: space-between;
|
||
align-items: center;
|
||
margin-top: auto;
|
||
}
|
||
|
||
.goods-points {
|
||
font-size: 32rpx;
|
||
font-weight: 400;
|
||
color: $primary-color;
|
||
}
|
||
|
||
.goods-quantity {
|
||
font-size: 32rpx;
|
||
color: $text-tertiary;
|
||
}
|
||
|
||
// 使用积分
|
||
.points-section {
|
||
padding: 32rpx;
|
||
}
|
||
|
||
.option-row {
|
||
display: flex;
|
||
justify-content: space-between;
|
||
align-items: center;
|
||
}
|
||
|
||
.option-label {
|
||
font-size: 32rpx;
|
||
font-weight: 400;
|
||
color: $text-primary;
|
||
}
|
||
|
||
.option-value {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 16rpx;
|
||
}
|
||
|
||
.points-text {
|
||
font-size: 32rpx;
|
||
color: $primary-color;
|
||
}
|
||
|
||
.checkbox {
|
||
width: 40rpx;
|
||
height: 40rpx;
|
||
border: 3rpx solid $primary-color;
|
||
border-radius: 50%;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
|
||
&.checked {
|
||
background-color: transparent;
|
||
border-color: $primary-color;
|
||
}
|
||
|
||
.check-icon {
|
||
color: $primary-color;
|
||
font-size: 24rpx;
|
||
font-weight: 600;
|
||
}
|
||
}
|
||
|
||
// 快递费用
|
||
.express-section {
|
||
padding: 32rpx;
|
||
}
|
||
|
||
.express-free {
|
||
font-size: 32rpx;
|
||
}
|
||
|
||
// 商品数量
|
||
.quantity-section {
|
||
padding: 32rpx;
|
||
}
|
||
|
||
.quantity-value {
|
||
font-size: 32rpx;
|
||
font-weight: 400;
|
||
color: $text-primary;
|
||
}
|
||
|
||
// 底部提交栏
|
||
.submit-bar {
|
||
position: fixed;
|
||
left: 0;
|
||
right: 0;
|
||
bottom: 0;
|
||
background-color: $card-bg;
|
||
border-top: 1rpx solid $border-color;
|
||
padding: 24rpx 32rpx;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
z-index: 100;
|
||
padding-bottom: calc(24rpx + constant(safe-area-inset-bottom));
|
||
padding-bottom: calc(24rpx + env(safe-area-inset-bottom));
|
||
}
|
||
|
||
.total-section {
|
||
display: flex;
|
||
flex-direction: column;
|
||
}
|
||
|
||
.total-label {
|
||
font-size: 28rpx;
|
||
color: $text-tertiary;
|
||
line-height: 1.4;
|
||
}
|
||
|
||
.total-price-row {
|
||
display: flex;
|
||
align-items: baseline;
|
||
gap: 16rpx;
|
||
}
|
||
|
||
.total-price {
|
||
font-size: 40rpx;
|
||
font-weight: 500;
|
||
color: $primary-color;
|
||
line-height: 1.4;
|
||
}
|
||
|
||
.balance-text {
|
||
font-size: 24rpx;
|
||
color: $text-muted;
|
||
}
|
||
|
||
.submit-btn {
|
||
background-color: $primary-color;
|
||
color: $card-bg;
|
||
font-size: 28rpx;
|
||
font-weight: 500;
|
||
padding: 24rpx 64rpx;
|
||
border-radius: 16rpx;
|
||
|
||
&.disabled {
|
||
background-color: #CCCCCC;
|
||
}
|
||
|
||
&:active {
|
||
opacity: 0.9;
|
||
}
|
||
}
|
||
</style>
|