补充提交
This commit is contained in:
parent
fddeeb0bc7
commit
a3e1bc98f4
|
|
@ -0,0 +1,845 @@
|
|||
<template>
|
||||
<view class="payment">
|
||||
<u-navbar
|
||||
title="缴费"
|
||||
:border-bottom="false"
|
||||
back-icon-color="#333"
|
||||
title-color="#333"
|
||||
:background="{ background: '#FFFFFF' }"
|
||||
/>
|
||||
|
||||
<view class="payment-content">
|
||||
<!-- 缴费金额输入 -->
|
||||
<view class="amount-section">
|
||||
<view class="section-title">缴费金额</view>
|
||||
<view class="amount-input-wrapper">
|
||||
<text class="currency">¥</text>
|
||||
<input
|
||||
class="amount-input"
|
||||
type="digit"
|
||||
v-model="amount"
|
||||
placeholder="请输入缴费金额"
|
||||
placeholder-class="placeholder"
|
||||
/>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 缴费说明 -->
|
||||
<view class="remark-section">
|
||||
<view class="section-title">缴费说明(选填)</view>
|
||||
<textarea
|
||||
class="remark-input"
|
||||
v-model="remark"
|
||||
placeholder="请输入缴费说明"
|
||||
placeholder-class="placeholder"
|
||||
maxlength="100"
|
||||
/>
|
||||
<text class="remark-count">{{ remark.length }}/100</text>
|
||||
</view>
|
||||
|
||||
<!-- 支付方式 -->
|
||||
<view class="payway-section">
|
||||
<view class="section-title">支付方式</view>
|
||||
<view class="payway-list">
|
||||
<view
|
||||
class="payway-item"
|
||||
v-for="item in payWayList"
|
||||
:key="item.pay_way"
|
||||
:class="{ active: selectedPayWay === item.pay_way }"
|
||||
@click="selectPayWay(item.pay_way)"
|
||||
>
|
||||
<view class="payway-info">
|
||||
<u-icon
|
||||
:name="getPayWayIcon(item.pay_way)"
|
||||
size="48"
|
||||
:color="getPayWayColor(item.pay_way)"
|
||||
/>
|
||||
<text class="payway-name">{{ item.name }}</text>
|
||||
</view>
|
||||
<view class="payway-check">
|
||||
<u-icon
|
||||
v-if="selectedPayWay === item.pay_way"
|
||||
name="checkmark-circle-fill"
|
||||
size="40"
|
||||
color="#3B82F6"
|
||||
/>
|
||||
<view v-else class="check-circle"></view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 底部提交按钮 -->
|
||||
<view class="footer">
|
||||
<view class="total-amount">
|
||||
<text class="label">合计:</text>
|
||||
<text class="currency">¥</text>
|
||||
<text class="amount">{{ amount || '0.00' }}</text>
|
||||
</view>
|
||||
<view
|
||||
class="submit-btn"
|
||||
:class="{ disabled: !canSubmit }"
|
||||
@click="handleSubmit"
|
||||
>
|
||||
立即缴费
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 支付密码弹窗 -->
|
||||
<u-popup v-model="showPasswordPopup" mode="center" border-radius="20">
|
||||
<view class="password-popup">
|
||||
<view class="popup-title">请输入支付密码</view>
|
||||
<u-message-input
|
||||
mode="box"
|
||||
:maxlength="6"
|
||||
:focus="true"
|
||||
v-model="password"
|
||||
@finish="onPasswordFinish"
|
||||
/>
|
||||
<view class="popup-cancel" @click="showPasswordPopup = false">
|
||||
取消
|
||||
</view>
|
||||
</view>
|
||||
</u-popup>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, computed, onMounted } from 'vue'
|
||||
import { getPayWay, prepay, getPayResult, alipayJspay, wechatJspay, unifiedTradeQuery } from '@/api/pay'
|
||||
import { useUserStore } from '@/stores/user'
|
||||
import config from '@/config'
|
||||
|
||||
const userStore = useUserStore()
|
||||
|
||||
// 支付配置
|
||||
const paymentConfig = config.payment
|
||||
|
||||
// 数据
|
||||
const amount = ref('')
|
||||
const remark = ref('')
|
||||
const payWayList = ref<any[]>([])
|
||||
const selectedPayWay = ref('')
|
||||
const showPasswordPopup = ref(false)
|
||||
const password = ref('')
|
||||
const orderId = ref('')
|
||||
|
||||
// 计算属性
|
||||
const canSubmit = computed(() => {
|
||||
const numAmount = parseFloat(amount.value)
|
||||
return numAmount > 0 && selectedPayWay.value
|
||||
})
|
||||
|
||||
// 获取支付方式 - 使用内置的开放银行支付方式
|
||||
const getPayWayData = async () => {
|
||||
// 直接设置开放银行支持的支付方式
|
||||
payWayList.value = [
|
||||
{
|
||||
pay_way: 'wechat',
|
||||
name: '微信支付'
|
||||
},
|
||||
{
|
||||
pay_way: 'alipay',
|
||||
name: '支付宝支付'
|
||||
}
|
||||
]
|
||||
selectedPayWay.value = 'wechat'
|
||||
}
|
||||
|
||||
// 选择支付方式
|
||||
const selectPayWay = (payWay: string) => {
|
||||
selectedPayWay.value = payWay
|
||||
}
|
||||
|
||||
// 获取支付方式图标
|
||||
const getPayWayIcon = (payWay: string) => {
|
||||
const iconMap: Record<string, string> = {
|
||||
'wechat': 'weixin-fill',
|
||||
'alipay': 'zhifubao-circle-fill',
|
||||
'balance': 'rmb-circle-fill'
|
||||
}
|
||||
return iconMap[payWay] || 'rmb-circle-fill'
|
||||
}
|
||||
|
||||
// 获取支付方式颜色
|
||||
const getPayWayColor = (payWay: string) => {
|
||||
const colorMap: Record<string, string> = {
|
||||
'wechat': '#07C160',
|
||||
'alipay': '#1677FF',
|
||||
'balance': '#FF6B00'
|
||||
}
|
||||
return colorMap[payWay] || '#999'
|
||||
}
|
||||
|
||||
// 提交缴费
|
||||
const handleSubmit = () => {
|
||||
if (!canSubmit.value) return
|
||||
|
||||
const numAmount = parseFloat(amount.value)
|
||||
if (numAmount <= 0) {
|
||||
uni.showToast({ title: '请输入有效的缴费金额', icon: 'none' })
|
||||
return
|
||||
}
|
||||
|
||||
// 余额支付需要输入密码
|
||||
if (selectedPayWay.value === 'balance') {
|
||||
showPasswordPopup.value = true
|
||||
return
|
||||
}
|
||||
|
||||
doPay()
|
||||
}
|
||||
|
||||
// 密码输入完成
|
||||
const onPasswordFinish = () => {
|
||||
showPasswordPopup.value = false
|
||||
doPay()
|
||||
}
|
||||
|
||||
// 执行支付
|
||||
const doPay = async () => {
|
||||
try {
|
||||
uni.showLoading({ title: '支付中...' })
|
||||
|
||||
const params: any = {
|
||||
pay_way: selectedPayWay.value,
|
||||
amount: parseFloat(amount.value),
|
||||
remark: remark.value
|
||||
}
|
||||
|
||||
if (selectedPayWay.value === 'balance') {
|
||||
params.password = password.value
|
||||
}
|
||||
|
||||
const res = await prepay(params)
|
||||
|
||||
if (res && res.order_id) {
|
||||
orderId.value = res.order_id
|
||||
|
||||
// 微信支付 - 开放银行微信支付
|
||||
if (selectedPayWay.value === 'wechat' && res.pay_params) {
|
||||
await wechatJspayPay(res.pay_params)
|
||||
}
|
||||
// 支付宝支付 - 开放银行服务窗支付
|
||||
else if (selectedPayWay.value === 'alipay' && res.pay_params) {
|
||||
await alipayJspayPay(res.pay_params)
|
||||
}
|
||||
// 余额支付直接成功
|
||||
else {
|
||||
uni.hideLoading()
|
||||
goToResult(true)
|
||||
}
|
||||
} else {
|
||||
throw new Error('支付参数错误')
|
||||
}
|
||||
} catch (error: any) {
|
||||
uni.hideLoading()
|
||||
uni.showToast({ title: error.message || '支付失败', icon: 'none' })
|
||||
password.value = ''
|
||||
}
|
||||
}
|
||||
|
||||
// 微信支付
|
||||
const wechatPay = (payParams: any) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
// #ifdef MP-WEIXIN
|
||||
uni.requestPayment({
|
||||
provider: 'wxpay',
|
||||
...payParams,
|
||||
success: () => {
|
||||
resolve(true)
|
||||
checkPayResult()
|
||||
},
|
||||
fail: (err: any) => {
|
||||
reject(err)
|
||||
goToResult(false)
|
||||
}
|
||||
})
|
||||
// #endif
|
||||
|
||||
// #ifdef H5
|
||||
if (payParams.mweb_url) {
|
||||
window.location.href = payParams.mweb_url
|
||||
} else if (payParams.jsapi_params) {
|
||||
// JSAPI支付
|
||||
const { appId, timeStamp, nonceStr, package: packageStr, signType, paySign } = payParams.jsapi_params
|
||||
if (typeof WeixinJSBridge !== 'undefined') {
|
||||
WeixinJSBridge.invoke(
|
||||
'getBrandWCPayRequest',
|
||||
{ appId, timeStamp, nonceStr, package: packageStr, signType, paySign },
|
||||
(res: any) => {
|
||||
if (res.err_msg === 'get_brand_wcpay_request:ok') {
|
||||
resolve(true)
|
||||
checkPayResult()
|
||||
} else {
|
||||
reject(res)
|
||||
goToResult(false)
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
// #endif
|
||||
|
||||
// #ifdef APP-PLUS
|
||||
uni.requestPayment({
|
||||
provider: 'wxpay',
|
||||
orderInfo: payParams,
|
||||
success: () => {
|
||||
resolve(true)
|
||||
checkPayResult()
|
||||
},
|
||||
fail: (err: any) => {
|
||||
reject(err)
|
||||
goToResult(false)
|
||||
}
|
||||
})
|
||||
// #endif
|
||||
})
|
||||
}
|
||||
|
||||
// 支付宝支付
|
||||
const alipay = (payParams: any) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
// #ifdef H5
|
||||
if (payParams.form) {
|
||||
const div = document.createElement('div')
|
||||
div.innerHTML = payParams.form
|
||||
document.body.appendChild(div)
|
||||
div.querySelector('form')?.submit()
|
||||
}
|
||||
// #endif
|
||||
|
||||
// #ifdef APP-PLUS
|
||||
uni.requestPayment({
|
||||
provider: 'alipay',
|
||||
orderInfo: payParams.order_str,
|
||||
success: () => {
|
||||
resolve(true)
|
||||
checkPayResult()
|
||||
},
|
||||
fail: (err: any) => {
|
||||
reject(err)
|
||||
goToResult(false)
|
||||
}
|
||||
})
|
||||
// #endif
|
||||
})
|
||||
}
|
||||
// 开放银行支付宝服务窗支付
|
||||
const alipayJspayPay = async (payParams: any) => {
|
||||
try {
|
||||
// 构建开放银行支付请求参数
|
||||
const params = {
|
||||
version: '3.0',
|
||||
charset: 'UTF-8',
|
||||
service: 'pay.alipay.jspay',
|
||||
mch_id: paymentConfig.mch_id, // 商户号
|
||||
out_trade_no: orderId.value,
|
||||
total_fee: String(Math.round(parseFloat(amount.value) * 100)), // 金额转换为分
|
||||
body: remark.value || '缴费支付',
|
||||
mch_create_ip: '127.0.0.1', // 需要获取真实IP
|
||||
notify_url: paymentConfig.alipay.notify_url,
|
||||
buyer_logon_id: '', // 买家支付宝账号(可选)
|
||||
'terminal_info.terminal_type': '11', // 终端类型
|
||||
'terminal_info.terminal_id': paymentConfig.terminal_id,
|
||||
'terminal_info.app_version': '1.000000'
|
||||
}
|
||||
|
||||
const res = await alipayJspay(params)
|
||||
|
||||
// 检查返回结果
|
||||
if (res && res.status === '0' && res.result_code === '0') {
|
||||
// 解析 pay_info
|
||||
const payInfo = JSON.parse(res.pay_info || '{}')
|
||||
|
||||
if (payInfo.tradeNO) {
|
||||
// #ifdef APP-PLUS
|
||||
// APP 环境使用 tradeNO 唤起支付宝
|
||||
uni.requestPayment({
|
||||
provider: 'alipay',
|
||||
orderInfo: {
|
||||
tradeNO: payInfo.tradeNO
|
||||
},
|
||||
success: () => {
|
||||
checkPayResult()
|
||||
},
|
||||
fail: (err: any) => {
|
||||
console.error('支付宝支付失败:', err)
|
||||
goToResult(false)
|
||||
}
|
||||
})
|
||||
// #endif
|
||||
|
||||
// #ifdef H5
|
||||
// H5 支付宝服务窗支付
|
||||
// 方式1:使用 pay_url 跳转
|
||||
if (res.pay_url) {
|
||||
window.location.href = res.pay_url
|
||||
return
|
||||
}
|
||||
// 方式2:使用 tradeNO 唤起支付宝
|
||||
if (payInfo.tradeNO && typeof AlipayJSBridge !== 'undefined') {
|
||||
AlipayJSBridge.call('tradePay', {
|
||||
tradeNO: payInfo.tradeNO
|
||||
}, (result: any) => {
|
||||
if (result.resultCode === '9000') {
|
||||
checkPayResult()
|
||||
} else {
|
||||
goToResult(false)
|
||||
}
|
||||
})
|
||||
}
|
||||
// #endif
|
||||
} else {
|
||||
throw new Error('获取支付参数失败')
|
||||
}
|
||||
} else {
|
||||
throw new Error(res.err_msg || res.message || '支付请求失败')
|
||||
}
|
||||
} catch (error: any) {
|
||||
console.error('开放银行支付错误:', error)
|
||||
uni.showToast({ title: error.message || '支付请求失败', icon: 'none' })
|
||||
goToResult(false)
|
||||
}
|
||||
}
|
||||
|
||||
// 开放银行微信支付(JSPay)
|
||||
const wechatJspayPay = async (payParams: any) => {
|
||||
try {
|
||||
// 构建开放银行微信支付请求参数
|
||||
const params: any = {
|
||||
version: '3.0',
|
||||
charset: 'UTF-8',
|
||||
service: 'pay.weixin.jspay',
|
||||
mch_id: paymentConfig.mch_id, // 商户号
|
||||
out_trade_no: orderId.value,
|
||||
total_fee: String(Math.round(parseFloat(amount.value) * 100)), // 金额转换为分
|
||||
body: remark.value || '缴费支付',
|
||||
mch_create_ip: '127.0.0.1', // 需要获取真实IP
|
||||
notify_url: paymentConfig.wechat.notify_url,
|
||||
'terminal_info.terminal_type': '11', // 终端类型
|
||||
'terminal_info.terminal_id': paymentConfig.terminal_id,
|
||||
'terminal_info.app_version': '1.000000'
|
||||
}
|
||||
|
||||
// 公众号/小程序支付需要 sub_appid 和 sub_openid
|
||||
// #ifdef MP-WEIXIN
|
||||
params.is_minipg = '1' // 小程序支付标识
|
||||
params.sub_appid = paymentConfig.wechat.sub_appid // 小程序 appid
|
||||
// 获取用户 openid
|
||||
const openid = userStore.userInfo?.openid || ''
|
||||
if (openid) {
|
||||
params.sub_openid = openid
|
||||
}
|
||||
// #endif
|
||||
|
||||
// #ifdef H5
|
||||
// H5 公众号支付 - 用户在微信内打开网页
|
||||
params.is_raw = '1' // 原生态 JS 支付
|
||||
params.sub_appid = paymentConfig.wechat.sub_appid // 公众号 appid
|
||||
// 获取用户 openid(如果在微信内)
|
||||
const openid = userStore.userInfo?.openid || ''
|
||||
if (openid) {
|
||||
params.sub_openid = openid
|
||||
}
|
||||
// #endif
|
||||
|
||||
const res = await wechatJspay(params)
|
||||
|
||||
// 检查返回结果
|
||||
if (res && res.status === '0' && res.result_code === '0') {
|
||||
const payInfo = res.pay_info
|
||||
|
||||
if (payInfo) {
|
||||
// #ifdef MP-WEIXIN
|
||||
// 小程序支付 - 解析 XML 格式的 pay_info
|
||||
const payParams = parseXmlPayInfo(payInfo)
|
||||
if (payParams) {
|
||||
uni.requestPayment({
|
||||
provider: 'wxpay',
|
||||
...payParams,
|
||||
success: () => {
|
||||
checkPayResult()
|
||||
},
|
||||
fail: (err: any) => {
|
||||
console.error('微信支付失败:', err)
|
||||
goToResult(false)
|
||||
}
|
||||
})
|
||||
} else {
|
||||
throw new Error('解析支付参数失败')
|
||||
}
|
||||
// #endif
|
||||
|
||||
// #ifdef H5
|
||||
// H5 公众号支付 - 解析 XML 格式的 pay_info
|
||||
const payParams = parseXmlPayInfo(payInfo)
|
||||
if (payParams && typeof WeixinJSBridge !== 'undefined') {
|
||||
WeixinJSBridge.invoke(
|
||||
'getBrandWCPayRequest',
|
||||
payParams,
|
||||
(res: any) => {
|
||||
if (res.err_msg === 'get_brand_wcpay_request:ok') {
|
||||
checkPayResult()
|
||||
} else {
|
||||
goToResult(false)
|
||||
}
|
||||
}
|
||||
)
|
||||
} else if (payParams) {
|
||||
// 使用 uni.requestPayment
|
||||
uni.requestPayment({
|
||||
provider: 'wxpay',
|
||||
...payParams,
|
||||
success: () => {
|
||||
checkPayResult()
|
||||
},
|
||||
fail: (err: any) => {
|
||||
console.error('微信支付失败:', err)
|
||||
goToResult(false)
|
||||
}
|
||||
})
|
||||
} else {
|
||||
throw new Error('解析支付参数失败')
|
||||
}
|
||||
// #endif
|
||||
|
||||
// #ifdef APP-PLUS
|
||||
// APP 环境
|
||||
uni.requestPayment({
|
||||
provider: 'wxpay',
|
||||
orderInfo: payInfo,
|
||||
success: () => {
|
||||
checkPayResult()
|
||||
},
|
||||
fail: (err: any) => {
|
||||
console.error('微信支付失败:', err)
|
||||
goToResult(false)
|
||||
}
|
||||
})
|
||||
// #endif
|
||||
} else {
|
||||
throw new Error('获取支付参数失败')
|
||||
}
|
||||
} else {
|
||||
throw new Error(res.err_msg || res.message || '支付请求失败')
|
||||
}
|
||||
} catch (error: any) {
|
||||
console.error('开放银行微信支付错误:', error)
|
||||
uni.showToast({ title: error.message || '支付请求失败', icon: 'none' })
|
||||
goToResult(false)
|
||||
}
|
||||
}
|
||||
|
||||
// 解析 XML 格式的支付参数
|
||||
const parseXmlPayInfo = (xmlStr: string) => {
|
||||
try {
|
||||
// 简单的 XML 解析
|
||||
const getValue = (xml: string, tag: string) => {
|
||||
const regex = new RegExp(`<${tag}><!\[CDATA\[(.*?)\]\]></${tag}>|<${tag}>(.*?)</${tag}>`, 'i')
|
||||
const match = xml.match(regex)
|
||||
return match ? (match[1] || match[2]) : ''
|
||||
}
|
||||
|
||||
return {
|
||||
appId: getValue(xmlStr, 'appId'),
|
||||
timeStamp: getValue(xmlStr, 'timeStamp'),
|
||||
nonceStr: getValue(xmlStr, 'nonceStr'),
|
||||
package: getValue(xmlStr, 'package'),
|
||||
signType: getValue(xmlStr, 'signType') || 'RSA',
|
||||
paySign: getValue(xmlStr, 'paySign')
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('解析 XML 失败:', error)
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
// 查询支付结果 - 使用开放银行订单查询接口
|
||||
const checkPayResult = async () => {
|
||||
try {
|
||||
uni.showLoading({ title: '查询中...' })
|
||||
|
||||
// 构建订单查询参数
|
||||
const params = {
|
||||
version: '3.0',
|
||||
service: 'unified.trade.query',
|
||||
mch_id: paymentConfig.mch_id, // 商户号
|
||||
out_trade_no: orderId.value
|
||||
}
|
||||
|
||||
const res = await unifiedTradeQuery(params)
|
||||
|
||||
uni.hideLoading()
|
||||
|
||||
// 检查查询结果
|
||||
if (res && res.status === '0' && res.result_code === '0') {
|
||||
// trade_state: SUCCESS-支付成功, REFUND-转入退款, NOTPAY-未支付,
|
||||
// CLOSED-已关闭, REVOKED-已撤销, USERPAYING-用户支付中, PAYERROR-支付失败
|
||||
const tradeState = res.trade_state
|
||||
|
||||
if (tradeState === 'SUCCESS') {
|
||||
// 支付成功
|
||||
goToResult(true)
|
||||
} else if (tradeState === 'NOTPAY' || tradeState === 'USERPAYING') {
|
||||
// 未支付或支付中,可以轮询查询
|
||||
uni.showToast({ title: '支付处理中,请稍后...', icon: 'none' })
|
||||
// 3秒后再次查询
|
||||
setTimeout(() => {
|
||||
checkPayResult()
|
||||
}, 3000)
|
||||
} else {
|
||||
// 其他状态视为失败
|
||||
goToResult(false)
|
||||
}
|
||||
} else {
|
||||
// 查询失败,使用备用查询方式
|
||||
console.error('开放银行订单查询失败:', res)
|
||||
await fallbackCheckPayResult()
|
||||
}
|
||||
} catch (error) {
|
||||
uni.hideLoading()
|
||||
console.error('查询支付结果错误:', error)
|
||||
// 使用备用查询方式
|
||||
await fallbackCheckPayResult()
|
||||
}
|
||||
}
|
||||
|
||||
// 备用查询方式 - 使用原系统接口
|
||||
const fallbackCheckPayResult = async () => {
|
||||
try {
|
||||
const res = await getPayResult({ order_id: orderId.value })
|
||||
if (res && res.pay_status === 1) {
|
||||
goToResult(true)
|
||||
} else {
|
||||
goToResult(false)
|
||||
}
|
||||
} catch (error) {
|
||||
goToResult(false)
|
||||
}
|
||||
}
|
||||
|
||||
// 跳转到结果页
|
||||
const goToResult = (success: boolean) => {
|
||||
uni.redirectTo({
|
||||
url: `/pages/payment_result/payment_result?status=${success ? 'success' : 'fail'}&order_id=${orderId.value}`
|
||||
})
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
getPayWayData()
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.payment {
|
||||
min-height: 100vh;
|
||||
background-color: #F5F7FA;
|
||||
padding-bottom: calc(180rpx + env(safe-area-inset-bottom));
|
||||
}
|
||||
|
||||
.payment-content {
|
||||
padding: 20rpx;
|
||||
}
|
||||
|
||||
.section-title {
|
||||
font-size: 28rpx;
|
||||
color: #666;
|
||||
margin-bottom: 20rpx;
|
||||
}
|
||||
|
||||
// 金额输入区域
|
||||
.amount-section {
|
||||
background: #FFFFFF;
|
||||
border-radius: 20rpx;
|
||||
padding: 30rpx;
|
||||
margin-bottom: 20rpx;
|
||||
|
||||
.amount-input-wrapper {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
border-bottom: 2rpx solid #E5E7EB;
|
||||
padding: 20rpx 0;
|
||||
|
||||
.currency {
|
||||
font-size: 60rpx;
|
||||
font-weight: 600;
|
||||
color: #333;
|
||||
margin-right: 20rpx;
|
||||
}
|
||||
|
||||
.amount-input {
|
||||
flex: 1;
|
||||
font-size: 60rpx;
|
||||
font-weight: 600;
|
||||
color: #333;
|
||||
height: 80rpx;
|
||||
}
|
||||
|
||||
.placeholder {
|
||||
font-size: 40rpx;
|
||||
color: #999;
|
||||
font-weight: normal;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 备注区域
|
||||
.remark-section {
|
||||
background: #FFFFFF;
|
||||
border-radius: 20rpx;
|
||||
padding: 30rpx;
|
||||
margin-bottom: 20rpx;
|
||||
position: relative;
|
||||
|
||||
.remark-input {
|
||||
width: 100%;
|
||||
height: 160rpx;
|
||||
font-size: 28rpx;
|
||||
color: #333;
|
||||
line-height: 1.6;
|
||||
}
|
||||
|
||||
.placeholder {
|
||||
font-size: 28rpx;
|
||||
color: #999;
|
||||
}
|
||||
|
||||
.remark-count {
|
||||
position: absolute;
|
||||
right: 30rpx;
|
||||
bottom: 20rpx;
|
||||
font-size: 24rpx;
|
||||
color: #999;
|
||||
}
|
||||
}
|
||||
|
||||
// 支付方式区域
|
||||
.payway-section {
|
||||
background: #FFFFFF;
|
||||
border-radius: 20rpx;
|
||||
padding: 30rpx;
|
||||
|
||||
.payway-list {
|
||||
.payway-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 30rpx 0;
|
||||
border-bottom: 2rpx solid #F3F4F6;
|
||||
|
||||
&:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
&.active {
|
||||
.payway-name {
|
||||
color: #333;
|
||||
font-weight: 500;
|
||||
}
|
||||
}
|
||||
|
||||
.payway-info {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
.payway-name {
|
||||
font-size: 30rpx;
|
||||
color: #666;
|
||||
margin-left: 20rpx;
|
||||
}
|
||||
}
|
||||
|
||||
.payway-check {
|
||||
.check-circle {
|
||||
width: 40rpx;
|
||||
height: 40rpx;
|
||||
border: 2rpx solid #D1D5DB;
|
||||
border-radius: 50%;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 底部区域
|
||||
.footer {
|
||||
position: fixed;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background: #FFFFFF;
|
||||
padding: 20rpx 30rpx;
|
||||
padding-bottom: calc(20rpx + env(safe-area-inset-bottom));
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
box-shadow: 0 -4rpx 20rpx rgba(0, 0, 0, 0.05);
|
||||
|
||||
.total-amount {
|
||||
display: flex;
|
||||
align-items: baseline;
|
||||
|
||||
.label {
|
||||
font-size: 28rpx;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.currency {
|
||||
font-size: 32rpx;
|
||||
color: #FF6B00;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.amount {
|
||||
font-size: 48rpx;
|
||||
color: #FF6B00;
|
||||
font-weight: 600;
|
||||
}
|
||||
}
|
||||
|
||||
.submit-btn {
|
||||
background: linear-gradient(135deg, #3B82F6 0%, #2563EB 100%);
|
||||
color: #FFFFFF;
|
||||
font-size: 32rpx;
|
||||
font-weight: 500;
|
||||
padding: 24rpx 60rpx;
|
||||
border-radius: 40rpx;
|
||||
|
||||
&:active {
|
||||
opacity: 0.9;
|
||||
}
|
||||
|
||||
&.disabled {
|
||||
background: #D1D5DB;
|
||||
color: #9CA3AF;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 密码弹窗
|
||||
.password-popup {
|
||||
width: 600rpx;
|
||||
padding: 40rpx;
|
||||
background: #FFFFFF;
|
||||
border-radius: 20rpx;
|
||||
|
||||
.popup-title {
|
||||
font-size: 32rpx;
|
||||
font-weight: 500;
|
||||
color: #333;
|
||||
text-align: center;
|
||||
margin-bottom: 40rpx;
|
||||
}
|
||||
|
||||
.popup-cancel {
|
||||
font-size: 28rpx;
|
||||
color: #999;
|
||||
text-align: center;
|
||||
margin-top: 40rpx;
|
||||
padding: 20rpx;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
Loading…
Reference in New Issue