Files
apple 079076a70e miao33: 从 main 同步 single_uniapp22miao,dart-sass 兼容修复,DEPLOY.md 更新
- 从 main 获取 single_uniapp22miao 子项目
- dart-sass: /deep/ -> ::v-deep,calc 运算符加空格
- DEPLOY.md 采用 shccd159 版本(4 子项目架构说明)

Made-with: Cursor
2026-03-16 11:16:42 +08:00

1100 lines
28 KiB
Vue
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<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>