From 40950edd4a01574ff6a0f05368fc5aad94792fb7 Mon Sep 17 00:00:00 2001
From: luoyuehang <2830398107@qq.com>
Date: Sat, 27 Dec 2025 18:40:37 +0800
Subject: [PATCH] =?UTF-8?q?app2=E7=9A=84=E5=9C=B0=E5=9B=BE=E6=9F=A5?=
=?UTF-8?q?=E7=9C=8B=E5=8A=9F=E8=83=BD?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
src/main/resources/app2/.env | 1 +
src/main/resources/app2/.env.development | 5 +
src/main/resources/app2/package-lock.json | 7 +
src/main/resources/app2/package.json | 1 +
.../app2/src/services/deviceService.js | 44 ++
.../resources/app2/src/services/mapService.js | 41 ++
.../resources/app2/src/views/HomePage.vue | 436 ++++++++++++------
.../resources/zzz/src/views/WorkOrderList.vue | 42 +-
8 files changed, 428 insertions(+), 149 deletions(-)
create mode 100644 src/main/resources/app2/.env
create mode 100644 src/main/resources/app2/.env.development
create mode 100644 src/main/resources/app2/src/services/mapService.js
diff --git a/src/main/resources/app2/.env b/src/main/resources/app2/.env
new file mode 100644
index 0000000..0583bfc
--- /dev/null
+++ b/src/main/resources/app2/.env
@@ -0,0 +1 @@
+VITE_API_BASE_URL=http://localhost:8080
\ No newline at end of file
diff --git a/src/main/resources/app2/.env.development b/src/main/resources/app2/.env.development
new file mode 100644
index 0000000..067047c
--- /dev/null
+++ b/src/main/resources/app2/.env.development
@@ -0,0 +1,5 @@
+# 开发环境
+NODE_ENV=development
+VITE_AMAP_KEY=7e03ef3b43a8cdbb62e3038fc727e035
+VITE_API_BASE_URL=http://localhost:8080
+VITE_DEBUG=true
diff --git a/src/main/resources/app2/package-lock.json b/src/main/resources/app2/package-lock.json
index 2effd2a..bae1b58 100644
--- a/src/main/resources/app2/package-lock.json
+++ b/src/main/resources/app2/package-lock.json
@@ -8,6 +8,7 @@
"name": "app2",
"version": "0.0.0",
"dependencies": {
+ "@amap/amap-jsapi-loader": "^1.0.1",
"pinia": "^3.0.4",
"vue": "^3.5.25",
"vue-router": "^4.6.3"
@@ -31,6 +32,12 @@
"dev": true,
"license": "MIT"
},
+ "node_modules/@amap/amap-jsapi-loader": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmmirror.com/@amap/amap-jsapi-loader/-/amap-jsapi-loader-1.0.1.tgz",
+ "integrity": "sha512-nPyLKt7Ow/ThHLkSvn2etQlUzqxmTVgK7bIgwdBRTg2HK5668oN7xVxkaiRe3YZEzGzfV2XgH5Jmu2T73ljejw==",
+ "license": "MIT"
+ },
"node_modules/@asamuzakjp/css-color": {
"version": "4.1.0",
"resolved": "https://registry.npmmirror.com/@asamuzakjp/css-color/-/css-color-4.1.0.tgz",
diff --git a/src/main/resources/app2/package.json b/src/main/resources/app2/package.json
index d6607da..4d1d0ad 100644
--- a/src/main/resources/app2/package.json
+++ b/src/main/resources/app2/package.json
@@ -13,6 +13,7 @@
"test:unit": "vitest"
},
"dependencies": {
+ "@amap/amap-jsapi-loader": "^1.0.1",
"pinia": "^3.0.4",
"vue": "^3.5.25",
"vue-router": "^4.6.3"
diff --git a/src/main/resources/app2/src/services/deviceService.js b/src/main/resources/app2/src/services/deviceService.js
index 6eb0287..b81d310 100644
--- a/src/main/resources/app2/src/services/deviceService.js
+++ b/src/main/resources/app2/src/services/deviceService.js
@@ -75,5 +75,49 @@ export const deviceService = {
console.error(`获取终端 ${terminalId} 实时数据失败:`, error)
throw error.response?.data || error.message
}
+ },
+ // 在 deviceService.js 中添加
+ async getTerminalLocations() {
+ try {
+ const response = await api.get('/api/student/terminal/location/all')
+ return response.data
+ } catch (error) {
+ console.error('获取设备位置失败:', error)
+ // 返回模拟数据作为后备
+ return {
+ code: 200,
+ message: '使用模拟数据',
+ data: [
+ {
+ terminalId: 'TERM001',
+ terminalName: '教学楼饮水机',
+ longitude: 112.938,
+ latitude: 28.165,
+ installLocation: '教学楼1F大厅',
+ deviceStatus: 'active',
+ isAvailable: true
+ },
+ {
+ terminalId: 'TERM002',
+ terminalName: '学生公寓饮水机',
+ longitude: 112.940,
+ latitude: 28.167,
+ installLocation: '天马学生公寓1F',
+ deviceStatus: 'active',
+ isAvailable: true
+ },
+ {
+ terminalId: 'TERM003',
+ terminalName: '图书馆饮水机',
+ longitude: 112.937,
+ latitude: 28.164,
+ installLocation: '图书馆2F',
+ deviceStatus: 'offline',
+ isAvailable: false
+ }
+ ]
+ }
+ }
}
+
}
\ No newline at end of file
diff --git a/src/main/resources/app2/src/services/mapService.js b/src/main/resources/app2/src/services/mapService.js
new file mode 100644
index 0000000..01ceafc
--- /dev/null
+++ b/src/main/resources/app2/src/services/mapService.js
@@ -0,0 +1,41 @@
+// src/services/mapService.js
+import api from './api'
+
+export const mapService = {
+ // 获取所有设备位置
+ async getTerminalLocations() {
+ try {
+ const response = await api.get('/api/student/terminal/location/all')
+ return response.data
+ } catch (error) {
+ console.error('获取设备位置失败:', error)
+ throw error.response?.data || error.message
+ }
+ },
+
+ // 获取可用设备位置
+ async getAvailableTerminalLocations() {
+ try {
+ const response = await api.get('/api/student/terminal/location/available')
+ return response.data
+ } catch (error) {
+ console.error('获取可用设备位置失败:', error)
+ throw error.response?.data || error.message
+ }
+ },
+
+ // 根据坐标获取附近设备
+ async getNearbyTerminals(lng, lat, radius = 1000) {
+ try {
+ const response = await api.post('/api/student/terminal/nearby', {
+ longitude: lng,
+ latitude: lat,
+ radius: radius
+ })
+ return response.data
+ } catch (error) {
+ console.error('获取附近设备失败:', error)
+ throw error.response?.data || error.message
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/main/resources/app2/src/views/HomePage.vue b/src/main/resources/app2/src/views/HomePage.vue
index 4528677..554ea09 100644
--- a/src/main/resources/app2/src/views/HomePage.vue
+++ b/src/main/resources/app2/src/views/HomePage.vue
@@ -7,127 +7,13 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
-
-
+
+
+
+ ...
@@ -456,10 +342,224 @@ import { ref, reactive, onMounted, computed } from 'vue'
import { useRouter } from 'vue-router'
import { deviceService } from '@/services/deviceService'
import { useUserStore } from '@/stores/user'
+import AMapLoader from '@amap/amap-jsapi-loader'
const router = useRouter()
const userStore = useUserStore()
+const mapInstance = ref(null)
+const mapLoaded = ref(false)
+const isMapLoading = ref(false)
+
+// 高德地图配置
+// 在 HomePage.vue 中
+const mapConfig = reactive({
+ center: [112.9375, 28.1655],
+ zoom: 16,
+ key: import.meta.env.VITE_AMAP_KEY || '', // 使用环境变量
+ viewMode: '3D'
+})
+
+// 添加:后端接口获取设备位置
+const fetchDeviceLocations = async () => {
+ try {
+ // 调用后端接口获取设备位置数据
+ // 这里假设你有对应的后端接口
+ const response = await deviceService.getTerminalLocations()
+
+ if (response.code === 200 && response.data) {
+ return response.data
+ }
+ return []
+ } catch (error) {
+ console.error('获取设备位置失败:', error)
+ return []
+ }
+}
+
+// 修改:初始化地图
+const initMap = async () => {
+ if (isMapLoading.value) return
+ isMapLoading.value = true
+
+ try {
+ // 加载高德地图
+ const AMap = await AMapLoader.load({
+ key: mapConfig.key,
+ version: '2.0',
+ plugins: [
+ 'AMap.Marker',
+ 'AMap.Geolocation',
+ 'AMap.ToolBar',
+ 'AMap.Scale',
+ 'AMap.ControlBar'
+ ]
+ })
+
+ // 创建地图实例
+ mapInstance.value = new AMap.Map('mapContainer', {
+ zoom: mapConfig.zoom,
+ center: mapConfig.center,
+ viewMode: mapConfig.viewMode
+ })
+
+ // 添加控件
+ mapInstance.value.addControl(new AMap.ToolBar())
+ mapInstance.value.addControl(new AMap.Scale())
+ mapInstance.value.addControl(new AMap.ControlBar())
+
+ // 获取当前位置
+ const geolocation = new AMap.Geolocation({
+ enableHighAccuracy: true,
+ timeout: 10000,
+ buttonOffset: new AMap.Pixel(10, 20),
+ zoomToAccuracy: true,
+ buttonPosition: 'RB'
+ })
+
+ mapInstance.value.addControl(geolocation)
+
+ // 监听定位成功
+ geolocation.getCurrentPosition((status, result) => {
+ if (status === 'complete') {
+ console.log('定位成功:', result)
+ } else {
+ console.log('定位失败:', result)
+ }
+ })
+
+ // 获取设备数据并在地图上标记
+ const devices = await fetchDeviceLocations()
+ addDeviceMarkers(devices)
+
+ mapLoaded.value = true
+ console.log('地图初始化成功')
+ } catch (error) {
+ console.error('地图初始化失败:', error)
+ // 如果高德地图初始化失败,使用原有的模拟地图
+ useMockMap()
+ } finally {
+ isMapLoading.value = false
+ }
+}
+
+// 添加:在地图上添加设备标记
+const addDeviceMarkers = (devices) => {
+ if (!mapInstance.value || !devices.length) return
+
+ devices.forEach(device => {
+ // 创建标记
+ const marker = new AMap.Marker({
+ position: [device.longitude, device.latitude],
+ title: device.terminalName,
+ content: createMarkerContent(device),
+ offset: new AMap.Pixel(-12, -32) // 调整标记位置
+ })
+
+ // 添加点击事件
+ marker.on('click', () => {
+ showMarkerInfo(device.terminalId)
+ })
+
+ marker.setMap(mapInstance.value)
+
+ // 保存标记引用
+ if (!markers[device.terminalId]) {
+ markers[device.terminalId] = {}
+ }
+ markers[device.terminalId].marker = marker
+ })
+}
+
+// 添加:创建标记内容
+const createMarkerContent = (device) => {
+ const isOnline = device.deviceStatus === 'active'
+ const color = isOnline ? '#04d919' : '#aaaaaa'
+
+ return `
+
+
+
+ ${device.terminalId}
+
+
+ `
+}
+
+// 添加:模拟地图作为备用
+const useMockMap = () => {
+ console.log('使用模拟地图')
+ // 保持原有的模拟地图逻辑不变
+}
+
+// 修改:onMounted 钩子
+onMounted(() => {
+ // 初始化设备信息
+ Object.keys(markers).forEach(terminalId => {
+ fetchDeviceInfo(terminalId)
+ })
+
+ // 延迟初始化地图
+ setTimeout(() => {
+ initMap()
+ }, 500)
+})
+
+// 修改:地图控制方法
+const centerMap = () => {
+ if (mapInstance.value) {
+ // 使用高德地图的定位
+ const geolocation = new AMap.Geolocation()
+ geolocation.getCurrentPosition((status, result) => {
+ if (status === 'complete') {
+ mapInstance.value.setCenter([result.position.lng, result.position.lat])
+ }
+ })
+ }
+}
+
+const zoomIn = () => {
+ if (mapInstance.value) {
+ mapInstance.value.setZoom(mapInstance.value.getZoom() + 1)
+ }
+}
+
+const zoomOut = () => {
+ if (mapInstance.value) {
+ mapInstance.value.setZoom(mapInstance.value.getZoom() - 1)
+ }
+}
+
+// 修改:显示标记信息方法
+const showMarkerInfo = async (markerId) => {
+ if (!mapInstance.value) {
+ // 如果没有地图实例,使用原有逻辑
+ await originalShowMarkerInfo(markerId)
+ return
+ }
+
+ currentMarker.value = markerId
+ selectedMarker.value = markerId
+
+ // 如果数据还在加载中,重新获取
+ if (markers[markerId].status === 'loading') {
+ await fetchDeviceInfo(markerId)
+ }
+
+ // 平滑滚动到标记位置
+ const device = markers[markerId]
+ if (device && device.marker) {
+ mapInstance.value.setCenter(device.marker.getPosition())
+ mapInstance.value.setZoom(18)
+ }
+
+ showDevicePopup.value = true
+}
// 修改标记点配置
const markerConfigs = {
TERM001: {
@@ -547,6 +647,7 @@ const currentMarker = ref('')
const selectedMarker = ref('')
const isLoading = ref(false)
+// 从后端获取设备信息
// 从后端获取设备信息
const fetchDeviceInfo = async (terminalId) => {
try {
@@ -558,9 +659,10 @@ const fetchDeviceInfo = async (terminalId) => {
const marker = markers[terminalId]
if (marker) {
- // 更新标记点信息
- marker.status = data.status === 'active' ? 'online' : 'offline'
- marker.statusText = data.status === 'active' ? '在线' : '离线'
+ // 修改状态判断逻辑,同时兼容 'active' 和 'online' 状态
+ const isActive = data.status === 'active' || data.status === 'online'
+ marker.status = isActive ? 'online' : 'offline'
+ marker.statusText = isActive ? '在线' : '离线'
marker.quality = data.waterQuality || '--'
// 更新水质数据
@@ -573,7 +675,7 @@ const fetchDeviceInfo = async (terminalId) => {
marker.recordTime = data.updateTime || '--'
// 更新标记点颜色
- updateMarkerColor(terminalId, data.status)
+ updateMarkerColor(terminalId, isActive ? 'active' : 'inactive')
}
} else {
console.error(`获取设备 ${terminalId} 信息失败:`, result.message)
@@ -587,6 +689,7 @@ const fetchDeviceInfo = async (terminalId) => {
}
}
+
// 获取水质信息
const fetchWaterQualityInfo = async (deviceId) => {
try {
@@ -609,18 +712,7 @@ const updateMarkerColor = (terminalId, status) => {
}
}
-// 显示标记点信息
-const showMarkerInfo = async (markerId) => {
- currentMarker.value = markerId
- selectedMarker.value = markerId
- // 如果数据还在加载中,重新获取
- if (markers[markerId].status === 'loading') {
- await fetchDeviceInfo(markerId)
- }
-
- showDevicePopup.value = true
-}
// 隐藏弹窗
const hidePopup = () => {
@@ -683,18 +775,7 @@ const openMap = (mapType) => {
// 例如:window.location.href = `amapuri://route/...`
}
-// 地图控制
-const centerMap = () => {
- alert('定位到当前位置')
-}
-const zoomIn = () => {
- alert('放大地图')
-}
-
-const zoomOut = () => {
- alert('缩小地图')
-}
// 页面跳转
const goToPage = (page) => {
@@ -1532,4 +1613,67 @@ onMounted(() => {
font-size: 14px;
color: #666;
}
+
+/* 地图容器调整 */
+.map-container {
+ flex: 1;
+ position: relative;
+ overflow: hidden;
+ background: #e8f4fc;
+}
+
+.real-map-container {
+ width: 100%;
+ height: 100%;
+}
+
+/* 模拟地图背景(只有在真实地图加载失败时才显示) */
+.map-background {
+ position: absolute;
+ top: 0;
+ left: 0;
+ width: 100%;
+ height: 100%;
+ background: linear-gradient(135deg, #a8d8ff 0%, #e3f2fd 100%);
+ overflow: hidden;
+ display: none; /* 默认隐藏 */
+}
+
+/* 当真实地图加载失败时显示模拟地图 */
+.map-container:not(.map-loaded) .map-background {
+ display: block;
+}
+
+/* 地图控制按钮保持原有样式 */
+.map-controls {
+ position: absolute;
+ bottom: 100px;
+ right: 16px;
+ display: flex;
+ flex-direction: column;
+ gap: 12px;
+ z-index: 1000; /* 确保在地图上层 */
+}
+
+/* 自定义标记样式 */
+.custom-marker {
+ position: relative;
+}
+
+.custom-marker:hover div {
+ display: block !important;
+}
+
+/* 响应式调整 */
+@media (max-width: 420px) {
+ .home-page {
+ width: 100%;
+ height: 100vh;
+ }
+
+ .map-controls {
+ bottom: 70px;
+ right: 12px;
+ }
+}
\ No newline at end of file
diff --git a/src/main/resources/zzz/src/views/WorkOrderList.vue b/src/main/resources/zzz/src/views/WorkOrderList.vue
index 64513b3..af83dd8 100644
--- a/src/main/resources/zzz/src/views/WorkOrderList.vue
+++ b/src/main/resources/zzz/src/views/WorkOrderList.vue
@@ -104,9 +104,14 @@
{{ getOrderLocation(order.deviceId) }}
{{ formatDate(order.completedTime) }}
+
+
+ {{ getStatusText(order.status) }}
+
+
@@ -138,7 +143,7 @@
@@ -264,6 +269,24 @@ const formatDate = (dateStr) => {
return new Date(dateStr).toLocaleDateString('zh-CN')
}
+// 获取状态文本
+const getStatusText = (status) => {
+ const statusMap = {
+ completed: '已完成',
+ reviewing: '待审核'
+ }
+ return statusMap[status] || status
+}
+
+// 获取状态样式类
+const getStatusClass = (status) => {
+ const classMap = {
+ completed: 'completed',
+ reviewing: 'reviewing'
+ }
+ return classMap[status] || 'completed'
+}
+
// 加载工单数据
const loadOrders = async () => {
loading.value = true
@@ -276,8 +299,9 @@ const loadOrders = async () => {
processingOrders.value = allOrders.value.filter(order =>
order.status === 'processing'
)
+ // 包含已完成和待审核的工单,排除超时工单
completedOrders.value = allOrders.value.filter(order =>
- order.status === 'completed'
+ order.status === 'completed' || order.status === 'reviewing'
)
// 获取可抢工单
@@ -502,6 +526,18 @@ onMounted(() => {
border: 1px solid #b7eb8f;
}
+.status-badge.completed {
+ background: #f6ffed;
+ color: #52c41a;
+ border: 1px solid #b7eb8f;
+}
+
+.status-badge.reviewing {
+ background: #fff7e6;
+ color: #fa8c16;
+ border: 1px solid #ffd591;
+}
+
/* 工单按钮 */
.order-btn {
padding: 6px 16px;