feat:对接获取附近设备列表
This commit is contained in:
@@ -68,7 +68,7 @@
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
@import "uview-ui/index.scss"
|
@import "@climblee/uv-ui/index.scss"
|
||||||
|
|
||||||
/*每个页面公共css */
|
/*每个页面公共css */
|
||||||
</style>
|
</style>
|
||||||
@@ -8,6 +8,47 @@ export const getDeviceInfo = (deviceNo) => {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 查询附近设备
|
||||||
|
export const getNearbyDevices = ({ userLatitude, userLongitude, queryType = 'rent', radiusKm = 5, pageNum = 1, pageSize = 100 }) => {
|
||||||
|
return request({
|
||||||
|
url: `/device/device/nearby?pageNum=${pageNum}&pageSize=${pageSize}`,
|
||||||
|
method: 'post',
|
||||||
|
data: {
|
||||||
|
userLatitude,
|
||||||
|
userLongitude,
|
||||||
|
queryType, // 'rent' 可租借 或 'return' 可归还
|
||||||
|
radiusKm
|
||||||
|
},
|
||||||
|
hideLoading: true // 不显示加载提示,由页面自己控制
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 转换设备数据为统一格式(兼容旧的场地数据结构)
|
||||||
|
export const transformDeviceData = (device) => {
|
||||||
|
return {
|
||||||
|
...device,
|
||||||
|
// 保持原有字段
|
||||||
|
positionId: device.deviceId, // 使用 deviceId 作为 positionId
|
||||||
|
name: device.name || device.positionName,
|
||||||
|
location: device.deviceLocation,
|
||||||
|
latitude: device.latitude,
|
||||||
|
longitude: device.longitude,
|
||||||
|
distance: device.distance ? `${device.distance}km` : '',
|
||||||
|
distanceInMeters: device.distance ? device.distance * 1000 : 999000,
|
||||||
|
// 设备特有字段
|
||||||
|
deviceNo: device.deviceNo,
|
||||||
|
deviceImg: device.deviceImg,
|
||||||
|
availablePowerBankCount: device.availablePowerBankCount,
|
||||||
|
availableEmptyGridCount: device.availableEmptyGridCount,
|
||||||
|
totalGridCount: device.totalGridCount,
|
||||||
|
remark: device.remark || '', // 计费备注信息
|
||||||
|
status: device.status || 'online',
|
||||||
|
// 添加租借和归还能力标识
|
||||||
|
canRent: (device.availablePowerBankCount || 0) > 0,
|
||||||
|
canReturn: (device.availableEmptyGridCount || 0) > 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 立即租借
|
// 立即租借
|
||||||
export const rentPowerBank = (deviceNo, phone) => {
|
export const rentPowerBank = (deviceNo, phone) => {
|
||||||
return request({
|
return request({
|
||||||
|
|||||||
+2
-2
@@ -1,6 +1,6 @@
|
|||||||
// export const URL = "https://my.gxfs123.com/api" //正式服务器
|
// export const URL = "https://my.gxfs123.com/api" //正式服务器
|
||||||
export const URL = "https://fansdev.gxfs123.com/api" //测试服务器
|
// export const URL = "https://fansdev.gxfs123.com/api" //测试服务器
|
||||||
// export const URL = "http://192.168.5.120:8080" //本地调试
|
export const URL = "http://192.168.5.120:8080" //本地调试
|
||||||
// export const URL = "http://127.0.0.1:8080" //本地调试
|
// export const URL = "http://127.0.0.1:8080" //本地调试
|
||||||
|
|
||||||
export const appid = "wx2165f0be356ae7a9" //小程序appid
|
export const appid = "wx2165f0be356ae7a9" //小程序appid
|
||||||
@@ -4,7 +4,7 @@ import { createSSRApp } from 'vue'
|
|||||||
import { createI18n } from 'vue-i18n'
|
import { createI18n } from 'vue-i18n'
|
||||||
import zhCN from './locale/zh-CN.js'
|
import zhCN from './locale/zh-CN.js'
|
||||||
import enUS from './locale/en-US.js'
|
import enUS from './locale/en-US.js'
|
||||||
import uView from "uview-ui"
|
import uView from '@climblee/uv-ui'
|
||||||
|
|
||||||
// 获取系统语言
|
// 获取系统语言
|
||||||
const getSystemLanguage = () => {
|
const getSystemLanguage = () => {
|
||||||
|
|||||||
+1
-2
@@ -2,8 +2,7 @@
|
|||||||
"easycom": {
|
"easycom": {
|
||||||
"autoscan": true,
|
"autoscan": true,
|
||||||
"custom": {
|
"custom": {
|
||||||
"^uv-(.*)": "@climblee/uv-ui/components/uv-$1/uv-$1.vue",
|
"^uv-(.*)": "@climblee/uv-ui/components/uv-$1/uv-$1.vue"
|
||||||
"^u-(.*)": "uview-ui/components/u-$1/u-$1.vue"
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"pages": [{
|
"pages": [{
|
||||||
|
|||||||
+89
-109
@@ -167,7 +167,9 @@
|
|||||||
URL
|
URL
|
||||||
} from "../../config/url.js"
|
} from "../../config/url.js"
|
||||||
import {
|
import {
|
||||||
getDeviceInfo
|
getDeviceInfo,
|
||||||
|
getNearbyDevices,
|
||||||
|
transformDeviceData
|
||||||
} from '../../config/api/device.js'
|
} from '../../config/api/device.js'
|
||||||
import {
|
import {
|
||||||
getPotionsDetail
|
getPotionsDetail
|
||||||
@@ -422,32 +424,34 @@ const noticePopup = ref(null)
|
|||||||
|
|
||||||
const loadPositions = async () => {
|
const loadPositions = async () => {
|
||||||
try {
|
try {
|
||||||
const res = await uni.request({
|
if (!userLocation.value || !userLocation.value.latitude || !userLocation.value.longitude) {
|
||||||
url: `${URL}/device/position/app/list`,
|
console.warn('用户位置信息不完整,无法查询附近设备')
|
||||||
method: 'GET',
|
|
||||||
header: {
|
|
||||||
'Authorization': "Bearer " + uni.getStorageSync('token'),
|
|
||||||
'Clientid': uni.getStorageSync('client_id')
|
|
||||||
},
|
|
||||||
data: {
|
|
||||||
latitude: userLocation.value.latitude,
|
|
||||||
longitude: userLocation.value.longitude
|
|
||||||
}
|
|
||||||
})
|
|
||||||
console.log(res);
|
|
||||||
|
|
||||||
if (res.statusCode === 401 || res.data?.code === 401 || res.data?.code === 40101) {
|
|
||||||
redirectToLogin()
|
|
||||||
return
|
return
|
||||||
} else if (res.statusCode === 200 && res.data.code === 200) {
|
}
|
||||||
positionList.value = res.data.rows || []
|
|
||||||
|
const res = await getNearbyDevices({
|
||||||
|
userLatitude: userLocation.value.latitude,
|
||||||
|
userLongitude: userLocation.value.longitude,
|
||||||
|
queryType: 'rent', // 默认查询可租借设备
|
||||||
|
radiusKm: 5,
|
||||||
|
pageNum: 1,
|
||||||
|
pageSize: 100
|
||||||
|
})
|
||||||
|
|
||||||
|
console.log('查询附近设备结果:', res)
|
||||||
|
|
||||||
|
if (res.code === 200) {
|
||||||
|
// 新接口返回的是 data.records,需要适配字段名
|
||||||
|
const devices = res.data?.records || []
|
||||||
|
// 将设备数据转换为统一格式
|
||||||
|
positionList.value = devices.map(transformDeviceData)
|
||||||
calculateDistances()
|
calculateDistances()
|
||||||
filteredPositions.value = [...positionList.value]
|
filteredPositions.value = [...positionList.value]
|
||||||
} else {
|
} else {
|
||||||
console.error('获取场地列表失败:', res.data.msg)
|
console.error('获取设备列表失败:', res.msg)
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('获取场地列表异常:', error)
|
console.error('获取设备列表异常:', error)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -494,50 +498,45 @@ const noticePopup = ref(null)
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log('根据地图中心加载场地:', center)
|
console.log('根据地图中心加载设备:', center)
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// 使用原有接口获取所有场地,传入中心点经纬度
|
// 使用新的附近设备查询接口
|
||||||
const res = await uni.request({
|
const res = await getNearbyDevices({
|
||||||
url: `${URL}/device/position/app/list`,
|
userLatitude: center.latitude,
|
||||||
method: 'GET',
|
userLongitude: center.longitude,
|
||||||
header: {
|
queryType: 'rent', // 默认查询可租借设备
|
||||||
'Authorization': "Bearer " + uni.getStorageSync('token'),
|
radiusKm: 5,
|
||||||
'Clientid': uni.getStorageSync('client_id')
|
pageNum: 1,
|
||||||
},
|
pageSize: 100
|
||||||
data: {
|
|
||||||
latitude: center.latitude,
|
|
||||||
longitude: center.longitude
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
|
|
||||||
if (res.statusCode === 401 || res.data?.code === 401 || res.data?.code === 40101) {
|
if (res.code === 200) {
|
||||||
redirectToLogin()
|
const devices = res.data?.records || []
|
||||||
return
|
console.log('加载到设备数量:', devices.length)
|
||||||
} else if (res.statusCode === 200 && res.data.code === 200) {
|
|
||||||
const rows = res.data.rows || []
|
// 将设备数据转换为统一格式
|
||||||
console.log('加载到场地数量:', rows.length)
|
positionList.value = devices.map(transformDeviceData)
|
||||||
|
|
||||||
positionList.value = rows
|
|
||||||
// 基于地图中心计算距离
|
// 基于地图中心计算距离
|
||||||
calculateDistances(center)
|
calculateDistances(center)
|
||||||
|
|
||||||
// 可以选择性过滤距离过远的场地(比如超过10km的)
|
// 可以选择性过滤距离过远的设备(比如超过10km的)
|
||||||
const maxDistanceInMeters = 10000 // 最大显示距离,单位米(10km)
|
const maxDistanceInMeters = 10000 // 最大显示距离,单位米(10km)
|
||||||
filteredPositions.value = positionList.value.filter(item => {
|
filteredPositions.value = positionList.value.filter(item => {
|
||||||
return !item.distanceInMeters || item.distanceInMeters <= maxDistanceInMeters
|
return !item.distanceInMeters || item.distanceInMeters <= maxDistanceInMeters
|
||||||
})
|
})
|
||||||
|
|
||||||
console.log('过滤后场地数量:', filteredPositions.value.length)
|
console.log('过滤后设备数量:', filteredPositions.value.length)
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
console.error('根据地图中心加载场地失败:', res.data.msg)
|
console.error('根据地图中心加载设备失败:', res.msg)
|
||||||
positionList.value = []
|
positionList.value = []
|
||||||
filteredPositions.value = []
|
filteredPositions.value = []
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('根据地图中心加载场地异常:', error)
|
console.error('根据地图中心加载设备异常:', error)
|
||||||
// 如果请求失败,保持当前的场地列表不变
|
// 如果请求失败,保持当前的设备列表不变
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1238,37 +1237,39 @@ const closeNoticePopup = () => {
|
|||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
// gap: 16rpx;
|
gap: 16rpx;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
|
|
||||||
.action-btn {
|
.action-btn {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
align-content: center;
|
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
font-size: 26rpx;
|
font-size: 24rpx;
|
||||||
font-weight: 600;
|
font-weight: 500;
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
|
||||||
|
&:active {
|
||||||
|
transform: scale(0.95);
|
||||||
|
opacity: 0.8;
|
||||||
|
}
|
||||||
|
|
||||||
&.primary {
|
&.primary {
|
||||||
background: #3EAB64;
|
background: #3EAB64;
|
||||||
color: #fff;
|
color: #fff;
|
||||||
border-radius: 64rpx;
|
border-radius: 56rpx;
|
||||||
height: 100rpx;
|
height: 112rpx;
|
||||||
min-width: 320rpx;
|
flex: 1;
|
||||||
// box-shadow: 0 16rpx 40rpx rgba(7, 193, 96, 0.35);
|
max-width: 400rpx;
|
||||||
padding: 12rpx 24rpx;
|
padding: 0 24rpx;
|
||||||
|
// box-shadow: 0 8rpx 24rpx rgba(62, 171, 100, 0.3);
|
||||||
|
|
||||||
.icon-wrap {
|
.icon-wrap {
|
||||||
width: 50rpx;
|
width: 48rpx;
|
||||||
height: 50rpx;
|
height: 48rpx;
|
||||||
border-radius: 50%;
|
|
||||||
// background: rgba(255, 255, 255, 0.25);
|
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
align-content: center;
|
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
// margin-bottom: 10rpx;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1277,66 +1278,44 @@ const closeNoticePopup = () => {
|
|||||||
color: #333;
|
color: #333;
|
||||||
border-radius: 24rpx;
|
border-radius: 24rpx;
|
||||||
height: 100rpx;
|
height: 100rpx;
|
||||||
min-width: 180rpx;
|
width: 140rpx;
|
||||||
// box-shadow: 0 8rpx 24rpx rgba(0, 0, 0, 0.08);
|
flex-shrink: 0;
|
||||||
padding: 12rpx 16rpx;
|
padding: 8rpx 12rpx;
|
||||||
|
// box-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.08);
|
||||||
|
// border: 1rpx solid #f0f0f0;
|
||||||
|
|
||||||
.icon-wrap {
|
.icon-wrap {
|
||||||
width: 40rpx;
|
width: 36rpx;
|
||||||
height: 40rpx;
|
height: 36rpx;
|
||||||
border-radius: 50%;
|
|
||||||
// background: #f7f8fa;
|
|
||||||
// border: 2rpx solid #eaeaea;
|
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
margin-bottom: 10rpx;
|
margin-bottom: 6rpx;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&.small {
|
|
||||||
height: 120rpx;
|
|
||||||
min-width: 180rpx;
|
|
||||||
border-radius: 28rpx;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.btn-nearby,
|
|
||||||
.btn-my {
|
|
||||||
gap: 10rpx;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.btn-scan {
|
.btn-scan {
|
||||||
/* 尺寸与布局(覆盖 primary 的默认尺寸) */
|
/* 中间扫码按钮:横向布局 */
|
||||||
height: 112rpx;
|
|
||||||
min-width: 360rpx;
|
|
||||||
padding: 0 32rpx;
|
|
||||||
border-radius: 56rpx;
|
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
// gap: 16rpx;
|
gap: 8rpx;
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
|
|
||||||
/* 左侧图标容器 */
|
|
||||||
.icon-wrap {
|
.icon-wrap {
|
||||||
width: 64rpx;
|
width: 48rpx;
|
||||||
height: 64rpx;
|
height: 48rpx;
|
||||||
border-radius: 50%;
|
|
||||||
margin: 0;
|
margin: 0;
|
||||||
margin-right: 12rpx;
|
|
||||||
// background: rgba(255, 255, 255, 0.18);
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
box-shadow: none;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 图标大小与反色 */
|
|
||||||
.action-icon {
|
.action-icon {
|
||||||
width: 40rpx;
|
width: 32rpx;
|
||||||
height: 40rpx;
|
height: 32rpx;
|
||||||
filter: brightness(0) invert(1);
|
filter: brightness(0) invert(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.primary-label {
|
||||||
|
font-size: 28rpx;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1506,17 +1485,18 @@ const closeNoticePopup = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.action-icon {
|
.action-icon {
|
||||||
width: 42rpx;
|
width: 36rpx;
|
||||||
height: 42rpx;
|
height: 36rpx;
|
||||||
filter: none;
|
filter: none;
|
||||||
box-shadow: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.btn-scan .action-icon {
|
|
||||||
filter: brightness(0) invert(1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.action-label {
|
.action-label {
|
||||||
|
line-height: 1.2;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.primary-label {
|
||||||
|
color: #ffffff;
|
||||||
line-height: 1;
|
line-height: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+56
-25
@@ -2,7 +2,8 @@
|
|||||||
<view class="position-detail-page">
|
<view class="position-detail-page">
|
||||||
<!-- 顶部设备柜图示 -->
|
<!-- 顶部设备柜图示 -->
|
||||||
<view class="device-illustration">
|
<view class="device-illustration">
|
||||||
<image src="/static/device-info.png" class="device-img" mode="aspectFit"></image>
|
<image v-if="positionInfo.deviceImg" :src="positionInfo.deviceImg" class="device-img" mode="aspectFit"></image>
|
||||||
|
<image v-else src="/static/device-info.png" class="device-img" mode="aspectFit"></image>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
<!-- 场地信息卡片 -->
|
<!-- 场地信息卡片 -->
|
||||||
@@ -28,6 +29,17 @@
|
|||||||
<text class="item-text">{{ $t('device.pricing') }}:{{ pricingText }}</text>
|
<text class="item-text">{{ $t('device.pricing') }}:{{ pricingText }}</text>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
|
<!-- 可用数量信息 -->
|
||||||
|
<view class="info-item" v-if="positionInfo.availablePowerBankCount !== undefined && positionInfo.availablePowerBankCount !== null">
|
||||||
|
<image src="/static/device-info.png" class="item-icon" mode="aspectFit"></image>
|
||||||
|
<text class="item-text">可租借风扇:{{ positionInfo.availablePowerBankCount }} 台</text>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<view class="info-item" v-if="positionInfo.availableEmptyGridCount !== undefined && positionInfo.availableEmptyGridCount !== null">
|
||||||
|
<image src="/static/device-info.png" class="item-icon" mode="aspectFit"></image>
|
||||||
|
<text class="item-text">可归还空位:{{ positionInfo.availableEmptyGridCount }} 个</text>
|
||||||
|
</view>
|
||||||
|
|
||||||
<!-- 按钮组 -->
|
<!-- 按钮组 -->
|
||||||
<view class="button-group">
|
<view class="button-group">
|
||||||
<view style="display: flex;flex-direction: row;gap: 10rpx;">
|
<view style="display: flex;flex-direction: row;gap: 10rpx;">
|
||||||
@@ -48,17 +60,21 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import {
|
import {
|
||||||
ref,
|
ref,
|
||||||
computed,
|
computed,
|
||||||
onMounted
|
onMounted
|
||||||
} from 'vue'
|
} from 'vue'
|
||||||
import {
|
import {
|
||||||
onLoad
|
onLoad
|
||||||
} from '@dcloudio/uni-app'
|
} from '@dcloudio/uni-app'
|
||||||
import {
|
import {
|
||||||
URL
|
getNearbyDevices,
|
||||||
} from '../../config/url.js'
|
transformDeviceData
|
||||||
|
} from '../../config/api/device.js'
|
||||||
|
import { useI18n } from '../../utils/i18n.js'
|
||||||
|
|
||||||
|
const { t: $t } = useI18n()
|
||||||
|
|
||||||
const positionInfo = ref({})
|
const positionInfo = ref({})
|
||||||
const positionId = ref('')
|
const positionId = ref('')
|
||||||
@@ -78,9 +94,12 @@
|
|||||||
})
|
})
|
||||||
|
|
||||||
const pricingText = computed(() => {
|
const pricingText = computed(() => {
|
||||||
// 这里可以根据实际的计费规则来显示
|
// 使用设备的 remark 字段作为计费信息
|
||||||
// 默认显示一个通用的计费说明
|
if (positionInfo.value?.remark) {
|
||||||
return '5元/小时,36元/24小时,总计¥899元'
|
return positionInfo.value.remark
|
||||||
|
}
|
||||||
|
// 如果 remark 为空,显示默认提示
|
||||||
|
return '暂无计费信息'
|
||||||
})
|
})
|
||||||
|
|
||||||
onLoad(async (options) => {
|
onLoad(async (options) => {
|
||||||
@@ -96,33 +115,45 @@
|
|||||||
title: $t('common.loading')
|
title: $t('common.loading')
|
||||||
})
|
})
|
||||||
|
|
||||||
const res = await uni.request({
|
// 获取用户位置用于查询附近设备
|
||||||
url: `${URL}/device/position/app/list`,
|
let userLocation = null
|
||||||
method: 'GET',
|
try {
|
||||||
header: {
|
userLocation = uni.getStorageSync('userLocation')
|
||||||
'Authorization': 'Bearer ' + uni.getStorageSync('token'),
|
} catch (e) {
|
||||||
'Clientid': uni.getStorageSync('client_id')
|
console.warn('获取用户位置失败:', e)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!userLocation || !userLocation.latitude || !userLocation.longitude) {
|
||||||
|
// 如果没有用户位置,使用默认位置
|
||||||
|
userLocation = { latitude: 39.916527, longitude: 116.397128 }
|
||||||
|
}
|
||||||
|
|
||||||
|
const res = await getNearbyDevices({
|
||||||
|
userLatitude: userLocation.latitude,
|
||||||
|
userLongitude: userLocation.longitude,
|
||||||
|
queryType: 'rent', // 查询可租借设备
|
||||||
|
radiusKm: 50, // 扩大查询范围以确保能找到目标设备
|
||||||
|
pageNum: 1,
|
||||||
|
pageSize: 100
|
||||||
})
|
})
|
||||||
|
|
||||||
if (res.statusCode === 200 && res.data?.code === 200) {
|
if (res.code === 200) {
|
||||||
const positions = res.data.rows || []
|
const devices = res.data?.records || []
|
||||||
|
// 将设备数据转换为统一格式
|
||||||
|
const positions = devices.map(transformDeviceData)
|
||||||
|
|
||||||
const position = positions.find(p => p.positionId === positionId.value)
|
const position = positions.find(p => p.positionId === positionId.value)
|
||||||
if (position) {
|
if (position) {
|
||||||
positionInfo.value = position
|
positionInfo.value = position
|
||||||
} else {
|
} else {
|
||||||
uni.showToast({
|
uni.showToast({
|
||||||
title: this.$t('location.notExist'),
|
title: $t('location.notExist'),
|
||||||
icon: 'none'
|
icon: 'none'
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
} else if (res.statusCode === 401 || res.data?.code === 401 || res.data?.code === 40101) {
|
|
||||||
uni.reLaunch({
|
|
||||||
url: '/pages/login/index'
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error('加载场地详情失败:', e)
|
console.error('加载设备详情失败:', e)
|
||||||
uni.showToast({
|
uni.showToast({
|
||||||
title: $t('common.loadFailed'),
|
title: $t('common.loadFailed'),
|
||||||
icon: 'none'
|
icon: 'none'
|
||||||
|
|||||||
+65
-18
@@ -19,7 +19,10 @@
|
|||||||
<view class="card" :class="{ available: isRentable(item), invalid: !isValidCoordinate(item.latitude, item.longitude) }"
|
<view class="card" :class="{ available: isRentable(item), invalid: !isValidCoordinate(item.latitude, item.longitude) }"
|
||||||
v-for="(item, index) in filteredPositions" :key="item.positionId || index"
|
v-for="(item, index) in filteredPositions" :key="item.positionId || index"
|
||||||
@click="goToPositionDetail(item)">
|
@click="goToPositionDetail(item)">
|
||||||
<view class="thumb"></view>
|
<view class="thumb">
|
||||||
|
<image v-if="item.deviceImg" :src="item.deviceImg" class="thumb-img" mode="aspectFill"></image>
|
||||||
|
<image v-else src="/static/device-info.png" class="thumb-img" mode="aspectFit"></image>
|
||||||
|
</view>
|
||||||
<view class="info">
|
<view class="info">
|
||||||
<view class="row top">
|
<view class="row top">
|
||||||
<view class="name">{{ item.name }}</view>
|
<view class="name">{{ item.name }}</view>
|
||||||
@@ -34,6 +37,15 @@
|
|||||||
<view class="row meta" v-if="!isValidCoordinate(item.latitude, item.longitude)">
|
<view class="row meta" v-if="!isValidCoordinate(item.latitude, item.longitude)">
|
||||||
<text class="time" style="color: #ff6b6b;">{{ $t('location.coordinateError') }}</text>
|
<text class="time" style="color: #ff6b6b;">{{ $t('location.coordinateError') }}</text>
|
||||||
</view>
|
</view>
|
||||||
|
<view class="row meta" v-if="item.availablePowerBankCount !== undefined && item.availablePowerBankCount !== null">
|
||||||
|
<text class="time">可租借:{{ item.availablePowerBankCount }} 台</text>
|
||||||
|
</view>
|
||||||
|
<view class="row meta" v-if="item.availableEmptyGridCount !== undefined && item.availableEmptyGridCount !== null">
|
||||||
|
<text class="time">可归还:{{ item.availableEmptyGridCount }} 个空位</text>
|
||||||
|
</view>
|
||||||
|
<view class="row meta remark-info" v-if="item.remark">
|
||||||
|
<text class="time">💰 {{ item.remark }}</text>
|
||||||
|
</view>
|
||||||
<view class="tags">
|
<view class="tags">
|
||||||
<view class="tag rent" v-if="isRentable(item)">{{ $t('location.rent') }}</view>
|
<view class="tag rent" v-if="isRentable(item)">{{ $t('location.rent') }}</view>
|
||||||
<view class="tag return" v-if="isReturnable(item)">{{ $t('location.return') }}</view>
|
<view class="tag return" v-if="isReturnable(item)">{{ $t('location.return') }}</view>
|
||||||
@@ -68,8 +80,9 @@
|
|||||||
} from 'vue'
|
} from 'vue'
|
||||||
import MapComponent from '../../components/MapComponent.vue'
|
import MapComponent from '../../components/MapComponent.vue'
|
||||||
import {
|
import {
|
||||||
URL
|
getNearbyDevices,
|
||||||
} from '../../config/url.js'
|
transformDeviceData
|
||||||
|
} from '../../config/api/device.js'
|
||||||
import {
|
import {
|
||||||
getUserLocation,
|
getUserLocation,
|
||||||
getRegeo,
|
getRegeo,
|
||||||
@@ -109,7 +122,10 @@
|
|||||||
|
|
||||||
const setTab = (name) => {
|
const setTab = (name) => {
|
||||||
activeTab.value = name
|
activeTab.value = name
|
||||||
applyFilter()
|
// 切换 tab 时重新查询设备列表(因为接口需要不同的 queryType)
|
||||||
|
if (userLocation.value) {
|
||||||
|
loadPositions(userLocation.value)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const applyFilter = () => {
|
const applyFilter = () => {
|
||||||
@@ -157,28 +173,43 @@
|
|||||||
const loadPositions = async (center) => {
|
const loadPositions = async (center) => {
|
||||||
try {
|
try {
|
||||||
isLoading.value = true
|
isLoading.value = true
|
||||||
const res = await uni.request({
|
|
||||||
url: `${URL}/device/position/app/list`,
|
if (!center || !center.latitude || !center.longitude) {
|
||||||
method: 'GET',
|
console.warn('中心点位置信息不完整,无法查询附近设备')
|
||||||
header: {
|
return
|
||||||
'Authorization': 'Bearer ' + uni.getStorageSync('token'),
|
}
|
||||||
'Clientid': uni.getStorageSync('client_id')
|
|
||||||
|
const res = await getNearbyDevices({
|
||||||
|
userLatitude: center.latitude,
|
||||||
|
userLongitude: center.longitude,
|
||||||
|
queryType: activeTab.value, // 使用当前选中的 tab (rent/return)
|
||||||
|
radiusKm: 5,
|
||||||
|
pageNum: 1,
|
||||||
|
pageSize: 100
|
||||||
|
})
|
||||||
|
|
||||||
|
if (res.code === 200) {
|
||||||
|
// 新接口返回的是 data.records
|
||||||
|
const devices = res.data?.records || []
|
||||||
|
|
||||||
|
// 将设备数据转换为统一格式
|
||||||
|
positionList.value = devices.map(device => {
|
||||||
|
const transformed = transformDeviceData(device)
|
||||||
|
// 根据当前 tab 设置租借和归还能力
|
||||||
|
return {
|
||||||
|
...transformed,
|
||||||
|
canRent: activeTab.value === 'rent' ? true : (device.availablePowerBankCount > 0),
|
||||||
|
canReturn: activeTab.value === 'return' ? true : (device.availableEmptyGridCount > 0)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
if (res.statusCode === 200 && res.data?.code === 200) {
|
|
||||||
// 过滤掉特定的 positionId
|
|
||||||
const filteredData = (res.data.rows || []).filter(item => item.positionId !== '1979008434641670145')
|
|
||||||
positionList.value = filteredData
|
|
||||||
calculateDistances(center)
|
calculateDistances(center)
|
||||||
} else if (res.statusCode === 401 || res.data?.code === 401 || res.data?.code === 40101) {
|
|
||||||
uni.reLaunch({
|
|
||||||
url: '/pages/login/index'
|
|
||||||
})
|
|
||||||
} else {
|
} else {
|
||||||
positionList.value = []
|
positionList.value = []
|
||||||
filteredPositions.value = []
|
filteredPositions.value = []
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
console.error('查询附近设备失败:', e)
|
||||||
positionList.value = []
|
positionList.value = []
|
||||||
filteredPositions.value = []
|
filteredPositions.value = []
|
||||||
} finally {
|
} finally {
|
||||||
@@ -359,6 +390,13 @@
|
|||||||
height: 120rpx;
|
height: 120rpx;
|
||||||
border-radius: 16rpx;
|
border-radius: 16rpx;
|
||||||
background: #F0F2F5;
|
background: #F0F2F5;
|
||||||
|
overflow: hidden;
|
||||||
|
|
||||||
|
.thumb-img {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
border-radius: 16rpx;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.info {
|
.info {
|
||||||
@@ -397,6 +435,15 @@
|
|||||||
.row.meta {
|
.row.meta {
|
||||||
color: #999;
|
color: #999;
|
||||||
font-size: 22rpx;
|
font-size: 22rpx;
|
||||||
|
|
||||||
|
&.remark-info {
|
||||||
|
color: #FF6B35;
|
||||||
|
font-weight: 500;
|
||||||
|
|
||||||
|
.time {
|
||||||
|
color: #FF6B35;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.tags {
|
.tags {
|
||||||
|
|||||||
Reference in New Issue
Block a user