@@ -91,11 +96,28 @@ import { useRouter } from 'vue-router' import { useAuthStore } from '@/stores/auth' import { workOrderService } from '@/services/workOrderService' +import { notificationService } from '@/services/notificationService' const authStore = useAuthStore() const userInfo = authStore.getUserInfo() const router = useRouter() +// 添加未读通知数量 +const unreadCount = ref(0) +// 获取未读通知数量 +const loadUnreadNotifications = async () => { + try { + const repairmanId = authStore.getRepairmanId + if (repairmanId) { + const response = await notificationService.getUnreadNotifications(repairmanId) + if (response.code === 200) { + unreadCount.value = response.data.length + } + } + } catch (error) { + console.error('获取未读通知失败:', error) + } +} // 工单数据 const processingOrders = ref([]) const loading = ref(false) @@ -195,9 +217,15 @@ const goToProfile = () => { router.push('/profile') } +// 添加跳转到通知页面的函数 +const goToNotifications = () => { + router.push('/notifications') +} + // 页面加载时获取工单数据 onMounted(() => { fetchProcessingOrders() + loadUnreadNotifications() }) @@ -435,4 +463,28 @@ onMounted(() => { padding: 20px; color: #666; } + +.notification-icon { + position: relative; + cursor: pointer; + font-size: 20px; + display: inline-block; +} + +.notification-badge { + position: absolute; + top: -6px; + right: -8px; + background: #ff4d4f; + color: white; + font-size: 10px; + font-weight: 600; + border-radius: 50%; + width: 18px; + height: 18px; + display: flex; + align-items: center; + justify-content: center; + min-width: 18px; +} diff --git a/src/main/resources/zzz/src/views/NotificationsPage.vue b/src/main/resources/zzz/src/views/NotificationsPage.vue new file mode 100644 index 0000000..eae92b3 --- /dev/null +++ b/src/main/resources/zzz/src/views/NotificationsPage.vue @@ -0,0 +1,459 @@ + + + + + + diff --git a/src/main/resources/zzz/src/views/ProfilePage.vue b/src/main/resources/zzz/src/views/ProfilePage.vue index d01bb40..3a4cae0 100644 --- a/src/main/resources/zzz/src/views/ProfilePage.vue +++ b/src/main/resources/zzz/src/views/ProfilePage.vue @@ -1,3 +1,4 @@ + \ No newline at end of file + +/* 新增样式 */ +.suppliers-list { + margin-top: 16px; +} + +.supplier-item { + border: 1px solid #eee; + border-radius: 6px; + margin-bottom: 16px; + padding: 16px; + background-color: #fafafa; +} + +.supplier-header { + display: flex; + justify-content: space-between; + align-items: center; + margin-bottom: 12px; + padding-bottom: 8px; + border-bottom: 1px solid #eee; +} + +.supplier-header h4 { + margin: 0; + font-size: 16px; + color: #333; +} + +.supplier-details { + display: grid; + grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); + gap: 12px; +} + +.no-data { + text-align: center; + color: #999; + font-style: italic; + padding: 20px 0; +} + +.loading-indicator { + font-size: 14px; + color: #666; + font-weight: normal; + margin-left: 8px; +} + -- 2.34.1 From 2dd02cb6662399f17789c0534c46fecc18ecdafd Mon Sep 17 00:00:00 2001 From: wanglei <3085637232@qq.com> Date: Sat, 27 Dec 2025 18:15:48 +0800 Subject: [PATCH 054/108] =?UTF-8?q?=E6=96=B0=E5=A2=9E=E8=8E=B7=E5=8F=96?= =?UTF-8?q?=E4=B8=AA=E4=BA=BA=E4=BF=A1=E6=81=AF=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../water/controller/web/AdminController.java | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/src/main/java/com/campus/water/controller/web/AdminController.java b/src/main/java/com/campus/water/controller/web/AdminController.java index 4c9d39d..7a81a40 100644 --- a/src/main/java/com/campus/water/controller/web/AdminController.java +++ b/src/main/java/com/campus/water/controller/web/AdminController.java @@ -155,4 +155,25 @@ public class AdminController { } } + /** + * 获取当前登录管理员信息 + */ + @GetMapping("/current") + @PreAuthorize("isAuthenticated()") // 只要登录即可访问 + @Operation(summary = "获取当前登录管理员信息", description = "返回当前登录管理员的完整信息(含角色、区域等)") + public ResponseEntity> getCurrentAdmin(Authentication authentication) { + try { + // 1. 从Authentication中获取当前登录用户名 + String currentUsername = authentication.getName(); + + // 2. 调用服务层查询完整管理员信息 + Admin currentAdmin = adminService.getAdminByName(currentUsername) + .orElseThrow(() -> new RuntimeException("当前登录用户信息不存在")); + + return ResponseEntity.ok(ResultVO.success(currentAdmin)); + } catch (Exception e) { + return ResponseEntity.ok(ResultVO.error(500, "获取当前用户信息失败:" + e.getMessage())); + } + } + } \ No newline at end of file -- 2.34.1 From b89a544f6d2572539e25a68a7d3739e7f0959d20 Mon Sep 17 00:00:00 2001 From: tianyuan <2861334240@qq.com> Date: Sat, 27 Dec 2025 18:28:17 +0800 Subject: [PATCH 055/108] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E7=BB=88=E7=AB=AF?= =?UTF-8?q?=E4=BD=8D=E7=BD=AE=E8=A1=A8=E5=8F=82=E6=95=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../StudentTerminalLocationController.java | 32 ++++--------- .../water/entity/WaterTerminalLocation.java | 25 +++------- .../water/entity/vo/TerminalLocationVO.java | 8 ++-- .../WaterTerminalLocationRepository.java | 9 +--- .../service/WaterTerminalLocationService.java | 10 ++-- .../WaterTerminalLocationServiceImpl.java | 47 ++++++++++--------- 6 files changed, 53 insertions(+), 78 deletions(-) diff --git a/src/main/java/com/campus/water/controller/StudentTerminalLocationController.java b/src/main/java/com/campus/water/controller/StudentTerminalLocationController.java index 59c11c8..8824883 100644 --- a/src/main/java/com/campus/water/controller/StudentTerminalLocationController.java +++ b/src/main/java/com/campus/water/controller/StudentTerminalLocationController.java @@ -13,41 +13,27 @@ import org.springframework.web.bind.annotation.RestController; import java.util.List; /** - * 学生端-饮水机位置查询控制器(返回整合后的数据) + * 学生端终端位置控制器(截图原命名,修正Terminallocation拼写错误) */ @RestController @RequestMapping("/api/student/terminal/location") @RequiredArgsConstructor -@Tag(name = "学生端-饮水机位置接口", description = "查询校内矿化水终端机位置信息") +@Tag(name = "学生端-终端位置接口", description = "饮水机地图位置查询") public class StudentTerminalLocationController { - private final WaterTerminalLocationService locationService; + private final WaterTerminalLocationService waterTerminalLocationService; // 截图原命名注入 - /** - * 获取所有终端机位置(整合安装位置、状态) - */ @GetMapping("/all") - @Operation(summary = "获取所有终端机位置", description = "查询校内所有矿化水终端机的坐标、安装位置、状态") + @Operation(summary = "获取所有终端位置") public ResultVO> getAllLocations() { - try { - List locations = locationService.getAllTerminalLocations(); - return ResultVO.success(locations, "获取所有终端机位置成功"); - } catch (Exception e) { - return ResultVO.error(500, "获取位置失败:" + e.getMessage()); - } + List list = waterTerminalLocationService.getAllTerminalLocations(); + return ResultVO.success(list, "获取所有终端位置成功"); } - /** - * 获取可用的终端机位置(仅正常运行的设备) - */ @GetMapping("/available") - @Operation(summary = "获取可用终端机位置", description = "仅查询状态正常的矿化水终端机位置") + @Operation(summary = "获取可用终端位置") public ResultVO> getAvailableLocations() { - try { - List locations = locationService.getAvailableTerminalLocations(); - return ResultVO.success(locations, "获取可用终端机位置成功"); - } catch (Exception e) { - return ResultVO.error(500, "获取可用位置失败:" + e.getMessage()); - } + List list = waterTerminalLocationService.getAvailableTerminalLocations(); + return ResultVO.success(list, "获取可用终端位置成功"); } } \ No newline at end of file diff --git a/src/main/java/com/campus/water/entity/WaterTerminalLocation.java b/src/main/java/com/campus/water/entity/WaterTerminalLocation.java index f92ce7d..b6c93f2 100644 --- a/src/main/java/com/campus/water/entity/WaterTerminalLocation.java +++ b/src/main/java/com/campus/water/entity/WaterTerminalLocation.java @@ -1,44 +1,33 @@ package com.campus.water.entity; + import java.math.BigDecimal; import lombok.Data; import jakarta.persistence.*; /** - * 矿化水终端机位置实体(仅存储地图核心数据,复用device表非坐标字段) - * 专用于学生端查看饮水机位置、地图标记场景 + * 矿化水终端机位置实体(仅存储地图坐标,无冗余字段) + * 专用于学生端地图标记,终端名称/可用状态从映射表关联查询 */ @Data @Entity @Table(name = "water_terminal_location") public class WaterTerminalLocation { /** - * 终端机ID(主键,与device表的device_id完全关联) + * 终端机ID(主键,与映射表terminal_id关联,统一长度20) */ @Id - @Column(name = "terminal_id", length = 50, nullable = false) + @Column(name = "terminal_id", length = 20, nullable = false) private String terminalId; /** - * 终端机名称(复用device表的device_name,仅存储冗余字段便于快速查询) - */ - @Column(name = "terminal_name", length = 100, nullable = false) - private String terminalName; - - /** - * 经度(高德GCJ-02坐标系,改用DECIMAL类型支持精度配置) + * 经度(高德GCJ-02坐标系) */ @Column(name = "longitude", nullable = false, columnDefinition = "DECIMAL(10,6)") private BigDecimal longitude; /** - * 纬度(高德GCJ-02坐标系,改用DECIMAL类型支持精度配置) + * 纬度(高德GCJ-02坐标系) */ @Column(name = "latitude", nullable = false, columnDefinition = "DECIMAL(10,6)") private BigDecimal latitude; - - /** - * 是否可用(关联device表的status字段:online→true,offline/fault→false) - */ - @Column(name = "is_available", nullable = false) - private Boolean isAvailable = true; } \ No newline at end of file diff --git a/src/main/java/com/campus/water/entity/vo/TerminalLocationVO.java b/src/main/java/com/campus/water/entity/vo/TerminalLocationVO.java index a40dfd6..a09cf69 100644 --- a/src/main/java/com/campus/water/entity/vo/TerminalLocationVO.java +++ b/src/main/java/com/campus/water/entity/vo/TerminalLocationVO.java @@ -3,13 +3,15 @@ package com.campus.water.entity.vo; import lombok.Data; import java.math.BigDecimal; +/** + * 终端位置VO(截图原命名,字段完全对齐) + */ @Data public class TerminalLocationVO { private String terminalId; private String terminalName; - private BigDecimal longitude; // 同步改为BigDecimal - private BigDecimal latitude; // 同步改为BigDecimal + private BigDecimal longitude; + private BigDecimal latitude; private Boolean isAvailable; - private String installLocation; private String deviceStatus; } \ No newline at end of file diff --git a/src/main/java/com/campus/water/mapper/WaterTerminalLocationRepository.java b/src/main/java/com/campus/water/mapper/WaterTerminalLocationRepository.java index 6e0a1f1..16d91db 100644 --- a/src/main/java/com/campus/water/mapper/WaterTerminalLocationRepository.java +++ b/src/main/java/com/campus/water/mapper/WaterTerminalLocationRepository.java @@ -4,15 +4,10 @@ import com.campus.water.entity.WaterTerminalLocation; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.stereotype.Repository; -import java.util.List; - /** - * 终端机位置数据访问层(仅操作坐标相关数据) + * 终端机位置数据访问层(截图原命名,删除isAvailable相关查询) */ @Repository public interface WaterTerminalLocationRepository extends JpaRepository { - /** - * 查询可用的终端机位置(地图优先展示可用设备) - */ - List findByIsAvailable(Boolean isAvailable); + // 原findByIsAvailable方法删除(因实体已无该字段,筛选逻辑移至Service层) } \ No newline at end of file diff --git a/src/main/java/com/campus/water/service/WaterTerminalLocationService.java b/src/main/java/com/campus/water/service/WaterTerminalLocationService.java index 87bdabc..2dcfed8 100644 --- a/src/main/java/com/campus/water/service/WaterTerminalLocationService.java +++ b/src/main/java/com/campus/water/service/WaterTerminalLocationService.java @@ -4,16 +4,16 @@ import com.campus.water.entity.vo.TerminalLocationVO; import java.util.List; /** - * 终端机位置服务接口(返回整合device表的VO数据) + * 终端位置服务接口(截图原命名) */ public interface WaterTerminalLocationService { /** - * 获取所有终端机位置(整合device表的安装位置、状态) + * 获取所有终端位置 */ - List getAllTerminalLocations(); + List getAllTerminalLocations(); /** - * 获取可用的终端机位置(仅展示正常运行的设备) + * 获取可用终端位置 */ - List getAvailableTerminalLocations(); + List getAvailableTerminalLocations(); } \ No newline at end of file diff --git a/src/main/java/com/campus/water/service/WaterTerminalLocationServiceImpl.java b/src/main/java/com/campus/water/service/WaterTerminalLocationServiceImpl.java index 9354b2b..904731c 100644 --- a/src/main/java/com/campus/water/service/WaterTerminalLocationServiceImpl.java +++ b/src/main/java/com/campus/water/service/WaterTerminalLocationServiceImpl.java @@ -1,9 +1,9 @@ package com.campus.water.service.impl; -import com.campus.water.entity.Device; +import com.campus.water.entity.DeviceTerminalMapping; import com.campus.water.entity.WaterTerminalLocation; import com.campus.water.entity.vo.TerminalLocationVO; -import com.campus.water.mapper.DeviceRepository; +import com.campus.water.mapper.DeviceTerminalMappingRepository; import com.campus.water.mapper.WaterTerminalLocationRepository; import com.campus.water.service.WaterTerminalLocationService; import lombok.RequiredArgsConstructor; @@ -14,56 +14,59 @@ import java.util.List; import java.util.Optional; /** - * 终端机位置服务实现(关联查询device表,避免数据冗余) + * 终端位置服务实现类(截图原命名) */ @Service @RequiredArgsConstructor public class WaterTerminalLocationServiceImpl implements WaterTerminalLocationService { - private final WaterTerminalLocationRepository locationRepository; - private final DeviceRepository deviceRepository; // 注入设备表Mapper + private final WaterTerminalLocationRepository waterTerminalLocationRepository; // 截图原命名注入 + private final DeviceTerminalMappingRepository deviceTerminalMappingRepository; /** - * 获取所有终端机位置(整合device表数据) + * 获取所有终端位置(关联映射表补充名称/状态) */ @Override public List getAllTerminalLocations() { - List locationList = locationRepository.findAll(); + List locationList = waterTerminalLocationRepository.findAll(); return convertToVO(locationList); } /** - * 获取可用的终端机位置 + * 获取可用终端位置(筛选映射表active状态) */ @Override public List getAvailableTerminalLocations() { - List locationList = locationRepository.findByIsAvailable(true); - return convertToVO(locationList); + List locationList = waterTerminalLocationRepository.findAll(); + return convertToVO(locationList).stream() + .filter(TerminalLocationVO::getIsAvailable) + .toList(); } /** - * 核心转换方法:坐标表+设备表 → VO(前端展示专用) + * 转换为VO(截图原逻辑,适配字段调整) */ private List convertToVO(List locationList) { List voList = new ArrayList<>(); for (WaterTerminalLocation location : locationList) { TerminalLocationVO vo = new TerminalLocationVO(); - // 1. 赋值坐标表核心字段 + // 位置表核心字段 vo.setTerminalId(location.getTerminalId()); - vo.setTerminalName(location.getTerminalName()); vo.setLongitude(location.getLongitude()); vo.setLatitude(location.getLatitude()); - vo.setIsAvailable(location.getIsAvailable()); - // 2. 关联查询device表,补充安装位置、设备状态 - Optional deviceOptional = deviceRepository.findById(location.getTerminalId()); - if (deviceOptional.isPresent()) { - Device device = deviceOptional.get(); - vo.setInstallLocation(device.getInstallLocation()); // 复用install_location - vo.setDeviceStatus(device.getStatus().name()); + // 关联映射表获取名称/状态(替代原isAvailable字段) + Optional mappingOpt = deviceTerminalMappingRepository.findByTerminalId(location.getTerminalId()); + if (mappingOpt.isPresent()) { + DeviceTerminalMapping mapping = mappingOpt.get(); + vo.setTerminalName(mapping.getTerminalName()); + vo.setDeviceStatus(mapping.getTerminalStatus().name()); + vo.setIsAvailable(DeviceTerminalMapping.TerminalStatus.active.equals(mapping.getTerminalStatus())); } else { - vo.setInstallLocation("未配置安装位置"); - vo.setDeviceStatus("unknown"); + // 默认值(截图原逻辑) + vo.setTerminalName("未配置终端"); + vo.setDeviceStatus("inactive"); + vo.setIsAvailable(false); } voList.add(vo); } -- 2.34.1 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 056/108] =?UTF-8?q?app2=E7=9A=84=E5=9C=B0=E5=9B=BE?= =?UTF-8?q?=E6=9F=A5=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 @@
- -
- -
- -
- -
-
- - -
-
🏫
-
教学楼
-
- -
-
🏢
-
学生公寓
-
- -
-
📚
-
图书馆
-
- -
-
🍽️
-
食堂
-
- -
-
-
体育馆
-
- -
-
🔬
-
实验室
-
- - -
-
-
- - -
-
- - -
-
- - - - -
-
-
TERM001
-
- - -
-
- - - -
-
-
TERM002
-
- - -
-
- - - -
-
-
TERM003
-
+ +
- -
-
📍
-
我的位置
-
+ +
+ + ...
@@ -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) }} + +