|
@@ -1,126 +1,3 @@
|
|
|
-<script setup>
|
|
|
|
|
-import { ref, onMounted } from "vue";
|
|
|
|
|
-import {
|
|
|
|
|
- ElCard,
|
|
|
|
|
- ElAvatar,
|
|
|
|
|
- ElDivider,
|
|
|
|
|
- ElBadge,
|
|
|
|
|
- ElTable,
|
|
|
|
|
- ElTableColumn,
|
|
|
|
|
- ElTag,
|
|
|
|
|
- ElProgress,
|
|
|
|
|
-} from "element-plus";
|
|
|
|
|
-import "element-plus/dist/index.css";
|
|
|
|
|
-import {
|
|
|
|
|
- Calendar,
|
|
|
|
|
- Location,
|
|
|
|
|
- User,
|
|
|
|
|
- Sunny,
|
|
|
|
|
- Cloudy,
|
|
|
|
|
- Monitor,
|
|
|
|
|
- Connection,
|
|
|
|
|
- WarningFilled,
|
|
|
|
|
- Bell,
|
|
|
|
|
-} from "@element-plus/icons-vue";
|
|
|
|
|
-
|
|
|
|
|
-// Personal info data
|
|
|
|
|
-const personalInfo = ref({
|
|
|
|
|
- name: "刘昊林",
|
|
|
|
|
- title: "系统管理员",
|
|
|
|
|
- avatar: "https://placeholder.co/150",
|
|
|
|
|
- description:
|
|
|
|
|
- "丰富系统管理经验,专注于IoT设备管理和系统维护。熟悉各类传感器和智能设备的部署与维护。",
|
|
|
|
|
- email: "guolianfa@500269.com",
|
|
|
|
|
- phone: "123-4567-8910",
|
|
|
|
|
-});
|
|
|
|
|
-// Weather data
|
|
|
|
|
-const weather = ref({
|
|
|
|
|
- location: "上海市",
|
|
|
|
|
- temperature: 24,
|
|
|
|
|
- condition: "晴朗",
|
|
|
|
|
- humidity: 65,
|
|
|
|
|
- wind: "东北风 3级",
|
|
|
|
|
- date: new Date().toLocaleDateString("zh-CN", {
|
|
|
|
|
- year: "numeric",
|
|
|
|
|
- month: "long",
|
|
|
|
|
- day: "numeric",
|
|
|
|
|
- weekday: "long",
|
|
|
|
|
- }),
|
|
|
|
|
-});
|
|
|
|
|
-
|
|
|
|
|
-// Device statistics
|
|
|
|
|
-const deviceStats = ref({
|
|
|
|
|
- online: 128,
|
|
|
|
|
- offline: 23,
|
|
|
|
|
- total: 151,
|
|
|
|
|
- onlinePercentage: 0,
|
|
|
|
|
-});
|
|
|
|
|
-
|
|
|
|
|
-// Calculate percentage
|
|
|
|
|
-onMounted(() => {
|
|
|
|
|
- deviceStats.value.onlinePercentage = Math.round(
|
|
|
|
|
- (deviceStats.value.online / deviceStats.value.total) * 100
|
|
|
|
|
- );
|
|
|
|
|
-});
|
|
|
|
|
-
|
|
|
|
|
-// Alarm data
|
|
|
|
|
-const alarms = ref([
|
|
|
|
|
- {
|
|
|
|
|
- id: 1,
|
|
|
|
|
- device: "井盖一号",
|
|
|
|
|
- type: "高温警报",
|
|
|
|
|
- location: "长沙",
|
|
|
|
|
- time: "2023-10-15 08:23:45",
|
|
|
|
|
- status: "未处理",
|
|
|
|
|
- },
|
|
|
|
|
- {
|
|
|
|
|
- id: 2,
|
|
|
|
|
- device: "井盖一号",
|
|
|
|
|
- type: "连接中断",
|
|
|
|
|
- location: "长沙",
|
|
|
|
|
- time: "2023-10-15 07:15:22",
|
|
|
|
|
- status: "已处理",
|
|
|
|
|
- },
|
|
|
|
|
- {
|
|
|
|
|
- id: 3,
|
|
|
|
|
- device: "井盖一号",
|
|
|
|
|
- type: "未授权访问",
|
|
|
|
|
- location: "长沙",
|
|
|
|
|
- time: "2023-10-14 23:42:10",
|
|
|
|
|
- status: "处理中",
|
|
|
|
|
- },
|
|
|
|
|
- {
|
|
|
|
|
- id: 4,
|
|
|
|
|
- device: "电表一号",
|
|
|
|
|
- type: "离线",
|
|
|
|
|
- location: "长沙",
|
|
|
|
|
- time: "2023-10-14 18:05:37",
|
|
|
|
|
- status: "已处理",
|
|
|
|
|
- },
|
|
|
|
|
-]);
|
|
|
|
|
-
|
|
|
|
|
-// Tag type mapping for alarm levels
|
|
|
|
|
-const tagType = {
|
|
|
|
|
- critical: "danger",
|
|
|
|
|
- warning: "warning",
|
|
|
|
|
- info: "info",
|
|
|
|
|
-};
|
|
|
|
|
-
|
|
|
|
|
-// Status tag mapping
|
|
|
|
|
-const statusTag = {
|
|
|
|
|
- 未处理: "danger",
|
|
|
|
|
- 处理中: "warning",
|
|
|
|
|
- 已处理: "success",
|
|
|
|
|
-};
|
|
|
|
|
-
|
|
|
|
|
-// Get weather icon based on condition
|
|
|
|
|
-const getWeatherIcon = (condition) => {
|
|
|
|
|
- if (condition.includes("晴")) return Sunny;
|
|
|
|
|
- if (condition.includes("云") || condition.includes("阴")) return Cloudy;
|
|
|
|
|
- return Sunny; // Default
|
|
|
|
|
-};
|
|
|
|
|
-</script>
|
|
|
|
|
-
|
|
|
|
|
<template>
|
|
<template>
|
|
|
<div class="dashboard-container">
|
|
<div class="dashboard-container">
|
|
|
<!-- Header -->
|
|
<!-- Header -->
|
|
@@ -173,20 +50,22 @@ const getWeatherIcon = (condition) => {
|
|
|
<template #header>
|
|
<template #header>
|
|
|
<div class="flex justify-between items-center">
|
|
<div class="flex justify-between items-center">
|
|
|
<h2 class="text-lg font-medium">天气信息</h2>
|
|
<h2 class="text-lg font-medium">天气信息</h2>
|
|
|
- <component class="w-10" :is="getWeatherIcon(weather.condition)" />
|
|
|
|
|
|
|
+ <component class="w-10" :is="getWeatherIcon(weathernow?.now?.text || '')" />
|
|
|
</div>
|
|
</div>
|
|
|
</template>
|
|
</template>
|
|
|
<div class="flex flex-col items-center">
|
|
<div class="flex flex-col items-center">
|
|
|
<div class="flex items-center mb-4">
|
|
<div class="flex items-center mb-4">
|
|
|
<Location class="mr-2 w-10" />
|
|
<Location class="mr-2 w-10" />
|
|
|
- <span>{{ weather.location }}</span>
|
|
|
|
|
|
|
+ <span>{{ weathernow?.location?.city }}</span>
|
|
|
</div>
|
|
</div>
|
|
|
- <div class="text-4xl font-bold mb-2">{{ weather.temperature }}°C</div>
|
|
|
|
|
- <div class="text-lg mb-4">{{ weather.condition }}</div>
|
|
|
|
|
|
|
+ <div class="text-4xl font-bold mb-2">{{ weathernow?.now?.temp }}°C</div>
|
|
|
|
|
+ <div class="text-lg mb-4">{{ weathernow?.now?.text }}</div>
|
|
|
<ElDivider />
|
|
<ElDivider />
|
|
|
<div class="w-full grid grid-cols-2 gap-2 text-sm">
|
|
<div class="w-full grid grid-cols-2 gap-2 text-sm">
|
|
|
- <div>湿度: {{ weather.humidity }}%</div>
|
|
|
|
|
- <div>风力: {{ weather.wind }}</div>
|
|
|
|
|
|
|
+ <div>湿度: {{ weathernow?.now?.rh }}%</div>
|
|
|
|
|
+ <div>
|
|
|
|
|
+ 风力: {{ weathernow?.now?.wind_dir }}{{ weathernow?.now?.wind_class }}
|
|
|
|
|
+ </div>
|
|
|
</div>
|
|
</div>
|
|
|
</div>
|
|
</div>
|
|
|
</ElCard>
|
|
</ElCard>
|
|
@@ -286,6 +165,184 @@ const getWeatherIcon = (condition) => {
|
|
|
</div>
|
|
</div>
|
|
|
</template>
|
|
</template>
|
|
|
|
|
|
|
|
|
|
+<script setup>
|
|
|
|
|
+import { ref, onMounted } from "vue";
|
|
|
|
|
+import {
|
|
|
|
|
+ ElCard,
|
|
|
|
|
+ ElAvatar,
|
|
|
|
|
+ ElDivider,
|
|
|
|
|
+ ElBadge,
|
|
|
|
|
+ ElTable,
|
|
|
|
|
+ ElTableColumn,
|
|
|
|
|
+ ElTag,
|
|
|
|
|
+ ElProgress,
|
|
|
|
|
+} from "element-plus";
|
|
|
|
|
+import "element-plus/dist/index.css";
|
|
|
|
|
+import {
|
|
|
|
|
+ Calendar,
|
|
|
|
|
+ Location,
|
|
|
|
|
+ User,
|
|
|
|
|
+ Sunny,
|
|
|
|
|
+ Cloudy,
|
|
|
|
|
+ Monitor,
|
|
|
|
|
+ Connection,
|
|
|
|
|
+ WarningFilled,
|
|
|
|
|
+ Bell,
|
|
|
|
|
+} from "@element-plus/icons-vue";
|
|
|
|
|
+import request from "@/utils/request.js";
|
|
|
|
|
+
|
|
|
|
|
+import { ElMessage } from "element-plus";
|
|
|
|
|
+
|
|
|
|
|
+// Personal info data
|
|
|
|
|
+const personalInfo = ref({
|
|
|
|
|
+ name: "刘昊林",
|
|
|
|
|
+ title: "系统管理员",
|
|
|
|
|
+ avatar: "https://placeholder.co/150",
|
|
|
|
|
+ description:
|
|
|
|
|
+ "丰富系统管理经验,专注于IoT设备管理和系统维护。熟悉各类传感器和智能设备的部署与维护。",
|
|
|
|
|
+ email: "guolianfa@500269.com",
|
|
|
|
|
+ phone: "123-4567-8910",
|
|
|
|
|
+});
|
|
|
|
|
+// Weather data
|
|
|
|
|
+const weather = ref({
|
|
|
|
|
+ location: "长沙市",
|
|
|
|
|
+ temperature: 24,
|
|
|
|
|
+ condition: "晴朗",
|
|
|
|
|
+ humidity: 65,
|
|
|
|
|
+ wind: "东北风 3级",
|
|
|
|
|
+ date: new Date().toLocaleDateString("zh-CN", {
|
|
|
|
|
+ year: "numeric",
|
|
|
|
|
+ month: "long",
|
|
|
|
|
+ day: "numeric",
|
|
|
|
|
+ weekday: "long",
|
|
|
|
|
+ }),
|
|
|
|
|
+});
|
|
|
|
|
+
|
|
|
|
|
+// Device statistics
|
|
|
|
|
+const deviceStats = ref({
|
|
|
|
|
+ online: 128,
|
|
|
|
|
+ offline: 23,
|
|
|
|
|
+ total: 151,
|
|
|
|
|
+ onlinePercentage: 0,
|
|
|
|
|
+});
|
|
|
|
|
+
|
|
|
|
|
+// Calculate percentage
|
|
|
|
|
+onMounted(() => {
|
|
|
|
|
+ deviceStats.value.onlinePercentage = Math.round(
|
|
|
|
|
+ (deviceStats.value.online / deviceStats.value.total) * 100
|
|
|
|
|
+ );
|
|
|
|
|
+});
|
|
|
|
|
+
|
|
|
|
|
+// Alarm data
|
|
|
|
|
+const alarms = ref([
|
|
|
|
|
+ {
|
|
|
|
|
+ id: 1,
|
|
|
|
|
+ device: "井盖一号",
|
|
|
|
|
+ type: "高温警报",
|
|
|
|
|
+ location: "长沙",
|
|
|
|
|
+ time: "2023-10-15 08:23:45",
|
|
|
|
|
+ status: "未处理",
|
|
|
|
|
+ },
|
|
|
|
|
+ {
|
|
|
|
|
+ id: 2,
|
|
|
|
|
+ device: "井盖一号",
|
|
|
|
|
+ type: "连接中断",
|
|
|
|
|
+ location: "长沙",
|
|
|
|
|
+ time: "2023-10-15 07:15:22",
|
|
|
|
|
+ status: "已处理",
|
|
|
|
|
+ },
|
|
|
|
|
+ {
|
|
|
|
|
+ id: 3,
|
|
|
|
|
+ device: "井盖一号",
|
|
|
|
|
+ type: "未授权访问",
|
|
|
|
|
+ location: "长沙",
|
|
|
|
|
+ time: "2023-10-14 23:42:10",
|
|
|
|
|
+ status: "处理中",
|
|
|
|
|
+ },
|
|
|
|
|
+ {
|
|
|
|
|
+ id: 4,
|
|
|
|
|
+ device: "电表一号",
|
|
|
|
|
+ type: "离线",
|
|
|
|
|
+ location: "长沙",
|
|
|
|
|
+ time: "2023-10-14 18:05:37",
|
|
|
|
|
+ status: "已处理",
|
|
|
|
|
+ },
|
|
|
|
|
+]);
|
|
|
|
|
+
|
|
|
|
|
+// Tag type mapping for alarm levels
|
|
|
|
|
+const tagType = {
|
|
|
|
|
+ critical: "danger",
|
|
|
|
|
+ warning: "warning",
|
|
|
|
|
+ info: "info",
|
|
|
|
|
+};
|
|
|
|
|
+
|
|
|
|
|
+// Status tag mapping
|
|
|
|
|
+const statusTag = {
|
|
|
|
|
+ 未处理: "danger",
|
|
|
|
|
+ 处理中: "warning",
|
|
|
|
|
+ 已处理: "success",
|
|
|
|
|
+};
|
|
|
|
|
+
|
|
|
|
|
+// Get weather icon based on condition
|
|
|
|
|
+const getWeatherIcon = (condition) => {
|
|
|
|
|
+ if (condition.includes("晴")) return Sunny;
|
|
|
|
|
+ if (condition.includes("云") || condition.includes("阴")) return Cloudy;
|
|
|
|
|
+ return Sunny; // Default
|
|
|
|
|
+};
|
|
|
|
|
+// 常量定义
|
|
|
|
|
+const WEATHER_API = {
|
|
|
|
|
+ url: "/visualization/getBaiDuWeather",
|
|
|
|
|
+ method: "POST",
|
|
|
|
|
+};
|
|
|
|
|
+
|
|
|
|
|
+const weathernow = ref({});
|
|
|
|
|
+// 获取天气数据
|
|
|
|
|
+const fetchWeatherData = async () => {
|
|
|
|
|
+ try {
|
|
|
|
|
+ const controller = new AbortController();
|
|
|
|
|
+ const response = await request({
|
|
|
|
|
+ ...WEATHER_API,
|
|
|
|
|
+ data: {
|
|
|
|
|
+ /* 实际请求参数 */
|
|
|
|
|
+ }, // POST 参数应放 data
|
|
|
|
|
+ signal: controller.signal,
|
|
|
|
|
+ });
|
|
|
|
|
+
|
|
|
|
|
+ if (response.code !== 200) {
|
|
|
|
|
+ throw new Error(`API Error: ${response.data?.msg || "Unknown error"}`);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ weathernow.value = response.data;
|
|
|
|
|
+
|
|
|
|
|
+ console.log(123321, weathernow.value);
|
|
|
|
|
+ return response.data;
|
|
|
|
|
+ } catch (error) {
|
|
|
|
|
+ handleWeatherError(error);
|
|
|
|
|
+ throw error; // 继续抛出错误供上层处理
|
|
|
|
|
+ }
|
|
|
|
|
+};
|
|
|
|
|
+
|
|
|
|
|
+// 统一错误处理
|
|
|
|
|
+const handleWeatherError = (error) => {
|
|
|
|
|
+ const defaultMsg = "天气数据获取失败";
|
|
|
|
|
+
|
|
|
|
|
+ if (error.response) {
|
|
|
|
|
+ // HTTP 错误
|
|
|
|
|
+ ElMessage.error(error.response.data?.msg || defaultMsg);
|
|
|
|
|
+ console.error("API 响应错误:", error.response);
|
|
|
|
|
+ } else if (error.request) {
|
|
|
|
|
+ // 网络错误
|
|
|
|
|
+ ElMessage.error("网络连接异常");
|
|
|
|
|
+ console.error("网络错误:", error);
|
|
|
|
|
+ } else {
|
|
|
|
|
+ // 代码逻辑错误
|
|
|
|
|
+ console.error("应用程序错误:", error);
|
|
|
|
|
+ }
|
|
|
|
|
+};
|
|
|
|
|
+
|
|
|
|
|
+fetchWeatherData();
|
|
|
|
|
+</script>
|
|
|
|
|
+
|
|
|
<style>
|
|
<style>
|
|
|
.dashboard-container {
|
|
.dashboard-container {
|
|
|
font-family: "PingFang SC", "Microsoft YaHei", sans-serif;
|
|
font-family: "PingFang SC", "Microsoft YaHei", sans-serif;
|