优化驾驶舱页面
This commit is contained in:
@@ -32,7 +32,7 @@ const config = useConfig()
|
||||
const tree = ref()
|
||||
const treRef = ref()
|
||||
const changeDeviceType = (val: any, obj: any) => {
|
||||
console.log("🚀 ~ changeDeviceType ~ val:", val,obj)
|
||||
console.log('🚀 ~ changeDeviceType ~ val:', val, obj)
|
||||
emit('deviceTypeChange', val, obj)
|
||||
}
|
||||
getDeviceTree().then(res => {
|
||||
@@ -50,7 +50,7 @@ getDeviceTree().then(res => {
|
||||
item2.color = config.getColorVal('elementUiPrimary')
|
||||
item2.children.forEach((item3: any) => {
|
||||
item3.icon = 'el-icon-Platform'
|
||||
item3.level = 2
|
||||
item3.level = 2
|
||||
item3.color = config.getColorVal('elementUiPrimary')
|
||||
if (item3.comFlag === 1) {
|
||||
item3.color = '#e26257 !important'
|
||||
@@ -83,8 +83,8 @@ getDeviceTree().then(res => {
|
||||
// })
|
||||
})
|
||||
})
|
||||
}else if (item.name == '在线设备') {
|
||||
item.children.forEach((item: any) => {
|
||||
} else if (item.name == '在线设备') {
|
||||
item.children.forEach((item: any) => {
|
||||
item.icon = 'el-icon-HomeFilled'
|
||||
item.color = config.getColorVal('elementUiPrimary')
|
||||
item.children.forEach((item2: any) => {
|
||||
@@ -102,41 +102,40 @@ getDeviceTree().then(res => {
|
||||
})
|
||||
}
|
||||
})
|
||||
console.log("🚀 ~ file: deviceTree.vue ~ line 18 ~ getDeviceTree ~ tree:", arr,arr2,arr3)
|
||||
console.log('🚀 ~ file: deviceTree.vue ~ line 18 ~ getDeviceTree ~ tree:', arr, arr2, arr3)
|
||||
tree.value = res.data
|
||||
|
||||
|
||||
nextTick(() => {
|
||||
if (arr.length) {
|
||||
treRef.value.treeRef1.setCurrentKey(arr[0].id)
|
||||
// 注册父组件事件
|
||||
emit('init', {
|
||||
level: 2,
|
||||
...arr[0]
|
||||
})
|
||||
return
|
||||
}
|
||||
if (arr2.length) {
|
||||
treRef.value.treeRef2.setCurrentKey(arr2[0].id)
|
||||
// 注册父组件事件
|
||||
emit('init', {
|
||||
level: 2,
|
||||
...arr2[0]
|
||||
})
|
||||
return
|
||||
}
|
||||
if (arr3.length) {
|
||||
treRef.value.treeRef3.setCurrentKey(arr3[0].id)
|
||||
// 注册父组件事件
|
||||
emit('init', {
|
||||
level: 2,
|
||||
...arr3[0]
|
||||
})
|
||||
return
|
||||
}
|
||||
else {
|
||||
emit('init')
|
||||
return
|
||||
}
|
||||
setTimeout(() => {
|
||||
if (arr.length > 0) {
|
||||
treRef.value.treeRef1.setCurrentKey(arr[0].id)
|
||||
// 注册父组件事件
|
||||
emit('init', {
|
||||
level: 2,
|
||||
...arr[0]
|
||||
})
|
||||
return
|
||||
} else if (arr2.length > 0) {
|
||||
treRef.value.treeRef2.setCurrentKey(arr2[0].id)
|
||||
// 注册父组件事件
|
||||
emit('init', {
|
||||
level: 2,
|
||||
...arr2[0]
|
||||
})
|
||||
return
|
||||
} else if (arr3.length > 0) {
|
||||
treRef.value.treeRef3.setCurrentKey(arr3[0].id)
|
||||
// 注册父组件事件
|
||||
emit('init', {
|
||||
level: 2,
|
||||
...arr3[0]
|
||||
})
|
||||
return
|
||||
} else {
|
||||
emit('init')
|
||||
return
|
||||
}
|
||||
}, 500)
|
||||
})
|
||||
})
|
||||
const handleCheckChange = (data: any, checked: any, indeterminate: any) => {
|
||||
|
||||
@@ -99,38 +99,37 @@ const info = () => {
|
||||
})
|
||||
tree.value = res.data
|
||||
nextTick(() => {
|
||||
if (arr1.length) {
|
||||
//初始化选中
|
||||
treRef.value.treeRef1.setCurrentKey(arr1[0].id)
|
||||
// 注册父组件事件
|
||||
emit('init', {
|
||||
level: 2,
|
||||
...arr1[0]
|
||||
})
|
||||
return
|
||||
}
|
||||
if (arr2.length) {
|
||||
//初始化选中
|
||||
treRef.value.treeRef2.setCurrentKey(arr2[0].id)
|
||||
// 注册父组件事件
|
||||
emit('init', {
|
||||
level: 2,
|
||||
...arr2[0]
|
||||
})
|
||||
return
|
||||
}
|
||||
if(arr3.length){
|
||||
treRef.value.treeRef3.setCurrentKey(arr3[0].id)
|
||||
emit('init', {
|
||||
level: 2,
|
||||
...arr3[0]
|
||||
})
|
||||
return
|
||||
}
|
||||
else {
|
||||
emit('init')
|
||||
return
|
||||
}
|
||||
setTimeout(() => {
|
||||
if (arr1.length > 0) {
|
||||
//初始化选中
|
||||
treRef.value.treeRef1.setCurrentKey(arr1[0].id)
|
||||
// 注册父组件事件
|
||||
emit('init', {
|
||||
level: 2,
|
||||
...arr1[0]
|
||||
})
|
||||
return
|
||||
} else if (arr2.length > 0) {
|
||||
//初始化选中
|
||||
treRef.value.treeRef2.setCurrentKey(arr2[0].id)
|
||||
// 注册父组件事件
|
||||
emit('init', {
|
||||
level: 2,
|
||||
...arr2[0]
|
||||
})
|
||||
return
|
||||
} else if (arr3.length > 0) {
|
||||
treRef.value.treeRef3.setCurrentKey(arr3[0].id)
|
||||
emit('init', {
|
||||
level: 2,
|
||||
...arr3[0]
|
||||
})
|
||||
return
|
||||
} else {
|
||||
emit('init')
|
||||
return
|
||||
}
|
||||
}, 500)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
@@ -1,242 +1,246 @@
|
||||
<template>
|
||||
<div class="nav-tabs" ref="tabScrollbarRef">
|
||||
<div
|
||||
v-for="(item, idx) in navTabs.state.tabsView"
|
||||
@click="onTab(item)"
|
||||
@contextmenu.prevent="onContextmenu(item, $event)"
|
||||
class="ba-nav-tab"
|
||||
:class="navTabs.state.activeIndex == idx ? 'active' : ''"
|
||||
:ref="tabsRefs.set"
|
||||
:key="idx"
|
||||
>
|
||||
{{ item.meta.title }}
|
||||
<transition @after-leave="selectNavTab(tabsRefs[navTabs.state.activeIndex])" name="el-fade-in">
|
||||
<Icon
|
||||
v-if="navTabs.state.tabsView.length > 1"
|
||||
class="close-icon"
|
||||
@click.stop="closeTab(item)"
|
||||
size="15"
|
||||
name="el-icon-Close"
|
||||
/>
|
||||
</transition>
|
||||
</div>
|
||||
<!-- <div :style='activeBoxStyle' class='nav-tabs-active-box'></div>-->
|
||||
</div>
|
||||
<Contextmenu ref="contextmenuRef" :items="state.contextmenuItems" @contextmenuItemClick="onContextmenuItem" />
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { nextTick, onMounted, reactive, ref } from 'vue'
|
||||
import { useRoute, useRouter, onBeforeRouteUpdate, type RouteLocationNormalized } from 'vue-router'
|
||||
import { useConfig } from '@/stores/config'
|
||||
import { useNavTabs } from '@/stores/navTabs'
|
||||
import { useTemplateRefsList } from '@vueuse/core'
|
||||
import type { ContextMenuItem, ContextmenuItemClickEmitArg } from '@/components/contextmenu/interface'
|
||||
import useCurrentInstance from '@/utils/useCurrentInstance'
|
||||
import Contextmenu from '@/components/contextmenu/index.vue'
|
||||
import horizontalScroll from '@/utils/horizontalScroll'
|
||||
import { getFirstRoute, routePush } from '@/utils/router'
|
||||
import { adminBaseRoutePath } from '@/router/static'
|
||||
|
||||
const route = useRoute()
|
||||
const router = useRouter()
|
||||
const config = useConfig()
|
||||
const navTabs = useNavTabs()
|
||||
|
||||
const { proxy } = useCurrentInstance()
|
||||
const tabScrollbarRef = ref()
|
||||
const tabsRefs = useTemplateRefsList<HTMLDivElement>()
|
||||
|
||||
const contextmenuRef = ref()
|
||||
|
||||
const state: {
|
||||
contextmenuItems: ContextMenuItem[]
|
||||
} = reactive({
|
||||
contextmenuItems: [
|
||||
{ name: 'refresh', label: '重新加载', icon: 'fa fa-refresh' },
|
||||
{ name: 'close', label: '关闭标签', icon: 'fa fa-times' },
|
||||
{ name: 'fullScreen', label: '当前标签全屏', icon: 'el-icon-FullScreen' },
|
||||
{ name: 'closeOther', label: '关闭其他标签', icon: 'fa fa-minus' },
|
||||
{ name: 'closeAll', label: '关闭全部标签', icon: 'fa fa-stop' }
|
||||
]
|
||||
})
|
||||
|
||||
const activeBoxStyle = reactive({
|
||||
width: '0',
|
||||
transform: 'translateX(0px)'
|
||||
})
|
||||
|
||||
const onTab = (menu: RouteLocationNormalized) => {
|
||||
router.push(menu)
|
||||
}
|
||||
|
||||
const onContextmenu = (menu: RouteLocationNormalized, el: MouseEvent) => {
|
||||
// 禁用刷新
|
||||
state.contextmenuItems[0].disabled = route.path !== menu.path
|
||||
// 禁用关闭其他和关闭全部
|
||||
state.contextmenuItems[4].disabled = state.contextmenuItems[3].disabled =
|
||||
navTabs.state.tabsView.length == 1 ? true : false
|
||||
|
||||
const { clientX, clientY } = el
|
||||
contextmenuRef.value.onShowContextmenu(menu, {
|
||||
x: clientX,
|
||||
y: clientY
|
||||
})
|
||||
}
|
||||
|
||||
// tab 激活状态切换
|
||||
const selectNavTab = function (dom: HTMLDivElement) {
|
||||
if (!dom) {
|
||||
return false
|
||||
}
|
||||
activeBoxStyle.width = dom.clientWidth + 'px'
|
||||
activeBoxStyle.transform = `translateX(${dom.offsetLeft}px)`
|
||||
|
||||
let scrollLeft = dom.offsetLeft + dom.clientWidth - tabScrollbarRef.value.clientWidth
|
||||
if (dom.offsetLeft < tabScrollbarRef.value.scrollLeft) {
|
||||
tabScrollbarRef.value.scrollTo(dom.offsetLeft, 0)
|
||||
} else if (scrollLeft > tabScrollbarRef.value.scrollLeft) {
|
||||
tabScrollbarRef.value.scrollTo(scrollLeft, 0)
|
||||
}
|
||||
}
|
||||
|
||||
const toLastTab = () => {
|
||||
const lastTab = navTabs.state.tabsView.slice(-1)[0]
|
||||
if (lastTab) {
|
||||
router.push(lastTab)
|
||||
} else {
|
||||
router.push(adminBaseRoutePath)
|
||||
}
|
||||
}
|
||||
|
||||
const closeTab = (route: RouteLocationNormalized) => {
|
||||
navTabs.closeTab(route)
|
||||
proxy.eventBus.emit('onTabViewClose', route)
|
||||
if (navTabs.state.activeRoute?.path === route.path) {
|
||||
toLastTab()
|
||||
} else {
|
||||
navTabs.setActiveRoute(navTabs.state.activeRoute!)
|
||||
nextTick(() => {
|
||||
selectNavTab(tabsRefs.value[navTabs.state.activeIndex])
|
||||
})
|
||||
}
|
||||
|
||||
contextmenuRef.value.onHideContextmenu()
|
||||
}
|
||||
|
||||
const closeOtherTab = (menu: RouteLocationNormalized) => {
|
||||
navTabs.closeTabs(menu)
|
||||
navTabs.setActiveRoute(menu)
|
||||
if (navTabs.state.activeRoute?.path !== route.path) {
|
||||
router.push(menu!.path)
|
||||
}
|
||||
}
|
||||
|
||||
const closeAllTab = (menu: RouteLocationNormalized) => {
|
||||
let firstRoute = getFirstRoute(navTabs.state.tabsViewRoutes)
|
||||
if (firstRoute && firstRoute.path == menu.path) {
|
||||
return closeOtherTab(menu)
|
||||
}
|
||||
if (firstRoute && firstRoute.path == navTabs.state.activeRoute?.path) {
|
||||
return closeOtherTab(navTabs.state.activeRoute)
|
||||
}
|
||||
navTabs.closeTabs(false)
|
||||
if (firstRoute) routePush(firstRoute.path)
|
||||
}
|
||||
|
||||
const onContextmenuItem = async (item: ContextmenuItemClickEmitArg) => {
|
||||
const { name, menu } = item
|
||||
if (!menu) return
|
||||
switch (name) {
|
||||
case 'refresh':
|
||||
proxy.eventBus.emit('onTabViewRefresh', menu)
|
||||
break
|
||||
case 'close':
|
||||
closeTab(menu)
|
||||
break
|
||||
case 'closeOther':
|
||||
closeOtherTab(menu)
|
||||
break
|
||||
case 'closeAll':
|
||||
closeAllTab(menu)
|
||||
break
|
||||
case 'fullScreen':
|
||||
if (route.path !== menu?.path) {
|
||||
router.push(menu?.path as string)
|
||||
}
|
||||
navTabs.setFullScreen(true)
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
const updateTab = function (newRoute: RouteLocationNormalized) {
|
||||
// 添加tab
|
||||
navTabs.addTab(newRoute)
|
||||
// 激活当前tab
|
||||
navTabs.setActiveRoute(newRoute)
|
||||
|
||||
nextTick(() => {
|
||||
selectNavTab(tabsRefs.value[navTabs.state.activeIndex])
|
||||
})
|
||||
}
|
||||
|
||||
onBeforeRouteUpdate(async to => {
|
||||
|
||||
|
||||
updateTab(to)
|
||||
|
||||
})
|
||||
|
||||
onMounted(() => {
|
||||
updateTab(router.currentRoute.value)
|
||||
new horizontalScroll(tabScrollbarRef.value)
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.dark {
|
||||
.close-icon {
|
||||
color: v-bind('config.getColorVal("headerBarTabColor")') !important;
|
||||
}
|
||||
|
||||
.ba-nav-tab.active {
|
||||
.close-icon {
|
||||
color: v-bind('config.getColorVal("headerBarTabActiveColor")') !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.nav-tabs {
|
||||
overflow-x: auto;
|
||||
overflow-y: hidden;
|
||||
margin-right: var(--ba-main-space);
|
||||
scrollbar-width: none;
|
||||
|
||||
&::-webkit-scrollbar {
|
||||
height: 5px;
|
||||
}
|
||||
|
||||
//
|
||||
//&::-webkit-scrollbar-thumb {
|
||||
// background: #eaeaea;
|
||||
// border-radius: var(--el-border-radius-base);
|
||||
// box-shadow: none;
|
||||
// -webkit-box-shadow: none;
|
||||
//}
|
||||
//
|
||||
//&::-webkit-scrollbar-track {
|
||||
// background: v-bind('config.layout.layoutMode == "Default" ? "none":config.getColorVal("headerBarBackground")');
|
||||
//}
|
||||
//
|
||||
//&:hover {
|
||||
// &::-webkit-scrollbar-thumb:hover {
|
||||
// background: #c8c9cc;
|
||||
// }
|
||||
//}
|
||||
}
|
||||
|
||||
.ba-nav-tab {
|
||||
white-space: nowrap;
|
||||
height: 40px;
|
||||
}
|
||||
</style>
|
||||
<template>
|
||||
<div class="nav-tabs" ref="tabScrollbarRef">
|
||||
|
||||
<div
|
||||
v-for="(item, idx) in navTabs.state.tabsView"
|
||||
@click="onTab(item)"
|
||||
@contextmenu.prevent="onContextmenu(item, $event)"
|
||||
class="ba-nav-tab"
|
||||
:class="navTabs.state.activeIndex == idx ? 'active' : ''"
|
||||
:ref="tabsRefs.set"
|
||||
:key="idx"
|
||||
>
|
||||
{{ item.meta.title }}
|
||||
<transition @after-leave="selectNavTab(tabsRefs[navTabs.state.activeIndex])" name="el-fade-in">
|
||||
<Icon
|
||||
v-if="navTabs.state.tabsView.length > 1"
|
||||
class="close-icon"
|
||||
@click.stop="closeTab(item)"
|
||||
size="15"
|
||||
name="el-icon-Close"
|
||||
/>
|
||||
</transition>
|
||||
</div>
|
||||
<!-- <div :style='activeBoxStyle' class='nav-tabs-active-box'></div>-->
|
||||
</div>
|
||||
<Contextmenu ref="contextmenuRef" :items="state.contextmenuItems" @contextmenuItemClick="onContextmenuItem" />
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { nextTick, onMounted, reactive, ref } from 'vue'
|
||||
import { useRoute, useRouter, onBeforeRouteUpdate, type RouteLocationNormalized } from 'vue-router'
|
||||
import { useConfig } from '@/stores/config'
|
||||
import { useNavTabs } from '@/stores/navTabs'
|
||||
import { useTemplateRefsList } from '@vueuse/core'
|
||||
import type { ContextMenuItem, ContextmenuItemClickEmitArg } from '@/components/contextmenu/interface'
|
||||
import useCurrentInstance from '@/utils/useCurrentInstance'
|
||||
import Contextmenu from '@/components/contextmenu/index.vue'
|
||||
import horizontalScroll from '@/utils/horizontalScroll'
|
||||
import { getFirstRoute, routePush } from '@/utils/router'
|
||||
import { adminBaseRoutePath } from '@/router/static'
|
||||
|
||||
const route = useRoute()
|
||||
const router = useRouter()
|
||||
const config = useConfig()
|
||||
const navTabs = useNavTabs()
|
||||
|
||||
const { proxy } = useCurrentInstance()
|
||||
const tabScrollbarRef = ref()
|
||||
const tabsRefs = useTemplateRefsList<HTMLDivElement>()
|
||||
|
||||
const contextmenuRef = ref()
|
||||
|
||||
const state: {
|
||||
contextmenuItems: ContextMenuItem[]
|
||||
} = reactive({
|
||||
contextmenuItems: [
|
||||
{ name: 'refresh', label: '重新加载', icon: 'fa fa-refresh' },
|
||||
{ name: 'close', label: '关闭标签', icon: 'fa fa-times' },
|
||||
{ name: 'fullScreen', label: '当前标签全屏', icon: 'el-icon-FullScreen' },
|
||||
{ name: 'closeOther', label: '关闭其他标签', icon: 'fa fa-minus' },
|
||||
{ name: 'closeAll', label: '关闭全部标签', icon: 'fa fa-stop' }
|
||||
]
|
||||
})
|
||||
|
||||
const activeBoxStyle = reactive({
|
||||
width: '0',
|
||||
transform: 'translateX(0px)'
|
||||
})
|
||||
|
||||
const onTab = (menu: RouteLocationNormalized) => {
|
||||
router.push(menu)
|
||||
}
|
||||
|
||||
const onContextmenu = (menu: RouteLocationNormalized, el: MouseEvent) => {
|
||||
|
||||
// 禁用刷新
|
||||
state.contextmenuItems[0].disabled = route.path !== menu.path
|
||||
|
||||
|
||||
// 禁用关闭其他和关闭全部
|
||||
state.contextmenuItems[4].disabled = state.contextmenuItems[3].disabled =
|
||||
navTabs.state.tabsView.length == 1 ? true : false
|
||||
|
||||
const { clientX, clientY } = el
|
||||
contextmenuRef.value.onShowContextmenu(menu, {
|
||||
x: clientX,
|
||||
y: clientY
|
||||
})
|
||||
}
|
||||
|
||||
// tab 激活状态切换
|
||||
const selectNavTab = function (dom: HTMLDivElement) {
|
||||
if (!dom) {
|
||||
return false
|
||||
}
|
||||
activeBoxStyle.width = dom.clientWidth + 'px'
|
||||
activeBoxStyle.transform = `translateX(${dom.offsetLeft}px)`
|
||||
|
||||
let scrollLeft = dom.offsetLeft + dom.clientWidth - tabScrollbarRef.value.clientWidth
|
||||
if (dom.offsetLeft < tabScrollbarRef.value.scrollLeft) {
|
||||
tabScrollbarRef.value.scrollTo(dom.offsetLeft, 0)
|
||||
} else if (scrollLeft > tabScrollbarRef.value.scrollLeft) {
|
||||
tabScrollbarRef.value.scrollTo(scrollLeft, 0)
|
||||
}
|
||||
}
|
||||
|
||||
const toLastTab = () => {
|
||||
const lastTab = navTabs.state.tabsView.slice(-1)[0]
|
||||
if (lastTab) {
|
||||
router.push(lastTab)
|
||||
} else {
|
||||
router.push(adminBaseRoutePath)
|
||||
}
|
||||
}
|
||||
|
||||
const closeTab = (route: RouteLocationNormalized) => {
|
||||
navTabs.closeTab(route)
|
||||
proxy.eventBus.emit('onTabViewClose', route)
|
||||
if (navTabs.state.activeRoute?.path === route.path) {
|
||||
toLastTab()
|
||||
} else {
|
||||
navTabs.setActiveRoute(navTabs.state.activeRoute!)
|
||||
nextTick(() => {
|
||||
selectNavTab(tabsRefs.value[navTabs.state.activeIndex])
|
||||
})
|
||||
}
|
||||
|
||||
contextmenuRef.value.onHideContextmenu()
|
||||
}
|
||||
|
||||
const closeOtherTab = (menu: RouteLocationNormalized) => {
|
||||
navTabs.closeTabs(menu)
|
||||
navTabs.setActiveRoute(menu)
|
||||
if (navTabs.state.activeRoute?.path !== route.path) {
|
||||
router.push(menu!.path)
|
||||
}
|
||||
}
|
||||
|
||||
const closeAllTab = (menu: RouteLocationNormalized) => {
|
||||
let firstRoute = getFirstRoute(navTabs.state.tabsViewRoutes)
|
||||
if (firstRoute && firstRoute.path == menu.path) {
|
||||
return closeOtherTab(menu)
|
||||
}
|
||||
if (firstRoute && firstRoute.path == navTabs.state.activeRoute?.path) {
|
||||
return closeOtherTab(navTabs.state.activeRoute)
|
||||
}
|
||||
navTabs.closeTabs(false)
|
||||
if (firstRoute) routePush(firstRoute.path)
|
||||
}
|
||||
|
||||
const onContextmenuItem = async (item: ContextmenuItemClickEmitArg) => {
|
||||
const { name, menu } = item
|
||||
if (!menu) return
|
||||
switch (name) {
|
||||
case 'refresh':
|
||||
proxy.eventBus.emit('onTabViewRefresh', menu)
|
||||
break
|
||||
case 'close':
|
||||
closeTab(menu)
|
||||
break
|
||||
case 'closeOther':
|
||||
closeOtherTab(menu)
|
||||
break
|
||||
case 'closeAll':
|
||||
closeAllTab(menu)
|
||||
break
|
||||
case 'fullScreen':
|
||||
if (route.path !== menu?.path) {
|
||||
router.push(menu?.path as string)
|
||||
}
|
||||
navTabs.setFullScreen(true)
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
const updateTab = function (newRoute: RouteLocationNormalized) {
|
||||
// 添加tab
|
||||
navTabs.addTab(newRoute)
|
||||
// 激活当前tab
|
||||
navTabs.setActiveRoute(newRoute)
|
||||
|
||||
nextTick(() => {
|
||||
selectNavTab(tabsRefs.value[navTabs.state.activeIndex])
|
||||
})
|
||||
}
|
||||
|
||||
onBeforeRouteUpdate(async to => {
|
||||
|
||||
|
||||
updateTab(to)
|
||||
|
||||
})
|
||||
|
||||
onMounted(() => {
|
||||
updateTab(router.currentRoute.value)
|
||||
new horizontalScroll(tabScrollbarRef.value)
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.dark {
|
||||
.close-icon {
|
||||
color: v-bind('config.getColorVal("headerBarTabColor")') !important;
|
||||
}
|
||||
|
||||
.ba-nav-tab.active {
|
||||
.close-icon {
|
||||
color: v-bind('config.getColorVal("headerBarTabActiveColor")') !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.nav-tabs {
|
||||
overflow-x: auto;
|
||||
overflow-y: hidden;
|
||||
margin-right: var(--ba-main-space);
|
||||
scrollbar-width: none;
|
||||
|
||||
&::-webkit-scrollbar {
|
||||
height: 5px;
|
||||
}
|
||||
|
||||
//
|
||||
//&::-webkit-scrollbar-thumb {
|
||||
// background: #eaeaea;
|
||||
// border-radius: var(--el-border-radius-base);
|
||||
// box-shadow: none;
|
||||
// -webkit-box-shadow: none;
|
||||
//}
|
||||
//
|
||||
//&::-webkit-scrollbar-track {
|
||||
// background: v-bind('config.layout.layoutMode == "Default" ? "none":config.getColorVal("headerBarBackground")');
|
||||
//}
|
||||
//
|
||||
//&:hover {
|
||||
// &::-webkit-scrollbar-thumb:hover {
|
||||
// background: #c8c9cc;
|
||||
// }
|
||||
//}
|
||||
}
|
||||
|
||||
.ba-nav-tab {
|
||||
white-space: nowrap;
|
||||
height: 40px;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,108 +1,169 @@
|
||||
import { reactive } from 'vue'
|
||||
import { defineStore } from 'pinia'
|
||||
import { STORE_TAB_VIEW_CONFIG } from '@/stores/constant/cacheKey'
|
||||
import type { NavTabs } from '@/stores/interface/index'
|
||||
import type { RouteLocationNormalized, RouteRecordRaw } from 'vue-router'
|
||||
import { adminBaseRoutePath } from '@/router/static'
|
||||
|
||||
export const useNavTabs = defineStore(
|
||||
'navTabs',
|
||||
() => {
|
||||
const state: NavTabs = reactive({
|
||||
// 激活tab的index
|
||||
activeIndex: 0,
|
||||
// 激活的tab
|
||||
activeRoute: null,
|
||||
// tab列表
|
||||
tabsView: [],
|
||||
// 当前tab是否全屏
|
||||
tabFullScreen: false,
|
||||
// 从后台加载到的菜单路由列表
|
||||
tabsViewRoutes: [],
|
||||
// 按钮权限节点
|
||||
authNode: new Map(),
|
||||
})
|
||||
|
||||
function addTab(route: RouteLocationNormalized) {
|
||||
if (!route.meta.addtab) return
|
||||
for (const key in state.tabsView) {
|
||||
if (state.tabsView[key].path === route.path) {
|
||||
state.tabsView[key].params = route.params ? route.params : state.tabsView[key].params
|
||||
state.tabsView[key].query = route.query ? route.query : state.tabsView[key].query
|
||||
return
|
||||
}
|
||||
}
|
||||
state.tabsView.push(route)
|
||||
}
|
||||
|
||||
function closeTab(route: RouteLocationNormalized) {
|
||||
state.tabsView.map((v, k) => {
|
||||
if (v.path == route.path) {
|
||||
state.tabsView.splice(k, 1)
|
||||
return
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 关闭多个标签
|
||||
* @param retainMenu 需要保留的标签,否则关闭全部标签
|
||||
*/
|
||||
const closeTabs = (retainMenu: RouteLocationNormalized | false = false) => {
|
||||
if (retainMenu) {
|
||||
state.tabsView = [retainMenu]
|
||||
} else {
|
||||
state.tabsView = []
|
||||
}
|
||||
}
|
||||
|
||||
const setActiveRoute = (route: RouteLocationNormalized): void => {
|
||||
const currentRouteIndex: number = state.tabsView.findIndex((item: RouteLocationNormalized) => {
|
||||
return item.path === route.path
|
||||
})
|
||||
if (currentRouteIndex === -1) return
|
||||
state.activeRoute = route
|
||||
state.activeIndex = currentRouteIndex
|
||||
}
|
||||
|
||||
const setTabsViewRoutes = (data: RouteRecordRaw[]): void => {
|
||||
state.tabsViewRoutes = encodeRoutesURI(data)
|
||||
}
|
||||
|
||||
const setAuthNode = (key: string, data: string[]) => {
|
||||
state.authNode.set(key, data)
|
||||
}
|
||||
|
||||
const fillAuthNode = (data: Map<string, string[]>) => {
|
||||
state.authNode = data
|
||||
}
|
||||
|
||||
const setFullScreen = (fullScreen: boolean): void => {
|
||||
state.tabFullScreen = fullScreen
|
||||
}
|
||||
|
||||
return { state, addTab, closeTab, closeTabs, setActiveRoute, setTabsViewRoutes, setAuthNode, fillAuthNode, setFullScreen }
|
||||
},
|
||||
{
|
||||
persist: {
|
||||
key: STORE_TAB_VIEW_CONFIG,
|
||||
paths: ['state.tabFullScreen'],
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
/**
|
||||
* 对iframe的url进行编码
|
||||
*/
|
||||
function encodeRoutesURI(data: RouteRecordRaw[]) {
|
||||
data.forEach((item) => {
|
||||
if (item.meta?.menu_type == 'iframe') {
|
||||
item.path = adminBaseRoutePath + '/iframe/' + encodeURIComponent(item.path)
|
||||
}
|
||||
|
||||
if (item.children && item.children.length) {
|
||||
item.children = encodeRoutesURI(item.children)
|
||||
}
|
||||
})
|
||||
return data
|
||||
}
|
||||
import { reactive } from 'vue'
|
||||
import { defineStore } from 'pinia'
|
||||
import { STORE_TAB_VIEW_CONFIG } from '@/stores/constant/cacheKey'
|
||||
import type { NavTabs } from '@/stores/interface/index'
|
||||
import type { RouteLocationNormalized, RouteRecordRaw } from 'vue-router'
|
||||
import { adminBaseRoutePath } from '@/router/static'
|
||||
import { set } from 'lodash'
|
||||
|
||||
export const useNavTabs = defineStore(
|
||||
'navTabs',
|
||||
() => {
|
||||
const state: NavTabs = reactive({
|
||||
// 激活tab的index
|
||||
activeIndex: 0,
|
||||
// 激活的tab
|
||||
activeRoute: null,
|
||||
// tab列表
|
||||
tabsView: [],
|
||||
// 当前tab是否全屏
|
||||
tabFullScreen: false,
|
||||
// 从后台加载到的菜单路由列表
|
||||
tabsViewRoutes: [],
|
||||
// 按钮权限节点
|
||||
authNode: new Map()
|
||||
})
|
||||
|
||||
function addTab(route: RouteLocationNormalized) {
|
||||
console.log('🚀 ~ addTab ~ route:', route)
|
||||
if (!route.meta.addtab) return
|
||||
for (const key in state.tabsView) {
|
||||
if (state.tabsView[key].path === route.path) {
|
||||
state.tabsView[key].params = route.params ? route.params : state.tabsView[key].params
|
||||
state.tabsView[key].query = route.query ? route.query : state.tabsView[key].query
|
||||
state.tabsView[key].meta = route.query ? route.meta : state.tabsView[key].meta
|
||||
return
|
||||
}
|
||||
}
|
||||
state.tabsView.push(route)
|
||||
}
|
||||
|
||||
function closeTab(route: RouteLocationNormalized) {
|
||||
state.tabsView.map((v, k) => {
|
||||
if (v.path == route.path) {
|
||||
state.tabsView.splice(k, 1)
|
||||
return
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 关闭多个标签
|
||||
* @param retainMenu 需要保留的标签,否则关闭全部标签
|
||||
*/
|
||||
const closeTabs = (retainMenu: RouteLocationNormalized | false = false) => {
|
||||
if (retainMenu) {
|
||||
state.tabsView = [retainMenu]
|
||||
} else {
|
||||
state.tabsView = []
|
||||
}
|
||||
}
|
||||
|
||||
const setActiveRoute = (route: RouteLocationNormalized): void => {
|
||||
const currentRouteIndex: number = state.tabsView.findIndex((item: RouteLocationNormalized) => {
|
||||
return item.path === route.path
|
||||
})
|
||||
if (currentRouteIndex === -1) return
|
||||
state.activeRoute = route
|
||||
state.activeIndex = currentRouteIndex
|
||||
}
|
||||
|
||||
const setTabsViewRoutes = (data: RouteRecordRaw[]): void => {
|
||||
state.tabsViewRoutes = encodeRoutesURI(data)
|
||||
}
|
||||
|
||||
const setAuthNode = (key: string, data: string[]) => {
|
||||
state.authNode.set(key, data)
|
||||
}
|
||||
|
||||
const fillAuthNode = (data: Map<string, string[]>) => {
|
||||
state.authNode = data
|
||||
}
|
||||
|
||||
const setFullScreen = (fullScreen: boolean): void => {
|
||||
state.tabFullScreen = fullScreen
|
||||
}
|
||||
|
||||
const refresh = () => {
|
||||
// setTimeout(() => {
|
||||
// console.log(123, state.tabsViewRoutes)
|
||||
|
||||
let list = matchAndReturnRouteData(state.tabsViewRoutes, state.tabsView)
|
||||
state.tabsView = []
|
||||
list.forEach(item => {
|
||||
addTab(item)
|
||||
})
|
||||
// }, 1000)
|
||||
}
|
||||
return {
|
||||
state,
|
||||
addTab,
|
||||
closeTab,
|
||||
closeTabs,
|
||||
setActiveRoute,
|
||||
setTabsViewRoutes,
|
||||
setAuthNode,
|
||||
fillAuthNode,
|
||||
setFullScreen,
|
||||
refresh
|
||||
}
|
||||
},
|
||||
{
|
||||
persist: {
|
||||
key: STORE_TAB_VIEW_CONFIG,
|
||||
paths: ['state.tabFullScreen']
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
/**
|
||||
* 核心逻辑:
|
||||
* 1. 递归遍历树形菜单,筛选出与routeList中name匹配的节点
|
||||
* 2. 将匹配到的节点格式转换为routeList的结构并返回
|
||||
*/
|
||||
function matchAndReturnRouteData(tree, routeList) {
|
||||
// 1. 构建路由name映射(name -> 完整路由对象)
|
||||
const routeMap = new Map()
|
||||
routeList.forEach(route => {
|
||||
if (route.name) {
|
||||
routeMap.set(route.name, route)
|
||||
}
|
||||
})
|
||||
|
||||
// 2. 递归遍历树形菜单,收集匹配的节点
|
||||
const matchedNodes = []
|
||||
function recursion(node) {
|
||||
// 匹配当前节点
|
||||
if (routeMap.has(node.name)) {
|
||||
// 深度克隆路由对象,避免修改原数据
|
||||
const matchedRoute = JSON.parse(JSON.stringify(routeMap.get(node.name)))
|
||||
matchedNodes.push(matchedRoute)
|
||||
}
|
||||
// 递归处理子节点
|
||||
if (node.children && node.children.length) {
|
||||
node.children.forEach(child => recursion(child))
|
||||
}
|
||||
}
|
||||
|
||||
// 遍历所有顶级节点
|
||||
tree.forEach(node => recursion(node))
|
||||
|
||||
// 3. 返回匹配后的第二个数据格式(和routeList结构一致)
|
||||
return matchedNodes
|
||||
}
|
||||
|
||||
/**
|
||||
* 对iframe的url进行编码
|
||||
*/
|
||||
function encodeRoutesURI(data: RouteRecordRaw[]) {
|
||||
data.forEach(item => {
|
||||
if (item.meta?.menu_type == 'iframe') {
|
||||
item.path = adminBaseRoutePath + '/iframe/' + encodeURIComponent(item.path)
|
||||
}
|
||||
|
||||
if (item.children && item.children.length) {
|
||||
item.children = encodeRoutesURI(item.children)
|
||||
}
|
||||
})
|
||||
return data
|
||||
}
|
||||
|
||||
@@ -839,6 +839,7 @@ const lineId: any = ref('')
|
||||
const dataLevel: any = ref('')
|
||||
const dataSource = ref([])
|
||||
const nodeClick = async (e: anyObj) => {
|
||||
console.log("🚀 ~ nodeClick ~ e:", e)
|
||||
if (e == undefined || e.level == 2) {
|
||||
return (loading.value = false)
|
||||
}
|
||||
|
||||
167
src/views/govern/reportCore/statisticsWx/index_ypt.vue
Normal file
167
src/views/govern/reportCore/statisticsWx/index_ypt.vue
Normal file
@@ -0,0 +1,167 @@
|
||||
<template>
|
||||
<div class="default-main" :style="height">
|
||||
<splitpanes style="height: 100%" class="default-theme" id="navigation-splitpanes">
|
||||
<pane :size="size">
|
||||
<!-- <pointTreeWx :default-expand-all="false" template @node-click="handleNodeClick" @init="handleNodeClick"
|
||||
@Policy="stencil">
|
||||
</pointTreeWx> -->
|
||||
<CloudDeviceEntryTree
|
||||
ref="TerminalRef"
|
||||
template
|
||||
@Policy="stencil"
|
||||
@node-click="handleNodeClick"
|
||||
@init="handleNodeClick"
|
||||
></CloudDeviceEntryTree>
|
||||
</pane>
|
||||
<pane :size="(100 - size)" style="background: #fff" :style="height">
|
||||
<TableHeader ref="TableHeaderRef" :showReset="false">
|
||||
<template v-slot:select>
|
||||
<el-form-item label="时间:">
|
||||
<DatePicker ref="datePickerRef"></DatePicker>
|
||||
</el-form-item>
|
||||
<el-form-item label="模板策略">
|
||||
<el-select v-model.trim="Template" @change="changetype" placeholder="请选择模版" value-key="id">
|
||||
<el-option v-for="item in templatePolicy" :key="item.id" :label="item.name"
|
||||
:value="item"></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</template>
|
||||
<template #operation>
|
||||
<el-button icon="el-icon-Download" type="primary" @click="exportEvent">导出excel</el-button>
|
||||
</template>
|
||||
</TableHeader>
|
||||
<div class="box" v-loading="tableStore.table.loading">
|
||||
<div id="luckysheet"
|
||||
:style="`height: calc(${tableStore.table.height} + 45px)`"
|
||||
v-if="tableStore.table.data.length > 0"></div>
|
||||
<el-empty :style="`height: calc(${tableStore.table.height} + 45px)`" v-else description="暂无数据" />
|
||||
</div>
|
||||
</pane>
|
||||
</splitpanes>
|
||||
</div>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { onMounted, ref, provide } from 'vue'
|
||||
import TableStore from '@/utils/tableStore'
|
||||
import pointTreeWx from '@/components/tree/govern/pointTreeWx.vue'
|
||||
import TableHeader from '@/components/table/header/index.vue'
|
||||
import { useDictData } from '@/stores/dictData'
|
||||
import { mainHeight } from '@/utils/layout'
|
||||
import { getTemplateByDept } from '@/api/harmonic-boot/luckyexcel'
|
||||
import { exportExcel } from '@/views/system/reportForms/export.js'
|
||||
import 'splitpanes/dist/splitpanes.css'
|
||||
import DatePicker from '@/components/form/datePicker/time.vue'
|
||||
import { Splitpanes, Pane } from 'splitpanes'
|
||||
import CloudDeviceEntryTree from '@/components/tree/govern/cloudDeviceEntryTree.vue'
|
||||
// import data from './123.json'
|
||||
defineOptions({
|
||||
name: 'govern/reportCore/statisticsWx/index'
|
||||
})
|
||||
const height = mainHeight(20)
|
||||
const size = ref(0)
|
||||
const dictData = useDictData()
|
||||
const TableHeaderRef = ref()
|
||||
const dotList: any = ref({})
|
||||
const Template: any = ref({})
|
||||
const reportForm: any = ref('')
|
||||
const datePickerRef = ref()
|
||||
const templatePolicy: any = ref([])
|
||||
|
||||
const tableStore = new TableStore({
|
||||
url: '/cs-harmonic-boot/customReport/getSensitiveUserReport',
|
||||
method: 'POST',
|
||||
column: [],
|
||||
beforeSearchFun: () => {
|
||||
tableStore.table.params.tempId = Template.value.id
|
||||
tableStore.table.params.lineId = dotList.value.id
|
||||
tableStore.table.params.startTime = datePickerRef.value.timeValue[0],
|
||||
tableStore.table.params.endTime = datePickerRef.value.timeValue[1],
|
||||
delete tableStore.table.params.searchBeginTime
|
||||
delete tableStore.table.params.searchEndTime
|
||||
delete tableStore.table.params.timeFlag
|
||||
},
|
||||
loadCallback: () => {
|
||||
console.log("🚀 ~ tableStore.table:", tableStore.table)
|
||||
|
||||
// tableStore.table.data.forEach((item: any) => {
|
||||
// item.data1 ? (item.data = JSON.parse(item.data1)) : ''
|
||||
// item.celldata.forEach((k: any) => {
|
||||
|
||||
// item.data[k.r][k.c].v ? (item.data[k.r][k.c] = k.v) : ''
|
||||
// })
|
||||
// })
|
||||
console.log("🚀 ~ tableStore.table:", tableStore.table)
|
||||
|
||||
setTimeout(() => {
|
||||
luckysheet.create({
|
||||
container: 'luckysheet',
|
||||
title: '', // 表 头名
|
||||
lang: 'zh', // 中文
|
||||
showtoolbar: false, // 是否显示工具栏
|
||||
showinfobar: false, // 是否显示顶部信息栏
|
||||
showsheetbar: true, // 是否显示底部sheet按钮
|
||||
allowEdit: false, // 禁止所有编辑操作(必填)
|
||||
data: tableStore.table.data
|
||||
// tableStore.table.data
|
||||
})
|
||||
}, 10)
|
||||
}
|
||||
})
|
||||
provide('tableStore', tableStore)
|
||||
tableStore.table.params.resourceType = 1
|
||||
tableStore.table.params.customType = 1
|
||||
const flag = ref(true)
|
||||
onMounted(() => {
|
||||
nextTick(() => {
|
||||
const dom = document.getElementById('navigation-splitpanes')
|
||||
if (dom && dom.offsetHeight > 0) {
|
||||
size.value = ((280 / (dom.offsetWidth - 7)) * 100)
|
||||
} else {
|
||||
// 设置默认值
|
||||
size.value = 20
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
// getTemplateByDept({ id: dictData.state.area[0].id }).then((res: any) => {
|
||||
// templatePolicy.value = res.data
|
||||
|
||||
|
||||
// })
|
||||
|
||||
const stencil = (val: any) => {
|
||||
templatePolicy.value = val.filter((item: any) => item.name != '稳态治理报表')
|
||||
Template.value = templatePolicy.value[0]
|
||||
reportForm.value = templatePolicy.value[0]?.reportForm
|
||||
|
||||
}
|
||||
|
||||
const changetype = (val: any) => {
|
||||
reportForm.value = val.reportForm
|
||||
}
|
||||
|
||||
const handleNodeClick = (data: any, node: any) => {
|
||||
|
||||
if (data?.level==4) {
|
||||
dotList.value = data
|
||||
setTimeout(() => {
|
||||
tableStore.index()
|
||||
}, 500)
|
||||
} else {
|
||||
tableStore.table.loading = false
|
||||
}
|
||||
}
|
||||
|
||||
const exportEvent = () => {
|
||||
exportExcel(luckysheet.getAllSheets(), '稳态报表')
|
||||
}
|
||||
</script>
|
||||
<style lang="scss">
|
||||
.splitpanes.default-theme .splitpanes__pane {
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
.box {
|
||||
padding: 10px;
|
||||
}
|
||||
</style>
|
||||
@@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<div>
|
||||
<el-dialog v-model="dialogVisible" title="设置" width="600">
|
||||
<el-dialog v-model="dialogVisible" title="自定义功能管理" width="600">
|
||||
<div style="display: flex; justify-content: end" class="mb10">
|
||||
<el-button icon="el-icon-Plus" type="primary" @click="add">新增</el-button>
|
||||
</div>
|
||||
@@ -52,12 +52,13 @@ import { defaultAttribute } from '@/components/table/defaultAttribute'
|
||||
import { getDashboardPageByUserId, deleteDashboard, activatePage } from '@/api/system-boot/csstatisticalset'
|
||||
import { useAdminInfo } from '@/stores/adminInfo'
|
||||
import { ElMessage, ElMessageBox } from 'element-plus'
|
||||
|
||||
import { useNavTabs } from '@/stores/navTabs'
|
||||
import { getMenu } from '@/utils/router'
|
||||
|
||||
const { push } = useRouter()
|
||||
const dialogVisible = ref(false)
|
||||
const route = useRouter()
|
||||
const navTabs = useNavTabs()
|
||||
const adminInfo = useAdminInfo()
|
||||
const pageList: any = ref([])
|
||||
|
||||
@@ -92,7 +93,7 @@ const beforeChange = (row: any): Promise<boolean> => {
|
||||
type: 'warning'
|
||||
})
|
||||
.then(() => {
|
||||
activatePage({ id: row.id, state: row.state == 0 ? 1 : 0 }).then((res: any) => {
|
||||
activatePage({ id: row.id, state: row.state == 0 ? 1 : 0 }).then( async(res: any) => {
|
||||
if (res.code == 'A0000') {
|
||||
ElMessage({
|
||||
type: 'success',
|
||||
@@ -101,7 +102,11 @@ const beforeChange = (row: any): Promise<boolean> => {
|
||||
}
|
||||
init()
|
||||
resolve(true)
|
||||
getMenu()
|
||||
await getMenu()
|
||||
await setTimeout(() => {
|
||||
navTabs.refresh()
|
||||
}, 1000)
|
||||
|
||||
})
|
||||
})
|
||||
.catch(() => {
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
<div class="default-main">
|
||||
<TableHeader :showSearch="false" v-show="flag">
|
||||
<template v-slot:select>
|
||||
<el-form-item label="日期">
|
||||
<el-form-item label="日期" v-show="layout?.length != 1">
|
||||
<DatePicker
|
||||
ref="datePickerRef"
|
||||
:nextFlag="false"
|
||||
@@ -13,7 +13,14 @@
|
||||
</template>
|
||||
<template v-slot:operation>
|
||||
<el-button type="primary" icon="el-icon-Edit" @click="editd">编辑</el-button>
|
||||
<el-button type="primary" icon="el-icon-Tools" @click="settings">设置</el-button>
|
||||
<el-button
|
||||
type="primary"
|
||||
icon="el-icon-Tools"
|
||||
@click="settings"
|
||||
v-if="router.currentRoute.value.name == 'dashboard/index'"
|
||||
>
|
||||
自定义功能管理
|
||||
</el-button>
|
||||
</template>
|
||||
</TableHeader>
|
||||
<GridLayout
|
||||
@@ -221,6 +228,10 @@ const fetchLayoutData = async () => {
|
||||
component: registerComponent(item.path)
|
||||
}))
|
||||
layoutCopy.value = JSON.parse(JSON.stringify(layout.value))
|
||||
if (layout.value.length == 1) {
|
||||
setZoom(layout.value[0])
|
||||
}
|
||||
|
||||
initRowHeight()
|
||||
} catch (error) {
|
||||
console.error('获取布局数据失败:', error)
|
||||
|
||||
@@ -21,21 +21,30 @@
|
||||
@load="onIframeLoad"
|
||||
></iframe>
|
||||
</div>
|
||||
|
||||
<el-card class="bottom-container" style="min-height: 230px">
|
||||
<!-- <div class="buttonBox">
|
||||
</div>
|
||||
<div class="bottom-container">
|
||||
<el-button
|
||||
type="primary"
|
||||
:icon="show ? 'el-icon-ArrowDownBold' : 'el-icon-ArrowUpBold'"
|
||||
@click="show = !show"
|
||||
style="width: 100%"
|
||||
>
|
||||
事件列表
|
||||
</el-button>
|
||||
<!-- <div class="buttonBox">
|
||||
<el-button type="primary" icon="el-icon-Aim" @click="reset">复位</el-button>
|
||||
</div> -->
|
||||
<div class="tableBox">
|
||||
<!-- <Table ref="tableRef" height="100%"></Table> -->
|
||||
<vxe-table border auto-resize height="100%" :data="tableData" ref="tableRef">
|
||||
|
||||
<transition name="table-fade">
|
||||
<div class="tableBox" v-if="show">
|
||||
<vxe-table border auto-resize height="230px" :data="tableData" ref="tableRef">
|
||||
<vxe-column type="seq" title="序号" align="center" width="80px"></vxe-column>
|
||||
<vxe-column field="date" align="center" title="时间" width="200px"></vxe-column>
|
||||
<vxe-column field="name" align="center" title="监测点名" width="200px"></vxe-column>
|
||||
<vxe-column field="address" align="center" title="事件描述"></vxe-column>
|
||||
</vxe-table>
|
||||
</div>
|
||||
</el-card>
|
||||
</transition>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
@@ -49,7 +58,7 @@ import { mainHeight } from '@/utils/layout'
|
||||
// const props = defineProps<{
|
||||
// project: { id: string; name: string } | null
|
||||
// }>()
|
||||
|
||||
const show = ref(false)
|
||||
const prop = defineProps({
|
||||
width: { type: [String, Number] },
|
||||
height: { type: [String, Number] },
|
||||
@@ -57,7 +66,9 @@ const prop = defineProps({
|
||||
timeValue: { type: Object }
|
||||
})
|
||||
|
||||
const tableData = ref()
|
||||
const tableData = ref([
|
||||
|
||||
])
|
||||
|
||||
// 在父页面中添加事件监听器
|
||||
window.addEventListener('message', function (event) {
|
||||
@@ -195,10 +206,10 @@ const sendKeysToIframe = (keyList: string[]) => {
|
||||
flex: 3.5;
|
||||
}
|
||||
|
||||
:deep(.el-card__body) {
|
||||
display: flex;
|
||||
padding: 10px;
|
||||
height: 100%;
|
||||
.bottom-container {
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
bottom: 0px;
|
||||
|
||||
.buttonBox {
|
||||
display: flex;
|
||||
@@ -212,4 +223,39 @@ const sendKeysToIframe = (keyList: string[]) => {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
.tableBox {
|
||||
/* 必须:初始高度/overflow 配合动画 */
|
||||
overflow: hidden;
|
||||
/* 与表格高度一致,保证展开后高度正确 */
|
||||
height: 230px;
|
||||
// margin-top: 10px;
|
||||
}
|
||||
|
||||
/* 过渡动画核心样式 */
|
||||
.table-fade-enter-from,
|
||||
.table-fade-leave-to {
|
||||
/* 关闭时:高度收为0 + 透明度0 */
|
||||
height: 0;
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.table-fade-enter-to,
|
||||
.table-fade-leave-from {
|
||||
/* 展开时:高度恢复 + 透明度1 */
|
||||
height: 230px;
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
/* 动画过渡时长 + 曲线(可自定义) */
|
||||
.table-fade-enter-active,
|
||||
.table-fade-leave-active {
|
||||
transition: all 0.3s ease;
|
||||
/* 防止动画过程中出现滚动条 */
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
/* 解决动画结束后瞬间闪回的问题 */
|
||||
.table-fade-enter-active {
|
||||
transition-delay: 0.05s;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -17,11 +17,20 @@
|
||||
<el-form-item label="页面排序" prop="sort">
|
||||
<el-input-number style="width: 100%" v-model.trim="form.sort" :min="0" :max="10000" :step="1" />
|
||||
</el-form-item>
|
||||
<!-- <el-form-item label="绑定页面">
|
||||
<el-select v-model="form.pagePath" filterable placeholder="请选择绑定页面" style="width: 100%" clearable>
|
||||
<el-option v-for="item in pageList" :key="item.path" :label="item.name" :value="item.path" />
|
||||
</el-select>
|
||||
</el-form-item> -->
|
||||
|
||||
<el-form-item label="是否激活">
|
||||
|
||||
<el-switch
|
||||
v-model="form.state"
|
||||
inline-prompt
|
||||
:disabled="form.pagePath == 'dashboard/index'"
|
||||
:active-value="1"
|
||||
:inactive-value="0"
|
||||
active-text="是"
|
||||
inactive-text="否"
|
||||
|
||||
/>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="备注" class="top">
|
||||
<el-input
|
||||
@@ -33,6 +42,7 @@
|
||||
v-model.trim="form.remark"
|
||||
></el-input>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item>
|
||||
<div style="width: 100%; display: flex; justify-content: end">
|
||||
<el-button type="primary" icon="el-icon-Check" @click="onSubmit">保存</el-button>
|
||||
@@ -135,14 +145,17 @@ import { addDashboard, updateDashboard, queryById } from '@/api/system-boot/csst
|
||||
import html2canvas from 'html2canvas'
|
||||
import { useRoute } from 'vue-router'
|
||||
import { getMenu } from '@/utils/router'
|
||||
|
||||
import { useNavTabs } from '@/stores/navTabs'
|
||||
// defineOptions({
|
||||
// name: 'cockpit/popup'
|
||||
// })
|
||||
const { go } = useRouter()
|
||||
const navTabs = useNavTabs()
|
||||
const { query } = useRoute()
|
||||
const router = useRouter()
|
||||
const height = mainHeight(108)
|
||||
const indicatorHeight = mainHeight(128)
|
||||
const height = mainHeight(148)
|
||||
const indicatorHeight = mainHeight(168)
|
||||
const rowHeight = ref(0)
|
||||
const pageList: any = ref([])
|
||||
const GridHeight = ref(0)
|
||||
@@ -153,7 +166,7 @@ const form: any = reactive({
|
||||
containerConfig: [],
|
||||
sort: '100',
|
||||
id: '',
|
||||
|
||||
state: 1,
|
||||
icon: '',
|
||||
pagePath: '',
|
||||
remark: '',
|
||||
@@ -209,6 +222,7 @@ const info = () => {
|
||||
form.sort = res.data.sort
|
||||
form.remark = res.data.remark
|
||||
form.id = res.data.id
|
||||
form.state = res.data.state
|
||||
form.icon = res.data.icon
|
||||
})
|
||||
} else {
|
||||
@@ -367,22 +381,28 @@ const onSubmit = () => {
|
||||
|
||||
if (valid) {
|
||||
if (form.id == '') {
|
||||
addDashboard({ ...form, containerConfig: JSON.stringify(layout.value), thumbnail: url }).then(
|
||||
(res: any) => {
|
||||
await addDashboard({ ...form, containerConfig: JSON.stringify(layout.value), thumbnail: url }).then(
|
||||
async (res: any) => {
|
||||
ElMessage.success('新增页面成功!')
|
||||
go(-1)
|
||||
getMenu()
|
||||
// go(-1)
|
||||
await getMenu()
|
||||
}
|
||||
)
|
||||
} else {
|
||||
updateDashboard({ ...form, containerConfig: JSON.stringify(layout.value), thumbnail: url }).then(
|
||||
(res: any) => {
|
||||
await updateDashboard({ ...form, containerConfig: JSON.stringify(layout.value), thumbnail: url }).then(
|
||||
async (res: any) => {
|
||||
ElMessage.success('修改页面成功!')
|
||||
go(-1)
|
||||
getMenu()
|
||||
// go(-1)
|
||||
await getMenu()
|
||||
}
|
||||
)
|
||||
}
|
||||
await setTimeout(() => {
|
||||
router.push({
|
||||
name: form.state == 1 ? form.pagePath : 'dashboard/index'
|
||||
})
|
||||
navTabs.refresh()
|
||||
}, 500)
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -414,8 +434,9 @@ onBeforeUnmount(() => {
|
||||
justify-content: space-between;
|
||||
.el-form-item {
|
||||
display: flex;
|
||||
flex: 1;
|
||||
align-items: center;
|
||||
// flex: 1;
|
||||
// align-items: center;
|
||||
width: 24%;
|
||||
.el-form-item__content {
|
||||
width: 100%;
|
||||
flex: 1;
|
||||
|
||||
Reference in New Issue
Block a user