Browse Source

图表修改

develop
fuguobin 1 year ago
parent
commit
2f7c0dae65
  1. 4
      .env.production
  2. 2
      src/api/device/types.ts
  3. 11
      src/store/modules/user.ts
  4. 2
      src/types/auto-imports.d.ts
  5. 202
      src/views/details/index - 副本 (2).vue
  6. 187
      src/views/details/index - 副本.vue
  7. 226
      src/views/details/index.vue
  8. 574
      src/views/monitoring/components/header.vue
  9. 4
      src/views/monitoring/screen/components/main.vue
  10. 4
      vite.config.ts

4
.env.production

@ -5,6 +5,6 @@ VITE_APP_PORT = 8089
#VITE_APP_WS_API = 'ws://board.heatiot.cn:8001/prod-api' ## websocket地址 #VITE_APP_WS_API = 'ws://board.heatiot.cn:8001/prod-api' ## websocket地址
#VITE_APP_BASE_API = 'http://board.heatiot.cn:8001/prod-api/' ## 线上接口 #VITE_APP_BASE_API = 'http://board.heatiot.cn:8001/prod-api/' ## 线上接口
#VITE_APP_WS_API = 'ws://${window.location.host}/ws' ## websocket地址 ws://10.10.10.56:9000/websocket/ #VITE_APP_WS_API = 'ws://${window.location.host}/ws' ## websocket地址 ws://10.10.10.56:9000/websocket/
VITE_APP_BASE_API = '/prod-api/' ## 正式环境 # VITE_APP_BASE_API = '/prod-api/' ## 正式环境
# VITE_APP_BASE_API = '/biprod-api/' ## 测试环境 VITE_APP_BASE_API = '/biprod-api/' ## 测试环境

2
src/api/device/types.ts

@ -74,10 +74,12 @@ export interface parameterVo {
version: null; version: null;
} }
export interface seriesVo { export interface seriesVo {
index: number;
name: string; name: string;
type: string; type: string;
smooth: boolean; smooth: boolean;
symbol: string; symbol: string;
paramUnit: string; paramUnit: string;
unit: string;
data: Array<string | number>; data: Array<string | number>;
} }

11
src/store/modules/user.ts

@ -13,6 +13,7 @@ import { useSessionStorage } from '@vueuse/core';
export const useUserStore = defineStore('user', () => { export const useUserStore = defineStore('user', () => {
// state // state
const token = useSessionStorage('userToken', ''); const token = useSessionStorage('userToken', '');
const userInfo = useSessionStorage('userInfo', {});
const nickname = ref(''); const nickname = ref('');
const avatar = ref(''); const avatar = ref('');
const roles = ref<Array<string>>([]); // 用户角色编码集合 → 判断路由权限 const roles = ref<Array<string>>([]); // 用户角色编码集合 → 判断路由权限
@ -27,7 +28,7 @@ export const useUserStore = defineStore('user', () => {
function login(loginData: LoginData) { function login(loginData: LoginData) {
return new Promise<void>((resolve, reject) => { return new Promise<void>((resolve, reject) => {
loginApi(loginData) loginApi(loginData)
.then((response:any) => { .then((response: any) => {
const userToken = response.token; const userToken = response.token;
token.value = 'Bearer ' + userToken; // Bearer eyJhbGciOiJIUzI1NiJ9.xxx.xxx token.value = 'Bearer ' + userToken; // Bearer eyJhbGciOiJIUzI1NiJ9.xxx.xxx
resolve(); resolve();
@ -42,19 +43,20 @@ export const useUserStore = defineStore('user', () => {
function getInfo() { function getInfo() {
return new Promise<UserInfo>((resolve, reject) => { return new Promise<UserInfo>((resolve, reject) => {
getUserInfo() getUserInfo()
.then((data:any) => { .then((data: any) => {
if (!data) { if (!data) {
return reject('Verification failed, please Login again.'); return reject('Verification failed, please Login again.');
} }
if (!data.roles || data.roles.length <= 0) { if (!data.roles || data.roles.length <= 0) {
reject('getUserInfo: roles must be a non-null array!'); reject('getUserInfo: roles must be a non-null array!');
} }
const user=data.user const user = data.user;
nickname.value = user.nickName; nickname.value = user.nickName;
avatar.value = user.avatar; avatar.value = user.avatar;
roles.value = data.roles; roles.value = data.roles;
perms.value = data.permissions; perms.value = data.permissions;
useSessionStorage('userInfo', user); userInfo.value = user;
// useSessionStorage('userInfo', user);
resolve(data); resolve(data);
}) })
.catch(error => { .catch(error => {
@ -81,6 +83,7 @@ export const useUserStore = defineStore('user', () => {
// 重置 // 重置
function resetToken() { function resetToken() {
token.value = ''; token.value = '';
userInfo.value = {};
nickname.value = ''; nickname.value = '';
avatar.value = ''; avatar.value = '';
roles.value = []; roles.value = [];

2
src/types/auto-imports.d.ts

@ -2,7 +2,6 @@
export {} export {}
declare global { declare global {
const EffectScope: typeof import('vue')['EffectScope'] const EffectScope: typeof import('vue')['EffectScope']
const ElForm: typeof import('element-plus/es')['ElForm']
const ElMessage: typeof import('element-plus/es')['ElMessage'] const ElMessage: typeof import('element-plus/es')['ElMessage']
const ElMessageBox: typeof import('element-plus/es')['ElMessageBox'] const ElMessageBox: typeof import('element-plus/es')['ElMessageBox']
const ElNotification: typeof import('element-plus/es')['ElNotification'] const ElNotification: typeof import('element-plus/es')['ElNotification']
@ -273,7 +272,6 @@ import { UnwrapRef } from 'vue'
declare module 'vue' { declare module 'vue' {
interface ComponentCustomProperties { interface ComponentCustomProperties {
readonly EffectScope: UnwrapRef<typeof import('vue')['EffectScope']> readonly EffectScope: UnwrapRef<typeof import('vue')['EffectScope']>
readonly ElForm: UnwrapRef<typeof import('element-plus/es')['ElForm']>
readonly ElMessage: UnwrapRef<typeof import('element-plus/es')['ElMessage']> readonly ElMessage: UnwrapRef<typeof import('element-plus/es')['ElMessage']>
readonly ElMessageBox: UnwrapRef<typeof import('element-plus/es')['ElMessageBox']> readonly ElMessageBox: UnwrapRef<typeof import('element-plus/es')['ElMessageBox']>
readonly ElNotification: UnwrapRef<typeof import('element-plus/es')['ElNotification']> readonly ElNotification: UnwrapRef<typeof import('element-plus/es')['ElNotification']>

202
src/views/details/index - 副本 (2).vue

@ -1,202 +0,0 @@
<template>
<div class="details">
<el-card class="search" shadow="always">
<el-form ref="searchRef" :inline="true" :model="searchForm" label-width="100px" class="demo-ruleForm">
<el-form-item label="时间" prop="time">
<el-date-picker
v-model="searchForm.time"
type="datetimerange"
start-placeholder="开始时间"
end-placeholder="结束时间"
:default-time="defaultTime1"
/>
</el-form-item>
<el-form-item label="颗粒度" prop="particle">
<el-select v-model="searchForm.particle" placeholder="请选择">
<el-option v-for="item in particleData" :key="item.value" :label="item.label" :value="item.value" />
</el-select>
</el-form-item>
<el-form-item label="设备" prop="device">
<el-select v-model="searchForm.device" placeholder="请选择">
<el-option v-for="item in optionss" :key="item.value" :label="item.label" :value="item.value" />
</el-select>
</el-form-item>
<el-form-item label="参数" prop="parameter">
<el-select v-model="searchForm.parameter" placeholder="请选择">
<el-option v-for="item in optionss" :key="item.value" :label="item.label" :value="item.value" />
</el-select>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="submitForm(searchRef)">确认</el-button>
<el-button @click="resetForm(searchRef)">重置</el-button>
</el-form-item>
</el-form>
</el-card>
<el-card class="echart" shadow="always">
<div class="comparisonInfo">
<div ref="stackedRef" class="stackedLine" />
</div>
</el-card>
</div>
</template>
<script lang="ts" setup>
import * as echarts from 'echarts';
import { Ref } from 'vue';
const stackedRef: Ref<HTMLElement | any> = ref(null);
import type { FormInstance } from 'element-plus';
const searchRef = ref<FormInstance>();
const defaultTime1 = new Date(2000, 1, 1, 12, 0, 0); // '12:00:00'
const searchForm = reactive({
time: '',
particle: '',
device: '',
parameter: ''
});
const submitForm = (formEl: FormInstance | undefined) => {
if (!formEl) return;
formEl.validate(valid => {
if (valid) {
console.log('submit!');
} else {
console.log('error submit!');
return false;
}
});
};
const resetForm = (formEl: FormInstance | undefined) => {
if (!formEl) return;
formEl.resetFields();
};
const particleData = [
{ label: '分钟', value: 1 },
{ label: '小时', value: 2 }
];
const optionss = [
{
value: 'Option1',
label: 'Option1'
},
{
value: 'Option2',
label: 'Option2'
}
];
const colors = ['#EE6666', '#91CC75', '#5470C6'];
const options = {
color: colors,
tooltip: {
trigger: 'axis',
axisPointer: {
type: 'cross'
}
},
grid: {
right: '20%'
},
toolbox: {
feature: {
dataView: { show: true, readOnly: false },
restore: { show: true },
saveAsImage: { show: true }
}
},
legend: {
data: ['回温', '供压', '回压']
},
xAxis: [
{
type: 'category',
axisTick: {
alignWithLabel: true
},
// prettier-ignore
data: ['2021', '2022', '2023', '2024', '2025', '2026', '2027', '2028', '2029', '2030', '2031', '2032']
}
],
yAxis: [
{
type: 'value',
name: '回温',
position: 'right',
alignTicks: true,
axisLine: {
show: true,
lineStyle: {
color: colors[0]
}
},
axisLabel: {
formatter: '{value} ml'
}
},
{
type: 'value',
name: '供压',
position: 'right',
alignTicks: true,
offset: 80,
axisLine: {
show: true,
lineStyle: {
color: colors[1]
}
},
axisLabel: {
formatter: '{value} ml'
}
},
{
type: 'value',
name: '回压',
position: 'left',
alignTicks: true,
axisLine: {
show: true,
lineStyle: {
color: colors[2]
}
},
axisLabel: {
formatter: '{value} °C'
}
}
],
series: [
{
name: '回温',
type: 'line',
data: [2.0, 4.9, 7.0, 23.2, 25.6, 76.7, 135.6, 162.2, 32.6, 20.0, 6.4, 3.3]
},
{
name: '供压',
type: 'line',
yAxisIndex: 2,
data: [5.0, 2.2, 3.3, 4.5, 6.3, 10.2, 20.3, 23.4, 23.0, 16.5, 12.0, 6.2]
},
{
name: '回压',
type: 'line',
yAxisIndex: 1,
data: [2.6, 5.9, 9.0, 26.4, 28.7, 70.7, 175.6, 182.2, 48.7, 18.8, 6.0, 2.3]
}
]
};
onMounted(() => {
//
const chart = echarts.init(stackedRef.value);
chart.setOption(options);
//
window.addEventListener('resize', () => {
chart.resize();
});
});
</script>
<style lang="scss" scoped>
@import './index.scss';
</style>

187
src/views/details/index - 副本.vue

@ -1,187 +0,0 @@
<template>
<div class="details">
<el-card class="search" shadow="always">
<el-form ref="searchRef" :inline="true" :model="searchForm" label-width="100px" class="demo-ruleForm">
<el-form-item label="时间" prop="time">
<el-date-picker
v-model="searchForm.time"
type="datetimerange"
start-placeholder="开始时间"
end-placeholder="结束时间"
:default-time="defaultTime1"
/>
</el-form-item>
<!-- <el-form-item label="颗粒度" prop="particle">
<el-select v-model="searchForm.particle" placeholder="请选择">
<el-option v-for="item in optionss" :key="item.value" :label="item.label" :value="item.value" />
</el-select>
</el-form-item> -->
<el-form-item label="设备" prop="device">
<el-select v-model="searchForm.device" placeholder="请选择">
<el-option v-for="item in optionss" :key="item.value" :label="item.label" :value="item.value" />
</el-select>
</el-form-item>
<el-form-item label="参数" prop="parameter">
<el-select v-model="searchForm.parameter" placeholder="请选择">
<el-option v-for="item in optionss" :key="item.value" :label="item.label" :value="item.value" />
</el-select>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="submitForm(searchRef)">确认</el-button>
<el-button @click="resetForm(searchRef)">重置</el-button>
</el-form-item>
</el-form>
</el-card>
<el-card class="echart" shadow="always">
<div class="comparisonInfo">
<div ref="stackedRef" class="stackedLine" />
</div>
</el-card>
</div>
</template>
<script lang="ts" setup>
import * as echarts from 'echarts';
import { Ref } from 'vue';
const stackedRef: Ref<HTMLElement | any> = ref(null);
import type { FormInstance } from 'element-plus';
const searchRef = ref<FormInstance>();
const defaultTime1 = new Date(2000, 1, 1, 12, 0, 0); // '12:00:00'
const searchForm = reactive({
time: '',
particle: '',
device: '',
parameter: ''
});
const submitForm = (formEl: FormInstance | undefined) => {
if (!formEl) return;
formEl.validate(valid => {
if (valid) {
console.log('submit!');
} else {
console.log('error submit!');
return false;
}
});
};
const resetForm = (formEl: FormInstance | undefined) => {
if (!formEl) return;
formEl.resetFields();
};
const optionss = [
{
value: 'Option1',
label: 'Option1'
},
{
value: 'Option2',
label: 'Option2'
},
{
value: 'Option3',
label: 'Option3'
},
{
value: 'Option4',
label: 'Option4'
},
{
value: 'Option5',
label: 'Option5'
}
];
const options = {
title: {
text: 'Temperature Change in the Coming Week'
},
tooltip: {
trigger: 'axis'
},
legend: {},
toolbox: {
show: true,
feature: {
dataZoom: {
yAxisIndex: 'none'
},
dataView: { readOnly: false },
magicType: { type: ['line', 'bar'] },
restore: {},
saveAsImage: {}
}
},
xAxis: {
type: 'category',
boundaryGap: false,
data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
},
yAxis: {
type: 'value',
axisLabel: {
formatter: '{value} °C'
}
},
series: [
{
name: 'Highest',
type: 'line',
data: [10, 11, 13, 11, 12, 12, 9],
markPoint: {
data: [
{ type: 'max', name: 'Max' },
{ type: 'min', name: 'Min' }
]
},
markLine: {
data: [{ type: 'average', name: 'Avg' }]
}
},
{
name: 'Lowest',
type: 'line',
data: [1, -2, 2, 5, 3, 2, 0],
markPoint: {
data: [{ name: '周最低', value: -2, xAxis: 1, yAxis: -1.5 }]
},
markLine: {
data: [
{ type: 'average', name: 'Avg' },
[
{
symbol: 'none',
x: '90%',
yAxis: 'max'
},
{
symbol: 'circle',
label: {
position: 'start',
formatter: 'Max'
},
type: 'max',
name: '最高点'
}
]
]
}
}
]
};
onMounted(() => {
//
const chart = echarts.init(stackedRef.value);
chart.setOption(options);
//
window.addEventListener('resize', () => {
chart.resize();
});
});
</script>
<style lang="scss" scoped>
@import './index.scss';
</style>

226
src/views/details/index.vue

@ -793,30 +793,30 @@ const options2 = {
color: colors[1] color: colors[1]
} }
} }
},
{
type: 'value',
name: '累计热量(JG)',
position: 'right',
alignTicks: true,
offset: 100,
scale: true, //
minInterval: 1, //
nameTextStyle: {
fontSize: 12,
padding: [0, 0, 0, 0] //name
},
axisTick: {
//
show: false
},
axisLine: {
show: true,
lineStyle: {
color: colors[2]
}
}
} }
// {
// type: 'value',
// name: '(JG)',
// position: 'right',
// alignTicks: true,
// offset: 100,
// scale: true, //
// minInterval: 1, //
// nameTextStyle: {
// fontSize: 12,
// padding: [0, 0, 0, 0] //name
// },
// axisTick: {
// //
// show: false
// },
// axisLine: {
// show: true,
// lineStyle: {
// color: colors[2]
// }
// }
// }
], ],
// yAxis: { // yAxis: {
// type: 'value', // type: 'value',
@ -982,9 +982,9 @@ const options2 = {
type: 'line', type: 'line',
smooth: true, smooth: true,
symbol: 'none', symbol: 'none',
yAxisIndex: 2, yAxisIndex: 1,
data: [ data: [
['2023-10-01 08:00:00', Math.round(Math.random() * 500)], ['2023-10-01 08:00:00', Math.round(Math.random() * 600)],
['2023-10-01 09:00:00', Math.round(Math.random() * 500)], ['2023-10-01 09:00:00', Math.round(Math.random() * 500)],
['2023-10-01 10:00:00', Math.round(Math.random() * 500)], ['2023-10-01 10:00:00', Math.round(Math.random() * 500)],
['2023-10-01 11:00:00', Math.round(Math.random() * 500)], ['2023-10-01 11:00:00', Math.round(Math.random() * 500)],
@ -1097,76 +1097,114 @@ function init(data: any) {
options.series = []; options.series = [];
if (data.mainInfos.length === 0) { if (data.mainInfos.length === 0) {
options.title.text = '暂无数据'; options.title.text = '暂无数据';
} else { return;
options.title.text = data.additionalInfo.name;
options.title.x = 'top';
options.title.y = 'left';
if (multipleLimit.value === 0 && parameterLimit.value === 1) {
console.log('单设备多参数');
data.mainInfos.map((item: seriesVo, index: number) => {
const offsetData = index === 0 ? 0 : index === 1 ? 0 : (index - 1) * 100;
console.log('offsetData--', offsetData);
options.legend.data.push(item.name);
options.yAxis.push({
type: 'value',
name: `${item.name}(${item.paramUnit})`,
position: `${index === 0 ? 'left' : 'right'}`,
alignTicks: true,
offset: offsetData,
scale: true, //
// minInterval: 1, //
nameTextStyle: {
fontSize: 12,
padding: [0, 0, 0, 0] //name
},
axisTick: {
//
show: false
},
axisLine: {
show: true,
lineStyle: {
color: colors[index]
}
}
});
options.series.push({
name: item.name,
type: 'line',
smooth: true,
symbol: 'none',
yAxisIndex: index,
data: item.data
});
});
} else {
console.log('多设备单参数');
options.yAxis.push({
type: 'value',
scale: true, //
minInterval: 1, //
name: `${data.additionalInfo.name}(${data.additionalInfo.unit})`,
nameTextStyle: {
fontSize: 12,
padding: [0, 0, 0, 0] //name
},
axisTick: {
//
show: false
}
});
data.mainInfos.map((item: seriesVo) => {
options.legend.data.push(item.name);
options.series.push({
name: item.name,
type: 'line',
smooth: true,
symbol: 'none',
data: item.data
});
});
}
} }
options.title.text = data.additionalInfo.name;
options.title.x = 'top';
options.title.y = 'left';
data.units.map((item: seriesVo, index: number) => {
const offsetData = index === 0 ? 0 : index === 1 ? 0 : (index - 1) * 100;
console.log('offsetData--', offsetData);
options.yAxis.push({
type: 'value',
name: `${item.name}(${item.unit})`,
position: `${index === 0 ? 'left' : 'right'}`,
alignTicks: true,
offset: offsetData,
scale: true, //
// minInterval: 1, //
nameTextStyle: {
fontSize: 12,
padding: [0, 0, 0, 0] //name
},
axisTick: {
//
show: false
},
axisLine: {
show: true,
lineStyle: {
color: colors[index]
}
}
});
});
data.mainInfos.map((item: seriesVo, index: number) => {
options.legend.data.push(item.name);
options.series.push({
name: item.name,
type: 'line',
smooth: true,
symbol: 'none',
yAxisIndex: item.index,
data: item.data
});
});
// if (multipleLimit.value === 0 && parameterLimit.value === 1) {
// console.log('');
// data.mainInfos.map((item: seriesVo, index: number) => {
// const offsetData = index === 0 ? 0 : index === 1 ? 0 : (index - 1) * 100;
// console.log('offsetData--', offsetData);
// options.legend.data.push(item.name);
// options.yAxis.push({
// type: 'value',
// name: `${item.name}(${item.paramUnit})`,
// position: `${index === 0 ? 'left' : 'right'}`,
// alignTicks: true,
// offset: offsetData,
// scale: true, //
// // minInterval: 1, //
// nameTextStyle: {
// fontSize: 12,
// padding: [0, 0, 0, 0] //name
// },
// axisTick: {
// //
// show: false
// },
// axisLine: {
// show: true,
// lineStyle: {
// color: colors[index]
// }
// }
// });
// options.series.push({
// name: item.name,
// type: 'line',
// smooth: true,
// symbol: 'none',
// yAxisIndex: index,
// data: item.data
// });
// });
// } else {
// console.log('');
// options.yAxis.push({
// type: 'value',
// scale: true, //
// minInterval: 1, //
// name: `${data.additionalInfo.name}(${data.additionalInfo.unit})`,
// nameTextStyle: {
// fontSize: 12,
// padding: [0, 0, 0, 0] //name
// },
// axisTick: {
// //
// show: false
// }
// });
// data.mainInfos.map((item: seriesVo) => {
// options.legend.data.push(item.name);
// options.series.push({
// name: item.name,
// type: 'line',
// smooth: true,
// symbol: 'none',
// data: item.data
// });
// });
// }
const chart = echarts.init(stackedRef.value); const chart = echarts.init(stackedRef.value);
chart.clear(); chart.clear();
chart.resize(); chart.resize();

574
src/views/monitoring/components/header.vue

@ -1,200 +1,222 @@
<template> <template>
<div class="title"> <div class="title">
<h3>{{ titleData }}</h3> <h3>{{ titleData }}</h3>
</div>
<div class="weather">
<div class="time">{{ currentTime }} {{ lunarDay.ncWeek }}</div>
<div class="line"></div>
<div class="forecast">
<span>{{ weatherData.city }}{{ weatherData.weather }} {{ weatherData.temperature }}</span>
<svg-icon class="weatherSvg" :icon-class="weatherData.weatherImg" />
<!-- <img src="../../../assets/images/weather/duoyun.png" /> -->
</div> </div>
<div class="weather"> </div>
<div class="time"> <div class="seeting">
{{ currentTime }} {{ lunarDay.ncWeek }} <n-tooltip trigger="hover">
<template #trigger>
<n-button class="tooltips" circle quaternary @click="lineClick">
<template #icon>
<n-icon>
<ChartLine />
</n-icon>
</template>
</n-button>
</template>
图表
</n-tooltip>
<n-tooltip trigger="hover" v-if="settingShow">
<template #trigger>
<n-button class="tooltips" circle quaternary @click="showClick">
<template #icon>
<n-icon>
<Settings />
</n-icon>
</template>
</n-button>
</template>
显示项
</n-tooltip>
<n-tooltip trigger="hover">
<template #trigger>
<n-button class="tooltips" circle quaternary @click="returnBack">
<template #icon>
<n-icon>
<Power />
</n-icon>
</template>
</n-button>
</template>
返回上一页
</n-tooltip>
<n-tooltip trigger="hover" v-if="warningShow">
<template #trigger>
<n-badge class="warningbadge" :value="waringData.length" :max="15">
<n-button class="tooltips" circle quaternary @click="waringClick">
<template #icon>
<n-icon>
<Bell />
</n-icon>
</template>
</n-button>
</n-badge>
</template>
报警
</n-tooltip>
</div>
<n-drawer class="waringDrawer" v-model:show="waringDrawer" :default-width="420" resizable placement="right">
<n-drawer-content closable>
<template #header>
<div class="title">
<span>消息</span>
<span class="button" @click="waringMore">更多</span>
</div> </div>
<div class="line"></div> </template>
<div class="forecast"> <div class="waringList">
<span>{{ weatherData.city }}{{ weatherData.weather }} {{ weatherData.temperature }}</span> <div class="item" v-for="(item, index) in waringData" :key="index">
<svg-icon class="weatherSvg" :icon-class="weatherData.weatherImg" /> <div class="name">
<!-- <img src="../../../assets/images/weather/duoyun.png" /> --> <span>{{ item.deviceName }}</span>
<span class="time">{{ item.alertTime }}</span>
</div>
<div class="info">
<span>{{ item.paramName }}</span>
<n-button type="info" size="small" @click="waringConfirm(item)">确认</n-button>
</div>
</div> </div>
</div> </div>
<div class="seeting"> </n-drawer-content>
<n-tooltip trigger="hover" v-if="settingShow"> </n-drawer>
<template #trigger> <n-modal class="waringModal" v-model:show="waringModal">
<n-button class="tooltips" circle quaternary @click="showClick"> <n-card :bordered="false" size="huge" role="dialog" aria-modal="true">
<template #icon> <el-table
<n-icon> class="waringTable"
<Settings /> :data="waringList"
</n-icon> header-row-class-name="headerRowClass"
</template> header-cell-class-name="headerCellClass"
</n-button> row-class-name="rowClass"
</template> cell-class-name="cellClass"
显示项 height="350"
</n-tooltip> stripe
<n-tooltip trigger="hover"> >
<template #trigger> <el-table-column prop="deviceName" label="设备名称" align="center" />
<n-button class="tooltips" circle quaternary @click="returnBack"> <el-table-column prop="paramName" label="变量名称" align="center" />
<template #icon> <el-table-column prop="alertName" label="告警级别" align="center">
<n-icon> <template #default="scope">
<Power /> <span class="level">{{ scope.row.alertName }}</span>
</n-icon> </template>
</template> </el-table-column>
</n-button> <el-table-column prop="totalCounts" label="告警累计" align="center" />
</template> <el-table-column label="报警时间" align="center">
返回上一页 <el-table-column prop="alertFirstTime" label="首次告警时间" align="center" />
</n-tooltip> <el-table-column prop="alertLastTime" label="末次告警时间" align="center" />
<n-tooltip trigger="hover" v-if="warningShow"> </el-table-column>
<template #trigger> <el-table-column fixed="right" label="操作" align="center">
<n-badge class="warningbadge" :value="waringData.length" :max="15"> <template #default="scope">
<n-button class="tooltips" circle quaternary @click="waringClick"> <el-button class="confirm" type="info" size="small" @click="waringConfirm(scope.row)">确认</el-button>
<template #icon> </template>
<n-icon> </el-table-column>
<Bell /> </el-table>
</n-icon> <div class="warClose" @click="warClose">
</template> <CloseCircleOutline />
</n-button> </div>
</n-badge> </n-card>
</template> </n-modal>
报警
</n-tooltip>
</div>
<n-drawer class="waringDrawer" v-model:show="waringDrawer" :default-width="420" resizable placement="right">
<n-drawer-content closable>
<template #header>
<div class="title">
<span>消息</span>
<span class="button" @click="waringMore">更多</span>
</div>
</template>
<div class="waringList">
<div class="item" v-for="(item, index) in waringData" :key="index">
<div class="name">
<span>{{ item.deviceName }}</span>
<span class="time">{{ item.alertTime }}</span>
</div>
<div class="info">
<span>{{ item.paramName }}</span>
<n-button type="info" size="small" @click="waringConfirm(item)">确认</n-button>
</div>
</div>
</div>
</n-drawer-content>
</n-drawer>
<n-modal class="waringModal" v-model:show="waringModal">
<n-card :bordered="false" size="huge" role="dialog" aria-modal="true">
<el-table class="waringTable" :data="waringList" header-row-class-name="headerRowClass"
header-cell-class-name="headerCellClass" row-class-name="rowClass" cell-class-name="cellClass" height="350"
stripe>
<el-table-column prop="deviceName" label="设备名称" align="center" />
<el-table-column prop="paramName" label="变量名称" align="center" />
<el-table-column prop="alertName" label="告警级别" align="center">
<template #default="scope">
<span class="level">{{ scope.row.alertName }}</span>
</template>
</el-table-column>
<el-table-column prop="totalCounts" label="告警累计" align="center" />
<el-table-column label="报警时间" align="center">
<el-table-column prop="alertFirstTime" label="首次告警时间" align="center" />
<el-table-column prop="alertLastTime" label="末次告警时间" align="center" />
</el-table-column>
<el-table-column fixed="right" label="操作" align="center">
<template #default="scope">
<el-button class="confirm" type="info" size="small" @click="waringConfirm(scope.row)">确认</el-button>
</template>
</el-table-column>
</el-table>
<div class="warClose" @click="warClose">
<CloseCircleOutline />
</div>
</n-card>
</n-modal>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { useRoute, useRouter } from "vue-router"; import { useRoute, useRouter } from 'vue-router';
import { getWeather } from '@/api/user/index'; import { getWeather } from '@/api/user/index';
import { getWarList, process } from '@/api/waring/index'; import { getWarList, process } from '@/api/waring/index';
import { waringVo } from '@/api/waring/types'; import { waringVo } from '@/api/waring/types';
import { Filter, Maximize, Settings, Power, Bell } from '@vicons/tabler'; import { Filter, Maximize, Settings, Power, Bell, ChartLine } from '@vicons/tabler';
import { CloseCircleOutline } from '@vicons/ionicons5'; import { CloseCircleOutline } from '@vicons/ionicons5';
import { useDateFormat, useNow } from '@vueuse/core'; import { useDateFormat, useNow } from '@vueuse/core';
import { uniqueArrayObject } from '@/utils/index'; import { uniqueArrayObject } from '@/utils/index';
import mitt from '@/plugins/bus'; import mitt from '@/plugins/bus';
import calendar from '@/utils/lunar'; import calendar from '@/utils/lunar';
const route = useRoute() const route = useRoute();
const router = useRouter() const router = useRouter();
const currentTime = useDateFormat(useNow(), 'YYYY-MM-DD HH:mm:ss'); const currentTime = useDateFormat(useNow(), 'YYYY-MM-DD HH:mm:ss');
const emit = defineEmits(['showModalClick', 'returnClick']); const emit = defineEmits(['showModalClick', 'returnClick']);
const timer = ref() const timer = ref();
const isCurrentRoute = ref(true) const isCurrentRoute = ref(true);
const waringDrawer = ref(false) const waringDrawer = ref(false);
const waringModal = ref(false) const waringModal = ref(false);
const waringData = ref<waringVo[]>([]) const waringData = ref<waringVo[]>([]);
const waringList = ref<waringVo[]>([]) const waringList = ref<waringVo[]>([]);
const routerType = ref('') const routerType = ref('');
const weatherData = ref( const weatherData = ref({ city: '', weather: '', temperature: '', weatherImg: '' });
{ city: "", weather: "", temperature: "", weatherImg: "" }
);
const lunarDay: any = calendar.solarToLunar( const lunarDay: any = calendar.solarToLunar(
useNow().value.getUTCFullYear(), useNow().value.getUTCFullYear(),
useNow().value.getUTCMonth() + 1, useNow().value.getUTCMonth() + 1,
useNow().value.getUTCDate() useNow().value.getUTCDate()
); );
const props = defineProps({ const props = defineProps({
titleData: { titleData: {
type: String, type: String,
default: '数据大屏', default: '数据大屏'
}, },
settingShow: { settingShow: {
type: Boolean, type: Boolean,
default: false default: false
}, },
warningShow: { warningShow: {
type: Boolean, type: Boolean,
default: false default: false
} }
}); });
onMounted(() => { onMounted(() => {
routerType.value = route.query?.id === undefined ? "0" : "1" routerType.value = route.query?.id === undefined ? '0' : '1';
getWeatherData() getWeatherData();
}); });
mitt.on('waringMessage', (res: any) => { mitt.on('waringMessage', (res: any) => {
// //
console.log("waringMessage--", res.data); console.log('waringMessage--', res.data);
waringData.value = res.data waringData.value = res.data;
// waringData.value.push(res.data) // waringData.value.push(res.data)
// console.log("waringData--", waringData.value); // console.log("waringData--", waringData.value);
// waringData.value = uniqueArrayObject(waringData.value, "id") // waringData.value = uniqueArrayObject(waringData.value, "id")
// console.log("waringData--", waringData.value); // console.log("waringData--", waringData.value);
}); });
function showClick() { function showClick() {
/// ///
emit('showModalClick', true); emit('showModalClick', true);
// showModal.value = true; // showModal.value = true;
} }
function returnBack() { function returnBack() {
// //
// emit('returnClick', ''); // emit('returnClick', '');
if (routerType.value === '1' && route.path != "/screen") { if (routerType.value === '1' && route.path != '/screen') {
router.push({ router.push({
path: "/screen", path: '/screen',
query: { id: sessionStorage.getItem('id') } query: { id: sessionStorage.getItem('id') }
}) });
} else { } else {
router.replace("/dashboard") router.replace('/dashboard');
} }
} }
function waringClick() { function waringClick() {
// //
// if (waringData.value.length === 0) { // if (waringData.value.length === 0) {
// ElNotification({ // ElNotification({
// message: '', // message: '',
// type: 'info', // type: 'info',
// }) // })
// } else { // } else {
waringDrawer.value = true waringDrawer.value = true;
// } // }
}
function lineClick() {
//
router.push({
path: '/details'
});
} }
// function getWeatherData() { // function getWeatherData() {
@ -207,150 +229,152 @@ function waringClick() {
// } // }
function getWeatherData() { function getWeatherData() {
// //
getWeather().then((res: any) => { getWeather().then((res: any) => {
if (res.code === 200) { if (res.code === 200) {
if (isCurrentRoute) { if (isCurrentRoute) {
timer.value = setTimeout(async () => { timer.value = setTimeout(async () => {
await (timer.value && clearTimeout(timer.value)); await (timer.value && clearTimeout(timer.value));
await getWeatherData(); await getWeatherData();
}, 600000) }, 600000);
} }
weatherData.value = res.data; weatherData.value = res.data;
} else { } else {
clearTimeout(timer.value); clearTimeout(timer.value);
} }
}); });
} }
function waringMore() { function waringMore() {
// //
waringDrawer.value = false waringDrawer.value = false;
waringModal.value = true waringModal.value = true;
getwaringList() getwaringList();
} }
function getwaringList() { function getwaringList() {
const params = 0; const params = 0;
getWarList(params).then((res: any) => { getWarList(params).then((res: any) => {
if (res.code === 200) { if (res.code === 200) {
waringList.value = res.rows; waringList.value = res.rows;
} }
}); });
} }
function waringConfirm(item: any) { function waringConfirm(item: any) {
// //
ElMessageBox.confirm('是否确认操作?', '提示', { ElMessageBox.confirm('是否确认操作?', '提示', {
confirmButtonText: '确认', confirmButtonText: '确认',
cancelButtonText: '取消', cancelButtonText: '取消',
type: 'warning', type: 'warning'
}).then(() => { })
const params = item.id; .then(() => {
process(params).then((res: any) => { const params = item.id;
if (res.code === 200) { process(params).then((res: any) => {
waringList.value = res.data; if (res.code === 200) {
// waringDrawer.value = false waringList.value = res.data;
// waringModal.value = false // waringDrawer.value = false
getwaringList() // waringModal.value = false
ElMessage({ getwaringList();
message: res.msg, ElMessage({
type: 'success', message: res.msg,
}) type: 'success'
} });
}); }
}).catch(() => { }) });
})
.catch(() => {});
} }
function warClose() { function warClose() {
// //
waringModal.value = false waringModal.value = false;
} }
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
.header { .header {
display: flex; display: flex;
justify-content: space-between; justify-content: space-between;
align-items: center; align-items: center;
// height: 5.7rem; // height: 5.7rem;
.title { .title {
width: 80%; width: 80%;
background: url(@/assets/images/title-bg.png); background: url(@/assets/images/title-bg.png);
background-size: 100%; background-size: 100%;
text-align: center; text-align: center;
padding-bottom: 38px; padding-bottom: 38px;
margin: 0 auto; margin: 0 auto;
h3 { h3 {
height: 57px; height: 57px;
font-size: 3.8rem; font-size: 3.8rem;
font-family: 'YouSheBiaoTiHei'; font-family: 'YouSheBiaoTiHei';
font-weight: 400; font-weight: 400;
letter-spacing: 4px; letter-spacing: 4px;
background: linear-gradient(180deg, #FEFDFF 0%, #95DAFF 97%); background: linear-gradient(180deg, #fefdff 0%, #95daff 97%);
background-clip: text; background-clip: text;
-webkit-background-clip: text; -webkit-background-clip: text;
-webkit-text-fill-color: transparent; -webkit-text-fill-color: transparent;
margin: 0; margin: 0;
}
} }
}
} }
.weather { .weather {
display: flex;
align-items: center;
position: absolute;
top: 2.5rem;
left: 7rem;
color: #b2d4ff;
font-size: 1.8rem;
line-height: 2.2rem;
font-family: 'AlibabaPuHuiTiRegular';
.line {
width: 2px;
height: 2rem;
background: linear-gradient(to top, #000e38, #1ea8dd, #000e38);
margin: 0 1rem;
}
.forecast {
display: flex; display: flex;
align-items: center; align-items: center;
position: absolute;
top: 2.5rem;
left: 7rem;
color: #B2D4FF;
font-size: 1.8rem;
line-height: 2.2rem;
font-family: 'AlibabaPuHuiTiRegular';
.line { .weatherSvg {
width: 2px; width: 1.5em !important;
height: 2rem; height: 1.5em !important;
background: linear-gradient(to top, #000E38, #1EA8DD, #000E38); margin-left: 10px;
margin: 0 1rem;
} }
.forecast { // img {
display: flex; // width: 25px;
align-items: center; // margin-left: 10px;
// }
.weatherSvg { }
width: 1.5em !important;
height: 1.5em !important;
margin-left: 10px;
}
// img {
// width: 25px;
// margin-left: 10px;
// }
}
} }
.seeting { .seeting {
position: absolute; position: absolute;
top: 2.5rem; top: 2.5rem;
right: 7rem; right: 7rem;
.warningbadge { .warningbadge {
margin-top: -10px; margin-top: -10px;
} }
.tooltips { .tooltips {
width: 36px; width: 36px;
height: 36px; height: 36px;
background: linear-gradient(180deg, #003269 1%, rgba(3, 79, 163, 0.2314) 56%, #003269 100%); background: linear-gradient(180deg, #003269 1%, rgba(3, 79, 163, 0.2314) 56%, #003269 100%);
border-radius: 0px 0px 0px 0px; border-radius: 0px 0px 0px 0px;
opacity: 1; opacity: 1;
:deep(span) { :deep(span) {
color: #5beff9; color: #5beff9;
}
margin-left: 10px;
} }
margin-left: 10px;
}
} }
</style> </style>

4
src/views/monitoring/screen/components/main.vue

@ -161,8 +161,8 @@ const userInfo = JSON.parse(userStorageInfo === null ? '' : userStorageInfo);
// const baseApi = "http://board.heatiot.cn:8001/prod-api"//websocket // const baseApi = "http://board.heatiot.cn:8001/prod-api"//websocket
//const baseApi = import.meta.env.VITE_APP_BASE_API //const baseApi = import.meta.env.VITE_APP_BASE_API
//const apiUrl = baseApi.replace(/https?:/, ''); //const apiUrl = baseApi.replace(/https?:/, '');
// const wsUrl = `ws://${window.location.host}/ws/websocket/${userInfo.userName}`; //websocket const wsUrl = `ws://${window.location.host}/ws/websocket/${userInfo.userName}`; //websocket
const wsUrl = `ws://10.10.10.56:9010/websocket/${userInfo.userName}`; //websocket // const wsUrl = `ws://172.1.2.158:9010/websocket/${userInfo.userName}`; //websocket
const emit = defineEmits(['tableHeaderData']); const emit = defineEmits(['tableHeaderData']);
// const listData = ref([ // const listData = ref([

4
vite.config.ts

@ -46,8 +46,8 @@ export default defineConfig(({ mode }: ConfigEnv): UserConfig => {
proxy: { proxy: {
[env.VITE_APP_BASE_API]: { [env.VITE_APP_BASE_API]: {
// target: 'http://172.1.2.196:9010/', //本地接口地址 // target: 'http://172.1.2.196:9010/', //本地接口地址
target: 'http://172.1.2.139:9010/', //本地接口地址 // target: 'http://172.1.2.158:9010/', //本地接口地址
// target: 'http://10.10.10.56:9010/', //线上测试接口地址 target: 'http://10.10.10.56:9010/', //线上测试接口地址
changeOrigin: true, changeOrigin: true,
rewrite: path => path.replace(new RegExp('^' + env.VITE_APP_BASE_API), '') rewrite: path => path.replace(new RegExp('^' + env.VITE_APP_BASE_API), '')
} }

Loading…
Cancel
Save