fuguobin
1 year ago
23 changed files with 4806 additions and 184 deletions
@ -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> |
@ -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> |
@ -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> |
@ -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> |
@ -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%); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
@ -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> |
@ -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> |
@ -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> |
@ -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> |
@ -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> |
@ -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); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
@ -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> |
@ -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> |
Loading…
Reference in new issue