Files
uni-fans-score/pages/device/detail.vue
T
2025-01-09 15:48:41 +08:00

465 lines
10 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="detail-container">
<!-- 设备状态卡片 -->
<view class="device-card">
<view class="device-header">
<view class="device-title">
<text class="name">共享风扇</text>
<text class="id">设备号{{ deviceId }}</text>
</view>
<view class="status" :class="deviceStatus.class">{{ deviceStatus.text }}</view>
</view>
<view class="device-info">
<view class="info-item">
<text class="label">设备位置</text>
<text class="value">{{ deviceLocation }}</text>
</view>
<view class="info-item">
<text class="label">电池电量</text>
<text class="value">{{ batteryLevel }}%</text>
</view>
</view>
</view>
<!-- 套餐选择 -->
<view class="package-section" v-if="!hasActiveOrder">
<view class="section-title">选择套餐</view>
<view class="package-list">
<view
v-for="(pkg, index) in packages"
:key="index"
class="package-item"
:class="{ active: selectedPackage === index }"
@click="selectPackage(index)"
>
<view class="package-content">
<text class="time">{{ pkg.time }}</text>
<text class="price">{{ pkg.price }}</text>
</view>
<text class="unit-price">{{ pkg.unitPrice }}/小时</text>
</view>
</view>
</view>
<!-- 使用说明 -->
<view class="notice-section">
<view class="section-title">使用说明</view>
<view class="notice-list">
<view class="notice-item">
<view class="dot"></view>
<text>请在使用前检查设备是否完好</text>
</view>
<view class="notice-item">
<view class="dot"></view>
<text>超出使用时间将自动按小时计费</text>
</view>
<view class="notice-item">
<view class="dot"></view>
<text>请在指定区域内使用设备</text>
</view>
</view>
</view>
<!-- 底部操作栏 -->
<view class="bottom-bar">
<view class="price-info" v-if="!hasActiveOrder">
<text class="deposit-text">押金</text>
<text class="deposit-amount">99</text>
</view>
<button
class="action-btn"
:class="hasActiveOrder ? 'return' : 'rent'"
@click="handleAction"
>
{{ hasActiveOrder ? '归还设备' : '立即租借' }}
</button>
</view>
</view>
</template>
<script>
export default {
data() {
return {
deviceId: '',
deviceLocation: '一号教学楼大厅',
batteryLevel: 95,
hasActiveOrder: false,
deviceStatus: {
text: '可使用',
class: 'available'
},
selectedPackage: 0,
packages: [
{ time: '1小时', price: '2.00', unitPrice: '2.00' },
{ time: '4小时', price: '6.00', unitPrice: '1.50' },
{ time: '12小时', price: '15.00', unitPrice: '1.25' }
],
isLoggedIn: false
}
},
onLoad(options) {
this.deviceId = options.deviceId
this.checkLoginAndOrder()
},
methods: {
// 检查登录状态和订单
async checkLoginAndOrder() {
try {
// 检查登录状态
const token = uni.getStorageSync('token')
if (!token) {
this.isLoggedIn = false
this.showLoginTip()
return
}
this.isLoggedIn = true
// 检查是否有进行中的订单
await this.checkOrderStatus()
} catch (error) {
uni.showToast({
title: '网络错误,请重试',
icon: 'none'
})
}
},
// 显示登录提示
showLoginTip() {
uni.showModal({
title: '提示',
content: '请先登录后再操作',
confirmText: '去登录',
success: (res) => {
if (res.confirm) {
uni.navigateTo({
url: '/pages/login/index'
})
}
}
})
},
// 检查订单状态
async checkOrderStatus() {
try {
// 调用接口检查是否有进行中的订单
const result = await this.$api.checkActiveOrder()
if (result.hasOrder) {
// 如果有正在进行的订单,跳转到归还页面,带上设备ID
uni.redirectTo({
url: `/pages/device/return?deviceId=${this.deviceId}`
})
}
} catch (error) {
uni.showToast({
title: '订单状态查询失败',
icon: 'none'
})
}
},
// 处理租借操作
handleRent() {
if (!this.isLoggedIn) {
this.showLoginTip()
return
}
const selectedPkg = this.packages[this.selectedPackage]
uni.showModal({
title: '确认租借',
content: `确认支付押金¥99.00及${selectedPkg.time}套餐费用¥${selectedPkg.price}`,
success: (res) => {
if (res.confirm) {
this.submitRentOrder()
}
}
})
},
// 提交租借订单
async submitRentOrder() {
try {
uni.showLoading({
title: '处理中'
})
const selectedPkg = this.packages[this.selectedPackage]
// TODO: 调用租借接口
const result = await this.$api.createOrder({
deviceId: this.deviceId,
packageId: this.selectedPackage,
duration: selectedPkg.time,
amount: selectedPkg.price
})
uni.hideLoading()
if (result.success) {
uni.showToast({
title: '租借成功',
icon: 'success'
})
// 跳转到使用中页面
setTimeout(() => {
uni.redirectTo({
url: `/pages/return/index?deviceId=${this.deviceId}&orderId=${result.orderId}`
})
}, 1500)
}
} catch (error) {
uni.hideLoading()
uni.showToast({
title: '租借失败,请重试',
icon: 'none'
})
}
}
}
}
</script>
<style lang="scss" scoped>
.detail-container {
min-height: 100vh;
background: #f8f8f8;
padding: 30rpx;
padding-bottom: 180rpx;
box-sizing: border-box;
.device-card {
background: #fff;
border-radius: 24rpx;
padding: 30rpx;
margin-bottom: 30rpx;
box-shadow: 0 4rpx 16rpx rgba(0,0,0,0.04);
.device-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 30rpx;
.device-title {
.name {
font-size: 36rpx;
font-weight: 600;
color: #333;
margin-right: 20rpx;
}
.id {
font-size: 24rpx;
color: #999;
}
}
.status {
padding: 8rpx 24rpx;
border-radius: 24rpx;
font-size: 24rpx;
&.available {
background: #E8F5E9;
color: #4CAF50;
}
&.in-use {
background: #E3F2FD;
color: #1976D2;
}
}
}
.device-info {
.info-item {
display: flex;
justify-content: space-between;
margin-bottom: 16rpx;
&:last-child {
margin-bottom: 0;
}
.label {
font-size: 28rpx;
color: #666;
}
.value {
font-size: 28rpx;
color: #333;
}
}
}
}
.package-section {
background: #fff;
border-radius: 24rpx;
padding: 30rpx;
margin-bottom: 30rpx;
box-shadow: 0 4rpx 16rpx rgba(0,0,0,0.04);
.section-title {
font-size: 32rpx;
font-weight: 600;
color: #333;
margin-bottom: 24rpx;
}
.package-list {
display: flex;
justify-content: space-between;
.package-item {
flex: 1;
margin: 0 10rpx;
padding: 24rpx;
background: #F5F5F5;
border-radius: 16rpx;
text-align: center;
transition: all 0.3s;
&:first-child {
margin-left: 0;
}
&:last-child {
margin-right: 0;
}
&.active {
background: #E3F2FD;
border: 2rpx solid #1976D2;
.package-content {
.time, .price {
color: #1976D2;
}
}
}
.package-content {
margin-bottom: 8rpx;
.time {
font-size: 28rpx;
color: #333;
margin-bottom: 8rpx;
display: block;
}
.price {
font-size: 36rpx;
font-weight: 600;
color: #333;
}
}
.unit-price {
font-size: 24rpx;
color: #999;
}
}
}
}
.notice-section {
background: #fff;
border-radius: 24rpx;
padding: 30rpx;
box-shadow: 0 4rpx 16rpx rgba(0,0,0,0.04);
.section-title {
font-size: 32rpx;
font-weight: 600;
color: #333;
margin-bottom: 24rpx;
}
.notice-list {
.notice-item {
display: flex;
align-items: center;
margin-bottom: 16rpx;
&:last-child {
margin-bottom: 0;
}
.dot {
width: 12rpx;
height: 12rpx;
background: #1976D2;
border-radius: 50%;
margin-right: 16rpx;
}
text {
font-size: 28rpx;
color: #666;
line-height: 1.5;
}
}
}
}
.bottom-bar {
position: fixed;
left: 0;
right: 0;
bottom: 0;
background: #fff;
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 16rpx rgba(0,0,0,0.04);
.price-info {
.deposit-text {
font-size: 28rpx;
color: #666;
}
.deposit-amount {
font-size: 36rpx;
font-weight: 600;
color: #FF9800;
}
}
.action-btn {
flex: 1;
margin-left: 30rpx;
height: 88rpx;
border-radius: 44rpx;
font-size: 32rpx;
font-weight: 600;
display: flex;
align-items: center;
justify-content: center;
border: none;
&.rent {
background: linear-gradient(135deg, #1976D2, #42A5F5);
color: #fff;
}
&.return {
background: linear-gradient(135deg, #FF9800, #FFB74D);
color: #fff;
}
&:active {
transform: scale(0.98);
}
}
}
}
</style>