Files
uni-fans-score/pages/position/detail.vue
T

331 lines
7.4 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="position-detail-page">
<!-- 顶部设备柜图示 -->
<view class="device-illustration">
<image src="/static/device-info.png" class="device-img" mode="aspectFit"></image>
</view>
<!-- 场地信息卡片 -->
<view class="info-card">
<!-- 场地名称 -->
<view class="position-name">{{ positionInfo.name || $t('common.loading') }}</view>
<!-- 地址信息 -->
<view class="info-item" v-if="positionInfo.location">
<image src="/static/device-location.png" class="item-icon" mode="aspectFit"></image>
<text class="item-text">{{ positionInfo.location }}</text>
</view>
<!-- 营业时间 -->
<view class="info-item" v-if="positionInfo.workTime && positionInfo.workTime !== '0'">
<image src="/static/device-time.png" class="item-icon" mode="aspectFit"></image>
<text class="item-text">{{ $t('location.businessHours') }}{{ positionInfo.workTime }}</text>
</view>
<!-- 计费信息 -->
<view class="info-item">
<image src="/static/device-price.png" class="item-icon" mode="aspectFit"></image>
<text class="item-text">{{ $t('device.pricing') }}{{ pricingText }}</text>
</view>
<!-- 按钮组 -->
<view class="button-group">
<view style="display: flex;flex-direction: row;gap: 10rpx;">
<view class="status-btn" v-if="isRentable">{{ $t('location.rent') }}</view>
<view class="status-btn" v-if="isReturnable">{{ $t('location.return') }}</view>
</view>
<view class="nav-btn" @click.stop="navigateToPosition">{{ $t('location.navigateHere') }}</view>
</view>
</view>
<!-- 底部操作按钮 -->
<view class="footer-actions">
<button class="action-btn btn-outline" @click="reportError">{{ $t('device.reportError') }}</button>
<button class="action-btn btn-primary" @click="scanCode">{{ $t('device.scanToUse') }}</button>
</view>
</view>
</template>
<script setup>
import {
ref,
computed,
onMounted
} from 'vue'
import {
onLoad
} from '@dcloudio/uni-app'
import {
URL
} from '../../config/url.js'
const positionInfo = ref({})
const positionId = ref('')
const isRentable = computed(() => {
if (typeof positionInfo.value?.canRent !== 'undefined') {
return !!positionInfo.value.canRent
}
return String(positionInfo.value?.status || '').toLowerCase() === 'online'
})
const isReturnable = computed(() => {
if (typeof positionInfo.value?.canReturn !== 'undefined') {
return !!positionInfo.value.canReturn
}
return String(positionInfo.value?.status || '').toLowerCase() === 'online'
})
const pricingText = computed(() => {
// 这里可以根据实际的计费规则来显示
// 默认显示一个通用的计费说明
return '5元/小时,36元/24小时,总计¥899元'
})
onLoad(async (options) => {
if (options.positionId) {
positionId.value = options.positionId
await loadPositionDetail()
}
})
const loadPositionDetail = async () => {
try {
uni.showLoading({
title: $t('common.loading')
})
const res = await uni.request({
url: `${URL}/device/position/app/list`,
method: 'GET',
header: {
'Authorization': 'Bearer ' + uni.getStorageSync('token'),
'Clientid': uni.getStorageSync('client_id')
}
})
if (res.statusCode === 200 && res.data?.code === 200) {
const positions = res.data.rows || []
const position = positions.find(p => p.positionId === positionId.value)
if (position) {
positionInfo.value = position
} else {
uni.showToast({
title: this.$t('location.notExist'),
icon: 'none'
})
}
} else if (res.statusCode === 401 || res.data?.code === 401 || res.data?.code === 40101) {
uni.reLaunch({
url: '/pages/login/index'
})
}
} catch (e) {
console.error('加载场地详情失败:', e)
uni.showToast({
title: $t('common.loadFailed'),
icon: 'none'
})
} finally {
uni.hideLoading()
}
}
const navigateToPosition = () => {
if (!positionInfo.value.latitude || !positionInfo.value.longitude) {
uni.showToast({
title: $t('location.coordinateError'),
icon: 'none'
})
return
}
const latitude = parseFloat(positionInfo.value.latitude)
const longitude = parseFloat(positionInfo.value.longitude)
// 验证坐标有效性
if (isNaN(latitude) || isNaN(longitude) ||
latitude < -90 || latitude > 90 ||
longitude < -180 || longitude > 180 ||
(latitude === 0 && longitude === 0)) {
uni.showToast({
title: $t('location.coordinateError'),
icon: 'none'
})
return
}
uni.openLocation({
latitude,
longitude,
name: positionInfo.value.name,
address: positionInfo.value.location
})
}
const reportError = () => {
uni.navigateTo({
url: '/pages/feedback/index'
})
}
const scanCode = () => {
uni.scanCode({
scanType: ['qrCode', 'barCode'],
success: (res) => {
console.log('扫码结果:', res)
// 处理扫码结果,跳转到设备详情页
if (res.result) {
// 假设二维码内容是设备号
uni.navigateTo({
url: `/pages/device/detail?deviceNo=${res.result}`
})
}
},
fail: (err) => {
console.error('扫码失败:', err)
uni.showToast({
title: this.$t('home.scanFailed'),
icon: 'none'
})
}
})
}
</script>
<style lang="scss" scoped>
.position-detail-page {
min-height: 100vh;
background: linear-gradient(180deg, #D1FFE1 0%, #F5F9F7 100%);
padding-bottom: 200rpx;
}
.device-illustration {
display: flex;
align-items: center;
justify-content: center;
padding: 40rpx 0 30rpx;
.device-img {
width: 480rpx;
height: 480rpx;
}
}
.info-card {
background: #ffffff;
margin: 0 32rpx;
border-radius: 32rpx;
padding: 44rpx 36rpx 36rpx;
box-shadow: 0 4rpx 20rpx rgba(0, 0, 0, 0.06);
.position-name {
font-size: 44rpx;
font-weight: 700;
color: #1A1A1A;
margin-bottom: 32rpx;
line-height: 1.3;
}
.info-item {
display: flex;
align-items: flex-start;
margin-bottom: 20rpx;
.item-icon {
width: 32rpx;
height: 32rpx;
margin-right: 12rpx;
margin-top: 2rpx;
flex-shrink: 0;
}
.item-text {
flex: 1;
font-size: 28rpx;
color: #666666;
line-height: 1.6;
}
}
.button-group {
display: flex;
gap: 12rpx;
margin-top: 36rpx;
justify-content: space-between;
flex-wrap: wrap;
.status-btn {
padding: 12rpx 28rpx;
border-radius: 40rpx;
font-size: 26rpx;
font-weight: 500;
border: 2rpx solid #3EAB64;
color: #3EAB64;
background: #ffffff;
}
.nav-btn {
padding: 12rpx 28rpx;
border-radius: 40rpx;
font-size: 26rpx;
font-weight: 500;
border: 2rpx solid #3EAB64;
color: #ffffff;
background: #3EAB64;
&:active {
opacity: 0.8;
}
}
}
}
.footer-actions {
position: fixed;
bottom: 0;
left: 0;
right: 0;
background: #ffffff;
padding: 24rpx 32rpx;
padding-bottom: calc(24rpx + env(safe-area-inset-bottom));
box-shadow: 0 -2rpx 16rpx rgba(0, 0, 0, 0.08);
display: flex;
gap: 16rpx;
.action-btn {
flex: 1;
height: 96rpx;
border-radius: 48rpx;
display: flex;
align-items: center;
justify-content: center;
font-size: 32rpx;
font-weight: 600;
border: none;
&.btn-outline {
border: 2rpx solid #3EAB64;
color: #3EAB64;
background: #ffffff;
}
&.btn-primary {
background: #3EAB64;
color: #ffffff;
}
&:active {
opacity: 0.85;
transform: scale(0.98);
}
&::after {
border: none;
}
}
}
</style>