Files
uni-fans-score/pages/index/index.vue
T

662 lines
15 KiB
Vue
Raw 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="container">
<!-- 顶部区域 -->
<view class="header">
<view class="header-bg">
<view class="circle-decoration circle-1"></view>
<view class="circle-decoration circle-2"></view>
<view class="wave-decoration"></view>
</view>
<view class="header-content">
<view class="brand-area">
<image class="brand-logo" src="@/static/logo.png" mode="aspectFit"></image>
<view class="brand-text">
<text class="title">共享风扇</text>
<text class="subtitle">随时随地享受清凉</text>
</view>
</view>
<view class="header-info">
<view class="service-tag">
<text>便捷租赁</text>
<text class="dot">·</text>
<text>品质保障</text>
</view>
</view>
</view>
</view>
<!-- 主扫码区域 -->
<view class="scan-section">
<view class="scan-card">
<view class="scan-btn" @click="handleScan">
<image class="scan-icon" src="@/static/scan-icon.png" mode="aspectFit" />
<text class="scan-text">扫码使用</text>
</view>
<view class="scan-desc">
<text>扫描设备二维码即可使用或归还</text>
</view>
</view>
</view>
<!-- 收费规则卡片 -->
<view class="price-card">
<view class="card-header">
<text class="card-title">收费规则</text>
</view>
<!-- 微信免押金标识 -->
<!-- <view class="deposit-free">
<image class="deposit-icon" src="@/static/images/wxpayflag.png" mode="aspectFit" />
<text class="deposit-text">微信支付分免押金</text>
</view> -->
<view class="price-rules">
<view class="price-item">
<view class="price-tag">5.0<text class="unit">/小时</text></view>
</view>
<view class="divider"></view>
<view class="rule-list">
<view class="rule-item">
<view class="rule-dot"></view>
<text>15分钟内归还免费</text>
</view>
<view class="rule-item">
<view class="rule-dot"></view>
<text>不足1小时按1小时计费</text>
</view>
<view class="rule-item">
<view class="rule-dot"></view>
<text>封顶99元计费达99元视为买断</text>
</view>
</view>
</view>
</view>
<!-- 使用流程 -->
<view class="usage-steps">
<view class="steps-header">
<text class="steps-title">使用流程</text>
</view>
<view class="steps-container">
<view class="step-item">
<view class="step-icon">
<text class="step-number">1</text>
</view>
<text class="step-text">扫码弹出</text>
</view>
<view class="step-arrow"></view>
<view class="step-item">
<view class="step-icon">
<text class="step-number">2</text>
</view>
<text class="step-text">使用风扇</text>
</view>
<view class="step-arrow"></view>
<view class="step-item">
<view class="step-icon">
<text class="step-number">3</text>
</view>
<text class="step-text">插入归还</text>
</view><view class="step-arrow"></view>
<view class="step-item">
<view class="step-icon">
<text class="step-number">4</text>
</view>
<text class="step-text">结束订单</text>
</view>
</view>
</view>
<!-- 手机号授权弹窗 -->
<view class="phone-auth-popup" v-if="showPhoneAuthPopup">
<view class="popup-mask" @click.stop="showPhoneAuthPopup = false"></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">
<text>一键获取手机号</text>
</button>
<view class="auth-cancel" @click="showPhoneAuthPopup = false">
<text>暂不授权</text>
</view>
</view>
</view>
</view>
</view>
</template>
<script>
import {
getQueryString,
wxLogin
} from '@/util/index.js'
import {
URL
} from "@/config/url.js"
import {
getDeviceInfo
} from '@/config/user.js'
export default {
methods: {
async handleScan() {
try {
const scanResult = await new Promise((resolve, reject) => {
uni.scanCode({
success: resolve,
fail: reject
})
})
console.log(scanResult.path);
let deviceNo = getQueryString(scanResult.path, 'deviceNo')
if (!deviceNo) {
uni.showToast({
title: '无效的设备二维码',
icon: 'none'
})
return
}
// 直接在当前页面查询是否有使用中的订单,避免跳转到中间页面
if (!uni.getStorageSync('token')) {
await wxLogin()
}
// 检查是否有使用中的订单
const inUseRes = await uni.request({
url: `${URL || 'http://127.0.0.1:8080'}/app/order/inUse`,
method: 'GET',
header: {
'Authorization': "Bearer " + uni.getStorageSync('token'),
'Clientid': uni.getStorageSync('client_id')
}
})
if (inUseRes.statusCode == 200 && inUseRes.data.code == 200 && inUseRes.data.data) {
// 存在使用中的订单,跳转到归还页面
const inUseOrder = inUseRes.data.data
// 直接使用reLaunch而不是navigateTo以确保页面跳转
uni.reLaunch({
url: `/pages/return/index?orderId=${inUseOrder.orderId}&deviceId=${deviceNo || inUseOrder.deviceNo}`
})
console.log('已发起页面跳转')
return
}
// 检查是否有待支付订单
const orderRes = await uni.request({
url: `${URL || 'http://127.0.0.1:8080'}/app/order/unpaid`,
method: 'GET',
header: {
'Authorization': "Bearer " + uni.getStorageSync('token'),
'Clientid': uni.getStorageSync('client_id')
}
})
console.log('待支付订单检查结果:', JSON.stringify(orderRes))
if (orderRes.statusCode == 200 && orderRes.data.code == 200 && orderRes.data.data) {
// 存在待支付订单,跳转到支付页面
const unpaidOrder = orderRes.data.data
uni.navigateTo({
url: `/pages/order/payment?orderId=${unpaidOrder.orderId}`
})
} else {
try {
// 获取设备信息
const deviceInfoRes = await getDeviceInfo(deviceNo)
if (deviceInfoRes.code == 200 && deviceInfoRes.data && deviceInfoRes.data.device) {
const deviceInfo = deviceInfoRes.data.device
// 如果有feeConfig,直接解析并处理
if (deviceInfo.feeConfig) {
console.log('获取到设备feeConfig信息:', deviceInfo.feeConfig)
// 这里可以直接解析feeConfig并进行前端处理
try {
const feeConfig = JSON.parse(deviceInfo.feeConfig)
// 根据解析后的feeConfig进行页面跳转并传递信息
uni.navigateTo({
url: `/pages/device/detail?deviceNo=${deviceNo}&feeConfig=${encodeURIComponent(deviceInfo.feeConfig)}`
})
} catch (e) {
console.error('解析feeConfig失败:', e)
// 解析失败时仍然跳转到详情页面
uni.navigateTo({
url: `/pages/device/detail?deviceNo=${deviceNo}`
})
}
} else {
// 没有feeConfig时,跳转到详情页面
uni.navigateTo({
url: `/pages/device/detail?deviceNo=${deviceNo}`
})
}
} else {
console.error('获取设备信息失败:', deviceInfoRes.msg || '未知错误')
uni.showToast({
title: '获取设备信息失败',
icon: 'none'
})
// 失败时仍然跳转到详情页面
uni.navigateTo({
url: `/pages/device/detail?deviceNo=${deviceNo}`
})
}
} catch (error) {
console.error('获取设备信息异常:', error)
uni.showToast({
title: '获取设备信息失败',
icon: 'none'
})
// 异常时仍然跳转到详情页面
uni.navigateTo({
url: `/pages/device/detail?deviceNo=${deviceNo}`
})
}
}
} catch (error) {
console.error('扫码处理失败:', error)
uni.showToast({
title: '扫码失败',
icon: 'none'
})
}
}
}
}
</script>
<style lang="scss" scoped>
.container {
min-height: 100vh;
background-color: #f6f7fb;
padding-bottom: 40rpx;
}
/* 顶部区域 */
.header {
height: 300rpx;
background: linear-gradient(135deg, #1E88E5, #29B6F6);
position: relative;
overflow: hidden;
.header-bg {
position: absolute;
left: 0;
top: 0;
width: 100%;
height: 100%;
z-index: 1;
.circle-decoration {
position: absolute;
border-radius: 50%;
background: rgba(255, 255, 255, 0.1);
}
.circle-1 {
width: 240rpx;
height: 240rpx;
right: -60rpx;
top: -90rpx;
}
.circle-2 {
width: 160rpx;
height: 160rpx;
left: -40rpx;
bottom: 30rpx;
background: rgba(255, 255, 255, 0.08);
}
.wave-decoration {
position: absolute;
left: 0;
bottom: 0;
width: 100%;
height: 40rpx;
// background: url('@/static/images/wave.png') repeat-x;
background-size: auto 100%;
opacity: 0.6;
}
}
.header-content {
position: relative;
z-index: 2;
padding: 40rpx 40rpx 0;
height: 100%;
display: flex;
flex-direction: column;
justify-content: space-between;
.brand-area {
display: flex;
align-items: center;
.brand-logo {
width: 90rpx;
height: 90rpx;
margin-right: 20rpx;
}
.brand-text {
display: flex;
flex-direction: column;
.title {
font-size: 48rpx;
color: #ffffff;
font-weight: bold;
line-height: 1.2;
text-shadow: 0 2rpx 4rpx rgba(0, 0, 0, 0.1);
}
.subtitle {
font-size: 28rpx;
color: rgba(255, 255, 255, 0.9);
}
}
}
.header-info {
display: flex;
flex-wrap: wrap;
gap: 20rpx;
margin-bottom: 30rpx;
.service-tag {
display: flex;
align-items: center;
background: rgba(255, 255, 255, 0.2);
border-radius: 40rpx;
padding: 10rpx 20rpx;
text {
font-size: 24rpx;
color: #ffffff;
}
.dot {
margin: 0 8rpx;
font-weight: bold;
}
}
}
}
}
/* 扫码区域 */
.scan-section {
padding: 0 30rpx;
// margin-top: -60rpx;
.scan-card {
background: #ffffff;
border-radius: 16rpx;
box-shadow: 0 10rpx 30rpx rgba(0, 0, 0, 0.05);
padding: 36rpx 0;
display: flex;
flex-direction: column;
align-items: center;
.scan-btn {
width: 220rpx;
height: 220rpx;
background: linear-gradient(135deg, #00B0FF, #0091EA);
border-radius: 50%;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
margin-bottom: 24rpx;
box-shadow: 0 10rpx 20rpx rgba(0, 176, 255, 0.2);
position: relative;
transition: all 0.2s ease;
&:active {
transform: scale(0.96);
}
.scan-icon {
width: 80rpx;
height: 80rpx;
margin-bottom: 12rpx;
}
.scan-text {
font-size: 36rpx;
color: #ffffff;
font-weight: 500;
}
}
.scan-desc {
font-size: 28rpx;
color: #666;
}
}
}
/* 收费规则卡片 */
.price-card {
margin: 30rpx;
background: #ffffff;
border-radius: 16rpx;
overflow: hidden;
box-shadow: 0 6rpx 20rpx rgba(0, 0, 0, 0.04);
.card-header {
padding: 24rpx 30rpx;
background: linear-gradient(to right, #f5f9ff, #ffffff);
border-bottom: 2rpx solid #f0f0f0;
.card-title {
font-size: 32rpx;
font-weight: 600;
color: #333;
position: relative;
padding-left: 20rpx;
&::before {
content: '';
position: absolute;
left: 0;
top: 50%;
transform: translateY(-50%);
width: 6rpx;
height: 28rpx;
background: #2196F3;
border-radius: 3rpx;
}
}
}
/* 微信免押金区域 */
.deposit-free {
margin: 20rpx 30rpx 0;
padding: 12rpx 16rpx;
background: #f0f9ff;
border-radius: 8rpx;
border-left: 4rpx solid #03A9F4;
display: flex;
align-items: center;
.deposit-icon {
width: 40rpx;
height: 40rpx;
margin-right: 16rpx;
}
.deposit-text {
font-size: 26rpx;
color: #03A9F4;
font-weight: 500;
}
}
.price-rules {
padding: 20rpx 30rpx 30rpx;
.price-item {
display: flex;
flex-direction: column;
align-items: center;
margin-bottom: 20rpx;
.price-tag {
font-size: 60rpx;
color: #FF6E00;
font-weight: bold;
line-height: 1;
.unit {
font-size: 32rpx;
font-weight: normal;
margin-left: 4rpx;
}
}
.price-desc {
font-size: 28rpx;
color: #666;
margin-top: 10rpx;
}
}
.divider {
height: 2rpx;
background-color: #f0f0f0;
margin: 20rpx 0 30rpx;
}
.rule-list {
.rule-item {
display: flex;
align-items: flex-start;
margin-bottom: 20rpx;
&:last-child {
margin-bottom: 0;
}
.rule-dot {
width: 12rpx;
height: 12rpx;
background: #2196F3;
border-radius: 50%;
margin: 12rpx 16rpx 0 0;
flex-shrink: 0;
}
text {
font-size: 28rpx;
color: #666;
line-height: 1.5;
}
}
}
}
}
/* 使用流程 */
.usage-steps {
margin: 0 30rpx;
background: #ffffff;
border-radius: 16rpx;
box-shadow: 0 6rpx 20rpx rgba(0, 0, 0, 0.04);
overflow: hidden;
.steps-header {
padding: 24rpx 30rpx;
background: linear-gradient(to right, #f5f9ff, #ffffff);
border-bottom: 2rpx solid #f0f0f0;
.steps-title {
font-size: 32rpx;
font-weight: 600;
color: #333;
position: relative;
padding-left: 20rpx;
&::before {
content: '';
position: absolute;
left: 0;
top: 50%;
transform: translateY(-50%);
width: 6rpx;
height: 28rpx;
background: #2196F3;
border-radius: 3rpx;
}
}
}
.steps-container {
padding: 40rpx 30rpx;
display: flex;
align-items: center;
justify-content: space-between;
.step-item {
display: flex;
flex-direction: column;
align-items: center;
flex: 1;
.step-icon {
width: 80rpx;
height: 80rpx;
background: #f0f9ff;
border: 2rpx solid #e1f5fe;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
margin-bottom: 16rpx;
.step-number {
font-size: 36rpx;
color: #2196F3;
font-weight: 600;
}
}
.step-text {
font-size: 26rpx;
color: #666;
}
}
.step-arrow {
width: 40rpx;
height: 4rpx;
background: #e1f5fe;
position: relative;
&::after {
content: '';
position: absolute;
right: 0;
top: 50%;
margin-top: -8rpx;
border-left: 12rpx solid #e1f5fe;
border-top: 8rpx solid transparent;
border-bottom: 8rpx solid transparent;
}
}
}
}
</style>