Browse Source

数据大屏样式重构

develop
fuguobin 1 year ago
parent
commit
6b61d0b8ce
  1. 5
      src/router/index.ts
  2. 32
      src/styles/index.scss
  3. 4
      src/types/auto-imports.d.ts
  4. 423
      src/views/dataScreen/components/header.vue
  5. 291
      src/views/dataScreen/components/menu.vue
  6. 434
      src/views/dataScreen/devicemanage/components/main.vue
  7. 68
      src/views/dataScreen/devicemanage/components/menu.vue
  8. 739
      src/views/dataScreen/devicemanage/index.scss
  9. 57
      src/views/dataScreen/devicemanage/index.vue
  10. 149
      src/views/dataScreen/screen/components/infoPanel.vue
  11. 519
      src/views/dataScreen/screen/components/main.vue
  12. 68
      src/views/dataScreen/screen/components/menu.vue
  13. 299
      src/views/dataScreen/screen/components/showTree.vue
  14. 691
      src/views/dataScreen/screen/index.scss
  15. 194
      src/views/dataScreen/screen/index.vue
  16. 2
      src/views/details/index.scss
  17. 66
      src/views/monitoring/components/header.vue
  18. 33
      src/views/monitoring/components/menu.vue
  19. 423
      src/views/monitoring/devicemanage/components/header.vue
  20. 259
      src/views/monitoring/devicemanage/components/menu.vue
  21. 4
      src/views/monitoring/devicemanage/index.vue
  22. 110
      src/views/monitoring/screen/components/main.vue
  23. 120
      src/views/monitoring/screen/index.scss

5
src/router/index.ts

@ -29,6 +29,11 @@ export const constantRoutes: RouteRecordRaw[] = [
component: () => import('@/views/login/index.vue'),
meta: { hidden: true }
},
{
path: '/dataScreen',
component: () => import('@/views/dataScreen/screen/index.vue'),
meta: { hidden: true }
},
{
path: '/screen',
component: () => import('@/views/monitoring/screen/index.vue'),

32
src/styles/index.scss

@ -19,14 +19,14 @@
.n-drawer-container {
.waringDrawer {
color: #fff;
background: #0f2856;
backdrop-filter: blur(10px);
// color: #fff;
// background: #0f2856;
// backdrop-filter: blur(10px);
overflow: hidden;
.n-drawer-header {
color: #fff;
border-bottom: 1px solid #1a3960;
// color: #fff;
// border-bottom: 1px solid #1a3960;
.n-drawer-header__main {
flex: 1;
@ -39,7 +39,7 @@
.button {
font-size: 14px;
color: #b1e3ff;
// color: #b1e3ff;
padding-right: 20px;
}
}
@ -52,11 +52,11 @@
.waringList {
padding: 10px;
background: #08173e;
// background: #08173e;
.item {
padding-bottom: 10px;
border-bottom: 1px solid #1a3960;
// border-bottom: 1px solid #1a3960;
margin-bottom: 10px;
.name {
@ -71,7 +71,7 @@
span.time {
font-size: 14px;
color: #b1e3ff;
// color: #b1e3ff;
}
}
@ -80,14 +80,14 @@
justify-content: space-between;
align-items: center;
span {
color: #b1e3ff;
}
// span {
// color: #b1e3ff;
// }
.n-button {
background-color: #022a5a !important;
border: 1px solid #114073;
}
// .n-button {
// background-color: #022a5a !important;
// border: 1px solid #114073;
// }
}
}

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

@ -5,8 +5,6 @@ declare global {
const ElForm: typeof import('element-plus/es')['ElForm']
const ElMessage: typeof import('element-plus/es')['ElMessage']
const ElMessageBox: typeof import('element-plus/es')['ElMessageBox']
const ElNotification: typeof import('element-plus/es')['ElNotification']
const NEllipsis: typeof import('naive-ui')['NEllipsis']
const asyncComputed: typeof import('@vueuse/core')['asyncComputed']
const autoResetRef: typeof import('@vueuse/core')['autoResetRef']
const computed: typeof import('vue')['computed']
@ -276,8 +274,6 @@ declare module 'vue' {
readonly ElForm: UnwrapRef<typeof import('element-plus/es')['ElForm']>
readonly ElMessage: UnwrapRef<typeof import('element-plus/es')['ElMessage']>
readonly ElMessageBox: UnwrapRef<typeof import('element-plus/es')['ElMessageBox']>
readonly ElNotification: UnwrapRef<typeof import('element-plus/es')['ElNotification']>
readonly NEllipsis: UnwrapRef<typeof import('naive-ui')['NEllipsis']>
readonly asyncComputed: UnwrapRef<typeof import('@vueuse/core')['asyncComputed']>
readonly autoResetRef: UnwrapRef<typeof import('@vueuse/core')['autoResetRef']>
readonly computed: UnwrapRef<typeof import('vue')['computed']>

423
src/views/dataScreen/components/header.vue

@ -0,0 +1,423 @@
<template>
<div class="title">
<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="seeting">
<n-tooltip trigger="hover">
<template #trigger>
<n-button class="tooltips" circle quaternary @click="returnBack">
<template #icon>
<n-icon>
<ReturnDownBack />
</n-icon>
</template>
</n-button>
</template>
返回上一页
</n-tooltip>
<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" 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>
</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="alertFirstTimeS" label="首次告警时间" align="center" />
<el-table-column prop="alertLastTimeS" 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>
<el-pagination
class="waringPagination"
layout="prev, pager, next"
:current-page.sync="params.pageNum"
:page-size="params.pageSize"
:total="params.total"
hide-on-single-page
@current-change="handleCurrentChange"
/>
<div class="warClose" @click="warClose">
<CloseCircleOutline />
</div>
</n-card>
</n-modal>
</template>
<script lang="ts" setup>
import { useRoute, useRouter } from 'vue-router';
import { getWeather } from '@/api/user/index';
import { getWarList, process } from '@/api/waring/index';
import { waringVo } from '@/api/waring/types';
import { Filter, Maximize, Settings, Power, Bell, ChartLine } from '@vicons/tabler';
import { CloseCircleOutline, ReturnDownBack } from '@vicons/ionicons5';
import { useDateFormat, useNow } from '@vueuse/core';
import { uniqueArrayObject } from '@/utils/index';
import mitt from '@/plugins/bus';
import calendar from '@/utils/lunar';
const route = useRoute();
const router = useRouter();
const currentTime = useDateFormat(useNow(), 'YYYY-MM-DD HH:mm:ss');
const emit = defineEmits(['showModalClick', 'returnClick']);
const timer = ref();
const isCurrentRoute = ref(true);
const waringDrawer = ref(false);
const waringModal = ref(false);
const waringData = ref<waringVo[]>([]);
const waringList = ref<waringVo[]>([]);
const routerType = ref('');
const deptId = ref(0);
const params = reactive({
total: 10,
pageSize: 10,
pageNum: 1
});
const weatherData = ref({ city: '', weather: '', temperature: '', weatherImg: '' });
const lunarDay: any = calendar.solarToLunar(
useNow().value.getUTCFullYear(),
useNow().value.getUTCMonth() + 1,
useNow().value.getUTCDate()
);
const props = defineProps({
titleData: {
type: String,
default: '数据大屏'
},
settingShow: {
type: Boolean,
default: false
},
warningShow: {
type: Boolean,
default: false
}
});
onMounted(() => {
deptId.value = sessionStorage.getItem('deptId') === null ? 0 : Number(sessionStorage.getItem('deptId'));
routerType.value = route.query?.id === undefined ? '0' : '1';
getWeatherData();
});
mitt.on('waringMessage', (res: any) => {
//
console.log('waringMessage--', res.data);
waringData.value = res.data;
// waringData.value.push(res.data)
// console.log("waringData--", waringData.value);
// waringData.value = uniqueArrayObject(waringData.value, "id")
// console.log("waringData--", waringData.value);
});
function showClick() {
///
emit('showModalClick', true);
// showModal.value = true;
}
function returnBack() {
//
// emit('returnClick', '');
if (routerType.value === '1' && route.path != '/screen') {
router.push({
path: '/screen',
query: { id: sessionStorage.getItem('id') }
});
} else {
router.replace('/dashboard');
}
}
function waringClick() {
//
// if (waringData.value.length === 0) {
// ElNotification({
// message: '',
// type: 'info',
// })
// } else {
waringDrawer.value = true;
// }
}
function lineClick() {
//
router.push({
path: '/details'
});
}
function handleCurrentChange(val: any) {
//
params.pageNum = val;
getwaringList();
}
function getWeatherData() {
//
getWeather().then((res: any) => {
if (res.code === 200) {
if (isCurrentRoute) {
timer.value = setTimeout(async () => {
await (timer.value && clearTimeout(timer.value));
await getWeatherData();
}, 600000);
}
weatherData.value = res.data;
} else {
clearTimeout(timer.value);
}
});
}
function waringMore() {
//
waringDrawer.value = false;
waringModal.value = true;
getwaringList();
}
function getwaringList() {
//
const paramsr = {
beginTime: '',
endTime: '',
orgCode: sessionStorage.getItem('deptId') === null ? 0 : Number(sessionStorage.getItem('deptId')),
params
};
getWarList(paramsr).then((res: any) => {
if (res.code === 200) {
waringList.value = res.rows;
params.total = res.total;
// page.pageSize = res.size;
// page.pageSize = res.current;
}
});
}
function waringConfirm(item: any) {
//
ElMessageBox.confirm('是否确认操作?', '提示', {
confirmButtonText: '确认',
cancelButtonText: '取消',
type: 'warning'
})
.then(() => {
const params = item.id;
process(params).then((res: any) => {
if (res.code === 200) {
waringList.value = res.data;
// waringDrawer.value = false
// waringModal.value = false
getwaringList();
ElMessage({
message: res.msg,
type: 'success'
});
}
});
})
.catch(() => {});
}
function warClose() {
//
waringModal.value = false;
}
</script>
<style lang="scss" scoped>
.header {
display: flex;
justify-content: space-between;
align-items: center;
// height: 5.7rem;
.title {
width: 80%;
background: url(@/assets/images/title-bg.png);
background-size: 100%;
text-align: center;
padding-bottom: 38px;
margin: 0 auto;
h3 {
height: 57px;
font-size: 3.8rem;
font-family: 'YouSheBiaoTiHei';
font-weight: 400;
letter-spacing: 4px;
background: linear-gradient(180deg, #fefdff 0%, #95daff 97%);
background-clip: text;
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
margin: 0;
}
}
}
.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;
align-items: center;
.weatherSvg {
width: 1.5em !important;
height: 1.5em !important;
margin-left: 10px;
}
// img {
// width: 25px;
// margin-left: 10px;
// }
}
}
.seeting {
position: absolute;
top: 2.5rem;
right: 7rem;
.warningbadge {
margin-top: -10px;
}
.tooltips {
width: 36px;
height: 36px;
background: linear-gradient(180deg, #003269 1%, rgba(3, 79, 163, 0.2314) 56%, #003269 100%);
border-radius: 0px 0px 0px 0px;
opacity: 1;
:deep(span) {
color: #5beff9;
}
margin-left: 10px;
}
}
.waringModal {
.waringPagination {
justify-content: right;
margin-top: 5px;
:deep(button) {
color: #b1e3ff;
background: transparent;
}
:deep(.el-pager) {
.number,
.more {
color: #b1e3ff;
background: transparent;
}
.number.is-active {
color: #409eff;
}
}
}
}
</style>

291
src/views/dataScreen/components/menu.vue

@ -0,0 +1,291 @@
<template>
<div class="menuCantent">
<n-menu
ref="menuInstRef"
class="menu"
:indent="0"
:options="menuOptions"
v-model:value="selectedKey"
key-field="deptId"
label-field="deptName"
:default-expand-all="false"
:watch-props="['defaultExpandedKeys']"
:render-label="renderMenuLabel"
@update:value="menuUpdateValue"
/>
</div>
</template>
<script lang="ts" setup>
import { useRoute } from 'vue-router';
import type { MenuOption } from 'naive-ui';
// import { NEllipsis } from 'naive-ui';
import { getMenu } from '@/api/table/list';
import { getMenuData } from '@/api/device/index';
import { getFirstNodeLastLevel } from '@/utils/index';
import useStorage from '@/utils/useStorage';
import mitt from '@/plugins/bus';
const router = useRoute();
const menuOptions = ref([]);
const selectedKey = ref();
const sessionStorageIns = useStorage('sessionStorage');
const routerType = ref('');
const id = ref(0);
const deptId = ref(0);
const menuDeptKey = ref(0);
const menuIdKey = ref(0);
const emit = defineEmits(['tableMenuData']);
const props = defineProps({
menuType: {
type: String,
default: '1'
}
});
onMounted(() => {
routerType.value = router.query?.id === undefined ? '0' : '1';
id.value = sessionStorage.getItem('id') === null ? 0 : Number(sessionStorage.getItem('id'));
deptId.value = sessionStorage.getItem('deptId') === null ? 0 : Number(sessionStorage.getItem('deptId'));
if (props.menuType === '1') {
menuApi();
} else if (props.menuType === '2') {
comMenuApi();
}
});
function menuApi() {
//
getMenu().then((res: any) => {
if (res.code === 200) {
menuDeptKey.value =
routerType.value === '1'
? deptId.value
: routerType.value === '0' && deptId.value != 0
? deptId.value
: getFirstNodeLastLevel(res.data).deptId;
removeChildren(res.data);
menuOptions.value = res.data;
selectedKey.value = menuDeptKey.value;
sessionStorageIns.setUseStorage('deptId', menuDeptKey.value);
mitt.emit('menuKey', menuDeptKey.value);
emit('tableMenuData', res.data);
}
});
}
function comMenuApi() {
//
getMenuData().then((res: any) => {
if (res.code === 200) {
menuIdKey.value =
routerType.value === '1'
? id.value
: routerType.value === '0' && id.value != 0
? id.value
: getFirstNodeLastLevel(res.data).deptId;
const parentId = routerType.value === '1' ? deptId.value : getFirstNodeLastLevel(res.data).parentId;
removeChildren(res.data);
menuOptions.value = res.data;
selectedKey.value = menuIdKey.value;
sessionStorageIns.setUseStorage('deptId', routerType.value === '1' ? deptId.value : parentId);
mitt.emit('deviceMenuKey', menuIdKey.value);
emit('tableMenuData', res.data);
}
});
}
function removeChildren(menu: any) {
//children
if (!Array.isArray(menu)) {
return;
}
menu.forEach(item => {
if (item.children && item.children.length === 0) {
delete item.children;
} else {
removeChildren(item.children);
}
});
}
// function renderMenuLabel(option: MenuOption) {
const renderMenuLabel = (option: MenuOption) => {
//
// return h(NEllipsis, null, option.deptName as string);
return h(NEllipsis, null, { default: () => option.deptName });
};
function menuUpdateValue(key: string, item: MenuOption) {
//
sessionStorageIns.setUseStorage(props.menuType === '1' ? 'deptId' : 'id', key);
sessionStorageIns.setUseStorage('currentPage', 1);
if (props.menuType === '1') {
mitt.emit('currentPageEmit', 1);
}
if (props.menuType === '2') {
sessionStorageIns.setUseStorage('deptId', item.parentId);
}
mitt.emit(props.menuType === '1' ? 'menuKey' : 'deviceMenuKey', key);
console.log(key, item);
}
</script>
<style lang="scss" scoped>
:root {
--n-item-text-color-child-active-hover: #fff;
--n-item-text-color-active-hover: #fff;
--n-item-text-color-child-active: #fff;
}
.menuCantent {
height: -webkit-fill-available;
overflow: auto;
.menu {
text-align: center;
:deep(.n-submenu) {
--n-item-color-hover: auto;
.n-menu-item {
.n-menu-item-content {
padding: 0 !important;
.n-ellipsis {
font-family: 'AlibabaPuHuiTiBold';
padding: 0 15px;
}
.n-menu-item-content__arrow {
color: #b1e3ff;
}
}
.n-menu-item-content.n-menu-item-content--child-active {
.n-menu-item-content-header {
color: #b1e3ff;
}
.n-menu-item-content__arrow {
color: #b1e3ff;
}
}
// .n-menu-item-content--child-active {
// .n-menu-item-content-header:hover {
// color: #fff !important;
// }
// .n-menu-item-content__arrow:hover {
// color: #fff !important;
// }
// }
// .n-menu-item-content--child-active:hover{
// color: #fff !important;
// }
.n-menu-item-content-header {
font-size: 2.2rem;
color: #b1e3ff;
}
}
.n-menu-item:hover {
color: red;
}
.n-submenu-children {
.n-menu-item-content-header {
font-size: 1.6rem;
}
.n-menu-item-content--selected {
.n-menu-item-content-header {
color: #fff;
.n-ellipsis {
position: relative;
span {
padding: 0 10px;
}
span::before {
content: '';
position: absolute;
left: 0;
top: 0.7rem;
width: 1.8rem;
height: 1.8rem;
background: url(@/assets/images/taps.png) no-repeat;
background-size: cover;
}
}
}
}
.n-menu-item-content--selected::before {
background: -webkit-linear-gradient(left, #1fc7ff29 0%, #1177e700 100%);
left: 0;
right: 0;
}
.n-menu-item-content--selected::after {
content: '';
position: absolute;
bottom: 0;
width: 100%;
height: 2px;
background: -webkit-linear-gradient(left, #1fc7ff29 0%, #1177e700 100%);
}
}
.n-base-icon {
color: #84e0f7;
right: 10px;
}
}
}
}
/*滚动条整体部分*/
.menuCantent::-webkit-scrollbar,
.tableGrid ::-webkit-scrollbar {
width: 8px;
height: 8px;
}
/*滚动条的轨道*/
.menuCantent::-webkit-scrollbar-track,
.tableGrid ::-webkit-scrollbar-track {
background-color: transparent;
-webkit-border-radius: 8px;
-moz-border-radius: 8px;
border-radius: 8px;
}
/*滚动条里面的小方块,能向上向下移动*/
.menuCantent::-webkit-scrollbar-thumb,
.tableGrid ::-webkit-scrollbar-thumb {
background-color: rgb(147, 147, 153, 0.5);
-webkit-border-radius: 8px;
-moz-border-radius: 8px;
border-radius: 8px;
}
.menuCantent::-webkit-scrollbar-thumb:hover,
.tableGrid ::-webkit-scrollbar-thumb:hover {
background-color: #a8a8a8;
}
.menuCantent::-webkit-scrollbar-thumb:active,
.tableGrid :-webkit-scrollbar-thumb:active {
background-color: #787878;
}
/*边角,即两个滚动条的交汇处*/
.menuCantent::-webkit-scrollbar-corner,
.tableGrid ::-webkit-scrollbar-corner {
background-color: transparent;
}
</style>

434
src/views/dataScreen/devicemanage/components/main.vue

@ -0,0 +1,434 @@
<template>
<div class="devicePrt">
<div class="deviceImg deviceImgA" v-if="zoneType === 1">
<div class="card card_a">
<div class="dataInfo" v-html="doubleCount('013', 0)"></div>
<div class="dataInfo" v-html="doubleCount('011', 0)"></div>
<div class="dataInfo" v-html="doubleCount('014', 0)"></div>
<div class="dataInfo" v-html="doubleCount('012', 0)"></div>
</div>
<div class="card card_b">
<div class="dataInfo" v-html="doubleCount('002', 0)"></div>
<div class="dataInfo" v-html="doubleCount('007', 0)"></div>
</div>
<div class="card card_c">
<div class="dataInfo dataFlex">
<div class="flexItem" v-html="doubleCount('047', 0)"></div>
<div class="flexItem" v-html="doubleCount('045', 0)"></div>
</div>
<div class="dataInfo dataFlex">
<div class="flexItem" v-html="doubleCount('048', 0)"></div>
<div class="flexItem" v-html="doubleCount('046', 0)"></div>
</div>
</div>
<div class="card card_f">
<div class="dataInfo" v-html="doubleCount('015', 0)"></div>
</div>
<!-- <div class="switch switch_a" @click="switchClick('001', 0)"></div> -->
<!-- <div class="switch switch_b" @click="switchClick('065', 0)"></div> -->
<img class="deviceImg" :src="deviceImg" />
<!-- <img class="deviceImg" src="@/assets/images/device01.gif" /> -->
</div>
<div class="deviceImg deviceImgB" v-if="zoneType === 2">
<div class="card card_a">
<div class="dataInfo" v-html="doubleCount('013', 0)"></div>
<div class="dataInfo" v-html="doubleCount('011', 0)"></div>
<div class="dataInfo" v-html="doubleCount('014', 0)"></div>
<div class="dataInfo" v-html="doubleCount('012', 0)"></div>
</div>
<div class="card card_b">
<div class="dataInfo" v-html="doubleCount('002', 0)"></div>
<div class="dataInfo" v-html="doubleCount('007', 0)"></div>
</div>
<div class="card card_c">
<div class="dataInfo dataFlex">
<div class="flexItem" v-html="doubleCount('047', 0)"></div>
<div class="flexItem" v-html="doubleCount('045', 0)"></div>
</div>
<div class="dataInfo dataFlex">
<div class="flexItem" v-html="doubleCount('048', 0)"></div>
<div class="flexItem" v-html="doubleCount('046', 0)"></div>
</div>
</div>
<div class="card card_d">
<div class="dataInfo dataFlex">
<div class="flexItem" v-html="doubleCount('047', 1)"></div>
<div class="flexItem" v-html="doubleCount('045', 1)"></div>
</div>
<div class="dataInfo dataFlex">
<div class="flexItem" v-html="doubleCount('048', 1)"></div>
<div class="flexItem" v-html="doubleCount('046', 1)"></div>
</div>
</div>
<div class="card card_f">
<div class="dataInfo" v-html="doubleCount('015', 0)"></div>
</div>
<img class="deviceImg" :src="deviceImg" />
<!-- <img class="deviceImg" src="@/assets/images/device02.gif" /> -->
</div>
<div class="deviceImg deviceImgC" v-if="zoneType === 3">
<div class="card card_a">
<div class="dataInfo" v-html="doubleCount('013', 0)"></div>
<div class="dataInfo" v-html="doubleCount('011', 0)"></div>
<div class="dataInfo" v-html="doubleCount('014', 0)"></div>
<div class="dataInfo" v-html="doubleCount('012', 0)"></div>
</div>
<div class="card card_b">
<div class="dataInfo" v-html="doubleCount('002', 0)"></div>
<div class="dataInfo" v-html="doubleCount('007', 0)"></div>
</div>
<div class="card card_c">
<div class="dataInfo dataFlex">
<div class="flexItem" v-html="doubleCount('047', 0)"></div>
<div class="flexItem" v-html="doubleCount('045', 0)"></div>
</div>
<div class="dataInfo dataFlex">
<div class="flexItem" v-html="doubleCount('048', 0)"></div>
<div class="flexItem" v-html="doubleCount('046', 0)"></div>
</div>
</div>
<div class="card card_d">
<div class="dataInfo dataFlex">
<div class="flexItem" v-html="doubleCount('047', 1)"></div>
<div class="flexItem" v-html="doubleCount('045', 1)"></div>
</div>
<div class="dataInfo dataFlex">
<div class="flexItem" v-html="doubleCount('048', 1)"></div>
<div class="flexItem" v-html="doubleCount('046', 1)"></div>
</div>
</div>
<div class="card card_e">
<div class="dataInfo dataFlex">
<div class="flexItem" v-html="doubleCount('047', 2)"></div>
<div class="flexItem" v-html="doubleCount('045', 2)"></div>
</div>
<div class="dataInfo dataFlex">
<div class="flexItem" v-html="doubleCount('048', 2)"></div>
<div class="flexItem" v-html="doubleCount('046', 2)"></div>
</div>
</div>
<div class="card card_f">
<div class="dataInfo" v-html="doubleCount('015', 0)"></div>
</div>
<img class="deviceImg" :src="deviceImg" />
<!-- <img class="deviceImg" src="@/assets/images/device03.gif" /> -->
</div>
<div class="devicInfo" v-if="infoData?.length != 0">
<div class="title">
<i />
<span>阀门控制</span>
</div>
<div class="infoPanel">
<n-scrollbar class="item">
<n-collapse class="collapse" :default-expanded-names="[0, 1, 2]">
<template #arrow>
<img src="@/assets/images/col_icon.png" />
</template>
<n-collapse-item
class="colItem"
:title="item.label"
:name="index"
v-for="(item, index) in infoData"
:key="index"
>
<div class="content">
<span v-for="(res, index) in item.header_valve" :key="index">
<i>{{ res.label }} </i>
<i v-if="res.ctrlFlag === 0">{{ res.value }}{{ res.paramUnit }}</i>
<i v-if="res.ctrlFlag === 1">
<n-switch
class="switch"
size="small"
v-model:value="res.value"
style="--n-rail-color-active: #409eff; --n-rail-color: #ff4949"
@update:value="submitBlur(res)"
v-if="res.ctrlpro.valueType === 'bool'"
>
<template #checked></template>
<template #unchecked></template>
</n-switch>
<n-input
size="tiny"
v-model:value="res.value"
readonly
placeholder="0"
style="width: 80px; opacity: 0.9; text-align: center"
v-if="res.ctrlpro.valueType != 'bool'"
@click="inputClick(res)"
/>
<!-- <n-input-group v-if="res.ctrlpro.valueType != 'bool'">
<n-input-number
size="tiny"
v-model:value="res.value"
style="width: 80px; opacity: 0.9; text-align: center"
button-placement="both"
placeholder=""
@keyup.enter="submitBlur(res)"
/>
<n-input-group-label
size="tiny"
style="opacity: 0.9; text-align: center; cursor: pointer"
@click="submitBlur(res)"
>确定</n-input-group-label
>
</n-input-group> -->
<!-- <n-input-number
size="tiny"
v-model:value="res.value"
style="width: 100px; opacity: 0.9; text-align: center"
button-placement="both"
placeholder=""
@blur="submitBlur(res)"
v-if="res.ctrlpro.valueType != 'bool'"
/> -->
</i>
</span>
</div>
</n-collapse-item>
</n-collapse>
</n-scrollbar>
<n-scrollbar class="item">
<n-collapse class="collapse" :default-expanded-names="[0, 1, 2]">
<template #arrow>
<img src="@/assets/images/col_icon.png" />
</template>
<n-collapse-item
class="colItem"
:title="item.label"
:name="index"
v-for="(item, index) in infoData"
:key="index"
>
<div class="content pump">
<span v-for="(res, index) in item.header_pumpx" :key="index">
<i>{{ res.label }} </i>
<i v-if="res.ctrlFlag === 0">{{ res.value }}{{ res.paramUnit }}</i>
<i v-if="res.ctrlFlag === 1">
<n-switch
class="switch"
size="small"
v-model:value="res.value"
style="--n-rail-color-active: #409eff; --n-rail-color: #ff4949"
@update:value="submitBlur(res)"
v-if="res.ctrlpro.valueType === 'bool'"
>
<template #checked></template>
<template #unchecked></template>
</n-switch>
<n-input
size="tiny"
v-model:value="res.value"
readonly
placeholder="0"
style="width: 80px; opacity: 0.9; text-align: center"
v-if="res.ctrlpro.valueType != 'bool'"
@click="inputClick(res)"
/>
</i>
</span>
<span v-for="(res, index) in item.header_pump" :key="index">
<i>{{ res.label }} </i>
<i v-if="res.ctrlFlag === 0">{{ res.value }}{{ res.paramUnit }}</i>
<i v-if="res.ctrlFlag === 1">
<n-switch
class="switch"
size="small"
v-model:value="res.value"
style="--n-rail-color-active: #409eff; --n-rail-color: #ff4949"
@update:value="submitBlur(res)"
v-if="res.ctrlpro.valueType === 'bool'"
>
<template #checked></template>
<template #unchecked></template>
</n-switch>
<n-input
size="tiny"
v-model:value="res.value"
readonly
placeholder="0"
style="width: 80px; opacity: 0.9; text-align: center"
v-if="res.ctrlpro.valueType != 'bool'"
@click="inputClick(res)"
/>
</i>
</span>
</div>
</n-collapse-item>
</n-collapse>
</n-scrollbar>
</div>
<!-- <div class="valves">
<div class="title l_green">阀门控制</div>
<div class="info">
<div class="table">
<div class="item" v-for="(item, index) in infoData" :key="index">
<div class="lable l_green">{{ item.label }}</div>
<div class="parameters">
<span class="name" v-for="(res, index) in item.header_valve" :key="index">{{ res.label }}:{{ res.value }}
{{ res.paramUnit }}</span>
</div>
</div>
</div>
</div>
</div>
<div class="pump">
<div class="item" v-for="(item, index) in infoData" :key="index">
<div class="title l_green">
{{ item.label }}循环泵控制
</div>
<div class="info">
<span class="name" v-for="(res, index) in item.header_pump" :key="index">{{ res.label }}:{{ res.value }}
{{ res.paramUnit }}</span>
</div>
</div>
</div> -->
</div>
<div class="tips" v-if="infoData?.length === 0">暂无设备信息</div>
<n-modal class="modalClass" v-model:show="showModal">
<n-card :title="labelValue" :bordered="false" size="huge" role="dialog" aria-modal="true" style="width: 40rem">
<n-input-number v-model:value="ctrlproValue" clearable placeholder="请输入数值" />
<template #footer>
<n-button @click="cancelClick">取消</n-button>
<n-button type="info" @click="submitClick(submitData)">确认</n-button>
</template>
</n-card>
</n-modal>
</div>
</template>
<script lang="ts" setup>
import { getViewInfo } from '@/api/device/index';
import { sendCtrl } from '@/api/table/list';
import { deviceVo } from '@/api/device/types';
import mitt from '@/plugins/bus';
// const active = ref(true)
const deviceMenuKey = ref();
const infoData = ref<deviceVo[]>();
const zoneType = ref(); //1:,2:2,3:3:,4:
const deviceImg = ref();
const timer = ref();
const isCurrentRoute = ref(true);
const showModal = ref(false);
const submitData = ref();
const labelValue = ref('设备');
const ctrlproValue = ref(null);
// const collapseDefault = ref<any[]>();
interface FormDataVO {
//url: string;
deviceName: string;
paramCode: string;
value: string;
}
const formData = ref<FormDataVO>({
//url: '',
deviceName: '',
paramCode: '',
value: ''
});
defineProps({
sidebarHeight: {
type: Number,
default: 0
}
});
mitt.on('deviceMenuKey', (res: any) => {
//
deviceMenuKey.value = res;
gitDevice();
});
function gitDevice() {
//
const params = deviceMenuKey.value;
getViewInfo(params).then((res: any) => {
if (res.code === 200) {
if (isCurrentRoute) {
timer.value = setTimeout(async () => {
await (timer.value && clearTimeout(timer.value));
await gitDevice();
}, 20000);
}
infoData.value = Object.keys(res.data).length === 0 ? [] : res.data.datas;
zoneType.value = Object.keys(res.data).length === 0 ? 0 : res.data.pCounts;
deviceImg.value = Object.keys(res.data).length === 0 ? '' : res.data.imgIndex;
console.log(deviceImg.value);
} else {
clearTimeout(timer.value);
}
});
}
onUnmounted(() => {
//setTimeout
if (timer.value !== null || timer.value !== undefined) {
clearTimeout(timer.value);
}
});
// function doubleCount (id:string) {
// const arr = infoData.value[0].header_main
// const obj=arr.find((item: any) => item.id === id)
// const lable=obj!=undefined?`${obj.label}:${obj.value}`:''
// debugger
// return lable;
// };
// const doubleCount = computed(() => {
// function doubleCount(id: string) {
// const arr = infoData.value[0].header_main
// const obj = arr.find((item: any) => item.id === id)
// const lable = obj != undefined ? `${obj.label}:${obj.value}` : ''
// debugger
// return lable;
// };
// });
const doubleCount = (id: string, index: number) => {
const arr = infoData.value[index].header_main;
const obj = arr.find((item: any) => item.id === id);
const lable = obj != undefined ? `<span>${obj.label}</span><span>${obj.value} ${obj.paramUnit}</span>` : '';
// const lable = obj != undefined ? `${obj.label}` : ''
// const value = obj != undefined ? `${obj.value}` : '0.0'
return lable;
};
console.log('doubleCount-', doubleCount);
function inputClick(data: any) {
//
submitData.value = data;
labelValue.value = data.label;
ctrlproValue.value = data.value;
showModal.value = true;
}
function cancelClick() {
//
labelValue.value = '设备';
ctrlproValue.value = null;
showModal.value = false;
}
function submitClick(data: any) {
//
if (ctrlproValue.value === '' || ctrlproValue.value === null) {
ElNotification({ message: '请输入数值!' });
} else {
data.value = ctrlproValue.value;
submitBlur(data);
}
}
function submitBlur(data: any) {
///
const submitData = data.ctrlpro;
submitData.value = data.value;
console.log(submitData);
sendCtrl(submitData).then((res: any) => {
if (res.code === 200) {
console.log(res.data);
showModal.value = false;
ElNotification({ message: res.data.msg });
}
});
}
</script>

68
src/views/dataScreen/devicemanage/components/menu.vue

@ -0,0 +1,68 @@
<template>
<n-menu ref="menuInstRef" class="menu" :indent="0" :options="menuOptions" v-model:value="selectedKey" key-field="deptId"
label-field="deptName" :default-expand-all="false" :watch-props="['defaultExpandedKeys']"
:render-label="renderMenuLabel" @update:value="menuUpdateValue" />
</template>
<script lang="ts" setup>
import type { MenuOption } from 'naive-ui';
// import { NEllipsis } from 'naive-ui';
import { getMenuData } from '@/api/device/index';
import { getFirstNodeLastLevel } from '@/utils/index';
import useStorage from '@/utils/useStorage'
import mitt from '@/plugins/bus';
const menuOptions = ref([]);
const selectedKey = ref();
const sessionStorageIns = useStorage('sessionStorage');
const emit = defineEmits(['tableMenuData']);
onMounted(() => {
menuApi();
});
function menuApi() {
//
getMenuData().then((res: any) => {
if (res.code === 200) {
const key = getFirstNodeLastLevel(res.data).deptId
removeChildren(res.data);
menuOptions.value = res.data;
selectedKey.value = key;
sessionStorageIns.setUseStorage('deptId', key);
mitt.emit('deviceMenuKey', key);
emit('tableMenuData', res.data);
}
});
}
function removeChildren(menu: any) {
//children
if (!Array.isArray(menu)) {
return;
}
menu.forEach((item) => {
if (item.children && item.children.length === 0) {
delete item.children;
} else {
removeChildren(item.children);
}
});
}
function renderMenuLabel(option: MenuOption) {
//
return h(NEllipsis, null, option.deptName as string);
}
function menuUpdateValue(key: string, item: MenuOption) {
//
sessionStorageIns.setUseStorage('id', key);
mitt.emit('deviceMenuKey', key);
console.log(key, item);
}
</script>
<style lang="scss" scoped>
@import '../index.scss';
</style>

739
src/views/dataScreen/devicemanage/index.scss

@ -0,0 +1,739 @@
.devicemanage {
position: relative;
width: 100%;
height: 100vh;
background: url(@/assets/images/screen.png);
// background-color: var(--tableBg);
background-size: 100% 100%;
// background-color: rgba(0, 0, 0, 0.3);
// background-blend-mode: multiply;
padding: 0 25px;
overflow: hidden;
.layout {
display: flex;
.sidebar {
width: 12%;
height: calc(100vh - 95px - 30px); //屏幕高度-头部header高度-底部高度
flex-shrink: 0;
border: 1px solid #0d55b0;
padding: 10px 0;
// box-shadow: inset 0px 0px 10px 0px rgb(36, 90, 12);
margin-right: 1vw;
position: relative;
overflow: hidden;
transition: width 0.28s;
background-color: rgba(2, 8, 46, 0.8);
// .menu {
// text-align: center;
// :deep(.n-submenu) {
// --n-item-color-hover: auto;
// .n-menu-item {
// .n-menu-item-content {
// padding: 0 !important;
// .n-ellipsis {
// font-family: 'AlibabaPuHuiTiBold';
// padding: 0 15px;
// }
// }
// .n-menu-item-content-header {
// font-size: 2.4rem;
// color: #B1E3FF;
// }
// }
// .n-submenu-children {
// .n-menu-item-content-header {
// font-size: 1.8rem;
// }
// .n-menu-item-content--selected {
// .n-menu-item-content-header {
// color: #fff;
// .n-ellipsis {
// position: relative;
// span {
// padding: 0 10px;
// }
// span::before {
// content: '';
// position: absolute;
// left: 0;
// top: 0.7rem;
// width: 1.8rem;
// height: 1.8rem;
// background: url(../../../assets/images/taps.png) no-repeat;
// background-size: cover;
// }
// }
// }
// }
// .n-menu-item-content--selected::before {
// background: -webkit-linear-gradient(left, #1fc7ff29 0%, #1177e700 100%);
// left: 0;
// right: 0;
// }
// .n-menu-item-content--selected::after {
// content: '';
// position: absolute;
// bottom: 0;
// width: 100%;
// height: 2px;
// background: -webkit-linear-gradient(left, #1fc7ff29 0%, #1177e700 100%);
// }
// }
// .n-base-icon {
// color: #84e0f7;
// right: 10px;
// }
// }
// }
}
.sidebar::after {
content: '';
position: absolute;
bottom: 0;
width: 100%;
height: 18rem;
background: url(@/assets/images/menu_bg.png) no-repeat;
background-size: 100% 100%;
}
.main {
width: 87%;
border: 2px solid #1e60a6;
box-shadow: inset 0px 0px 10px 0px rgb(36, 90, 124);
background-color: rgba(2, 8, 46, 0.8);
:deep(.devicePrt) {
.deviceImg {
position: relative;
.deviceImg {
width: 100%;
}
.card {
position: absolute;
display: inline-block;
color: #87e8de;
font-size: 1.4rem;
padding: 10px 20px;
border-radius: 10px;
background: rgba(255, 255, 255, 0.1);
backdrop-filter: blur(10px);
border: 1px solid rgba(255, 255, 255, 0.1);
box-shadow: 0 0 80px rgba(0, 0, 0, 0.25);
z-index: 99;
overflow: hidden;
.dataInfo {
padding: 5px 0;
span {
display: block;
}
}
.dataFlex {
display: flex;
.flexItem {
margin-right: 15px;
}
.flexItem:last-child {
margin-right: 0;
}
}
}
// .switch {
// position: absolute;
// z-index: 99;
// cursor: pointer;
// overflow: hidden;
// }
// .dataInfo {
// position: absolute;
// display: inline-block;
// color: #87e8de;
// padding: 10px;
// font-size: 16px;
// // border: 2px solid #39c33c;
// z-index: 99;
// span {
// display: block;
// }
// }
}
.deviceImgA {
.card_a {
top: 40%;
left: 5%;
}
.card_b {
top: 5%;
left: 5%;
}
.card_c {
top: 30%;
right: 3%;
}
.card_f {
top: 30%;
right: 20%;
}
// .switch_a {
// width: 35px;
// height: 60px;
// background: red;
// top: 23%;
// left: 16.5%;
// }
// .switch_b {
// width: 40px;
// height: 65px;
// background: red;
// top: 59%;
// left: 15.5%;
// }
}
.deviceImgB {
.card_a {
top: 42%;
left: 5%;
}
.card_b {
top: 8%;
left: 5%;
}
.card_c {
top: 16%;
right: 3%;
}
.card_d {
top: 52%;
right: 3%;
}
.card_f {
top: 30%;
right: 21%;
}
}
.deviceImgC {
.card_a {
top: 6%;
left: 6%;
}
.card_b {
top: 62%;
left: 5%;
}
.card_c {
top: 2%;
right: 2%;
}
.card_d {
top: 35%;
right: 2%;
}
.card_e {
top: 67%;
right: 2%;
}
.card_f {
top: 30%;
right: 21%;
}
}
// .deviceImgA {
// .dataInfo0 {
// top: 7%;
// left: 6%;
// }
// .dataInfo1 {
// top: 35%;
// left: 9%;
// }
// .dataInfo2 {
// top: 0%;
// left: 18%;
// }
// .dataInfo3 {
// top: 0%;
// left: 25%;
// }
// .dataInfo4 {
// top: 15%;
// left: 17.5%;
// }
// .dataInfo5 {
// top: 26%;
// left: 17.5%;
// }
// .dataInfo6 {
// top: 0%;
// right: 20%;
// }
// .dataInfo7 {
// top: 10%;
// right: 20%;
// }
// }
// .deviceImgB {
// .dataInfo0 {
// top: 23%;
// left: 10.5%;
// }
// .dataInfo1 {
// top: 55%;
// left: 12%;
// }
// .dataInfo2 {
// top: 0%;
// left: 23%;
// }
// .dataInfo3 {
// top: 0%;
// left: 30%;
// }
// .dataInfo4 {
// top: 10%;
// left: 23%;
// }
// .dataInfo5 {
// top: 20%;
// left: 23%;
// }
// .dataInfo6 {
// top: 0%;
// right: 36%;
// }
// .dataInfo7 {
// top: 10%;
// right: 36%;
// }
// .dataInfo8 {
// top: 26%;
// right: 31%;
// }
// .dataInfo9 {
// top: 36%;
// right: 31%;
// }
// }
// .deviceImgC {
// .dataInfo0 {
// bottom: 38%;
// left: 8.5%;
// }
// .dataInfo1 {
// bottom: 1%;
// left: 11%;
// }
// .dataInfo2 {
// top: 0%;
// left: 23%;
// }
// .dataInfo3 {
// top: 0%;
// left: 30%;
// }
// .dataInfo4 {
// top: 10%;
// left: 23%;
// }
// .dataInfo5 {
// top: 20%;
// left: 23%;
// }
// .dataInfo6 {
// top: 0%;
// right: 36%;
// }
// .dataInfo7 {
// top: 0%;
// right: 29%;
// }
// .dataInfo8 {
// top: 22%;
// right: 36%;
// }
// .dataInfo9 {
// top: 22%;
// right: 29%;
// }
// .dataInfo10 {
// top: 47%;
// right: 36%;
// }
// .dataInfo11 {
// top: 47%;
// right: 29%;
// }
// }
.devicInfo {
color: #b1e3ff;
padding: 0 3rem;
font-family: 'AlibabaPuHuiTiRegular';
.title {
display: flex;
align-items: center;
font-size: 20px;
background: url(@/assets/images/info_bg.png) no-repeat center;
background-size: 100% 100%;
i {
display: block;
width: 6px;
height: 50px;
background: linear-gradient(270deg, #679fff 0%, rgba(17, 119, 231, 0.698) 100%);
border-radius: 0px 0px 0px 0px;
margin-right: 18px;
}
}
.infoPanel {
display: flex;
justify-content: space-between;
margin-top: 15px;
.item {
width: 49%;
height: calc(100vh - 150px - 53rem);
padding: 15px 0;
background: -webkit-linear-gradient(top, #052266 0%, #011341 100%);
overflow: auto;
.collapse {
.colItem {
.n-collapse-item__header-main {
font-size: 18px;
color: #1fb1ff;
padding: 0 22px;
.n-collapse-item-arrow {
margin-right: 10px;
img {
width: 18px;
height: 16px;
}
}
}
.n-collapse-item__content-wrapper {
.n-collapse-item__content-inner {
padding-top: 10px;
.content {
display: flex;
flex-wrap: wrap;
padding: 0 15px;
font-size: 16px;
color: #c15757;
line-height: 30px;
span {
display: flex;
align-items: center;
flex: 0 0 calc(100% / 2);
i {
font-style: normal;
display: flex;
align-items: center;
.n-input-number {
display: flex;
align-items: center;
}
}
.switch {
font-size: 13px;
}
}
span:nth-child(even) {
color: #41a5d7;
}
}
// .content.pump {
// span {
// flex: auto;
// }
// }
}
}
}
.colItem.n-collapse-item--active {
.n-collapse-item-arrow {
transform: none;
}
}
.colItem:not(:first-child) {
border-top: none;
}
.colItem:not(:first-child)::before {
display: block;
content: '';
width: 100%;
height: 1px;
background: linear-gradient(
90deg,
rgba(31, 225, 255, 0) 0%,
rgba(189, 220, 255, 0.94) 50%,
rgba(31, 225, 255, 0) 97%
);
}
}
}
}
// .l_green {
// color: #39c33c;
// }
// .l_blue {
// color: #41a5d7;
// }
// .orange {
// color: #c15757;
// }
// .title {
// font-size: 16px;
// }
// .valves {
// display: flex;
// align-items: center;
// flex-shrink: 0;
// width: 40%;
// .title {
// writing-mode: vertical-rl;
// // transform: rotate(180deg);
// }
// .info {
// .select {
// font-weight: 800;
// .n-button {
// margin-right: 5px;
// background: linear-gradient(#3370cb, #162f68, #162f68);
// }
// }
// .table {
// border: 1px solid #39c33c;
// border-radius: 3px;
// margin: 10px 0 10px 20px;
// .item {
// display: flex;
// align-items: center;
// padding: 10px 20px;
// line-height: 26px;
// border-bottom: 1px solid #39c33c;
// .lable {
// font-size: 16px;
// flex-shrink: 0;
// }
// .parameters {
// display: flex;
// flex-wrap: wrap;
// .name {
// color: #c15757;
// margin-left: 15px;
// }
// .name:nth-child(even) {
// color: #41a5d7;
// }
// .n-radio__label {
// color: #41a5d7;
// }
// }
// }
// .item:last-child {
// border-bottom: none;
// }
// }
// .switch {
// display: flex;
// span {
// display: flex;
// align-items: center;
// margin-right: 5px;
// }
// }
// }
// }
// .pump {
// width: 55%;
// padding: 5px 10px;
// border: 1px solid #39c33c;
// .item {
// line-height: 28px;
// .info {
// display: flex;
// flex-wrap: wrap;
// .name {
// color: #c15757;
// margin-left: 15px;
// }
// .name:nth-child(even) {
// color: #41a5d7;
// }
// }
// }
// }
}
.tips {
font-size: 1.6rem;
font-family: 'AlibabaPuHuiTiRegular';
text-align: center;
color: #b1e3ff;
margin-top: 40vh;
}
}
}
/*滚动条整体部分*/
.tableGrid ::-webkit-scrollbar {
width: 8px;
height: 8px;
}
/*滚动条的轨道*/
.tableGrid ::-webkit-scrollbar-track {
background-color: transparent;
-webkit-border-radius: 8px;
-moz-border-radius: 8px;
border-radius: 8px;
}
/*滚动条里面的小方块,能向上向下移动*/
.tableGrid ::-webkit-scrollbar-thumb {
background-color: rgb(147, 147, 153, 0.5);
-webkit-border-radius: 8px;
-moz-border-radius: 8px;
border-radius: 8px;
}
.tableGrid ::-webkit-scrollbar-thumb:hover {
background-color: #a8a8a8;
}
.tableGrid :-webkit-scrollbar-thumb:active {
background-color: #787878;
}
/*边角,即两个滚动条的交汇处*/
.tableGrid ::-webkit-scrollbar-corner {
background-color: transparent;
}
}
}
.dark {
.devicemanage {
background-color: rgba(29, 30, 31, 0.8);
background-blend-mode: multiply;
.layout {
.sidebar {
background-color: rgba(29, 30, 31, 0.8);
}
.main {
background-color: rgba(29, 30, 31, 0.8);
.devicePrt {
:deep(.devicInfo) {
.infoPanel {
.item {
background: -webkit-linear-gradient(top, rgba(29, 30, 31, 0.8) 0%, rgba(28, 32, 37, 0.8) 100%);
}
}
}
}
}
}
}
}

57
src/views/dataScreen/devicemanage/index.vue

@ -0,0 +1,57 @@
<template>
<div ref="screenRef" class="devicemanage">
<section ref="titleRef" class="header">
<Header :titleData="titleData" :settingShow="false" @returnClick="returnClick" />
</section>
<section class="layout">
<div ref="sidebar" class="sidebar">
<Menu menuType="2" @tableMenuData="tableMenuData" />
</div>
<div class="main">
<Main :sidebarHeight="sidebarHeight" />
</div>
</section>
</div>
</template>
<script lang="ts" setup>
import router from '@/router';
import { Filter, Maximize, Settings, Power } from '@vicons/tabler';
import Header from '../components/header.vue';
import Menu from '../components/menu.vue';
import Main from './components/main.vue';
// import screenfull from 'screenfull'
const titleRef = ref<HTMLElement>();
const sidebar = ref<HTMLElement>();
const screenRef = ref<HTMLElement>();
const sidebarHeight = ref();
const titleData = ref('');
onMounted(() => {
console.log(sidebar.value);
sidebarHeight.value = sidebar.value?.offsetHeight; //
console.log('sidebar:', sidebar.value?.offsetHeight);
});
window.addEventListener('resize', () => {
//
sidebarHeight.value = sidebar.value?.offsetHeight; //
console.log('监听sidebar:', sidebar.value?.offsetHeight);
});
function tableMenuData(data: any) {
//
titleData.value = data[0].deptName;
}
function returnClick() {
//
router.replace('/dashboard');
}
// function screenClick() {
// if (screenfull.isEnabled) {
// //
// screenfull.toggle(screenRef.value)
// }
// }
</script>
<style lang="scss" scoped>
@import './index.scss';
</style>

149
src/views/dataScreen/screen/components/infoPanel.vue

@ -0,0 +1,149 @@
<template>
<div class="infoPanel">
<swiper
class="swiper"
:loop="false"
:autoplay="{ delay: 500000, pauseOnMouseEnter: true, disableOnInteraction: false }"
:modules="modules"
:slides-per-view="4"
:space-between="15"
navigation
:pagination="{ clickable: true }"
>
<swiper-slide class="item" v-for="(item, index) in panelData" :key="index">
<div class="content">
<div class="icon">
<img src="@/assets/images/panel_icon.png" />
</div>
<div class="numValue" v-if="item.type === 'A'">
<span>
<countTo :start="1" :end="item.value" :duration="3000"></countTo>
</span>
<i>{{ item.ext }}</i>
<p>{{ item.title }}</p>
</div>
<div class="numValueMore" v-if="item.type === 'B'">
<div class="numItem" v-for="(res, index) in item.extJsb.extData" :key="index">
<span>{{ res.name }}</span>
<span><countTo :start="1" :end="res.value" :duration="3000"></countTo></span>
<span>{{ res.unit }}</span>
</div>
</div>
</div>
</swiper-slide>
</swiper>
</div>
</template>
<script lang="ts" setup>
import { Swiper, SwiperSlide } from 'swiper/vue';
import { Navigation, Pagination, Autoplay } from 'swiper/modules';
import { getTableFooter } from '@/api/table/list';
import { PanelVo } from '@/api/table/types';
import countTo from '@/utils/countTo';
import mitt from '@/plugins/bus';
import 'swiper/css';
const modules = [Navigation, Pagination, Autoplay];
const panelData = ref<PanelVo[]>();
const deptId = ref(0);
// const panelData: PanelVo[] = [
// {
// title: '',
// value: 26449,
// ext: 'KJ',
// backImg: '/poll/hot',
// type: 'A',
// id: 2
// },
// {
// title: '',
// value: 9889,
// ext: 'm³',
// backImg: '/poll/onewater',
// type: 'A',
// id: 3
// },
// {
// title: '线',
// value: 40.425532,
// ext: '%',
// backImg: '/poll/dev',
// type: 'A',
// id: 1
// },
// {
// title: '',
// value: 27893,
// ext: '',
// backImg: '/poll/alert',
// type: 'A',
// id: 4
// },
// {
// title: '',
// value: 0,
// ext: [
// {
// name:'',
// value:'58996',
// ext:''
// },
// {
// name:'',
// value:'58996',
// ext:''
// },
// {
// name:'',
// value:'58996',
// ext:''
// },
// {
// name:'',
// value:'32369',
// ext:'t/h'
// },
// {
// name:'',
// value:'58996',
// ext:''
// },
// {
// name:'',
// value:'58996',
// ext:''
// },
// {
// name:'',
// value:'8956',
// ext:'T'
// }
// ],
// backImg: '/poll/alert',
// type: 'B',
// id: 5
// }
// ];
onMounted(() => {
deptId.value = sessionStorage.getItem('deptId') === null ? 0 : Number(sessionStorage.getItem('deptId'));
getPanel();
});
mitt.on('menuKey', (res: any) => {
//
deptId.value = res;
getPanel();
});
function getPanel() {
//
const params = deptId.value;
getTableFooter(params).then((res: any) => {
if (res.code === 200) {
panelData.value = res.data;
}
});
}
</script>

519
src/views/dataScreen/screen/components/main.vue

@ -0,0 +1,519 @@
<template>
<div class="headerInfo" v-show="tapsShow">
<div class="header">
<div class="headerItem" v-for="(item, index) in headerData" :key="index">
<div class="name">{{ item.name }}</div>
<div class="value">{{ item.value }}</div>
</div>
</div>
</div>
<!-- <div
class="mainTable"
:style="{ height: tapsShow ? 'calc(100vh - 5.7rem - 222px)' : 'calc(100vh - 5.7rem - 60px)' }"
> -->
<div class="mainTable" :style="{ height: `${sidebarHeight}px` }">
<n-spin :show="loadingShow">
<vxe-grid
ref="tableRef"
class="tableGrid"
align="center"
auto-resize
keep-source
:height="sidebarHeight - 4"
header-row-class-name="headerRowClass"
header-cell-class-name="headerCellClass"
row-class-name="tableRowClass"
cell-class-name="tableCellClass"
:sort-config="{ multiple: true, trigger: 'cell' }"
:stripe="!tableBorder"
:border="tableBorder"
:column-config="{ resizable: true, useKey: true }"
:row-config="{ useKey: true }"
:span-method="mergeRowMethod"
:columns="tableColumn"
:data="tableData"
@cell-dblclick="cellDBLClickEvent"
>
<template #deviceuuid_default="{ row }">
<div class="title">
<svg-icon
icon-class="warning_lights"
style="fill: currentColor; width: 15px; height: 15px; color: green"
v-if="row.deviceuuid.deviceStatus === 0"
/>
<svg-icon
icon-class="warning_lights"
style="fill: currentColor; width: 15px; height: 15px; color: red"
v-if="row.deviceuuid.deviceStatus === 2"
/>
<span class="name" @click.native="nameClick(row.deviceuuid)">{{ row.gTitle }}</span>
</div>
</template>
<template #pager>
<!--使用 pager 插槽-->
<vxe-pager
class="tablePage"
:layouts="['Sizes', 'PrevJump', 'PrevPage', 'Number', 'NextPage', 'NextJump', 'FullJump', 'Total']"
v-model:current-page="tablePage.currentPage"
v-model:page-size="tablePage.pageSize"
auto-hidden
:total="tablePage.total"
@page-change="handlePageChange"
>
</vxe-pager>
</template>
</vxe-grid>
<!-- <vxe-grid class="tableGrid" v-bind="gridOptions"> </vxe-grid> -->
</n-spin>
</div>
<vxe-modal :title="modalTitle" v-model="editModal">
<template #default>
<vxe-form
title-colon
ref="formRef"
title-align="right"
title-width="100"
:data="formData"
:loading="formLoading"
@submit="submitEvent"
@reset="resetEvent"
>
<vxe-form-item field="value" span="24" :item-render="{}" title-overflow>
<template #default="params">
<vxe-switch
v-model="params.data.value"
size="small"
open-label="启"
close-label="停"
v-if="params.data.valueType === 'bool'"
></vxe-switch>
<vxe-input
v-model="params.data.value"
placeholder="请输入数值"
type="number"
clearable
v-if="params.data.valueType != 'bool'"
></vxe-input>
<!-- <vxe-input
v-model="params.data.value"
placeholder="请输入数值"
clearable
v-if="params.data.valueType != 'bool'"
></vxe-input> -->
</template>
</vxe-form-item>
<vxe-form-item align="center" span="24">
<template #default>
<vxe-button type="submit" status="primary" content="确认"></vxe-button>
<vxe-button type="reset" content="重置"></vxe-button>
</template>
</vxe-form-item>
</vxe-form>
</template>
</vxe-modal>
</template>
<script lang="ts" setup>
import router from '@/router';
import {
VxeGridProps,
VxeGridInstance,
VxeTableEvents,
VxeColumnPropTypes,
VXETable,
VxeFormInstance,
VxeFormPropTypes,
VxeFormEvents,
VxeTablePropTypes,
VxePagerEvents
} from 'vxe-table';
import { getTableHeader, getStationInfo, getTableData, editConfig, sendCtrl } from '@/api/table/list';
import { TableVo } from '@/api/table/types';
import { tableStore } from '@/store/modules/table';
import mitt from '@/plugins/bus';
import socket from '@/utils/socket';
import useStorage from '@/utils/useStorage';
const sessionStorageIns = useStorage('sessionStorage');
const tableStoreCounter = tableStore();
// import type { MenuOption } from 'naive-ui'
// import { useMessage } from 'naive-ui'
// const message = useMessage()
// const mainHeight = ref('calc(100vh - 161px)');
const loadingShow = ref(false);
const editModal = ref(false);
const modalTitle = ref('');
const menuKey = ref(0);
const tableColumn = ref([]);
const tableData = ref<TableVo[]>([]);
const tableRef = ref<VxeGridInstance<TableVo>>();
const cellRow = ref({});
const cellColumn = ref();
const cellField = ref();
const tableBorder = ref(true);
const tablePage = reactive({
total: 0,
currentPage: 1,
pageSize: 10
});
// const fields = ref(['deviceuuid']) //
// const waringArrow = ref([])
interface FormDataVO {
centeruuid: string;
paramcode: string;
url: string;
valueType: string;
value: string | boolean;
}
const formRef = ref<VxeFormInstance>();
const formLoading = ref(false);
const formData = ref<FormDataVO>({
centeruuid: '',
paramcode: '',
url: '',
valueType: '',
value: ''
});
// const formRules = ref<VxeFormPropTypes.Rules>({
// value: [
// { required: true, message: '' },
// { min: 1, max: 100, message: ' 1 100 ' },
// {
// validator({ itemValue }) {
// //
// const reg = /^-?\d+\.?\d{0,2}$/;
// if (!reg.test(itemValue)) {
// return new Error('');
// }
// }
// }
// ]
// });
const userStorageInfo = sessionStorage.getItem('userInfo');
const userInfo = JSON.parse(userStorageInfo === null ? '' : userStorageInfo);
//const apiUrl = import.meta.env.VITE_APP_WS_API
//const wsUrl = `${apiUrl}websocket/${userInfo.userName}`; //websocket
//const wsUrl = `${apiUrl}${userInfo.userName}`; //websocket
// const loginIp = userInfo.loginIp.split('.').join('');
// const baseApi = "http://172.1.2.106:9000"//websocket
// const baseApi = "http://board.heatiot.cn:8001/prod-api"//websocket
//const baseApi = import.meta.env.VITE_APP_BASE_API
//const apiUrl = baseApi.replace(/https?:/, '');
const wsUrl = `ws://${window.location.host}/ws/websocket/${userInfo.userName}`; //websocket
// const wsUrl = `ws://172.1.2.6:9010/websocket/${userInfo.userName}`; //websocket
const emit = defineEmits(['tableHeaderData']);
// const listData = ref([
// {
// name: 'area_default',
// value: 1,
// },
// ]);
defineProps({
tapsShow: {
type: Boolean,
default: true
},
sidebarHeight: {
type: Number,
default: 0
}
});
// watch(
// () => tableStoreCounter.tableDataStore,
// (newValue, oldValue) => {
// console.log('', newValue, oldValue);
// const $table = tableRef.value;
// $table.loadData(newValue);
// }
// );
// watchEffect(() => {
// const titleRef = props.tapsShow;
// console.log(tableStoreCounter.tableDataStore);
// tableData.value = tableStoreCounter.tableDataStore;
// $table.loadData(tableStoreCounter.tableDataStore);
// });
interface HeaderVo {
code: string;
name: string;
value: string;
}
const headerData = ref<HeaderVo[]>();
onMounted(() => {
// stationInfo();
// tableHeader();
console.log('aaaa', sessionStorage.getItem('currentPage'));
tablePage.currentPage =
sessionStorage.getItem('currentPage') === null ? 1 : Number(sessionStorage.getItem('currentPage'));
console.log(Number(sessionStorage.getItem('currentPage')));
tablePage.pageSize = sessionStorage.getItem('pageSize') === null ? 10 : Number(sessionStorage.getItem('pageSize'));
socket.initialize(wsUrl); //websocket http://
});
mitt.on('currentPageEmit', (res: any) => {
//
tablePage.currentPage = res;
});
mitt.on('menuKey', (res: any) => {
//
menuKey.value = res;
tableHeader();
tableDatas();
});
mitt.on('treeData', (res: any) => {
//header
tableColumn.value = [];
nextTick(() => {
tableColumn.value = res;
});
const params = res;
editConfig(params).then((res: any) => {
if (res.code === 200) {
mitt.emit('treeClose', true);
}
});
// tableColumn.value=res
// gridOptions.columns?.push(...res);
// console.log('', gridOptions.columns);
});
mitt.on('tableMessage', (res: any) => {
//
console.log('tableMessage--', res.data);
const $table = tableRef.value;
const tableArray = tableData.value;
if ($table) {
console.log('tableRef--', tableRef.value);
res.data.map((item: any) => {
const index = tableArray.findIndex(obj => obj.id === item.id);
if (index !== -1) {
tableArray.splice(index, 1, item);
}
});
console.log('tableData--', tableArray);
$table.loadData(tableArray);
// if (res.code === 'datareal') {
// const index = tableData.value.findIndex((obj) => obj.id === res.data.id);
// if (index !== -1) {
// tableData.value.splice(index, 1, res.data);
// }
// res.data.map((item: any) => {
// console.log(item)
// debugger
// const index = tableData.value.findIndex((obj) => obj.id === item.id);
// if (index !== -1) {
// tableData.value.splice(index, 1, res.data);
// }
// })
// $table.loadData(mergedArray);
}
// } else if (res.code === 'alertDev') {
// waringArrow.value.push(res.data)
// waringArrow.value = uniqueArrayObject(waringArrow.value, "devUuid")
// }
// console.log("waringArrow:", waringArrow.value)
});
const handlePageChange: VxePagerEvents.PageChange = ({ currentPage, pageSize }) => {
tablePage.currentPage = currentPage;
tablePage.pageSize = pageSize;
sessionStorageIns.setUseStorage('currentPage', currentPage);
sessionStorageIns.setUseStorage('pageSize', pageSize);
tableDatas();
};
function stationInfo() {
//
getStationInfo().then((res: any) => {
if (res.code === 200) {
headerData.value = res.data;
}
});
}
function tableHeader() {
//header
getTableHeader().then((res: any) => {
console.log(res);
//
const tableCessText = [
{
id: 0,
title: 'ID',
field: 'id',
type: 'html',
formatter: formatRole,
visible: false
}
];
console.log(tableCessText);
res.data.map((item: any) => {
if (item.formatter != undefined || item.children != undefined) {
item.formatter = eval(item.formatter);
if (item.children && item.children.length) {
item.children.map((res: any) => {
res.formatter = eval(res.formatter);
});
}
}
});
nextTick(() => {
tableColumn.value = res.data;
});
// tableColumn.value = res.data;
// const arr = [
// {
// id: 1,
// title: '',
// field: 'deviceuuid',
// colSort: 2,
// colType: '2',
// width: 150,
// show: true,
// disabled: true,
// fixed: 'left',
// type: 'html',
// formatter: "formatRole",
// },
// ];
// arr.map((item)=>{
// item.formatter=eval(item.formatter);
// })
// console.log(arr)
// tableColumn.value = arr;
// gridOptions.columns = res.data;
// console.log('', gridOptions.value.columns);
emit('tableHeaderData', res.data);
// mitt.emit('tableHeaderData', res.data);
// tableDatas();
});
}
function tableDatas() {
//
// const params = menuKey.value;
const params = {
pageNum: tablePage.currentPage,
pageSize: tablePage.pageSize,
orgCode: menuKey.value
};
loadingShow.value = true;
getTableData(params).then((res: any) => {
if (res.code === 200) {
// tableData.value=oldData
tableData.value = res.rows;
tableStoreCounter.tableDataAction(res.rows);
tablePage.total = res.total;
// gridOptions.data = res.data;
loadingShow.value = false;
}
});
}
const cellDBLClickEvent: VxeTableEvents.CellDblclick<TableVo> = ({ row, column }) => {
//
//edit ty zhousq 2023-10-12 formdata
// ctrlPro.centeruuid UUID cellField.ctrlPro.paramcode cellField.val
//ctrlPro
console.log('cellData--', row, column);
const cellField = row[column.field];
//const data = row.data;
cellRow.value = row;
cellColumn.value = column;
cellField.value = cellField;
if (cellField.canBeControl === '1') {
modalTitle.value = column.title;
///formData.value.url = data.url;
//formData.value.deviceName = cellField.deviceName;
formData.value = cellField.ctrlPro;
formData.value.value = cellField.val;
// formData.value.paramCode = cellField.ctrlPro.paramcode;
editModal.value = true;
}
console.log(row[column.field]);
};
const formatRole: VxeColumnPropTypes.Formatter<HeaderVo> = ({ cellValue }) => {
//object
// console.log(cellValue);
// const iconFont=cellValue.changeProp===-1?'<i class="iconfont icon-decline" />':(cellValue.changeProp===1?'<i class="iconfont icon-rise" />':'<i/>')
// const cellData = `<span class="cellClass ${cellValue.alertProp===1?'warning':''}">${cellValue.val}</span>${iconFont}`;
// const cellData = `<span class="cellClass ${cellValue.alertProp === 1 ? 'warning' : cellValue.canBeControl === '1' ? 'cellEdit' : ''}">${cellValue.val}</span><i class="iconfont ${cellValue.changeProp === -1 ? 'icon-decline' : cellValue.changeProp === 1 ? 'icon-rise' : ''}" ></i>${cellValue.canBeControl === '1' ? '<i class="iconfont icon-edit-icon"></i>' : ''}`;
const cellData = `<span class="cellClass ${
cellValue.alertProp === 1 ? 'warning' : cellValue.canBeControl === '1' ? 'cellEdit' : ''
}">${
cellValue.ctrlPro.valueType != 'bool' ? cellValue.val : cellValue.val === 'true' ? '启' : '停'
}</span><i class="iconfont ${
cellValue.changeProp === -1 ? 'icon-decline' : cellValue.changeProp === 1 ? 'icon-rise' : ''
}" ></i>${cellValue.canBeControl === '1' ? '<i class="iconfont icon-edit-icon"></i>' : ''}`;
return cellData;
};
//
const mergeRowMethod: VxeTablePropTypes.SpanMethod<TableVo> = ({ row, _rowIndex, column, visibleData }) => {
const fields = ['gTitle'];
const cellValue = row[column.field];
if (cellValue && fields.includes(column.field)) {
const prevRow = visibleData[_rowIndex - 1];
let nextRow = visibleData[_rowIndex + 1];
if (prevRow && prevRow[column.field] === cellValue) {
return { rowspan: 0, colspan: 0 };
} else {
let countRowspan = 1;
while (nextRow && nextRow[column.field] === cellValue) {
nextRow = visibleData[++countRowspan + _rowIndex];
}
if (countRowspan > 1) {
return { rowspan: countRowspan, colspan: 1 };
}
}
}
};
const submitEvent: VxeFormEvents.Submit = () => {
//websocket
formLoading.value = true;
const $table = tableRef.value;
const submitData = formData.value;
console.log(submitData);
//Add by zhousq 2023-10-12 post
sendCtrl(submitData).then((res: any) => {
if (res.code === 200) {
ElNotification({ message: res.data.msg });
}
});
//socket.onSend(submitData);
formLoading.value = false;
editModal.value = false;
if ($table) {
const row = cellRow.value;
const field = cellColumn.value.field;
row[field].val = formData.value.value;
$table.reloadRow(row, null, field);
}
// VXETable.modal.message({ content: '', status: 'success' });
};
function nameClick(row: any) {
//
console.log(row);
sessionStorageIns.setUseStorage('id', row.id);
router.push({ path: '/devicemanage', query: { id: row.id } });
}
const resetEvent: VxeFormEvents.Reset = () => {
console.log({ content: '重置', status: 'info' });
};
</script>
<style lang="scss" scoped>
@import '../index.scss';
</style>

68
src/views/dataScreen/screen/components/menu.vue

@ -0,0 +1,68 @@
<template>
<n-menu ref="menuInstRef" class="menu" :indent="0" :options="menuOptions" v-model:value="selectedKey" key-field="deptId"
label-field="deptName" :default-expand-all="false" :watch-props="['defaultExpandedKeys']"
:render-label="renderMenuLabel" @update:value="menuUpdateValue" />
</template>
<script lang="ts" setup>
import type { MenuOption } from 'naive-ui';
// import { NEllipsis } from 'naive-ui';
import { getMenu } from '@/api/table/list';
import { getFirstNodeLastLevel } from '@/utils/index';
import useStorage from '@/utils/useStorage'
import mitt from '@/plugins/bus';
const menuOptions = ref([]);
const selectedKey = ref();
const sessionStorageIns = useStorage('sessionStorage');
const emit = defineEmits(['tableMenuData']);
onMounted(() => {
menuApi();
});
function menuApi() {
//
getMenu().then((res: any) => {
if (res.code === 200) {
const key = getFirstNodeLastLevel(res.data).deptId
removeChildren(res.data);
menuOptions.value = res.data;
selectedKey.value = key;
sessionStorageIns.setUseStorage('deptId', key);
mitt.emit('menuKey', key);
emit('tableMenuData', res.data);
}
});
}
function removeChildren(menu: any) {
//children
if (!Array.isArray(menu)) {
return;
}
menu.forEach((item) => {
if (item.children && item.children.length === 0) {
delete item.children;
} else {
removeChildren(item.children);
}
});
}
function renderMenuLabel(option: MenuOption) {
//
return h(NEllipsis, null, option.deptName as string);
}
function menuUpdateValue(key: string, item: MenuOption) {
//
sessionStorageIns.setUseStorage('id', key);
mitt.emit('menuKey', key);
console.log(key, item);
}
</script>
<style lang="scss" scoped>
@import '../index.scss';
</style>

299
src/views/dataScreen/screen/components/showTree.vue

@ -0,0 +1,299 @@
<template>
<div class="treeCard">
<el-tree ref="tree" class="showTree" :data="treeData" node-key="id" show-checkbox draggable :props="defaultProps"
:default-checked-keys="defaultCheckedKeys" :allow-drop="allowDrop" @node-drop="nodeDrop"
@check-change="treeCheckChange">
<template #default="{ node, data }">
<span class="custom-tree-node">
<span>{{ data.field === 'deviceStatus' ? '状态' : data.title }}</span>
</span>
<div class="weight" v-if="!data.children">
<span>宽度(px):</span>
<el-input v-model="data.width" size="small" :disabled="data.disabled" placeholder="请输入宽度" />
</div>
</template>
</el-tree>
<div class="treeBtn">
<el-button @click="cancelClick">取消</el-button>
<el-button type="primary" :loading="treeLoading" @click="confirmClick">{{ treeLoading ? '确认中' : '确认' }}</el-button>
</div>
</div>
</template>
<script lang="ts" setup>
import { getCurrentInstance, ComponentInternalInstance } from 'vue';
import mitt from '@/plugins/bus';
const { proxy } = getCurrentInstance() as ComponentInternalInstance
const defaultCheckedKeys = ref([]); //
const checkList = ref<TreeVo[]>([]); //
interface TreeVo {
id?: number;
colSort: number;
colType: string;
field: string;
fixed?: string;
visible: boolean;
title: string;
width: number;
controlValue?: number;
children?: TreeVo[];
}
const treeLoading = ref(false)
const treeData = ref<TreeVo[]>();
const emit = defineEmits(['cancelClick', 'confirmClick']);
const props: any = defineProps({
headerData: {
type: Array,
default: [],
},
});
onMounted(() => {
treeData.value = props.headerData;
const checkData: any = [];
props.headerData.map((item: TreeVo) => {
if (item.visible) {
checkData.push(item.id);
checkList.value.push(item);
if (item.children && item.children.length) {
item.children.map((res: TreeVo) => {
checkData.push(res.id);
checkList.value.push(item);
});
}
}
});
defaultCheckedKeys.value = checkData;
});
// mitt.on('tableHeaderData', (res:any) => {
// //header
// treeData.value=res
// console.log(res)
// });
mitt.on('treeClose', (res: any) => {
//
emit('cancelClick', '');
treeLoading.value = false
});
const defaultProps = {
children: 'children',
label: 'title',
};
// const treeData: TreeVo[] = [
// {
// title: '',
// id: '1',
// field: 'name',
// width: 150,
// show: true,
// disabled: true,
// slots: { default: 'name_default' },
// },
// {
// title: '',
// id: '2',
// field: 'area',
// width: 150,
// show: true,
// },
// {
// title: '',
// id: '3',
// show: true,
// children: [
// {
// title: '',
// id: '4',
// field: 'oneSupplyPressure',
// width: 150,
// show: true,
// slots: { default: 'oneSupplyPressure_default' },
// },
// {
// title: '',
// id: '5',
// field: 'oneBackPressure',
// width: 150,
// show: true,
// },
// {
// title: '',
// id: '6',
// field: 'oneSupplyTemperature',
// width: 150,
// show: true,
// },
// {
// title: '',
// id: '7',
// field: 'oneBackTemperature',
// width: 150,
// show: true,
// },
// ],
// },
// {
// title: '',
// id: '8',
// show: true,
// children: [
// {
// title: '',
// id: '9',
// field: 'twoSupplyPressure',
// width: 150,
// show: true,
// },
// {
// title: '',
// id: '10',
// field: 'twoBackPressure',
// width: 150,
// show: true,
// },
// {
// title: '',
// id: '11',
// field: 'twoSupplyTemperature',
// width: 150,
// show: true,
// },
// {
// title: '',
// id: '12',
// field: 'twoBackTemperature',
// width: 150,
// show: true,
// },
// {
// title: '',
// id: '13',
// field: 'averageTemperature',
// width: 150,
// show: true,
// },
// ],
// },
// {
// title: '',
// id: '14',
// field: 'totalFlow',
// width: 150,
// show: true,
// },
// {
// title: '',
// id: '15',
// field: 'trafficFlow',
// width: 150,
// show: true,
// },
// {
// title: '',
// id: '16',
// field: 'instantHeat',
// width: 150,
// show: true,
// },
// {
// title: '',
// id: '17',
// field: 'AaccumulatHeat',
// width: 150,
// show: true,
// },
// {
// title: '',
// id: '18',
// field: 'valve',
// width: 150,
// show: true,
// },
// {
// title: '',
// id: '19',
// field: 'waterLevel',
// width: 150,
// show: true,
// },
// {
// title: '',
// id: '20',
// field: 'cycleFrequency',
// width: 150,
// show: true,
// },
// {
// title: '',
// id: '21',
// field: 'waterFrequency',
// width: 150,
// show: true,
// editRender: {},
// slots: { edit: 'waterFrequency_edit' },
// },
// {
// title: '',
// id: '22',
// field: 'waterPolice',
// width: 150,
// show: true,
// },
// {
// title: '',
// id: '23',
// field: 'oneSupplementTwo',
// width: 150,
// show: true,
// },
// {
// title: '',
// id: '24',
// field: 'soundTurnedOn',
// width: 150,
// show: true,
// slots: { default: 'soundTurnedOn_default' },
// },
// ];
function allowDrop(draggingNode: any, dropNode: any, type: any) {
//
if (type !== 'inner') {
let control = draggingNode.level === dropNode.level ? true : false;
return control;
}
}
const treeCheckChange = (data: TreeVo, checked: boolean, indeterminate: boolean) => {
//
console.log(data, checked, indeterminate);
data.visible = checked;
console.log(treeData.value);
};
const nodeDrop = () => {
//
nextTick(() => {
proxy?.$refs.tree.setCheckedKeys(defaultCheckedKeys.value);
});
};
function cancelClick() {
//
emit('cancelClick', '');
}
function confirmClick() {
//
treeLoading.value = true
mitt.emit('treeData', treeData.value);
}
</script>
<style lang="scss" scoped>
@import '../index.scss';
</style>

691
src/views/dataScreen/screen/index.scss

@ -0,0 +1,691 @@
@import url('@/assets/fonts/font.css');
.screen {
position: relative;
width: 100%;
height: 100vh;
background: url(@/assets/images/screen.png) no-repeat;
// background-color: var(--tableBg);
background-size: 100% 100%;
// background-color: rgba(29,30,31,0.8);
// background-blend-mode: multiply;
padding: 0 25px;
overflow: hidden;
.menuShow {
width: 26px;
height: 26px;
position: absolute;
top: 118px;
left: 0;
color: #b1e3ff;
text-align: center;
border: 1px solid #0d55b0;
background-color: #02072e;
border-right: none;
cursor: pointer;
.iconfont {
display: inline-block;
}
.left {
transform: rotate(0deg);
-webkit-transform: rotate(0deg);
transition: transform 0.5s;
}
.right {
transform: rotate(180deg);
-webkit-transform: rotate(180deg);
transition: transform 0.5s;
}
}
.panelBtn {
position: absolute;
bottom: 0;
left: 0;
right: 0;
width: 70%;
text-align: center;
color: #a2ceff;
background: url(@/assets/images/panelBtn_bg.png) no-repeat center;
background-size: 100% 100%;
transition: width 0.28s;
margin: 0 auto;
cursor: pointer;
.iconfont {
display: inline-block;
font-size: 18px;
}
.up {
transform: rotate(0deg);
-webkit-transform: rotate(0deg);
transition: transform 0.5s;
}
.down {
transform: rotate(180deg);
-webkit-transform: rotate(180deg);
transition: transform 0.5s;
}
}
.panelBtn.left {
left: 14%;
}
// .header {
// display: flex;
// justify-content: space-between;
// align-items: center;
// // height: 5.7rem;
// .title {
// width: 1500px;
// background: url(@/assets/images/title-bg.png);
// background-size: 100%;
// text-align: center;
// padding-bottom: 38px;
// margin: 0 auto;
// h3 {
// font-size: 3.8rem;
// font-family: 'YouSheBiaoTiHei';
// font-weight: 400;
// letter-spacing: 4px;
// background: linear-gradient(180deg, #FEFDFF 0%, #95DAFF 97%);
// background-clip: text;
// -webkit-background-clip: text;
// -webkit-text-fill-color: transparent;
// margin: 0;
// }
// }
// }
// .weather {
// display: flex;
// align-items: center;
// position: absolute;
// top: 2.5rem;
// left: 7rem;
// color: #B2D4FF;
// font-size: 1.6rem;
// 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;
// align-items: center;
// img {
// width: 25px;
// margin-left: 10px;
// }
// }
// }
// .seeting {
// position: absolute;
// top: 2.5rem;
// right: 7rem;
// .tooltips {
// width: 36px;
// height: 36px;
// background: linear-gradient(180deg, #003269 1%, rgba(3, 79, 163, 0.2314) 56%, #003269 100%);
// border-radius: 0px 0px 0px 0px;
// opacity: 1;
// :deep(span) {
// color: #5beff9;
// }
// margin-left: 10px;
// }
// }
.layout {
display: flex;
// margin-top: 20px;
.sidebar {
width: 12%;
height: calc(100vh - 95px - 30px); //屏幕高度-头部header高度-底部高度
flex-shrink: 0;
border: 1px solid #0d55b0;
padding: 10px 0;
// box-shadow: inset 0px 0px 10px 0px rgb(36, 90, 12);
margin-right: 1vw;
position: relative;
overflow: auto;
transition: width 0.28s;
background-color: rgba(2, 8, 46, 0.8);
// .menu {
// text-align: center;
// :deep(.n-submenu) {
// --n-item-color-hover: auto;
// .n-menu-item {
// .n-menu-item-content {
// padding: 0 !important;
// .n-ellipsis {
// font-family: 'AlibabaPuHuiTiBold';
// padding: 0 15px;
// }
// }
// .n-menu-item-content-header {
// font-size: 2.4rem;
// color: #B1E3FF;
// }
// }
// .n-submenu-children {
// .n-menu-item-content-header {
// font-size: 1.8rem;
// }
// .n-menu-item-content--selected {
// .n-menu-item-content-header {
// color: #fff;
// .n-ellipsis {
// position: relative;
// span {
// padding: 0 10px;
// }
// span::before {
// content: '';
// position: absolute;
// left: 0;
// top: 0.7rem;
// width: 1.8rem;
// height: 1.8rem;
// background: url(../../../assets/images/taps.png) no-repeat;
// background-size: cover;
// }
// }
// }
// }
// .n-menu-item-content--selected::before {
// background: -webkit-linear-gradient(left, #1fc7ff29 0%, #1177e700 100%);
// left: 0;
// right: 0;
// }
// .n-menu-item-content--selected::after {
// content: '';
// position: absolute;
// bottom: 0;
// width: 100%;
// height: 2px;
// background: -webkit-linear-gradient(left, #1fc7ff29 0%, #1177e700 100%);
// }
// }
// .n-base-icon {
// color: #84e0f7;
// right: 10px;
// }
// }
// }
}
.sidebar.sidebarHide {
width: 0;
border: none;
margin-right: 0;
transition: width 0.28s;
}
.sidebar::after {
content: '';
position: absolute;
bottom: 0;
width: 100%;
height: 18rem;
background: url(@/assets/images/menu_bg.png) no-repeat;
background-size: 100% 100%;
}
.main {
position: relative;
width: 87%;
background-color: rgba(2, 8, 46, 0.8);
.headerInfo {
border: 1px solid #0d55b0;
// box-shadow: inset 0px 0px 10px 0px rgb(36, 90, 124);
margin-bottom: 10px;
.header {
display: flex;
align-items: center;
flex-wrap: wrap;
.headerItem {
width: 11.1%;
color: #fff;
text-align: center;
.name {
font-size: 12px;
line-height: 36px;
padding: 0 3rem;
color: #ffffffb3;
background-color: #123f7580;
border-top: 1px solid #265a89;
border-bottom: 1px solid #265a89;
white-space: nowrap;
text-overflow: ellipsis;
overflow: hidden;
}
.value {
font-size: 18px;
color: #5beff9;
line-height: 36px;
}
}
}
}
.mainTable {
// height: calc(100vh - 8rem - 202px);
// height: calc(100% - 162px);
background-color: rgba(0, 0, 0, 0.1);
transition: height 0.28s;
overflow: hidden;
.tableGrid {
--vxe-table-header-background-color: none;
--vxe-table-body-background-color: none;
--vxe-table-footer-background-color: none;
--vxe-table-border-color: rgba(12, 80, 166, 0.2);
// --vxe-table-border-color: none;
--vxe-font-color: #5beff9;
--vxe-table-header-font-color: #ffffffb3;
border: 1px solid #0d55b0;
// box-shadow: inset 0px 0px 10px 0px rgb(36, 90, 124);
:deep(.vxe-table) {
// height: calc(100vh - 5.7rem - 60px) !important;
.vxe-table--body-wrapper {
// height: calc(100vh - 5.7rem - 182px) !important;
}
.headerRowClass {
.headerCellClass {
color: #eee;
border: 1px solid rgba(12, 80, 166, 1) !important;
border-left: none !important;
.vxe-resizable.is--line:before {
content: none;
}
}
// .headerCellClass:nth-child(1){
// border-left: none !important;
// }
.headerCellClass.col--fixed {
// background-color: #020e38;
// box-shadow: inset 0px 0px 10px 0px #245a7c;
}
}
.tableRowClass {
.tableCellClass {
// border-bottom: 1px solid #265a89 !important;
.vxe-cell {
font-family: 'AlibabaPuHuiTiRegular';
color: #b1e3ff;
.title {
display: flex;
align-items: center;
text-align: left;
.svg-icon {
flex-shrink: 0;
}
}
}
.vxe-cell--html {
display: flex;
justify-content: center;
align-items: center;
.warning {
font-size: 15px;
font-weight: bold;
color: red;
}
.cellEdit {
cursor: pointer;
}
.iconfont {
font-size: 18px;
}
.iconfont.icon-rise {
color: green;
}
.iconfont.icon-decline {
color: red;
}
.iconfont.icon-edit-icon {
font-size: 16px;
margin-left: 5px;
cursor: pointer;
}
}
}
}
.tableRowClass.row--stripe {
background-color: rgba(0, 95, 199, 0.15);
}
.tips {
display: inline-block;
width: 10px;
height: 10px;
margin: 0 auto;
border-radius: 10px;
margin-right: 5px;
}
.tips.green {
background-color: green;
}
.tips.red {
background-color: red;
}
.name {
margin-left: 5px;
cursor: pointer;
}
.cellName {
display: flex;
justify-content: center;
align-items: center;
color: #fef961;
}
.cellInput {
input {
color: #222;
text-align: center;
}
}
.vxe-table--fixed-left-wrapper.scrolling--middle {
background: -webkit-linear-gradient(top, #02072b 0%, #02082b 100%);
box-shadow: inset 0px 0px 10px rgb(36, 90, 124) !important;
}
}
}
.tablePage {
--vxe-pager-background-color: none;
padding: 0 2rem;
color: #b1e3ff;
:deep(.vxe-select) {
.vxe-input--inner {
color: #b1e3ff;
border: 1px solid #b1e3ff;
background-color: transparent;
}
.vxe-select--panel {
color: #b1e3ff;
.vxe-select-option--wrapper {
border: 1px solid #b1e3ff;
background: -webkit-linear-gradient(top, #02072b 0%, #02082b 100%);
.vxe-select-option:not(.is--disabled).is--hover {
background: none;
}
}
}
}
:deep(.vxe-pager--jump) {
.vxe-pager--goto {
color: #b1e3ff;
border: 1px solid #b1e3ff;
background-color: transparent;
}
}
}
// /*滚动条整体部分*/
// .tableGrid ::-webkit-scrollbar {
// width: 8px;
// height: 8px;
// }
// /*滚动条的轨道*/
// .tableGrid ::-webkit-scrollbar-track {
// background-color: transparent;
// -webkit-border-radius: 8px;
// -moz-border-radius: 8px;
// border-radius: 8px;
// }
// /*滚动条里面的小方块能向上向下移动*/
// .tableGrid ::-webkit-scrollbar-thumb {
// background-color: rgb(147, 147, 153, 0.5);
// -webkit-border-radius: 8px;
// -moz-border-radius: 8px;
// border-radius: 8px;
// }
// .tableGrid ::-webkit-scrollbar-thumb:hover {
// background-color: #a8a8a8;
// }
// .tableGrid ::-webkit-scrollbar-thumb:active {
// background-color: #787878;
// }
// /*边角即两个滚动条的交汇处*/
// .tableGrid ::-webkit-scrollbar-corner {
// background-color: transparent;
// }
}
.infoPanel {
height: 280px;
margin-top: 20px;
transition: transform 0.5s;
:deep(.swiper) {
--swiper-theme-color: #ff6600;
/* 设置Swiper风格 */
--swiper-navigation-color: #00ff33;
/* 单独设置按钮颜色 */
--swiper-navigation-size: 30px;
/* 设置按钮大小 */
.item {
height: 280px;
.content {
display: flex;
align-items: center;
height: -webkit-fill-available;
border: 2px solid #0d54ae;
border-radius: 5px;
color: #fff;
padding: 15px;
background-color: rgba(2, 8, 46, 0.5);
.icon {
width: 35%;
img {
width: 100%;
}
}
.numValue {
flex: 1;
text-align: center;
color: #99e5ff;
span {
font-size: 5rem;
}
i {
font-size: 3rem;
font-style: normal;
}
p {
font-size: 2rem;
margin: 0;
color: #1782ff;
}
}
.numValueMore {
flex: 1;
margin-left: 1.5rem;
span {
font-size: 1.4rem;
line-height: 30px;
color: #99e5ff;
margin-right: 3px;
}
span:nth-child(1) {
font-size: 1.6rem;
color: #1782ff;
}
span:nth-child(2) {
font-size: 1.8rem;
margin-right: 5px;
}
}
}
}
}
}
}
/*滚动条整体部分*/
.tableGrid ::-webkit-scrollbar {
width: 8px;
height: 8px;
}
/*滚动条的轨道*/
.tableGrid ::-webkit-scrollbar-track {
background-color: transparent;
-webkit-border-radius: 8px;
-moz-border-radius: 8px;
border-radius: 8px;
}
/*滚动条里面的小方块,能向上向下移动*/
.tableGrid ::-webkit-scrollbar-thumb {
background-color: rgb(147, 147, 153, 0.5);
-webkit-border-radius: 8px;
-moz-border-radius: 8px;
border-radius: 8px;
}
.tableGrid ::-webkit-scrollbar-thumb:hover {
background-color: #a8a8a8;
}
.tableGrid :-webkit-scrollbar-thumb:active {
background-color: #787878;
}
/*边角,即两个滚动条的交汇处*/
.tableGrid ::-webkit-scrollbar-corner {
background-color: transparent;
}
}
}
// .cardClass {
.showTree {
.weight {
display: flex;
align-items: center;
margin-left: auto;
span {
margin-right: 2px;
}
}
}
.treeBtn {
margin-top: 20px;
text-align: right;
.n-button {
margin-left: 10px;
}
}
// }
.dark {
.screen {
background-color: rgba(29, 30, 31, 0.8);
background-blend-mode: multiply;
.layout {
.sidebar {
background-color: rgba(29, 30, 31, 0.8);
}
.main {
background-color: rgba(29, 30, 31, 0.8);
.mainTable {
.tableGrid {
:deep(.vxe-table) {
.vxe-table--fixed-left-wrapper.scrolling--middle {
background: -webkit-linear-gradient(top, rgba(21, 21, 25, 1) 0%, rgba(21, 21, 25, 1) 100%);
box-shadow: inset 0px 0px 10px rgb(36, 90, 124) !important;
}
}
}
}
}
.infoPanel {
:deep(.swiper) {
.item {
.content {
background-color: rgba(29, 30, 31, 0.8);
}
}
}
}
}
}
}

194
src/views/dataScreen/screen/index.vue

@ -0,0 +1,194 @@
<template>
<div ref="screenRef" class="screen">
<section ref="titleRef" class="header">
<Header :titleData="titleData" :settingShow="true" :warningShow="true" @showModalClick="showModalClick"
@returnClick="returnClick" />
<!-- <div class="title">
<h3>{{ titleData }}</h3>
</div>
<div class="weather">
<div class="time">
{{ currentTime }} {{ lunarDay.ncWeek }}
</div>
<div class="line"></div>
<div class="forecast">
<span>天气多云</span>
<img src="../../../assets/images/weather/duoyun.png" />
</div>
</div>
<div class="seeting">
<n-tooltip trigger="hover">
<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>
</div> -->
</section>
<section class="layout">
<div ref="sidebar" class="sidebar animate__animated animate__fadeIn" :class="menuShow ? '' : 'sidebarHide'">
<Menu menuType="1" @tableMenuData="tableMenuData" />
</div>
<div class="main" :style="`width: ${mainWidth}%`">
<Main :tapsShow="tapsShow" :sidebarHeight="sidebarHeight" @tableHeaderData="tableHeaderData" />
<InfoPanel class="animate__animated animate__fadeInUp" v-if="panelShow" />
</div>
</section>
<section>
<!-- <n-modal v-model:show="showModal"> -->
<el-dialog v-model="showModal" title="显示项" width="600">
<!-- <n-card class="cardClass" style="width: 600px" title="显示项" :bordered="false" size="huge" role="dialog"
aria-modal="true"> -->
<ShowTree :headerData="headerData" @cancelClick="cancelClick" />
<!-- <template #header-extra>
*
</template> -->
<!-- <template #footer>
<n-button>取消</n-button>
<n-button type="info"> 确定 </n-button>
</template> -->
<!-- </n-card> -->
</el-dialog>
<!-- </n-modal> -->
</section>
<div class="menuShow" @click="menuIsShow">
<i class="iconfont icon-angle-double" :class="menuShow ? 'left' : 'right'"></i>
</div>
<div class="panelBtn" :class="menuShow ? 'left' : 'right'" @click="panelClick">
<i class="iconfont icon-arrow-up" :class="!panelShow ? 'up' : 'down'"></i>
<!-- <n-button type="info" size="tiny" ghost @click="panelClick">按钮</n-button> -->
</div>
</div>
</template>
<script lang="ts" setup>
import { useRoute, useRouter, onBeforeRouteLeave } from "vue-router";
// import { useDateFormat, useNow } from '@vueuse/core';
// import { Filter, Maximize, Settings, Power } from '@vicons/tabler';
import Header from '../components/header.vue';
import Menu from '../components/menu.vue';
import Main from './components/main.vue';
import InfoPanel from './components/infoPanel.vue';
import ShowTree from './components/showTree.vue';
import useStorage from '@/utils/useStorage'
import socket from '@/utils/socket';
const sessionStorageIns = useStorage('sessionStorage');
const route = useRoute()
const router = useRouter()
// import calendar from '@/utils/lunar';
// const currentTime = useDateFormat(useNow(), 'YYYY-MM-DD HH:mm:ss');
// const lunarDay: any = calendar.solarToLunar(
// useNow().value.getUTCFullYear(),
// useNow().value.getUTCMonth() + 1,
// useNow().value.getUTCDate()
// );
// import screenfull from 'screenfull'
const tapsShow = ref(false);
const showModal = ref(false);
const screenRef = ref<HTMLElement>();
const titleRef = ref<HTMLElement>();
const sidebar = ref<HTMLElement>();
const sidebarHeight = ref()
const headerData = ref([]);
const mainWidth = ref(87)
const titleData = ref('')
const menuShow = ref(true)
const panelShow = ref(false)
const panelHeight = ref(0)
onMounted(() => {
// titleRef.value?.clientHeight; //
const offsetHeight = sidebar.value?.offsetHeight; //
sidebarHeight.value = offsetHeight === undefined ? 0 : offsetHeight - panelHeight.value
// menuShow.value=localStorage.getItem('menuShow')===undefined?true:JSON.parse(localStorage.getItem('menuShow'));
// console.log("sidebar:", sidebar.value?.offsetHeight)
});
window.addEventListener('resize', () => {
//
const offsetHeight = sidebar.value?.offsetHeight; //
sidebarHeight.value = offsetHeight === undefined ? 0 : offsetHeight - panelHeight.value
console.log("监听sidebar:", sidebar.value?.offsetHeight)
});
onBeforeRouteLeave((to, from) => {
//
console.log("onBeforeRouteLeave--", to.path, from.path)
if (to.path != from.path) {
console.log('离开页面');
socket.close(false)
}
})
function tableMenuData(data: any) {
//
titleData.value = data[0].deptName
}
function tableHeaderData(data: any) {
//header
headerData.value = data;
}
function filterClick() {
///
tapsShow.value = !tapsShow.value;
}
function showModalClick(val: boolean) {
///
showModal.value = val;
}
function cancelClick() {
//
showModal.value = false;
}
function returnClick(val: string) {
//
router.replace("/dashboard")
}
function menuIsShow() {
//
menuShow.value = !menuShow.value
mainWidth.value = menuShow.value ? 87 : 100
sessionStorageIns.setUseStorage('menuShow', menuShow.value);
}
function panelClick() {
//
panelShow.value = !panelShow.value
panelHeight.value = panelShow.value ? 300 : 0
const offsetHeight = sidebar.value?.offsetHeight; //
sidebarHeight.value = offsetHeight === undefined ? 0 : offsetHeight - panelHeight.value
sessionStorageIns.setUseStorage('panelShow', panelShow.value);
}
// function screenClick(){
// if (screenfull.isEnabled) {
// //
// screenfull.toggle(screenRef.value)
// }
// }
</script>
<style lang="scss" scoped>
@import './index.scss';
</style>

2
src/views/details/index.scss

@ -32,7 +32,7 @@
.comparisonInfo {
.stackedLine {
width: 100%;
height: 74vh;
height: 68vh;
font-size: 1.4rem;
text-align: center;
color: #606266;

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

@ -3,18 +3,21 @@
<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 class="users">{{ timePeriod }} {{ userStore.nickname }}</div>
<div class="timeTips">
<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>
<div class="seeting">
<n-tooltip trigger="hover">
<template #trigger>
<n-button class="tooltips" circle quaternary @click="returnBack">
<n-button class="tooltips" circle dashed @click="returnBack">
<template #icon>
<n-icon>
<ReturnDownBack />
@ -26,7 +29,7 @@
</n-tooltip>
<n-tooltip trigger="hover">
<template #trigger>
<n-button class="tooltips" circle quaternary @click="lineClick">
<n-button class="tooltips" circle dashed @click="lineClick">
<template #icon>
<n-icon>
<ChartLine />
@ -38,7 +41,7 @@
</n-tooltip>
<n-tooltip trigger="hover" v-if="settingShow">
<template #trigger>
<n-button class="tooltips" circle quaternary @click="showClick">
<n-button class="tooltips" circle dashed @click="showClick">
<template #icon>
<n-icon>
<Settings />
@ -51,7 +54,7 @@
<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">
<n-button class="tooltips" circle dashed @click="waringClick">
<template #icon>
<n-icon>
<Bell />
@ -132,6 +135,7 @@
</template>
<script lang="ts" setup>
import { useRoute, useRouter } from 'vue-router';
import { useUserStore } from '@/store/modules/user';
import { getWeather } from '@/api/user/index';
import { getWarList, process } from '@/api/waring/index';
import { waringVo } from '@/api/waring/types';
@ -142,6 +146,8 @@ import { uniqueArrayObject } from '@/utils/index';
import mitt from '@/plugins/bus';
import calendar from '@/utils/lunar';
const userStore = useUserStore();
const hoursNow = useNow().value.getHours();
const route = useRoute();
const router = useRouter();
@ -189,6 +195,22 @@ onMounted(() => {
getWeatherData();
});
const timePeriod = computed(() => {
if (hoursNow >= 3 && hoursNow < 8) {
return '早安!';
} else if (hoursNow >= 8 && hoursNow < 11) {
return '上午好!';
} else if (hoursNow >= 11 && hoursNow < 13) {
return '中午好!';
} else if (hoursNow >= 13 && hoursNow < 17) {
return '下午好!';
} else if (hoursNow >= 17 && hoursNow < 23) {
return '晚上好!';
} else if (hoursNow >= 23 && hoursNow < 3) {
return '晚安!';
}
});
mitt.on('waringMessage', (res: any) => {
//
console.log('waringMessage--', res.data);
@ -320,19 +342,19 @@ function warClose() {
.title {
width: 80%;
background: url(@/assets/images/title-bg.png);
background-size: 100%;
// background: url(@/assets/images/title-bg.png);
// background-size: 100%;
text-align: center;
padding-bottom: 38px;
margin: 0 auto;
h3 {
height: 57px;
font-size: 3.8rem;
font-size: 4.2rem;
font-family: 'YouSheBiaoTiHei';
font-weight: 400;
letter-spacing: 4px;
background: linear-gradient(180deg, #fefdff 0%, #95daff 97%);
background: linear-gradient(180deg, #fefdff 0%, #1677b3 100%);
background-clip: text;
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
@ -342,15 +364,17 @@ function warClose() {
}
.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';
.timeTips {
display: flex;
align-items: center;
// color: #b2d4ff;
}
.line {
width: 2px;
@ -388,13 +412,13 @@ function warClose() {
.tooltips {
width: 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;
opacity: 1;
:deep(span) {
color: #5beff9;
}
// :deep(span) {
// color: #5beff9;
// }
margin-left: 10px;
}

33
src/views/monitoring/components/menu.vue

@ -156,18 +156,18 @@ function menuUpdateValue(key: string, item: MenuOption) {
padding: 0 15px;
}
.n-menu-item-content__arrow {
color: #b1e3ff;
}
// .n-menu-item-content__arrow {
// color: #b1e3ff;
// }
}
.n-menu-item-content.n-menu-item-content--child-active {
.n-menu-item-content-header {
color: #b1e3ff;
}
// .n-menu-item-content-header {
// color: #b1e3ff;
// }
.n-menu-item-content__arrow {
color: #b1e3ff;
color: var(--n-arrow-color);
}
}
@ -186,12 +186,12 @@ function menuUpdateValue(key: string, item: MenuOption) {
.n-menu-item-content-header {
font-size: 2.2rem;
color: #b1e3ff;
color: var(--vxe-table-header-font-color);
}
}
.n-menu-item:hover {
color: red;
color: #409eff;
}
.n-submenu-children {
@ -201,7 +201,7 @@ function menuUpdateValue(key: string, item: MenuOption) {
.n-menu-item-content--selected {
.n-menu-item-content-header {
color: #fff;
color: #409eff;
.n-ellipsis {
position: relative;
@ -211,21 +211,22 @@ function menuUpdateValue(key: string, item: MenuOption) {
}
span::before {
content: '';
content: none;
position: absolute;
left: 0;
top: 0.7rem;
width: 1.8rem;
height: 1.8rem;
background: url(@/assets/images/taps.png) no-repeat;
background-size: cover;
// background: url(@/assets/images/taps.png) no-repeat;
// background-size: cover;
background-color: var(--menuActiveBg) !important;
}
}
}
}
.n-menu-item-content--selected::before {
background: -webkit-linear-gradient(left, #1fc7ff29 0%, #1177e700 100%);
background: -webkit-linear-gradient(left, #c9eaff 0%, #f2f3f5 100%);
left: 0;
right: 0;
}
@ -236,12 +237,12 @@ function menuUpdateValue(key: string, item: MenuOption) {
bottom: 0;
width: 100%;
height: 2px;
background: -webkit-linear-gradient(left, #1fc7ff29 0%, #1177e700 100%);
background: -webkit-linear-gradient(left, #409eff 0%, #f2f3f5 100%);
}
}
.n-base-icon {
color: #84e0f7;
// color: #84e0f7;
right: 10px;
}
}

423
src/views/monitoring/devicemanage/components/header.vue

@ -0,0 +1,423 @@
<template>
<div class="title">
<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="seeting">
<n-tooltip trigger="hover">
<template #trigger>
<n-button class="tooltips" circle quaternary @click="returnBack">
<template #icon>
<n-icon>
<ReturnDownBack />
</n-icon>
</template>
</n-button>
</template>
返回上一页
</n-tooltip>
<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" 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>
</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="alertFirstTimeS" label="首次告警时间" align="center" />
<el-table-column prop="alertLastTimeS" 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>
<el-pagination
class="waringPagination"
layout="prev, pager, next"
:current-page.sync="params.pageNum"
:page-size="params.pageSize"
:total="params.total"
hide-on-single-page
@current-change="handleCurrentChange"
/>
<div class="warClose" @click="warClose">
<CloseCircleOutline />
</div>
</n-card>
</n-modal>
</template>
<script lang="ts" setup>
import { useRoute, useRouter } from 'vue-router';
import { getWeather } from '@/api/user/index';
import { getWarList, process } from '@/api/waring/index';
import { waringVo } from '@/api/waring/types';
import { Filter, Maximize, Settings, Power, Bell, ChartLine } from '@vicons/tabler';
import { CloseCircleOutline, ReturnDownBack } from '@vicons/ionicons5';
import { useDateFormat, useNow } from '@vueuse/core';
import { uniqueArrayObject } from '@/utils/index';
import mitt from '@/plugins/bus';
import calendar from '@/utils/lunar';
const route = useRoute();
const router = useRouter();
const currentTime = useDateFormat(useNow(), 'YYYY-MM-DD HH:mm:ss');
const emit = defineEmits(['showModalClick', 'returnClick']);
const timer = ref();
const isCurrentRoute = ref(true);
const waringDrawer = ref(false);
const waringModal = ref(false);
const waringData = ref<waringVo[]>([]);
const waringList = ref<waringVo[]>([]);
const routerType = ref('');
const deptId = ref(0);
const params = reactive({
total: 10,
pageSize: 10,
pageNum: 1
});
const weatherData = ref({ city: '', weather: '', temperature: '', weatherImg: '' });
const lunarDay: any = calendar.solarToLunar(
useNow().value.getUTCFullYear(),
useNow().value.getUTCMonth() + 1,
useNow().value.getUTCDate()
);
const props = defineProps({
titleData: {
type: String,
default: '数据大屏'
},
settingShow: {
type: Boolean,
default: false
},
warningShow: {
type: Boolean,
default: false
}
});
onMounted(() => {
deptId.value = sessionStorage.getItem('deptId') === null ? 0 : Number(sessionStorage.getItem('deptId'));
routerType.value = route.query?.id === undefined ? '0' : '1';
getWeatherData();
});
mitt.on('waringMessage', (res: any) => {
//
console.log('waringMessage--', res.data);
waringData.value = res.data;
// waringData.value.push(res.data)
// console.log("waringData--", waringData.value);
// waringData.value = uniqueArrayObject(waringData.value, "id")
// console.log("waringData--", waringData.value);
});
function showClick() {
///
emit('showModalClick', true);
// showModal.value = true;
}
function returnBack() {
//
// emit('returnClick', '');
if (routerType.value === '1' && route.path != '/screen') {
router.push({
path: '/screen',
query: { id: sessionStorage.getItem('id') }
});
} else {
router.replace('/dashboard');
}
}
function waringClick() {
//
// if (waringData.value.length === 0) {
// ElNotification({
// message: '',
// type: 'info',
// })
// } else {
waringDrawer.value = true;
// }
}
function lineClick() {
//
router.push({
path: '/details'
});
}
function handleCurrentChange(val: any) {
//
params.pageNum = val;
getwaringList();
}
function getWeatherData() {
//
getWeather().then((res: any) => {
if (res.code === 200) {
if (isCurrentRoute) {
timer.value = setTimeout(async () => {
await (timer.value && clearTimeout(timer.value));
await getWeatherData();
}, 600000);
}
weatherData.value = res.data;
} else {
clearTimeout(timer.value);
}
});
}
function waringMore() {
//
waringDrawer.value = false;
waringModal.value = true;
getwaringList();
}
function getwaringList() {
//
const paramsr = {
beginTime: '',
endTime: '',
orgCode: sessionStorage.getItem('deptId') === null ? 0 : Number(sessionStorage.getItem('deptId')),
params
};
getWarList(paramsr).then((res: any) => {
if (res.code === 200) {
waringList.value = res.rows;
params.total = res.total;
// page.pageSize = res.size;
// page.pageSize = res.current;
}
});
}
function waringConfirm(item: any) {
//
ElMessageBox.confirm('是否确认操作?', '提示', {
confirmButtonText: '确认',
cancelButtonText: '取消',
type: 'warning'
})
.then(() => {
const params = item.id;
process(params).then((res: any) => {
if (res.code === 200) {
waringList.value = res.data;
// waringDrawer.value = false
// waringModal.value = false
getwaringList();
ElMessage({
message: res.msg,
type: 'success'
});
}
});
})
.catch(() => {});
}
function warClose() {
//
waringModal.value = false;
}
</script>
<style lang="scss" scoped>
.header {
display: flex;
justify-content: space-between;
align-items: center;
// height: 5.7rem;
.title {
width: 80%;
background: url(@/assets/images/title-bg.png);
background-size: 100%;
text-align: center;
padding-bottom: 38px;
margin: 0 auto;
h3 {
height: 57px;
font-size: 3.8rem;
font-family: 'YouSheBiaoTiHei';
font-weight: 400;
letter-spacing: 4px;
background: linear-gradient(180deg, #fefdff 0%, #95daff 97%);
background-clip: text;
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
margin: 0;
}
}
}
.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;
align-items: center;
.weatherSvg {
width: 1.5em !important;
height: 1.5em !important;
margin-left: 10px;
}
// img {
// width: 25px;
// margin-left: 10px;
// }
}
}
.seeting {
position: absolute;
top: 2.5rem;
right: 7rem;
.warningbadge {
margin-top: -10px;
}
.tooltips {
width: 36px;
height: 36px;
background: linear-gradient(180deg, #003269 1%, rgba(3, 79, 163, 0.2314) 56%, #003269 100%);
border-radius: 0px 0px 0px 0px;
opacity: 1;
:deep(span) {
color: #5beff9;
}
margin-left: 10px;
}
}
.waringModal {
.waringPagination {
justify-content: right;
margin-top: 5px;
:deep(button) {
color: #b1e3ff;
background: transparent;
}
:deep(.el-pager) {
.number,
.more {
color: #b1e3ff;
background: transparent;
}
.number.is-active {
color: #409eff;
}
}
}
}
</style>

259
src/views/monitoring/devicemanage/components/menu.vue

@ -1,36 +1,95 @@
<template>
<n-menu ref="menuInstRef" class="menu" :indent="0" :options="menuOptions" v-model:value="selectedKey" key-field="deptId"
label-field="deptName" :default-expand-all="false" :watch-props="['defaultExpandedKeys']"
:render-label="renderMenuLabel" @update:value="menuUpdateValue" />
<div class="menuCantent">
<n-menu
ref="menuInstRef"
class="menu"
:indent="0"
:options="menuOptions"
v-model:value="selectedKey"
key-field="deptId"
label-field="deptName"
:default-expand-all="false"
:watch-props="['defaultExpandedKeys']"
:render-label="renderMenuLabel"
@update:value="menuUpdateValue"
/>
</div>
</template>
<script lang="ts" setup>
import { useRoute } from 'vue-router';
import type { MenuOption } from 'naive-ui';
// import { NEllipsis } from 'naive-ui';
import { getMenu } from '@/api/table/list';
import { getMenuData } from '@/api/device/index';
import { getFirstNodeLastLevel } from '@/utils/index';
import useStorage from '@/utils/useStorage'
import useStorage from '@/utils/useStorage';
import mitt from '@/plugins/bus';
const router = useRoute();
const menuOptions = ref([]);
const selectedKey = ref();
const sessionStorageIns = useStorage('sessionStorage');
const routerType = ref('');
const id = ref(0);
const deptId = ref(0);
const menuDeptKey = ref(0);
const menuIdKey = ref(0);
const emit = defineEmits(['tableMenuData']);
const props = defineProps({
menuType: {
type: String,
default: '1'
}
});
onMounted(() => {
menuApi();
routerType.value = router.query?.id === undefined ? '0' : '1';
id.value = sessionStorage.getItem('id') === null ? 0 : Number(sessionStorage.getItem('id'));
deptId.value = sessionStorage.getItem('deptId') === null ? 0 : Number(sessionStorage.getItem('deptId'));
if (props.menuType === '1') {
menuApi();
} else if (props.menuType === '2') {
comMenuApi();
}
});
function menuApi() {
//
//
getMenu().then((res: any) => {
if (res.code === 200) {
menuDeptKey.value =
routerType.value === '1'
? deptId.value
: routerType.value === '0' && deptId.value != 0
? deptId.value
: getFirstNodeLastLevel(res.data).deptId;
removeChildren(res.data);
menuOptions.value = res.data;
selectedKey.value = menuDeptKey.value;
sessionStorageIns.setUseStorage('deptId', menuDeptKey.value);
mitt.emit('menuKey', menuDeptKey.value);
emit('tableMenuData', res.data);
}
});
}
function comMenuApi() {
//
getMenuData().then((res: any) => {
if (res.code === 200) {
const key = getFirstNodeLastLevel(res.data).deptId
menuIdKey.value =
routerType.value === '1'
? id.value
: routerType.value === '0' && id.value != 0
? id.value
: getFirstNodeLastLevel(res.data).deptId;
const parentId = routerType.value === '1' ? deptId.value : getFirstNodeLastLevel(res.data).parentId;
removeChildren(res.data);
menuOptions.value = res.data;
selectedKey.value = key;
sessionStorageIns.setUseStorage('deptId', key);
mitt.emit('deviceMenuKey', key);
selectedKey.value = menuIdKey.value;
sessionStorageIns.setUseStorage('deptId', routerType.value === '1' ? deptId.value : parentId);
mitt.emit('deviceMenuKey', menuIdKey.value);
emit('tableMenuData', res.data);
}
});
@ -42,7 +101,7 @@ function removeChildren(menu: any) {
return;
}
menu.forEach((item) => {
menu.forEach(item => {
if (item.children && item.children.length === 0) {
delete item.children;
} else {
@ -50,19 +109,183 @@ function removeChildren(menu: any) {
}
});
}
function renderMenuLabel(option: MenuOption) {
// function renderMenuLabel(option: MenuOption) {
const renderMenuLabel = (option: MenuOption) => {
//
return h(NEllipsis, null, option.deptName as string);
}
// return h(NEllipsis, null, option.deptName as string);
return h(NEllipsis, null, { default: () => option.deptName });
};
function menuUpdateValue(key: string, item: MenuOption) {
//
sessionStorageIns.setUseStorage('id', key);
mitt.emit('deviceMenuKey', key);
sessionStorageIns.setUseStorage(props.menuType === '1' ? 'deptId' : 'id', key);
sessionStorageIns.setUseStorage('currentPage', 1);
if (props.menuType === '1') {
mitt.emit('currentPageEmit', 1);
}
if (props.menuType === '2') {
sessionStorageIns.setUseStorage('deptId', item.parentId);
}
mitt.emit(props.menuType === '1' ? 'menuKey' : 'deviceMenuKey', key);
console.log(key, item);
}
</script>
<style lang="scss" scoped>
@import '../index.scss';
:root {
--n-item-text-color-child-active-hover: #fff;
--n-item-text-color-active-hover: #fff;
--n-item-text-color-child-active: #fff;
}
.menuCantent {
height: -webkit-fill-available;
overflow: auto;
.menu {
text-align: center;
:deep(.n-submenu) {
--n-item-color-hover: auto;
.n-menu-item {
.n-menu-item-content {
padding: 0 !important;
.n-ellipsis {
font-family: 'AlibabaPuHuiTiBold';
padding: 0 15px;
}
.n-menu-item-content__arrow {
color: #b1e3ff;
}
}
.n-menu-item-content.n-menu-item-content--child-active {
.n-menu-item-content-header {
color: #b1e3ff;
}
.n-menu-item-content__arrow {
color: #b1e3ff;
}
}
// .n-menu-item-content--child-active {
// .n-menu-item-content-header:hover {
// color: #fff !important;
// }
// .n-menu-item-content__arrow:hover {
// color: #fff !important;
// }
// }
// .n-menu-item-content--child-active:hover{
// color: #fff !important;
// }
.n-menu-item-content-header {
font-size: 2.2rem;
color: #b1e3ff;
}
}
.n-menu-item:hover {
color: red;
}
.n-submenu-children {
.n-menu-item-content-header {
font-size: 1.6rem;
}
.n-menu-item-content--selected {
.n-menu-item-content-header {
color: #fff;
.n-ellipsis {
position: relative;
span {
padding: 0 10px;
}
span::before {
content: '';
position: absolute;
left: 0;
top: 0.7rem;
width: 1.8rem;
height: 1.8rem;
background: url(@/assets/images/taps.png) no-repeat;
background-size: cover;
}
}
}
}
.n-menu-item-content--selected::before {
background: -webkit-linear-gradient(left, #1fc7ff29 0%, #1177e700 100%);
left: 0;
right: 0;
}
.n-menu-item-content--selected::after {
content: '';
position: absolute;
bottom: 0;
width: 100%;
height: 2px;
background: -webkit-linear-gradient(left, #1fc7ff29 0%, #1177e700 100%);
}
}
.n-base-icon {
color: #84e0f7;
right: 10px;
}
}
}
}
/*滚动条整体部分*/
.menuCantent::-webkit-scrollbar,
.tableGrid ::-webkit-scrollbar {
width: 8px;
height: 8px;
}
/*滚动条的轨道*/
.menuCantent::-webkit-scrollbar-track,
.tableGrid ::-webkit-scrollbar-track {
background-color: transparent;
-webkit-border-radius: 8px;
-moz-border-radius: 8px;
border-radius: 8px;
}
/*滚动条里面的小方块,能向上向下移动*/
.menuCantent::-webkit-scrollbar-thumb,
.tableGrid ::-webkit-scrollbar-thumb {
background-color: rgb(147, 147, 153, 0.5);
-webkit-border-radius: 8px;
-moz-border-radius: 8px;
border-radius: 8px;
}
.menuCantent::-webkit-scrollbar-thumb:hover,
.tableGrid ::-webkit-scrollbar-thumb:hover {
background-color: #a8a8a8;
}
.menuCantent::-webkit-scrollbar-thumb:active,
.tableGrid :-webkit-scrollbar-thumb:active {
background-color: #787878;
}
/*边角,即两个滚动条的交汇处*/
.menuCantent::-webkit-scrollbar-corner,
.tableGrid ::-webkit-scrollbar-corner {
background-color: transparent;
}
</style>

4
src/views/monitoring/devicemanage/index.vue

@ -16,8 +16,8 @@
<script lang="ts" setup>
import router from '@/router';
import { Filter, Maximize, Settings, Power } from '@vicons/tabler';
import Header from '../components/header.vue';
import Menu from '../components/menu.vue';
import Header from './components/header.vue';
import Menu from './components/menu.vue';
import Main from './components/main.vue';
// import screenfull from 'screenfull'
const titleRef = ref<HTMLElement>();

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

@ -12,59 +12,61 @@
:style="{ height: tapsShow ? 'calc(100vh - 5.7rem - 222px)' : 'calc(100vh - 5.7rem - 60px)' }"
> -->
<div class="mainTable" :style="{ height: `${sidebarHeight}px` }">
<n-spin :show="loadingShow">
<vxe-grid
ref="tableRef"
class="tableGrid"
align="center"
auto-resize
keep-source
:height="sidebarHeight - 4"
header-row-class-name="headerRowClass"
header-cell-class-name="headerCellClass"
row-class-name="tableRowClass"
cell-class-name="tableCellClass"
:sort-config="{ multiple: true, trigger: 'cell' }"
:stripe="!tableBorder"
:border="tableBorder"
:column-config="{ resizable: true, useKey: true }"
:row-config="{ useKey: true }"
:span-method="mergeRowMethod"
:columns="tableColumn"
:data="tableData"
@cell-dblclick="cellDBLClickEvent"
>
<template #deviceuuid_default="{ row }">
<div class="title">
<svg-icon
icon-class="warning_lights"
style="fill: currentColor; width: 15px; height: 15px; color: green"
v-if="row.deviceuuid.deviceStatus === 0"
/>
<svg-icon
icon-class="warning_lights"
style="fill: currentColor; width: 15px; height: 15px; color: red"
v-if="row.deviceuuid.deviceStatus === 2"
/>
<span class="name" @click.native="nameClick(row.deviceuuid)">{{ row.gTitle }}</span>
</div>
</template>
<template #pager>
<!--使用 pager 插槽-->
<vxe-pager
class="tablePage"
:layouts="['Sizes', 'PrevJump', 'PrevPage', 'Number', 'NextPage', 'NextJump', 'FullJump', 'Total']"
v-model:current-page="tablePage.currentPage"
v-model:page-size="tablePage.pageSize"
auto-hidden
:total="tablePage.total"
@page-change="handlePageChange"
>
</vxe-pager>
</template>
</vxe-grid>
<!-- <vxe-grid class="tableGrid" v-bind="gridOptions"> </vxe-grid> -->
</n-spin>
<!-- <n-spin :show="loadingShow"> -->
<vxe-grid
ref="tableRef"
class="tableGrid"
align="center"
auto-resize
keep-source
:height="sidebarHeight - 4"
header-row-class-name="headerRowClass"
header-cell-class-name="headerCellClass"
row-class-name="tableRowClass"
cell-class-name="tableCellClass"
:sort-config="{ multiple: true, trigger: 'cell' }"
:stripe="!tableBorder"
:border="tableBorder"
:column-config="{ resizable: true, useKey: true }"
:row-config="{ useKey: true }"
:span-method="mergeRowMethod"
:columns="tableColumn"
:data="tableData"
:loading="loadingShow"
show-overflow
@cell-dblclick="cellDBLClickEvent"
>
<template #deviceuuid_default="{ row }">
<div class="title">
<svg-icon
icon-class="warning_lights"
style="fill: currentColor; width: 15px; height: 15px; color: green"
v-if="row.deviceuuid.deviceStatus === 0"
/>
<svg-icon
icon-class="warning_lights"
style="fill: currentColor; width: 15px; height: 15px; color: red"
v-if="row.deviceuuid.deviceStatus === 2"
/>
<span class="name" @click.native="nameClick(row.deviceuuid)">{{ row.gTitle }}</span>
</div>
</template>
<template #pager>
<!--使用 pager 插槽-->
<vxe-pager
class="tablePage"
:layouts="['Sizes', 'PrevJump', 'PrevPage', 'Number', 'NextPage', 'NextJump', 'FullJump', 'Total']"
v-model:current-page="tablePage.currentPage"
v-model:page-size="tablePage.pageSize"
auto-hidden
:total="tablePage.total"
@page-change="handlePageChange"
>
</vxe-pager>
</template>
</vxe-grid>
<!-- <vxe-grid class="tableGrid" v-bind="gridOptions"> </vxe-grid> -->
<!-- </n-spin> -->
</div>
<vxe-modal :title="modalTitle" v-model="editModal">
<template #default>
@ -202,7 +204,7 @@ const userInfo = JSON.parse(userStorageInfo === null ? '' : userStorageInfo);
//const baseApi = import.meta.env.VITE_APP_BASE_API
//const apiUrl = baseApi.replace(/https?:/, '');
const wsUrl = `ws://${window.location.host}/ws/websocket/${userInfo.userName}`; //websocket
// const wsUrl = `ws://172.1.2.6:9010/websocket/${userInfo.userName}`; //websocket
// const wsUrl = `ws://10.10.10.55:8021/ws/websocket/${userInfo.userName}`; //websocket
const emit = defineEmits(['tableHeaderData']);
// const listData = ref([

120
src/views/monitoring/screen/index.scss

@ -4,9 +4,10 @@
position: relative;
width: 100%;
height: 100vh;
background: url(@/assets/images/screen.png) no-repeat;
background-color: #f2f3f5;
// background: url(@/assets/images/screen.png) no-repeat;
// background-color: var(--tableBg);
background-size: 100% 100%;
// background-size: 100% 100%;
// background-color: rgba(29,30,31,0.8);
// background-blend-mode: multiply;
padding: 0 25px;
@ -20,8 +21,8 @@
left: 0;
color: #b1e3ff;
text-align: center;
border: 1px solid #0d55b0;
background-color: #02072e;
// border: 1px solid #0d55b0;
// background-color: #02072e;
border-right: none;
cursor: pointer;
@ -50,8 +51,8 @@
width: 70%;
text-align: center;
color: #a2ceff;
background: url(@/assets/images/panelBtn_bg.png) no-repeat center;
background-size: 100% 100%;
// background: url(@/assets/images/panelBtn_bg.png) no-repeat center;
// background-size: 100% 100%;
transition: width 0.28s;
margin: 0 auto;
cursor: pointer;
@ -163,14 +164,14 @@
width: 12%;
height: calc(100vh - 95px - 30px); //屏幕高度-头部header高度-底部高度
flex-shrink: 0;
border: 1px solid #0d55b0;
border: 1px solid var(--vxe-table-border-color);
padding: 10px 0;
// box-shadow: inset 0px 0px 10px 0px rgb(36, 90, 12);
margin-right: 1vw;
position: relative;
overflow: auto;
transition: width 0.28s;
background-color: rgba(2, 8, 46, 0.8);
// background-color: rgba(2, 8, 46, 0.8);
// .menu {
// text-align: center;
@ -256,7 +257,7 @@
}
.sidebar::after {
content: '';
content: none;
position: absolute;
bottom: 0;
width: 100%;
@ -268,7 +269,7 @@
.main {
position: relative;
width: 87%;
background-color: rgba(2, 8, 46, 0.8);
// background-color: rgba(2, 8, 46, 0.8);
.headerInfo {
border: 1px solid #0d55b0;
@ -310,31 +311,35 @@
.mainTable {
// height: calc(100vh - 8rem - 202px);
// height: calc(100% - 162px);
background-color: rgba(0, 0, 0, 0.1);
background-color: #f2f3f5;
transition: height 0.28s;
overflow: hidden;
.tableGrid {
--vxe-table-header-background-color: none;
--vxe-table-body-background-color: none;
--vxe-table-footer-background-color: none;
--vxe-table-border-color: rgba(12, 80, 166, 0.2);
// --vxe-table-header-background-color: none;
// --vxe-table-body-background-color: none;
// --vxe-table-footer-background-color: none;
// --vxe-table-border-color: rgba(12, 80, 166, 0.2);
// --vxe-table-border-color: none;
--vxe-font-color: #5beff9;
--vxe-table-header-font-color: #ffffffb3;
border: 1px solid #0d55b0;
// --vxe-font-color: #5beff9;
// --vxe-table-header-font-color: #ffffffb3;
// border: 1px solid #0d55b0;
// box-shadow: inset 0px 0px 10px 0px rgb(36, 90, 124);
:deep(.vxe-table) {
// height: calc(100vh - 5.7rem - 60px) !important;
.vxe-table--body-wrapper {
background-color: #f2f3f5;
// height: calc(100vh - 5.7rem - 182px) !important;
}
.headerRowClass {
.headerCellClass {
font-size: 18px;
font-weight: 800;
color: #eee;
border: 1px solid rgba(12, 80, 166, 1) !important;
background-color: #1169c0;
// border: 1px solid rgba(12, 80, 166, 1) !important;
border-left: none !important;
.vxe-resizable.is--line:before {
@ -353,11 +358,14 @@
}
.tableRowClass {
font-size: 18px;
font-weight: 500;
.tableCellClass {
background-color: #f2f3f5;
// border-bottom: 1px solid #265a89 !important;
.vxe-cell {
font-family: 'AlibabaPuHuiTiRegular';
color: #b1e3ff;
// color: #b1e3ff;
.title {
display: flex;
@ -453,33 +461,34 @@
}
}
.tablePage {
--vxe-pager-background-color: none;
background-color: #f2f3f5;
// --vxe-pager-background-color: none;
padding: 0 2rem;
color: #b1e3ff;
:deep(.vxe-select) {
.vxe-input--inner {
color: #b1e3ff;
border: 1px solid #b1e3ff;
background-color: transparent;
}
.vxe-select--panel {
color: #b1e3ff;
.vxe-select-option--wrapper {
border: 1px solid #b1e3ff;
background: -webkit-linear-gradient(top, #02072b 0%, #02082b 100%);
.vxe-select-option:not(.is--disabled).is--hover {
background: none;
}
}
}
}
:deep(.vxe-pager--jump) {
.vxe-pager--goto {
color: #b1e3ff;
border: 1px solid #b1e3ff;
background-color: transparent;
}
}
// color: #b1e3ff;
// :deep(.vxe-select) {
// .vxe-input--inner {
// color: #b1e3ff;
// border: 1px solid #b1e3ff;
// background-color: transparent;
// }
// .vxe-select--panel {
// color: #b1e3ff;
// .vxe-select-option--wrapper {
// border: 1px solid #b1e3ff;
// background: -webkit-linear-gradient(top, #02072b 0%, #02082b 100%);
// .vxe-select-option:not(.is--disabled).is--hover {
// background: none;
// }
// }
// }
// }
// :deep(.vxe-pager--jump) {
// .vxe-pager--goto {
// color: #b1e3ff;
// border: 1px solid #b1e3ff;
// background-color: transparent;
// }
// }
}
// /*滚动条整体部分*/
@ -533,11 +542,11 @@
display: flex;
align-items: center;
height: -webkit-fill-available;
border: 2px solid #0d54ae;
border: 2px solid var(--vxe-table-border-color);
border-radius: 5px;
color: #fff;
padding: 15px;
background-color: rgba(2, 8, 46, 0.5);
color: #000;
// padding: 15px;
// background-color: rgba(2, 8, 46, 0.5);
.icon {
width: 35%;
@ -550,7 +559,7 @@
.numValue {
flex: 1;
text-align: center;
color: #99e5ff;
color: #606266;
span {
font-size: 5rem;
@ -574,7 +583,7 @@
span {
font-size: 1.4rem;
line-height: 30px;
color: #99e5ff;
color: #606266;
margin-right: 3px;
}
span:nth-child(1) {
@ -651,6 +660,13 @@
}
}
.treeCard {
.showTree {
height: 50vh;
overflow: auto;
}
}
// }
.dark {

Loading…
Cancel
Save