修改冀北问题
This commit is contained in:
377
src/views/pqs/harmonicMonitoring/embed/dataOverview_JB/index.vue
Normal file
377
src/views/pqs/harmonicMonitoring/embed/dataOverview_JB/index.vue
Normal file
@@ -0,0 +1,377 @@
|
||||
<template>
|
||||
<div class="default-main">
|
||||
<TableHeader :showSearch="false" v-show="flag">
|
||||
<template v-slot:select>
|
||||
<el-form-item label="日期">
|
||||
<DatePicker
|
||||
ref="datePickerRef"
|
||||
:nextFlag="false"
|
||||
:theCurrentTime="true"
|
||||
@change="handleDatePickerChange"
|
||||
></DatePicker>
|
||||
</el-form-item>
|
||||
</template>
|
||||
<template v-slot:operation></template>
|
||||
</TableHeader>
|
||||
|
||||
<GridLayout
|
||||
v-model:layout="layout"
|
||||
:row-height="rowHeight"
|
||||
:is-resizable="false"
|
||||
:is-draggable="false"
|
||||
:responsive="false"
|
||||
:vertical-compact="false"
|
||||
prevent-collision
|
||||
:col-num="12"
|
||||
>
|
||||
<template #item="{ item }">
|
||||
<div class="box">
|
||||
<div class="title">
|
||||
<div style="display: flex; align-items: center">
|
||||
<Icon class="HelpFilled" :name="(item as LayoutItem).icon" />
|
||||
{{ (item as LayoutItem).name }}
|
||||
</div>
|
||||
<!-- <img :src="flag ? img : img1" style="cursor: pointer; height: 16px" @click="zoom(item)" /> -->
|
||||
<el-tooltip effect="dark" content="查看详情" placement="top">
|
||||
<View style="cursor: pointer; height: 16px" @click="jump(item)" />
|
||||
</el-tooltip>
|
||||
</div>
|
||||
<div>
|
||||
<component
|
||||
:is="(item as LayoutItem).component"
|
||||
v-if="(item as LayoutItem).component"
|
||||
class="pd10"
|
||||
:key="key"
|
||||
:timeValue="datePickerRef?.timeValue || 3"
|
||||
:height="rowHeight * item.h - seRowHeight(item.h) + 'px'"
|
||||
:width="rowWidth * item.w - 30 + 'px'"
|
||||
:timeKey="(item as LayoutItem).timeKey"
|
||||
:interval="datePickerRef?.interval"
|
||||
:w="item.w"
|
||||
:h="item.h"
|
||||
/>
|
||||
<div v-else class="pd10">组件加载失败...</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</GridLayout>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, reactive, onMounted, markRaw, onUnmounted, computed, defineAsyncComponent, type Component } from 'vue'
|
||||
import TableHeader from '@/components/table/header/index.vue'
|
||||
import { GridLayout } from 'grid-layout-plus'
|
||||
import DatePicker from '@/components/form/datePicker/index.vue'
|
||||
import { useDebounceFn } from '@vueuse/core'
|
||||
import { useRouter, useRoute } from 'vue-router'
|
||||
import { View } from '@element-plus/icons-vue'
|
||||
import { useTimeCacheStore } from '@/stores/timeCache'
|
||||
import { adminBaseRoutePath } from '@/router/static'
|
||||
const { push } = useRouter()
|
||||
const datePickerRef = ref()
|
||||
const router = useRouter()
|
||||
const route = useRoute()
|
||||
const timeCacheStore = useTimeCacheStore()
|
||||
|
||||
defineOptions({
|
||||
name: 'harmonic-boot/preview'
|
||||
})
|
||||
// 定义类型
|
||||
interface LayoutItem {
|
||||
x: number
|
||||
y: number
|
||||
w: number
|
||||
h: number
|
||||
timeKey: number | string
|
||||
i: string | number
|
||||
name: string
|
||||
path: string
|
||||
icon?: string // 新增 icon 可选字段
|
||||
component?: Component | string
|
||||
loading?: boolean
|
||||
error?: any
|
||||
}
|
||||
const key = ref(0)
|
||||
const img = new URL(`@/assets/img/amplify.png`, import.meta.url).href
|
||||
const img1 = new URL(`@/assets/img/reduce.png`, import.meta.url).href
|
||||
// 响应式数据
|
||||
const rowHeight = ref(0)
|
||||
const rowWidth = ref(0)
|
||||
const layout: any = ref([
|
||||
// {
|
||||
// x: 4,
|
||||
// y: 0,
|
||||
// w: 4,
|
||||
// h: 2,
|
||||
// i: '1',
|
||||
// name: '',
|
||||
// path: '/src/views/pqs/runManage/assessment/components/uese/index.vue'
|
||||
// },
|
||||
])
|
||||
const layoutCopy: any = ref([])
|
||||
const flag = ref(true)
|
||||
// 组件映射
|
||||
const componentMap = reactive(new Map<string, Component | string>())
|
||||
const dataList: any = ref({})
|
||||
// 获取主内容区域高度
|
||||
const getMainHeight = () => {
|
||||
const elMain = document.querySelector('.el-main')
|
||||
return (elMain?.offsetHeight || 0) - 70
|
||||
}
|
||||
// 获取主内容区域高度
|
||||
const getMainWidth = () => {
|
||||
const elMain = document.querySelector('.el-main')
|
||||
return (elMain?.offsetWidth || 0) - 20
|
||||
}
|
||||
|
||||
// 初始化行高
|
||||
const initRowHeight = () => {
|
||||
rowHeight.value = Math.max(0, (getMainHeight() - 77 + (flag.value ? 0 : 56)) / 6)
|
||||
rowWidth.value = Math.max(0, getMainWidth() / 12)
|
||||
}
|
||||
|
||||
// 动态注册组件
|
||||
const registerComponent = (path: string): Component | string | null => {
|
||||
if (!path) return null
|
||||
|
||||
const cacheKey = path
|
||||
|
||||
// 使用缓存的组件
|
||||
if (componentMap.has(cacheKey)) {
|
||||
return componentMap.get(cacheKey)!
|
||||
}
|
||||
|
||||
try {
|
||||
// 动态导入组件
|
||||
const modules = import.meta.glob('@/**/*.vue')
|
||||
if (!modules[path]) {
|
||||
console.error(`组件加载失败: ${path}`)
|
||||
return null
|
||||
}
|
||||
|
||||
const AsyncComponent = defineAsyncComponent({
|
||||
loader: modules[path],
|
||||
loadingComponent: () => h('div', '加载中...'),
|
||||
errorComponent: ({ error }) => h('div', `加载错误: ${error.message}`),
|
||||
delay: 200,
|
||||
timeout: 10000
|
||||
})
|
||||
|
||||
// 保存到映射中
|
||||
componentMap.set(cacheKey, markRaw(AsyncComponent))
|
||||
return AsyncComponent
|
||||
} catch (error) {
|
||||
console.error('注册组件失败:', error)
|
||||
return null
|
||||
}
|
||||
}
|
||||
// 缩放
|
||||
const zoom = (value: any) => {
|
||||
if (flag.value) {
|
||||
layout.value = [{ ...value, x: 0, y: 0, w: 12, h: 6 }]
|
||||
} else {
|
||||
layout.value = layoutCopy.value.map((item: any, index: number) => ({
|
||||
...item,
|
||||
i: item.i || index, // 确保有唯一标识
|
||||
component: registerComponent(item.path)
|
||||
}))
|
||||
}
|
||||
|
||||
flag.value = !flag.value
|
||||
|
||||
initRowHeight()
|
||||
key.value += 1
|
||||
}
|
||||
// 跳转
|
||||
const jump = (item: any) => {
|
||||
if (item.routerPath) {
|
||||
push(adminBaseRoutePath + item.routerPath)
|
||||
}
|
||||
}
|
||||
// 计算组件高度
|
||||
const seRowHeight = (value: any) => {
|
||||
if (value == 6) return 0
|
||||
if (value == 5) return 12
|
||||
if (value == 4) return 20
|
||||
if (value == 3) return 30
|
||||
if (value == 2) return 40
|
||||
if (value == 1) return 50
|
||||
return 0
|
||||
}
|
||||
// 获取布局数据
|
||||
const fetchLayoutData = async () => {
|
||||
try {
|
||||
// const { data } = await queryByPagePath({ pagePath: router.currentRoute.value.name })
|
||||
// dataList.value = data
|
||||
dataList.value = {
|
||||
createBy: 'e6a67ccbe789493687766c4304fcb228',
|
||||
createTime: '2025-11-26 08:43:56',
|
||||
updateBy: 'e6a67ccbe789493687766c4304fcb228',
|
||||
updateTime: '2025-11-26 08:43:56',
|
||||
id: 'e8218545cc11e32d5d6b87c92fdd0fbc',
|
||||
pageName: '测试',
|
||||
thumbnail: '',
|
||||
remark: '',
|
||||
containerConfig: [
|
||||
{
|
||||
x: 0,
|
||||
y: 0,
|
||||
w: 6,
|
||||
h: 3,
|
||||
i: 0.9274640143002512,
|
||||
name: '终端运行评价',
|
||||
path: '/src/components/cockpit/terminalEvaluation/index.vue',
|
||||
icon: 'local-审计列表',
|
||||
timeKey: '3',
|
||||
routerPath: '/runManage/runEvaluate',
|
||||
moved: false
|
||||
},
|
||||
{
|
||||
x: 6,
|
||||
y: 0,
|
||||
w: 6,
|
||||
h: 3,
|
||||
i: 0.9154814002445102,
|
||||
name: '终端在线率',
|
||||
path: '/src/components/cockpit/onlineRate/index.vue',
|
||||
icon: 'local-告警中心',
|
||||
timeKey: '3',
|
||||
routerPath: '/harmonic-boot/area/OnlineRate',
|
||||
moved: false
|
||||
},
|
||||
{
|
||||
x: 0,
|
||||
y: 3,
|
||||
w: 6,
|
||||
h: 3,
|
||||
i: 0.6560899767923003,
|
||||
name: '监测点数据完整性',
|
||||
path: '/src/components/cockpit/integrity/index.vue',
|
||||
icon: 'local-稳态指标超标明细',
|
||||
timeKey: '3',
|
||||
routerPath: '/harmonic-boot/harmonic/getIntegrityData',
|
||||
moved: false
|
||||
},
|
||||
{
|
||||
x: 6,
|
||||
y: 3,
|
||||
w: 6,
|
||||
h: 3,
|
||||
i: 0.5812302648025226,
|
||||
name: '异常数据清洗',
|
||||
path: '/src/components/cockpit/dataCleaning/index.vue',
|
||||
icon: 'local-区域暂态评估',
|
||||
timeKey: '3',
|
||||
routerPath: '/runManage/cleaning',
|
||||
moved: false
|
||||
}
|
||||
],
|
||||
sort: 100,
|
||||
state: 1,
|
||||
pagePath: 'dashboard/index6',
|
||||
pathName: null,
|
||||
routeName: '/src/views/pqs/cockpit/homePage/index.vue',
|
||||
icon: ''
|
||||
}
|
||||
const parsedLayout = (dataList.value.containerConfig || '[]') as LayoutItem[]
|
||||
// 处理布局数据
|
||||
layout.value = parsedLayout.map((item, index) => ({
|
||||
...item,
|
||||
i: item.i || index, // 确保有唯一标识
|
||||
component: registerComponent(item.path)
|
||||
}))
|
||||
layoutCopy.value = JSON.parse(JSON.stringify(layout.value))
|
||||
initRowHeight()
|
||||
} catch (error) {
|
||||
console.error('获取布局数据失败:', error)
|
||||
// 可以添加错误提示逻辑
|
||||
}
|
||||
}
|
||||
|
||||
// 窗口大小变化处理 - 使用防抖
|
||||
const handleResize = useDebounceFn(() => {
|
||||
initRowHeight()
|
||||
// key.value += 1
|
||||
}, 200)
|
||||
|
||||
// 处理 DatePicker 值变化事件
|
||||
const handleDatePickerChange = (value: any) => {
|
||||
// 将值缓存到 timeCache
|
||||
if (value) {
|
||||
timeCacheStore.setCache(route.path, value.interval, value.timeValue)
|
||||
}
|
||||
}
|
||||
|
||||
// 生命周期钩子
|
||||
onMounted(() => {
|
||||
// initRowHeight()
|
||||
fetchLayoutData()
|
||||
|
||||
// 添加窗口大小变化监听器
|
||||
window.addEventListener('resize', handleResize)
|
||||
})
|
||||
|
||||
onUnmounted(() => {
|
||||
// 移除监听器防止内存泄漏
|
||||
window.removeEventListener('resize', handleResize)
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.vgl-layout {
|
||||
background-color: #f8f9fa;
|
||||
border-radius: 4px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
:deep(.vgl-item:not(.vgl-item--placeholder)) {
|
||||
background-color: #ffffff;
|
||||
border-radius: 4px;
|
||||
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.12);
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
:deep(.vgl-item:hover:not(.vgl-item--placeholder)) {
|
||||
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.12);
|
||||
}
|
||||
|
||||
:deep(.vgl-item--static) {
|
||||
background-color: #f0f2f5;
|
||||
}
|
||||
|
||||
.text {
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 16px;
|
||||
color: #606266;
|
||||
}
|
||||
|
||||
:deep(.vgl-item) {
|
||||
overflow: hidden;
|
||||
}
|
||||
.box {
|
||||
overflow: hidden;
|
||||
.title {
|
||||
border-bottom: 1px solid #000;
|
||||
font-size: 14px;
|
||||
height: 30px;
|
||||
font-weight: 600;
|
||||
padding: 0px 10px;
|
||||
color: #fff;
|
||||
background-color: var(--el-color-primary);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
}
|
||||
.HelpFilled {
|
||||
height: 16px;
|
||||
width: 16px;
|
||||
color: #fff !important;
|
||||
margin-right: 5px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user