|
@@ -1,83 +1,308 @@
|
|
|
<template>
|
|
<template>
|
|
|
<div class="app-container home">
|
|
<div class="app-container home">
|
|
|
- <el-row :gutter="20">
|
|
|
|
|
- <el-col :sm="24" :lg="12" style="padding-left: 20px">
|
|
|
|
|
- <h2>浪潮智能信发平台</h2>
|
|
|
|
|
-
|
|
|
|
|
- <p><b>当前版本:</b> <span>v4.1.0</span></p>
|
|
|
|
|
- </el-col>
|
|
|
|
|
- </el-row>
|
|
|
|
|
|
|
+ <div class="index-content">
|
|
|
|
|
+ <el-row :gutter="20">
|
|
|
|
|
+ <el-col :sm="24" :lg="12" style="padding-left: 20px">
|
|
|
|
|
+ <!-- <h2>{{tenantName}}</h2>-->
|
|
|
|
|
+ <h2>
|
|
|
|
|
+ <el-icon style="cursor: pointer;" @click="refreshIndex">
|
|
|
|
|
+ <Refresh/>
|
|
|
|
|
+ </el-icon>
|
|
|
|
|
+ 全局概览
|
|
|
|
|
+ </h2>
|
|
|
|
|
+ </el-col>
|
|
|
|
|
+ </el-row>
|
|
|
|
|
+ <el-divider style="margin: 5px"/>
|
|
|
|
|
+ <div class="statistic-card">
|
|
|
|
|
+ <el-row :gutter="20" justify="space-between">
|
|
|
|
|
+ <!-- 设备总数 -->
|
|
|
|
|
+ <el-col :span="6">
|
|
|
|
|
+ <el-statistic :value="totalNum" class="statistic-item" style="cursor: pointer;" @click="refreshDevice(1)">
|
|
|
|
|
+ <template #title>
|
|
|
|
|
+ <div class="statistic-title">
|
|
|
|
|
+ <span style="color: #07549a;">设备总数</span>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </template>
|
|
|
|
|
+ </el-statistic>
|
|
|
|
|
+ </el-col>
|
|
|
|
|
+ <!-- 在线设备 -->
|
|
|
|
|
+ <el-col :span="6">
|
|
|
|
|
+ <el-statistic :value="onlineNum" class="statistic-item" style="cursor: pointer;" @click="refreshDevice(2)">
|
|
|
|
|
+ <template #title>
|
|
|
|
|
+ <div class="statistic-title">
|
|
|
|
|
+ <span style="color: darkgreen">在线设备</span>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </template>
|
|
|
|
|
+ </el-statistic>
|
|
|
|
|
+ </el-col>
|
|
|
|
|
+ <!-- 离线设备 -->
|
|
|
|
|
+ <el-col :span="6">
|
|
|
|
|
+ <el-statistic :value="offlineNum" class="statistic-item" style="cursor: pointer;" @click="refreshDevice(3)">
|
|
|
|
|
+ <template #title>
|
|
|
|
|
+ <div class="statistic-title">
|
|
|
|
|
+ <span style="color: red;">离线设备</span>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </template>
|
|
|
|
|
+ </el-statistic>
|
|
|
|
|
+ </el-col>
|
|
|
|
|
+ <!-- 待接入设备 -->
|
|
|
|
|
+ <el-col :span="6">
|
|
|
|
|
+ <el-statistic :value="initNum" class="statistic-item" style="cursor: pointer;" @click="refreshDevice(4)">
|
|
|
|
|
+ <template #title>
|
|
|
|
|
+ <div class="statistic-title">
|
|
|
|
|
+ <span style="color: yellowgreen">待接入</span>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </template>
|
|
|
|
|
+ </el-statistic>
|
|
|
|
|
+ </el-col>
|
|
|
|
|
+ </el-row>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ <div class="device-card">
|
|
|
|
|
+ <el-row :gutter="20">
|
|
|
|
|
+ <el-col
|
|
|
|
|
+ v-for="(device, index) in deviceList"
|
|
|
|
|
+ :key="device.id"
|
|
|
|
|
+ :span="6"
|
|
|
|
|
+ style="margin-bottom: 20px;"
|
|
|
|
|
+ >
|
|
|
|
|
+ <div class="device-item">
|
|
|
|
|
+ <div class="device-header">
|
|
|
|
|
+ <span class="device-name">{{ device.name }}</span>
|
|
|
|
|
+ <span :class="getStatusClass(device.onlineStatus)">
|
|
|
|
|
+ {{ getOnlineStatusText(device.onlineStatus) }}
|
|
|
|
|
+ </span>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ <div class="device-info">
|
|
|
|
|
+ <p>分辨率: {{ device.resolution }}</p>
|
|
|
|
|
+ <p v-if="device.onlineStatus === 1">
|
|
|
|
|
+ 上次在线: {{ device.lastOnline }}
|
|
|
|
|
+ </p>
|
|
|
|
|
+ <p v-else-if="device.onlineStatus === 2">
|
|
|
|
|
+ 上次离线: {{ device.offlineTime }}
|
|
|
|
|
+ </p>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </el-col>
|
|
|
|
|
+ </el-row>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
</div>
|
|
</div>
|
|
|
</template>
|
|
</template>
|
|
|
|
|
|
|
|
<script setup name="Index" lang="ts">
|
|
<script setup name="Index" lang="ts">
|
|
|
-const goTarget = (url: string) => {
|
|
|
|
|
- window.open(url, '__blank');
|
|
|
|
|
-};
|
|
|
|
|
-</script>
|
|
|
|
|
|
|
+import useUserStore from "@/store/modules/user";
|
|
|
|
|
+import {indexGetTenant} from "@/api/system/tenant";
|
|
|
|
|
+import {ref} from "vue";
|
|
|
|
|
+import {DeviceStatisticsVo, DeviceVO} from "@/api/smsb/device/device_type";
|
|
|
|
|
+import {deviceStatistics, listIndexDevice} from "@/api/smsb/device/device";
|
|
|
|
|
+import {Refresh} from "@element-plus/icons-vue";
|
|
|
|
|
|
|
|
-<style scoped lang="scss">
|
|
|
|
|
-.home {
|
|
|
|
|
- blockquote {
|
|
|
|
|
- padding: 10px 20px;
|
|
|
|
|
- margin: 0 0 20px;
|
|
|
|
|
- font-size: 17.5px;
|
|
|
|
|
- border-left: 5px solid #eee;
|
|
|
|
|
- }
|
|
|
|
|
|
|
+const deviceStatisticsVo = ref<DeviceStatisticsVo>();
|
|
|
|
|
+const userStore = useUserStore();
|
|
|
|
|
+const tenantId = ref(userStore.tenantId);
|
|
|
|
|
+const tenantName = ref("");
|
|
|
|
|
+const totalNum = ref(0);
|
|
|
|
|
+const onlineNum = ref(0);
|
|
|
|
|
+const offlineNum = ref(0);
|
|
|
|
|
+const initNum = ref(0);
|
|
|
|
|
+const deviceList = ref<DeviceVO[]>([]);
|
|
|
|
|
|
|
|
- hr {
|
|
|
|
|
- margin-top: 20px;
|
|
|
|
|
- margin-bottom: 20px;
|
|
|
|
|
- border: 0;
|
|
|
|
|
- border-top: 1px solid #eee;
|
|
|
|
|
- }
|
|
|
|
|
|
|
+const getTenantName = async () => {
|
|
|
|
|
+ const res = await indexGetTenant(tenantId.value)
|
|
|
|
|
+ tenantName.value = res.data.companyName;
|
|
|
|
|
+}
|
|
|
|
|
|
|
|
- .col-item {
|
|
|
|
|
- margin-bottom: 20px;
|
|
|
|
|
|
|
+const getOnlineStatusText = (status) => {
|
|
|
|
|
+ switch (status) {
|
|
|
|
|
+ case 0:
|
|
|
|
|
+ return '未接入';
|
|
|
|
|
+ case 1:
|
|
|
|
|
+ return '在线';
|
|
|
|
|
+ case 2:
|
|
|
|
|
+ return '离线';
|
|
|
|
|
+ default:
|
|
|
|
|
+ return '未知';
|
|
|
}
|
|
}
|
|
|
|
|
+};
|
|
|
|
|
|
|
|
- ul {
|
|
|
|
|
- padding: 0;
|
|
|
|
|
- margin: 0;
|
|
|
|
|
|
|
+const getStatusClass = (status) => {
|
|
|
|
|
+ switch (status) {
|
|
|
|
|
+ case 0:
|
|
|
|
|
+ return 'status init';
|
|
|
|
|
+ case 1:
|
|
|
|
|
+ return 'status online';
|
|
|
|
|
+ case 2:
|
|
|
|
|
+ return 'status offline';
|
|
|
|
|
+ default:
|
|
|
|
|
+ return '';
|
|
|
|
|
+ }
|
|
|
|
|
+};
|
|
|
|
|
+const getDeviceStatistics = async () => {
|
|
|
|
|
+ const res = await deviceStatistics();
|
|
|
|
|
+ deviceStatisticsVo.value = res.data;
|
|
|
|
|
+ totalNum.value = deviceStatisticsVo.value.totalNum;
|
|
|
|
|
+ onlineNum.value = deviceStatisticsVo.value.onlineNum;
|
|
|
|
|
+ offlineNum.value = deviceStatisticsVo.value.offlineNum;
|
|
|
|
|
+ initNum.value = deviceStatisticsVo.value.initNum;
|
|
|
|
|
+};
|
|
|
|
|
+const getDeviceList = async () => {
|
|
|
|
|
+ const queryParams = {
|
|
|
|
|
+ pageNum: 1,
|
|
|
|
|
+ pageSize: 500
|
|
|
|
|
+ };
|
|
|
|
|
+ const res = await listIndexDevice(queryParams);
|
|
|
|
|
+ deviceList.value = res.data;
|
|
|
|
|
+ deviceList.value.forEach((data) => {
|
|
|
|
|
+ data.resolution = data.width + 'x' + data.height;
|
|
|
|
|
+ });
|
|
|
|
|
+};
|
|
|
|
|
+const refreshDevice = async (type: number) => {
|
|
|
|
|
+ const queryParams = {
|
|
|
|
|
+ pageNum: 1,
|
|
|
|
|
+ pageSize: 500,
|
|
|
|
|
+ onlineStatus: null
|
|
|
|
|
+ };
|
|
|
|
|
+ if (type === 2) {
|
|
|
|
|
+ queryParams.onlineStatus = 1;
|
|
|
|
|
+ }else if (type === 3) {
|
|
|
|
|
+ queryParams.onlineStatus = 2;
|
|
|
|
|
+ }else if (type === 4) {
|
|
|
|
|
+ queryParams.onlineStatus = 0;
|
|
|
}
|
|
}
|
|
|
|
|
+ const res = await listIndexDevice(queryParams);
|
|
|
|
|
+ deviceList.value = res.data;
|
|
|
|
|
+ deviceList.value.forEach((data) => {
|
|
|
|
|
+ data.resolution = data.width + 'x' + data.height;
|
|
|
|
|
+ });
|
|
|
|
|
+}
|
|
|
|
|
+const refreshIndex = () => {
|
|
|
|
|
+ getDeviceStatistics()
|
|
|
|
|
+ getDeviceList();
|
|
|
|
|
+}
|
|
|
|
|
+onMounted(() => {
|
|
|
|
|
+ // 根据租户ID,获取租户名称
|
|
|
|
|
+ getTenantName();
|
|
|
|
|
+ getDeviceStatistics()
|
|
|
|
|
+ getDeviceList();
|
|
|
|
|
+});
|
|
|
|
|
+</script>
|
|
|
|
|
|
|
|
|
|
+<style scoped lang="scss">
|
|
|
|
|
+.home {
|
|
|
font-family: 'open sans', 'Helvetica Neue', Helvetica, Arial, sans-serif;
|
|
font-family: 'open sans', 'Helvetica Neue', Helvetica, Arial, sans-serif;
|
|
|
font-size: 13px;
|
|
font-size: 13px;
|
|
|
color: #676a6c;
|
|
color: #676a6c;
|
|
|
overflow-x: hidden;
|
|
overflow-x: hidden;
|
|
|
-
|
|
|
|
|
- ul {
|
|
|
|
|
- list-style-type: none;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- h4 {
|
|
|
|
|
- margin-top: 0px;
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ padding: 0;
|
|
|
|
|
+ margin-top: 10px;
|
|
|
|
|
|
|
|
h2 {
|
|
h2 {
|
|
|
margin-top: 10px;
|
|
margin-top: 10px;
|
|
|
- font-size: 26px;
|
|
|
|
|
- font-weight: 100;
|
|
|
|
|
|
|
+ margin-bottom: 0px;
|
|
|
|
|
+ font-size: 22px;
|
|
|
|
|
+ font-weight: 600;
|
|
|
}
|
|
}
|
|
|
|
|
+}
|
|
|
|
|
|
|
|
- p {
|
|
|
|
|
- margin-top: 10px;
|
|
|
|
|
|
|
+.index-content {
|
|
|
|
|
+ height: calc(100vh - 70px);
|
|
|
|
|
+ border-left: #e7eaec 1px solid;
|
|
|
|
|
+ width: 99%;
|
|
|
|
|
+}
|
|
|
|
|
|
|
|
- b {
|
|
|
|
|
- font-weight: 700;
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
|
|
+.statistic-card {
|
|
|
|
|
+ border-radius: 1px;
|
|
|
|
|
+ box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.08);
|
|
|
|
|
+ border: 1px solid #ebeef5;
|
|
|
|
|
+ padding: 10px 0;
|
|
|
|
|
+ height: 80px;
|
|
|
|
|
+ background: #ffffff;
|
|
|
|
|
+ width: calc(100% - 3px);
|
|
|
|
|
+ margin-left: 10px;
|
|
|
|
|
+}
|
|
|
|
|
|
|
|
- .update-log {
|
|
|
|
|
- ol {
|
|
|
|
|
- display: block;
|
|
|
|
|
- list-style-type: decimal;
|
|
|
|
|
- margin-block-start: 1em;
|
|
|
|
|
- margin-block-end: 1em;
|
|
|
|
|
- margin-inline-start: 0;
|
|
|
|
|
- margin-inline-end: 0;
|
|
|
|
|
- padding-inline-start: 40px;
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
|
|
+.statistic-item {
|
|
|
|
|
+ text-align: center;
|
|
|
|
|
+ padding: 10px 0;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.statistic-title {
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ align-items: center;
|
|
|
|
|
+ justify-content: center;
|
|
|
|
|
+ gap: 8px;
|
|
|
|
|
+ font-size: 20px;
|
|
|
|
|
+ font-weight: 500;
|
|
|
|
|
+ margin-bottom: 8px;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.device-card {
|
|
|
|
|
+ height: calc(100vh - 210px);
|
|
|
|
|
+ box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.08);
|
|
|
|
|
+ border: 1px solid #ebeef5;
|
|
|
|
|
+ padding: 10px 10px;
|
|
|
|
|
+ margin: 10px;
|
|
|
|
|
+ width: calc(100% - 3px);
|
|
|
|
|
+ overflow-y: auto;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.device-item {
|
|
|
|
|
+ border: 1px solid #ebeef5;
|
|
|
|
|
+ border-radius: 4px;
|
|
|
|
|
+ padding: 15px;
|
|
|
|
|
+ height: 115px;
|
|
|
|
|
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05);
|
|
|
|
|
+ transition: box-shadow 0.3s ease;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.device-item:hover {
|
|
|
|
|
+ box-shadow: 0 4px 16px rgba(0, 0, 0, 0.1);
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.device-header {
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ justify-content: space-between;
|
|
|
|
|
+ align-items: center;
|
|
|
|
|
+ margin-bottom: 10px;
|
|
|
|
|
+ padding-bottom: 8px;
|
|
|
|
|
+ border-bottom: 1px solid #eee;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.device-name {
|
|
|
|
|
+ font-weight: bold;
|
|
|
|
|
+ font-size: 16px;
|
|
|
|
|
+ overflow: hidden;
|
|
|
|
|
+ text-overflow: ellipsis;
|
|
|
|
|
+ white-space: nowrap;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.status {
|
|
|
|
|
+ font-size: 12px;
|
|
|
|
|
+ padding: 2px 6px;
|
|
|
|
|
+ border-radius: 4px;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.online {
|
|
|
|
|
+ background-color: #f0f9eb;
|
|
|
|
|
+ color: #67c23a;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.offline {
|
|
|
|
|
+ background-color: #fef0f0;
|
|
|
|
|
+ color: #f56c6c;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.init {
|
|
|
|
|
+ background-color: #f0f5ff;
|
|
|
|
|
+ color: #409eff;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.device-info p {
|
|
|
|
|
+ margin: 5px 0;
|
|
|
|
|
+ font-size: 13px;
|
|
|
|
|
+ color: #666;
|
|
|
|
|
+ overflow: hidden;
|
|
|
|
|
+ text-overflow: ellipsis;
|
|
|
|
|
+ white-space: nowrap;
|
|
|
}
|
|
}
|
|
|
</style>
|
|
</style>
|