897 lines
21 KiB
Vue
897 lines
21 KiB
Vue
<template>
|
||
<view class="container">
|
||
<!-- 设备信息卡片 -->
|
||
<view class="card device-info-card">
|
||
<view class="device-location">
|
||
<view class="location-left">
|
||
<image src="/static/images/location-map.svg" mode="aspectFit" class="location-icon"></image>
|
||
<text class="location-name">{{ deviceLocation }}</text>
|
||
</view>
|
||
<view class="device-status" :class="deviceStatus.class">
|
||
<text class="status-text">{{ deviceStatus.text }}</text>
|
||
</view>
|
||
</view>
|
||
<view class="device-id">
|
||
<text class="id-label">设备号:</text>
|
||
<text class="id-value">{{ deviceId }}</text>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 计费规则 -->
|
||
<view class="card pricing-card">
|
||
<view class="card-header">
|
||
<text class="card-title">计费规则</text>
|
||
</view>
|
||
|
||
<view class="pricing-banner">
|
||
<view class="pricing-main">
|
||
<text class="price-symbol">¥</text>
|
||
<text class="price">{{ deviceFeeConfig.maxHourPrice || '5.00' }}</text>
|
||
<text class="unit">/小时</text>
|
||
</view>
|
||
<view class="cap-badge">
|
||
<text class="cap-text">{{ deviceInfo.depositAmount || '99' }}元封顶</text>
|
||
</view>
|
||
</view>
|
||
|
||
<view class="pricing-info">
|
||
<view class="info-icon">
|
||
<text class="icon-text">ⓘ</text>
|
||
</view>
|
||
<text class="info-text">5元/小时,45元/24小时</text>
|
||
</view>
|
||
<view class="pricing-info">
|
||
<view class="info-icon">
|
||
<text class="icon-text">ⓘ</text>
|
||
</view>
|
||
<text class="info-text">前15分钟内归还免费,不足60分钟按60分钟计费点总封顶99元,持续计费至99元视为买断</text>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 使用说明 -->
|
||
<view class="card notice-card">
|
||
<view class="card-header">
|
||
<text class="card-title">使用说明</text>
|
||
</view>
|
||
<view class="notice-items">
|
||
<view class="notice-item">
|
||
<view class="notice-dot"></view>
|
||
<text class="notice-text">请在使用前检查设备是否完好</text>
|
||
</view>
|
||
<view class="notice-item">
|
||
<view class="notice-dot"></view>
|
||
<text class="notice-text">超出使用时间将自动按小时计费</text>
|
||
</view>
|
||
<view class="notice-item">
|
||
<view class="notice-dot"></view>
|
||
<text class="notice-text">请在指定区域内使用设备</text>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 底部操作区 -->
|
||
<view class="footer">
|
||
<button class="rent-button" :class="{ 'return-button': hasActiveOrder }"
|
||
@click="handleRent('wx-score-pay')">
|
||
<text>{{ hasActiveOrder ? '归还设备' : '免押金租借' }}</text>
|
||
</button>
|
||
<view class="wechat-credit">
|
||
<image src="/static/images/wxpayflag.png" mode="aspectFit" class="wx-icon"></image>
|
||
<text class="credit-text">微信支付分 <text class="divider">|</text> 550分以上优享</text>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 手机号授权弹窗 -->
|
||
<view class="phone-auth-popup" v-if="showPhoneAuthPopup">
|
||
<view class="popup-mask" @click.stop></view>
|
||
<view class="popup-content">
|
||
<view class="popup-header">
|
||
<text class="popup-title">授权获取手机号</text>
|
||
</view>
|
||
<view class="popup-body">
|
||
<view class="auth-desc">
|
||
<text>为了提供更好的服务,需要授权获取您的手机号</text>
|
||
</view>
|
||
<button class="auth-btn" open-type="getPhoneNumber" @getphonenumber="onGetPhoneNumber">
|
||
一键获取手机号
|
||
</button>
|
||
<view class="auth-cancel" @click="showPhoneAuthPopup = false">
|
||
<text>暂不授权</text>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</template>
|
||
|
||
<script setup>
|
||
import {
|
||
ref,
|
||
reactive,
|
||
onMounted
|
||
} from 'vue'
|
||
import {
|
||
onLoad,
|
||
onShow
|
||
} from '@dcloudio/uni-app'
|
||
import {
|
||
getDeviceInfo,
|
||
rentPowerBank,
|
||
getOrderByOrderNoScore,
|
||
getOrderByOrderNoScorePayStatus,
|
||
getOrderByOrderNo,
|
||
updateOrderPackage,
|
||
cancelOrder
|
||
} from '@/config/user.js'
|
||
import {
|
||
URL
|
||
} from "@/config/url.js"
|
||
import {
|
||
initiateWeChatScorePayment,
|
||
getUserInfo,
|
||
getUserPhoneNumber
|
||
} from '@/util/index.js'
|
||
|
||
// 响应式状态
|
||
const deviceInfo = ref({})
|
||
const deviceId = ref('')
|
||
const deviceFeeConfig = ref({})
|
||
const deviceLocation = ref('一号教学楼大厅')
|
||
const batteryLevel = ref(95)
|
||
const hasActiveOrder = ref(false)
|
||
const deviceStatus = reactive({
|
||
text: '可使用',
|
||
class: 'available'
|
||
})
|
||
const isLoggedIn = ref(true)
|
||
const phoneNumber = ref('')
|
||
const showPhoneAuthPopup = ref(false)
|
||
|
||
// 生命周期 onLoad 钩子
|
||
onLoad(async (options) => {
|
||
if (options.deviceNo != uni.getStorageSync('deviceId') || !uni.getStorageSync('deviceId')) {
|
||
deviceId.value = options.deviceNo
|
||
uni.setStorageSync('deviceId', options.deviceNo)
|
||
} else {
|
||
deviceId.value = uni.getStorageSync('deviceId')
|
||
// uni.removeStorageSync('deviceId')
|
||
}
|
||
await checkOrderStatus()
|
||
await fetchDeviceInfo()
|
||
})
|
||
|
||
onMounted(async () => {
|
||
await checkUserPhone()
|
||
await fetchDeviceInfo()
|
||
})
|
||
|
||
// onShow(async () => {
|
||
// await fetchDeviceInfo()
|
||
// })
|
||
|
||
const checkUserPhone = async () => {
|
||
try {
|
||
const userInfoRes = await getUserInfo()
|
||
console.log(userInfoRes.data.phone, 'getUserInfoPhone')
|
||
|
||
if (userInfoRes.code == 200 && userInfoRes.data && userInfoRes.data.phone) {
|
||
phoneNumber.value = userInfoRes.data.phone
|
||
} else {
|
||
// 如果没有手机号,显示授权弹窗
|
||
showPhoneAuthPopup.value = true
|
||
}
|
||
} catch (error) {
|
||
console.error('获取用户信息失败:', error)
|
||
}
|
||
}
|
||
|
||
// 处理获取手机号
|
||
const onGetPhoneNumber = (e) => {
|
||
console.log('getPhoneNumber event:', e.detail)
|
||
|
||
// 用户拒绝授权的情况
|
||
if (e.detail.errMsg && e.detail.errMsg.includes('deny')) {
|
||
uni.showToast({
|
||
title: '需要授权手机号才能使用设备',
|
||
icon: 'none'
|
||
})
|
||
return
|
||
}
|
||
|
||
// 获取到授权code
|
||
if (e.detail.code) {
|
||
uni.showLoading({
|
||
title: '获取中...'
|
||
})
|
||
|
||
console.log('获取到的授权code:', e.detail.code)
|
||
|
||
// 添加 try-catch 以捕获任何 Promise 外部的错误
|
||
try {
|
||
getUserPhoneNumber(e.detail.code)
|
||
.then(res => {
|
||
console.log('获取手机号API响应原始数据:', JSON.stringify(res))
|
||
uni.hideLoading()
|
||
|
||
// 不立即抛出错误,而是记录问题并继续处理
|
||
if (!res) {
|
||
console.error('API返回数据为空')
|
||
uni.showModal({
|
||
title: '数据异常',
|
||
content: 'API返回为空',
|
||
showCancel: false
|
||
})
|
||
return
|
||
}
|
||
|
||
// 检查响应格式
|
||
console.log('响应code:', res.code, '响应类型:', typeof res.code)
|
||
console.log('是否有data:', !!res.data, '是否有phone:', res.data && !!res.data.phone)
|
||
|
||
if (res.code == 200 && res.data && res.data.phoneNumber) {
|
||
phoneNumber.value = res.data.phoneNumber
|
||
showPhoneAuthPopup.value = false
|
||
|
||
uni.showToast({
|
||
title: '手机号获取成功',
|
||
icon: 'success'
|
||
})
|
||
} else {
|
||
// 记录详细信息,不抛出错误
|
||
console.warn('获取手机号响应异常:', res.msg || '未知错误')
|
||
uni.showModal({
|
||
title: '获取手机号异常',
|
||
content: `状态码: ${res.code}, 消息: ${res.msg || '无'}`,
|
||
showCancel: false
|
||
})
|
||
}
|
||
})
|
||
.catch(err => {
|
||
uni.hideLoading()
|
||
console.error('获取手机号码失败(catch):', err)
|
||
|
||
// 显示更详细的错误信息
|
||
let errMsg = err.message || err.toString()
|
||
uni.showModal({
|
||
title: '获取手机号失败',
|
||
content: '错误信息: ' + errMsg,
|
||
showCancel: false
|
||
})
|
||
})
|
||
} catch (outerError) {
|
||
uni.hideLoading()
|
||
console.error('获取手机号外部错误:', outerError)
|
||
uni.showModal({
|
||
title: '意外错误',
|
||
content: '处理过程发生异常: ' + (outerError.message || outerError),
|
||
showCancel: false
|
||
})
|
||
}
|
||
} else {
|
||
uni.showToast({
|
||
title: '获取授权码失败',
|
||
icon: 'none'
|
||
})
|
||
}
|
||
}
|
||
|
||
// 检查登录状态和订单
|
||
const fetchDeviceInfo = async () => {
|
||
const res = await getDeviceInfo(deviceId.value)
|
||
if (res.code == 200) {
|
||
deviceInfo.value = res.data.device || {}
|
||
|
||
// 更新设备位置信息
|
||
if (deviceInfo.value.deviceLocation) {
|
||
deviceLocation.value = deviceInfo.value.deviceLocation
|
||
} else if (res.data.position && res.data.position.name) {
|
||
deviceLocation.value = res.data.position.name
|
||
}
|
||
|
||
// 更新设备状态
|
||
if (deviceInfo.value.status) {
|
||
if (deviceInfo.value.status === 'online') {
|
||
deviceStatus.text = '可使用'
|
||
deviceStatus.class = 'available'
|
||
} else if (deviceInfo.value.status === 'offline') {
|
||
deviceStatus.text = '离线'
|
||
deviceStatus.class = 'offline'
|
||
}
|
||
}
|
||
if (deviceInfo.value.feeConfig) {
|
||
deviceFeeConfig.value = JSON.parse(deviceInfo.value.feeConfig)[0] || {}
|
||
} else {
|
||
deviceFeeConfig.value = {
|
||
maxHourPrice: '5.00',
|
||
}
|
||
discount.value = '99.00'
|
||
}
|
||
|
||
}
|
||
}
|
||
|
||
// 显示登录提示
|
||
const showLoginTip = () => {
|
||
uni.showModal({
|
||
title: '提示',
|
||
content: '请先登录后再操作',
|
||
confirmText: '去登录',
|
||
success: (res) => {
|
||
if (res.confirm) {
|
||
uni.navigateTo({
|
||
url: '/pages/login/index'
|
||
})
|
||
}
|
||
}
|
||
})
|
||
}
|
||
|
||
// 检查订单状态
|
||
const checkOrderStatus = async () => {
|
||
try {
|
||
// 调用接口检查是否有进行中的订单
|
||
const result = await uni.$api.checkActiveOrder()
|
||
|
||
if (result.hasOrder) {
|
||
const order = result.order // 假设后端返回 order 对象
|
||
|
||
// 检查订单状态
|
||
if (order.status === 'waiting_for_payment') {
|
||
// 跳转支付页面,带上订单ID
|
||
uni.redirectTo({
|
||
url: `/pages/order/payment?orderId=${order.orderId}&deviceId=${deviceId.value}`
|
||
})
|
||
} else if (order.status === 'in_used') {
|
||
// 如果有正在进行的订单,跳转到归还页面,带上设备ID
|
||
uni.redirectTo({
|
||
url: `/pages/device/return?deviceId=${deviceId.value}`
|
||
})
|
||
}
|
||
}
|
||
} catch (error) {
|
||
uni.showToast({
|
||
title: '订单状态查询失败',
|
||
icon: 'none'
|
||
})
|
||
}
|
||
}
|
||
|
||
// 处理租借操作
|
||
const handleRent = (payWay) => {
|
||
if (!isLoggedIn.value) {
|
||
showLoginTip()
|
||
return
|
||
}
|
||
|
||
// 检查是否有手机号,如果没有则提示授权
|
||
if (!phoneNumber.value) {
|
||
showPhoneAuthPopup.value = true
|
||
return
|
||
}
|
||
|
||
// 提交订单
|
||
submitRentOrder(payWay)
|
||
}
|
||
|
||
const selectedPkg = reactive({
|
||
time: '1小时',
|
||
price: '5.00'
|
||
})
|
||
const depositAmount = ref('99.00')
|
||
|
||
// 提交租借订单
|
||
const submitRentOrder = async (payWay) => {
|
||
try {
|
||
// --- 第一步:先请求订阅消息(必须在用户点击的同步上下文中)---
|
||
if (payWay === 'wx-score-pay') {
|
||
console.log('准备请求订阅消息(在异步操作之前),时间:', new Date().toLocaleTimeString());
|
||
try {
|
||
await new Promise((resolve, reject) => {
|
||
uni.requestSubscribeMessage({
|
||
tmplIds: ['o7OMTIcHnFBR7mvsggxFtdt8FfIgSl-v0swVUefGx6w'],
|
||
success: (subscribeRes) => {
|
||
console.log('订阅消息success回调,时间:', new Date()
|
||
.toLocaleTimeString(), subscribeRes);
|
||
resolve(subscribeRes);
|
||
},
|
||
fail: (subscribeErr) => {
|
||
console.log('订阅消息fail回调,时间:', new Date().toLocaleTimeString(),
|
||
subscribeErr);
|
||
// 订阅失败不影响主流程
|
||
resolve(subscribeErr);
|
||
}
|
||
});
|
||
});
|
||
console.log('订阅消息完成,时间:', new Date().toLocaleTimeString());
|
||
} catch (subscribeError) {
|
||
console.log('订阅消息异常', subscribeError);
|
||
}
|
||
}
|
||
// --- 订阅消息请求完成 ---
|
||
|
||
uni.showLoading({
|
||
title: '处理中'
|
||
})
|
||
console.log(deviceId.value);
|
||
// 调用设备租借接口
|
||
const rentResult = await rentPowerBank(deviceId.value, phoneNumber.value)
|
||
if (rentResult.code !== 200) {
|
||
throw new Error(rentResult.msg || '设备租借失败')
|
||
}
|
||
|
||
// 获取后端返回的订单信息
|
||
const order = rentResult.data
|
||
console.log('订单信息', order);
|
||
|
||
// // --- 统一:先更新订单套餐信息 ---
|
||
// try {
|
||
// let packageTimeMinutes = 0;
|
||
// if (selectedPkg.time.includes('小时')) {
|
||
// packageTimeMinutes = parseInt(selectedPkg.time) * 60;
|
||
// } else if (selectedPkg.time.includes('分钟')) {
|
||
// packageTimeMinutes = parseInt(selectedPkg.time);
|
||
// } else {
|
||
// packageTimeMinutes = parseInt(selectedPkg.time) * 60; // 默认按小时处理
|
||
// }
|
||
|
||
// const updateRes = await updateOrderPackage({
|
||
// orderId: order.orderId,
|
||
// packageTime: packageTimeMinutes,
|
||
// packagePrice: parseFloat(selectedPkg.price)
|
||
// });
|
||
// if (updateRes.code !== 200) {
|
||
// console.warn("更新订单套餐信息失败:", updateRes.msg);
|
||
// // 这里可以选择是否提示用户或阻止流程,当前不阻止
|
||
// } else {
|
||
// console.log("订单套餐信息已提前更新");
|
||
// }
|
||
// } catch (updateError) {
|
||
// console.error("更新订单套餐信息时出错:", updateError);
|
||
// // 即使更新失败,也继续流程
|
||
// }
|
||
// --- 套餐信息更新结束 ---
|
||
|
||
if (payWay == 'wx-pay') {
|
||
//当支付方式为押金支付时
|
||
uni.hideLoading()
|
||
const res = await getOrderByOrderNo(order.orderNo);
|
||
console.log(res);
|
||
// --- 新增:计算总金额 ---
|
||
const deposit = parseFloat(order.depositAmount);
|
||
const packagePrice = parseFloat(order.unitPrice);
|
||
const totalAmount = deposit.toFixed(2);
|
||
// --- 计算结束 ---
|
||
|
||
uni.hideLoading()
|
||
|
||
// 跳转到订单支付页面,传递订单ID、套餐信息和总金额
|
||
uni.redirectTo({
|
||
url: `/pages/order/payment?orderId=${order.orderId}&packageTimeHours=${selectedPkg.time.replace('小时', '')}&packagePrice=${packagePrice}&totalAmount=${totalAmount}&depositAmount=${depositAmount.value}${deviceInfo.value && deviceInfo.value.feeConfig ? '&feeConfig=' + encodeURIComponent(deviceInfo.value.feeConfig) : ''}`
|
||
})
|
||
|
||
} else if (payWay == 'wx-score-pay') {
|
||
// 当支付方式为支付分支付时
|
||
uni.hideLoading()
|
||
// 获取支付分所需参数
|
||
const res = await getOrderByOrderNoScore(order.orderNo);
|
||
uni.hideLoading()
|
||
|
||
if (res && res.code === 200) {
|
||
try {
|
||
// 调用微信支付分小程序
|
||
const payResult = await initiateWeChatScorePayment(res);
|
||
// 成功则跳转等待页,轮询在等待页处理
|
||
if (payResult.errCode == '0') {
|
||
console.log('支付分授权成功,准备跳转,时间:', new Date().toLocaleTimeString());
|
||
// 直接跳转(订阅消息已经在前面完成了)
|
||
uni.redirectTo({
|
||
url: `/pages/waiting/index?orderNo=${order.orderNo}&deviceId=${deviceId.value}`
|
||
});
|
||
return;
|
||
}
|
||
// 用户取消等其他情况,不做特殊处理
|
||
} catch (payError) {
|
||
uni.showToast({
|
||
title: '支付分调用失败,请重试',
|
||
icon: 'none'
|
||
});
|
||
}
|
||
} else {
|
||
uni.showToast({
|
||
title: res?.msg || '获取支付参数失败',
|
||
icon: 'none'
|
||
});
|
||
}
|
||
}
|
||
} catch (error) {
|
||
uni.hideLoading()
|
||
uni.showToast({
|
||
title: error.message || '租借失败,请重试',
|
||
icon: 'none'
|
||
})
|
||
}
|
||
}
|
||
</script>
|
||
|
||
<style lang="scss" scoped>
|
||
.container {
|
||
min-height: 100vh;
|
||
background-color: #f5f7fa;
|
||
padding: 30rpx 30rpx 300rpx;
|
||
box-sizing: border-box;
|
||
}
|
||
|
||
// 卡片通用样式
|
||
.card {
|
||
background-color: #fff;
|
||
border-radius: 24rpx;
|
||
box-shadow: 0 2rpx 16rpx rgba(0, 0, 0, 0.04);
|
||
padding: 30rpx;
|
||
margin-bottom: 30rpx;
|
||
|
||
.card-header {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
margin-bottom: 24rpx;
|
||
|
||
.card-title {
|
||
font-size: 32rpx;
|
||
font-weight: 600;
|
||
color: #333;
|
||
}
|
||
}
|
||
}
|
||
|
||
// 设备信息卡片
|
||
.device-info-card {
|
||
|
||
.device-location {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
margin-bottom: 20rpx;
|
||
|
||
.location-left {
|
||
display: flex;
|
||
align-items: center;
|
||
|
||
.location-icon {
|
||
width: 40rpx;
|
||
height: 40rpx;
|
||
margin-right: 12rpx;
|
||
background-color: #10d673;
|
||
border-radius: 50%;
|
||
}
|
||
|
||
.location-name {
|
||
font-size: 32rpx;
|
||
color: #333;
|
||
font-weight: 500;
|
||
}
|
||
}
|
||
|
||
.device-status {
|
||
padding: 8rpx 24rpx;
|
||
border-radius: 30rpx;
|
||
font-size: 24rpx;
|
||
|
||
&.available {
|
||
background-color: #d4f4dd;
|
||
|
||
.status-text {
|
||
color: #07c160;
|
||
}
|
||
}
|
||
|
||
&.offline {
|
||
background-color: #f0f0f0;
|
||
|
||
.status-text {
|
||
color: #999;
|
||
}
|
||
}
|
||
|
||
.status-text {
|
||
font-size: 24rpx;
|
||
}
|
||
}
|
||
}
|
||
|
||
.device-id {
|
||
display: flex;
|
||
align-items: center;
|
||
|
||
.id-label {
|
||
font-size: 28rpx;
|
||
color: #999;
|
||
}
|
||
|
||
.id-value {
|
||
font-size: 28rpx;
|
||
color: #666;
|
||
}
|
||
}
|
||
}
|
||
|
||
// 计费规则卡片
|
||
.pricing-card {
|
||
.pricing-banner {
|
||
background: linear-gradient(135deg, #e8f5e9, #c8e6c9);
|
||
border-radius: 20rpx;
|
||
padding: 40rpx 30rpx;
|
||
margin-bottom: 24rpx;
|
||
display: flex;
|
||
flex-direction: column;
|
||
align-items: center;
|
||
|
||
.pricing-main {
|
||
display: flex;
|
||
align-items: baseline;
|
||
margin-bottom: 16rpx;
|
||
|
||
.price-symbol {
|
||
font-size: 48rpx;
|
||
font-weight: bold;
|
||
color: #07c160;
|
||
margin-right: 4rpx;
|
||
}
|
||
|
||
.price {
|
||
font-size: 80rpx;
|
||
font-weight: bold;
|
||
color: #07c160;
|
||
line-height: 1;
|
||
}
|
||
|
||
.unit {
|
||
font-size: 32rpx;
|
||
color: #07c160;
|
||
margin-left: 8rpx;
|
||
}
|
||
}
|
||
|
||
.cap-badge {
|
||
background-color: #07c160;
|
||
padding: 10rpx 32rpx;
|
||
border-radius: 30rpx;
|
||
|
||
.cap-text {
|
||
font-size: 26rpx;
|
||
color: #fff;
|
||
font-weight: 500;
|
||
}
|
||
}
|
||
}
|
||
|
||
.pricing-info {
|
||
display: flex;
|
||
align-items: flex-start;
|
||
margin-bottom: 16rpx;
|
||
|
||
&:last-child {
|
||
margin-bottom: 0;
|
||
}
|
||
|
||
.info-icon {
|
||
width: 32rpx;
|
||
height: 32rpx;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
margin-right: 12rpx;
|
||
margin-top: 2rpx;
|
||
|
||
.icon-text {
|
||
font-size: 28rpx;
|
||
color: #999;
|
||
}
|
||
}
|
||
|
||
.info-text {
|
||
flex: 1;
|
||
font-size: 26rpx;
|
||
color: #666;
|
||
line-height: 1.6;
|
||
}
|
||
}
|
||
}
|
||
|
||
// 使用说明卡片
|
||
.notice-card {
|
||
.notice-items {
|
||
.notice-item {
|
||
display: flex;
|
||
align-items: flex-start;
|
||
margin-bottom: 20rpx;
|
||
|
||
&:last-child {
|
||
margin-bottom: 0;
|
||
}
|
||
|
||
.notice-dot {
|
||
width: 12rpx;
|
||
height: 12rpx;
|
||
border-radius: 50%;
|
||
background-color: #07c160;
|
||
margin-right: 16rpx;
|
||
margin-top: 10rpx;
|
||
flex-shrink: 0;
|
||
}
|
||
|
||
.notice-text {
|
||
flex: 1;
|
||
font-size: 28rpx;
|
||
color: #666;
|
||
line-height: 1.6;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
// 底部操作区
|
||
.footer {
|
||
position: fixed;
|
||
bottom: 0;
|
||
left: 0;
|
||
right: 0;
|
||
background-color: #fff;
|
||
padding: 24rpx 30rpx;
|
||
padding-bottom: calc(24rpx + env(safe-area-inset-bottom));
|
||
box-shadow: 0 -4rpx 20rpx rgba(0, 0, 0, 0.06);
|
||
z-index: 100;
|
||
display: flex;
|
||
flex-direction: column;
|
||
align-items: center;
|
||
|
||
.rent-button {
|
||
width: 100%;
|
||
height: 96rpx;
|
||
border-radius: 48rpx;
|
||
background: linear-gradient(135deg, #07c160, #10d673);
|
||
color: #fff;
|
||
font-size: 34rpx;
|
||
font-weight: 600;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
border: none;
|
||
box-shadow: 0 8rpx 20rpx rgba(7, 193, 96, 0.3);
|
||
|
||
&.return-button {
|
||
background: linear-gradient(135deg, #FF9800, #FFB74D);
|
||
box-shadow: 0 8rpx 20rpx rgba(255, 152, 0, 0.3);
|
||
}
|
||
|
||
&:active {
|
||
transform: scale(0.98);
|
||
opacity: 0.9;
|
||
}
|
||
}
|
||
|
||
.wechat-credit {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
margin-top: 16rpx;
|
||
|
||
.wx-icon {
|
||
width: 48rpx;
|
||
height: 38rpx;
|
||
margin-right: 8rpx;
|
||
}
|
||
|
||
.credit-text {
|
||
font-size: 24rpx;
|
||
color: #999;
|
||
|
||
.divider {
|
||
margin: 0 8rpx;
|
||
color: #ddd;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
/* 手机号授权弹窗样式 */
|
||
.phone-auth-popup {
|
||
position: fixed;
|
||
top: 0;
|
||
left: 0;
|
||
right: 0;
|
||
bottom: 0;
|
||
z-index: 1000;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
background-color: rgba(0, 0, 0, 0.5);
|
||
}
|
||
|
||
.popup-mask {
|
||
position: absolute;
|
||
top: 0;
|
||
left: 0;
|
||
right: 0;
|
||
bottom: 0;
|
||
}
|
||
|
||
.popup-content {
|
||
background-color: #fff;
|
||
border-radius: 24rpx;
|
||
box-shadow: 0 8rpx 32rpx rgba(0, 0, 0, 0.15);
|
||
width: 90%;
|
||
max-width: 500rpx;
|
||
padding: 40rpx 30rpx;
|
||
position: relative;
|
||
z-index: 1001;
|
||
display: flex;
|
||
flex-direction: column;
|
||
align-items: center;
|
||
}
|
||
|
||
.popup-header {
|
||
margin-bottom: 30rpx;
|
||
text-align: center;
|
||
}
|
||
|
||
.popup-title {
|
||
font-size: 36rpx;
|
||
font-weight: bold;
|
||
color: #333;
|
||
}
|
||
|
||
.popup-body {
|
||
width: 100%;
|
||
display: flex;
|
||
flex-direction: column;
|
||
align-items: center;
|
||
margin-bottom: 30rpx;
|
||
}
|
||
|
||
.auth-desc {
|
||
font-size: 28rpx;
|
||
color: #666;
|
||
text-align: center;
|
||
margin-bottom: 30rpx;
|
||
line-height: 1.6;
|
||
}
|
||
|
||
.auth-btn {
|
||
width: 100%;
|
||
height: 92rpx;
|
||
border-radius: 46rpx;
|
||
background: linear-gradient(135deg, #07c160, #10d673);
|
||
color: #fff;
|
||
font-size: 32rpx;
|
||
font-weight: 600;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
border: none;
|
||
margin-bottom: 20rpx;
|
||
|
||
&:active {
|
||
transform: scale(0.98);
|
||
opacity: 0.9;
|
||
}
|
||
}
|
||
|
||
.auth-cancel {
|
||
width: 100%;
|
||
height: 92rpx;
|
||
border-radius: 46rpx;
|
||
background-color: #f5f7fa;
|
||
color: #333;
|
||
font-size: 32rpx;
|
||
font-weight: 600;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
border: none;
|
||
|
||
&:active {
|
||
transform: scale(0.98);
|
||
opacity: 0.9;
|
||
}
|
||
}
|
||
</style> |