20 changed files with 939 additions and 78 deletions
@ -0,0 +1,74 @@ |
|||
<template> |
|||
<div class="header-wrapper"> |
|||
<div class="left"> |
|||
<div class="logo"><img :src="Logo" alt="" style="height: 30px;width: 169px"></div> |
|||
<span class="menu-icon" @click="handleToggle"> |
|||
<!-- 使用 props.collapsed --> |
|||
<component v-if="!props.collapsed" :is="renderIcon('antd MenuFoldOutlined')"></component> |
|||
<component v-else :is="renderIcon('antd MenuUnfoldOutlined')"></component> |
|||
</span> |
|||
</div> |
|||
<div class="user"> |
|||
<span> |
|||
<component :is="renderIcon('element User')"></component> |
|||
</span> |
|||
</div> |
|||
</div> |
|||
</template> |
|||
|
|||
<script setup> |
|||
import {ref} from 'vue' |
|||
import { renderIcon } from '@/utils/webutils.js' |
|||
import Logo from '@/assets/images/logo.png' |
|||
// 接收 props |
|||
const props = defineProps({ |
|||
isMobile: Boolean, |
|||
collapsed: Boolean // 这个是父组件传进来的菜单状态 |
|||
}) |
|||
const emit = defineEmits(['toggle-collapse']) |
|||
function handleToggle() { |
|||
emit('toggle-collapse') |
|||
} |
|||
</script> |
|||
<style lang="less"> |
|||
.header-wrapper { |
|||
display: flex; |
|||
flex-direction: row; |
|||
overflow: hidden; |
|||
justify-content: space-between; |
|||
align-items: center; |
|||
height: 100%; |
|||
.left{ |
|||
flex:1; |
|||
display: flex; |
|||
flex-direction: row; |
|||
.logo { |
|||
display: flex; |
|||
align-items: center; |
|||
margin: 0 20px 0 10px; |
|||
} |
|||
.menu-icon{ |
|||
display: inline-flex; |
|||
padding:10px; |
|||
cursor: pointer; |
|||
.el-icon{ |
|||
font-size: 20px; |
|||
color:#fff; |
|||
} |
|||
} |
|||
} |
|||
.user { |
|||
display: flex; |
|||
flex-direction: row; |
|||
align-items: center; |
|||
|
|||
& > span { |
|||
display: inline-flex; |
|||
padding: 5px; |
|||
background: #f4c521; |
|||
border-radius: 15px; |
|||
color: #fff; |
|||
} |
|||
} |
|||
} |
|||
</style> |
|||
@ -1,50 +1,126 @@ |
|||
<template> |
|||
<div id="sence" ref="threeDomElement" tabindex="1"></div> |
|||
<div class="layout"> |
|||
<el-container style="height: 100%;overflow: hidden;"> |
|||
<!-- 头部 --> |
|||
<el-header class="header"> |
|||
<Header @toggle-collapse="toggleCollapse" :collapsed="collapsed" :is-mobile="isMobile" /> |
|||
</el-header> |
|||
<el-container style="height: 100%;overflow: hidden;"> |
|||
<!-- 侧边栏 --> |
|||
<el-aside v-show="!isMobile || !collapsed" :width="collapsed ? '64px' : '200px'" class="sidebar"> |
|||
<Sidebar :collapsed="collapsed" /> |
|||
</el-aside> |
|||
<!-- 内容 --> |
|||
<el-main class="main"> |
|||
<el-breadcrumb separator="/"> |
|||
<el-breadcrumb-item> |
|||
{{route.meta?.title}} |
|||
</el-breadcrumb-item> |
|||
</el-breadcrumb> |
|||
<div class="content"> |
|||
<router-view /> |
|||
</div> |
|||
</el-main> |
|||
</el-container> |
|||
</el-container> |
|||
</div> |
|||
<!-- 移动端遮罩层 --> |
|||
<div v-if="isMobile" v-show="!collapsed" class="mask" @click="toggleCollapse"></div> |
|||
</template> |
|||
<script setup> |
|||
import { onMounted, ref } from 'vue' |
|||
import * as THREE from 'three' |
|||
import { GUI } from 'dat.gui' |
|||
import _ from 'lodash' |
|||
|
|||
const threeDomElement = ref(null) |
|||
|
|||
onMounted(() => { |
|||
|
|||
// 测试 lodash |
|||
const arr = [1, 2, 3] |
|||
console.log(_.reverse(arr)) |
|||
<script setup> |
|||
import { ref, computed, onMounted} from 'vue' |
|||
import {useRoute} from "vue-router"; |
|||
import Sidebar from './Sidebar.vue' |
|||
import Header from './Header.vue' |
|||
const route = useRoute() |
|||
console.log(route.meta?.title) |
|||
const collapsed = ref(false) |
|||
const isMobile = ref(false) |
|||
|
|||
// 测试 Three.js |
|||
const scene = new THREE.Scene() |
|||
const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000) |
|||
// 切换菜单展开/收起 |
|||
function toggleCollapse() { |
|||
collapsed.value = !collapsed.value |
|||
} |
|||
|
|||
const renderer = new THREE.WebGLRenderer() |
|||
threeDomElement.value.appendChild(renderer.domElement) |
|||
renderer.setSize(window.innerWidth, window.innerHeight) |
|||
// 判断是否是移动设备 |
|||
function checkIsMobile() { |
|||
isMobile.value = window.innerWidth < 768 |
|||
if (isMobile.value) { |
|||
collapsed.value = true // 强制移动端默认关闭 |
|||
} |
|||
} |
|||
|
|||
const geometry = new THREE.BoxGeometry() |
|||
const material = new THREE.MeshBasicMaterial({ color: 0x00ff00 }) |
|||
const cube = new THREE.Mesh(geometry, material) |
|||
scene.add(cube) |
|||
onMounted(() => { |
|||
checkIsMobile() |
|||
window.addEventListener('resize', checkIsMobile) |
|||
}) |
|||
|
|||
camera.position.z = 5 |
|||
</script> |
|||
|
|||
function animate() { |
|||
requestAnimationFrame(animate) |
|||
cube.rotation.x += 0.01 |
|||
cube.rotation.y += 0.01 |
|||
renderer.render(scene, camera) |
|||
<style scoped lang="less"> |
|||
.layout { |
|||
height: 100vh; |
|||
} |
|||
.header { |
|||
height: 50px; |
|||
background: #545c64; |
|||
flex-shrink: 0; |
|||
padding:0 10px; |
|||
} |
|||
.sidebar { |
|||
transition: width 0.3s ease; |
|||
} |
|||
.main { |
|||
padding: 10px; |
|||
background: #f6f7fb; |
|||
display: flex; |
|||
flex-direction: column; |
|||
overflow: hidden; |
|||
width: 100%; |
|||
height: 100%; |
|||
.el-breadcrumb{ |
|||
margin:0 0 10px 10px; |
|||
} |
|||
&>.content{ |
|||
flex: 1; |
|||
overflow: hidden; |
|||
} |
|||
} |
|||
.mask { |
|||
position: fixed; |
|||
top: 0; |
|||
left: 0; |
|||
right: 0; |
|||
bottom: 0; |
|||
background: rgba(0,0,0,.4); |
|||
z-index: 999; |
|||
} |
|||
@media (max-width: 768px) { |
|||
.layout { |
|||
flex-direction: column; |
|||
} |
|||
.el-aside { |
|||
position: fixed; |
|||
top: 0; |
|||
left: 0; |
|||
height: 100%; |
|||
z-index: 1000; |
|||
transform: translateX(0); |
|||
transition: transform 0.6s ease; |
|||
background: #fff; |
|||
|
|||
animate() |
|||
&.open { |
|||
transform: translateX(0); |
|||
} |
|||
} |
|||
|
|||
// 测试 Dat.GUI |
|||
const gui = new GUI() |
|||
const cubeFolder = gui.addFolder('Cube') |
|||
cubeFolder.add(cube.rotation, 'x', 0, Math.PI * 2) |
|||
cubeFolder.add(cube.rotation, 'y', 0, Math.PI * 2) |
|||
cubeFolder.open() |
|||
}) |
|||
.el-aside[style*='transform: translateX(0px)'] { |
|||
transform: translateX(0); |
|||
} |
|||
|
|||
</script> |
|||
.el-aside[style*='transform: translateX(-100%)'] { |
|||
transform: translateX(-100%); |
|||
} |
|||
} |
|||
</style> |
|||
|
|||
@ -0,0 +1,85 @@ |
|||
<template> |
|||
<el-menu |
|||
default-active="dashboard" |
|||
class="menu" |
|||
:collapse="collapsed" |
|||
:collapse-transition="false" |
|||
router |
|||
> |
|||
<el-menu-item index="/dashboard"> |
|||
<component :is="renderIcon('antd DashboardOutlined')"></component> |
|||
<!-- antd BarChartOutlined--> |
|||
<span>仪表盘</span> |
|||
</el-menu-item> |
|||
<el-menu-item index="/modelingSimulation"> |
|||
<component :is="renderIcon('antd BankFilled')"></component> |
|||
<span>建模仿真控制平台</span> |
|||
</el-menu-item> |
|||
<el-sub-menu index="/taskManagement"> |
|||
<template #title> |
|||
<component :is="renderIcon('fa Tasks')"></component><span>任务管理</span></template> |
|||
<el-menu-item index="/taskQuery"> |
|||
<component :is="renderIcon('antd FileSearchOutlined')"></component>任务查询</el-menu-item> |
|||
<el-menu-item index="/automatedPresentation"> |
|||
<component :is="renderIcon('fa ChalkboardTeacher')"></component>自动演示管理</el-menu-item> |
|||
</el-sub-menu> |
|||
<el-sub-menu index="/log"> |
|||
<template #title> |
|||
<component :is="renderIcon('antd FileSearchOutlined')"></component> |
|||
<span>日志查询</span> |
|||
</template> |
|||
<el-menu-item index="/upstream"> |
|||
<component :is="renderIcon('element Memo')"></component>上游接口日志</el-menu-item> |
|||
<el-menu-item index="/device"> |
|||
<component :is="renderIcon('element MessageBox')"></component>设备报文日志</el-menu-item> |
|||
</el-sub-menu> |
|||
<el-sub-menu index="/device"> |
|||
<template #title> |
|||
<component :is="renderIcon('antd DatabaseOutlined')"></component> |
|||
<span>设备管理</span> |
|||
</template> |
|||
<el-menu-item index="/points"> |
|||
<component :is="renderIcon('antd EnvironmentOutlined')"></component>点位管理</el-menu-item> |
|||
<el-menu-item index="/locations"> |
|||
<component :is="renderIcon('antd BorderOuterOutlined')"></component>货位管理</el-menu-item> |
|||
<el-menu-item index="/vehicles"> |
|||
<component :is="renderIcon('antd CarOutlined')"></component>车辆管理</el-menu-item> |
|||
<el-menu-item index="/chargers"> |
|||
<component :is="renderIcon('antd ThunderboltOutlined')"></component>充电位管理</el-menu-item> |
|||
</el-sub-menu> |
|||
<el-sub-menu index="/inventory"> |
|||
<template #title> |
|||
<component :is="renderIcon('fa EditRegular')"></component> |
|||
<span>库存管理</span> |
|||
</template> |
|||
<el-menu-item index="/query"> |
|||
<component :is="renderIcon('antd FileSearchOutlined')"></component>库存查询</el-menu-item> |
|||
<el-menu-item index="/account"> |
|||
<component :is="renderIcon('antd SearchOutlined')"></component>帐页查询</el-menu-item> |
|||
</el-sub-menu> |
|||
<el-sub-menu index="/user"> |
|||
<template #title> |
|||
<component :is="renderIcon('element User')"></component> |
|||
<span>用户管理</span> |
|||
</template> |
|||
<el-menu-item index="/users"> |
|||
<component :is="renderIcon('antd UserOutlined')"></component>用户管理</el-menu-item> |
|||
<el-menu-item index="/roles"> |
|||
<component :is="renderIcon('antd UserSwitchOutlined')"></component>角色管理</el-menu-item> |
|||
</el-sub-menu> |
|||
</el-menu> |
|||
</template> |
|||
|
|||
<script setup> |
|||
import { renderIcon } from '@/utils/webutils.js' |
|||
defineProps({ |
|||
collapsed: Boolean |
|||
}) |
|||
</script> |
|||
|
|||
<style scoped> |
|||
.menu { |
|||
border-right: none; |
|||
height: 100%; |
|||
} |
|||
</style> |
|||
@ -0,0 +1,58 @@ |
|||
<template> |
|||
<div ref="chart" class="chart"></div> |
|||
</template> |
|||
<script setup> |
|||
import * as echarts from 'echarts'; |
|||
import { ref, onMounted, watch,nextTick} from 'vue'; |
|||
import { useResizeObserver } from '@vueuse/core'; |
|||
const props=defineProps({ |
|||
options:{ |
|||
type:Object, |
|||
required:true |
|||
} |
|||
}) |
|||
const chart =ref(null); |
|||
let chartInstance=null;//用来定义图表实例 |
|||
|
|||
//初始化图表 |
|||
const initChart=()=>{ |
|||
if(chartInstance) chartInstance.dispose() |
|||
chartInstance=echarts.init(chart.value) |
|||
chartInstance.setOption(props.options) |
|||
} |
|||
|
|||
// 更新图表 |
|||
const updateChart = (newOptions) => { |
|||
if (chartInstance) { |
|||
chartInstance.setOption(newOptions); |
|||
} |
|||
}; |
|||
|
|||
//监听窗口大小变化,并调整图表大小 |
|||
const handleResize=()=>{ |
|||
if(chartInstance) chartInstance.resize(); |
|||
} |
|||
|
|||
//当options改变时更新图表 |
|||
watch(()=>props.options,(newOptions)=>{ |
|||
if(chartInstance) chartInstance.setOption(newOptions, true) |
|||
},{ deep: true }) |
|||
|
|||
|
|||
onMounted(() => { |
|||
nextTick(() => { |
|||
initChart(); |
|||
useResizeObserver(chart, handleResize); |
|||
}); |
|||
}); |
|||
|
|||
// 暴露方法给父组件 |
|||
defineExpose({ |
|||
updateChart |
|||
}); |
|||
</script> |
|||
<style scoped> |
|||
.chart { |
|||
height: 100%; |
|||
} |
|||
</style> |
|||
@ -0,0 +1,281 @@ |
|||
<template> |
|||
<div class="dashboard"> |
|||
<div class="stat-row"> |
|||
<div class="stat-card purple"> |
|||
<div class="title">穿梭板数</div> |
|||
<div class="number">11</div> |
|||
</div> |
|||
<div class="stat-card blue"> |
|||
<div class="title">提升机数</div> |
|||
<div class="number">16</div> |
|||
</div> |
|||
<div class="stat-card red"> |
|||
<div class="title">使用库位数/总库位数</div> |
|||
<div class="number">1864/8404</div> |
|||
</div> |
|||
<div class="stat-card green"> |
|||
<div class="title">存储率</div> |
|||
<div class="number">22%</div> |
|||
</div> |
|||
</div> |
|||
<el-row :gutter="10"> |
|||
<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12"> |
|||
<el-card class="chart-card"> |
|||
<template #header> |
|||
<div class="card-header"> |
|||
<span>设备任务状态占比</span> |
|||
</div> |
|||
</template> |
|||
<div class="chart-wrap"> |
|||
<EChartWrapper :options="option1"></EChartWrapper> |
|||
</div> |
|||
</el-card> |
|||
</el-col> |
|||
<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12"> |
|||
<el-card class="chart-card"> |
|||
<template #header> |
|||
<div class="card-header"> |
|||
<span>业务任务趋势</span> |
|||
</div> |
|||
</template> |
|||
<div class="chart-wrap"> |
|||
<EChartWrapper :options="option2"></EChartWrapper> |
|||
</div> |
|||
</el-card> |
|||
</el-col> |
|||
</el-row> |
|||
</div> |
|||
</template> |
|||
<script setup> |
|||
import * as echarts from 'echarts'; |
|||
import { ref, onMounted, watch,nextTick} from 'vue'; |
|||
import EChartWrapper from './EChartWrapper.vue' |
|||
const option1=ref({ |
|||
tooltip: { |
|||
trigger: 'axis', |
|||
formatter: (params) => { |
|||
// params 是一个数组,包含每个系列的数据 |
|||
let result = `${params[0].name}<br/>`; // 显示 x 轴的名称 |
|||
params.forEach((item) => { |
|||
result += `${item.seriesName}: ${item.value || 0}单<br/>`; |
|||
}); |
|||
return result; |
|||
} |
|||
}, |
|||
grid: { |
|||
left: '3%', |
|||
right: '4%', |
|||
bottom: '3%', |
|||
top: '3%', |
|||
containLabel: true |
|||
}, |
|||
xAxis: { |
|||
type: 'category', |
|||
data: (() => { |
|||
const dates = [] |
|||
for (let i = 6; i >= 0; i--) { |
|||
const date = new Date() |
|||
date.setDate(date.getDate() - i) |
|||
dates.push(date.toLocaleDateString('zh-CN', { month: '2-digit', day: '2-digit' })) |
|||
} |
|||
return dates |
|||
})() |
|||
}, |
|||
yAxis: { |
|||
type: 'value', |
|||
name: '单', |
|||
nameTextStyle: { |
|||
padding: [0, 0, 0, 30] |
|||
}, |
|||
}, |
|||
series: [{ |
|||
name: '1F', |
|||
type: 'bar', |
|||
data: [120, 150, 80, 160, 10, 270, 110], |
|||
itemStyle: { |
|||
color: '#409EFF' |
|||
}, |
|||
},{ |
|||
name: '2F', |
|||
type: 'bar', |
|||
data: [110, 50, 10, 160, 140, 120, 130], |
|||
itemStyle: { |
|||
color: '#1bc042' |
|||
}, |
|||
},{ |
|||
name: '3F', |
|||
type: 'bar', |
|||
data: [20, 100, 120, 160, 40, 170, 100], |
|||
itemStyle: { |
|||
color: '#ffa640' |
|||
}, |
|||
}] |
|||
}) |
|||
const option2=ref({ |
|||
tooltip: { |
|||
trigger: 'axis', |
|||
formatter: (params) => { |
|||
// params 是一个数组,包含每个系列的数据 |
|||
let result = `${params[0].name}<br/>`; // 显示 x 轴的名称 |
|||
params.forEach((item) => { |
|||
result += `${item.seriesName}: ${item.value || 0}单<br/>`; |
|||
}); |
|||
return result; |
|||
} |
|||
}, |
|||
grid: { |
|||
left: '3%', |
|||
right: '4%', |
|||
bottom: '3%', |
|||
top: '3%', |
|||
containLabel: true |
|||
}, |
|||
xAxis: { |
|||
type: 'category', |
|||
data: (() => { |
|||
const dates = [] |
|||
for (let i = 6; i >= 0; i--) { |
|||
const date = new Date() |
|||
date.setDate(date.getDate() - i) |
|||
dates.push(date.toLocaleDateString('zh-CN', { month: '2-digit', day: '2-digit' })) |
|||
} |
|||
return dates |
|||
})() |
|||
}, |
|||
yAxis: { |
|||
type: 'value', |
|||
name: '单', |
|||
nameTextStyle: { |
|||
padding: [0, 0, 0, 30] |
|||
}, |
|||
}, |
|||
series: [{ |
|||
name: '1F', |
|||
type: 'bar', |
|||
data: [120, 150, 80, 160, 10, 270, 110], |
|||
itemStyle: { |
|||
color: '#409EFF' |
|||
}, |
|||
},{ |
|||
name: '2F', |
|||
type: 'bar', |
|||
data: [110, 50, 10, 160, 140, 120, 130], |
|||
itemStyle: { |
|||
color: '#1bc042' |
|||
}, |
|||
},{ |
|||
name: '3F', |
|||
type: 'bar', |
|||
data: [20, 100, 120, 160, 40, 170, 100], |
|||
itemStyle: { |
|||
color: '#ffa640' |
|||
}, |
|||
}] |
|||
}) |
|||
</script> |
|||
<style lang="less"> |
|||
.dashboard{ |
|||
height: 100%; |
|||
overflow-x: hidden; |
|||
overflow-y: auto; |
|||
.stat-row{ |
|||
height: 120px; |
|||
display: flex; |
|||
flex-direction: row; |
|||
margin-bottom: 20px; |
|||
gap: 20px; |
|||
.stat-card { |
|||
flex:1; |
|||
height: 120px; |
|||
padding: 20px; |
|||
border-radius: 8px; |
|||
color: #fff; |
|||
display: flex; |
|||
flex-direction: column; |
|||
justify-content: space-between; |
|||
align-items: center; |
|||
box-shadow: 0 2px 12px 0 rgba(0,0,0,0.1); |
|||
transition: all 0.3s; |
|||
|
|||
&:hover { |
|||
transform: translateY(-5px); |
|||
box-shadow: 0 5px 15px 0 rgba(0,0,0,0.15); |
|||
} |
|||
|
|||
.title { |
|||
font-size: 14px; |
|||
opacity: 0.9; |
|||
} |
|||
|
|||
.number { |
|||
font-size: 28px; |
|||
font-weight: bold; |
|||
margin-top: 10px; |
|||
} |
|||
|
|||
&.purple { |
|||
background: linear-gradient(135deg, #5e71fc 0%, #aa7bfc 100%); |
|||
} |
|||
|
|||
&.blue { |
|||
background: linear-gradient(135deg, #3da2f5 0%, #6885fa 100%); |
|||
} |
|||
|
|||
&.red { |
|||
background: linear-gradient(135deg, #ea6274 0%, #f09165 100%); |
|||
} |
|||
|
|||
&.green { |
|||
background: linear-gradient(135deg, #46c0ab 0%, #7ceba6 100%); |
|||
} |
|||
|
|||
&.orange { |
|||
background: linear-gradient(135deg, #efa03b 0%, #fad46f 100%); |
|||
} |
|||
} |
|||
} |
|||
.chart-card { |
|||
background-color: #fff; |
|||
border-radius: 4px; |
|||
|
|||
:deep(.el-card__header){ |
|||
padding:0; |
|||
border-bottom: 0; |
|||
} |
|||
|
|||
.card-header { |
|||
display: flex; |
|||
justify-content: space-between; |
|||
align-items: center; |
|||
padding: 12px 20px; |
|||
|
|||
span { |
|||
font-size: 14px; |
|||
} |
|||
} |
|||
|
|||
.chart { |
|||
height: 300px; |
|||
} |
|||
:deep(.date-picker){ |
|||
width: 100px; |
|||
} |
|||
|
|||
.chart-wrap { |
|||
height: 300px; |
|||
} |
|||
} |
|||
.el-card__header{ |
|||
padding:0; |
|||
border: none; |
|||
} |
|||
} |
|||
@media (max-width: 768px) { |
|||
.stat-row { |
|||
overflow: auto; |
|||
} |
|||
.el-col-xs-24 + .el-col-xs-24{ |
|||
margin-top:20px; |
|||
} |
|||
} |
|||
</style> |
|||
@ -0,0 +1,12 @@ |
|||
<template> |
|||
<div class="modeling-simulation"> |
|||
chargers |
|||
</div> |
|||
</template> |
|||
<script setup> |
|||
</script> |
|||
<style lang="less"> |
|||
.dashboard{ |
|||
|
|||
} |
|||
</style> |
|||
@ -0,0 +1,12 @@ |
|||
<template> |
|||
<div class="modeling-simulation"> |
|||
locations |
|||
</div> |
|||
</template> |
|||
<script setup> |
|||
</script> |
|||
<style lang="less"> |
|||
.dashboard{ |
|||
|
|||
} |
|||
</style> |
|||
@ -0,0 +1,12 @@ |
|||
<template> |
|||
<div class="modeling-simulation"> |
|||
points |
|||
</div> |
|||
</template> |
|||
<script setup> |
|||
</script> |
|||
<style lang="less"> |
|||
.dashboard{ |
|||
|
|||
} |
|||
</style> |
|||
@ -0,0 +1,12 @@ |
|||
<template> |
|||
<div class="modeling-simulation"> |
|||
vehicles |
|||
</div> |
|||
</template> |
|||
<script setup> |
|||
</script> |
|||
<style lang="less"> |
|||
.dashboard{ |
|||
|
|||
} |
|||
</style> |
|||
@ -0,0 +1,12 @@ |
|||
<template> |
|||
<div class="dashboard"> |
|||
dashboard |
|||
</div> |
|||
</template> |
|||
<script setup> |
|||
</script> |
|||
<style lang="less"> |
|||
.dashboard{ |
|||
|
|||
} |
|||
</style> |
|||
@ -0,0 +1,12 @@ |
|||
<template> |
|||
<div class="modeling-simulation"> |
|||
query |
|||
</div> |
|||
</template> |
|||
<script setup> |
|||
</script> |
|||
<style lang="less"> |
|||
.dashboard{ |
|||
|
|||
} |
|||
</style> |
|||
@ -0,0 +1,12 @@ |
|||
<template> |
|||
<div class="modeling-simulation"> |
|||
device |
|||
</div> |
|||
</template> |
|||
<script setup> |
|||
</script> |
|||
<style lang="less"> |
|||
.dashboard{ |
|||
|
|||
} |
|||
</style> |
|||
@ -0,0 +1,12 @@ |
|||
<template> |
|||
<div class="modeling-simulation"> |
|||
upstream |
|||
</div> |
|||
</template> |
|||
<script setup> |
|||
</script> |
|||
<style lang="less"> |
|||
.dashboard{ |
|||
|
|||
} |
|||
</style> |
|||
@ -0,0 +1,12 @@ |
|||
<template> |
|||
<div class="modeling-simulation"> |
|||
modelingSimulation |
|||
</div> |
|||
</template> |
|||
<script setup> |
|||
</script> |
|||
<style lang="less"> |
|||
.dashboard{ |
|||
|
|||
} |
|||
</style> |
|||
@ -0,0 +1,12 @@ |
|||
<template> |
|||
<div class="modeling-simulation"> |
|||
automatedPresentation.vue |
|||
</div> |
|||
</template> |
|||
<script setup> |
|||
</script> |
|||
<style lang="less"> |
|||
.dashboard{ |
|||
|
|||
} |
|||
</style> |
|||
@ -0,0 +1,12 @@ |
|||
<template> |
|||
<div class="modeling-simulation"> |
|||
taskQuery.vue |
|||
</div> |
|||
</template> |
|||
<script setup> |
|||
</script> |
|||
<style lang="less"> |
|||
.dashboard{ |
|||
|
|||
} |
|||
</style> |
|||
@ -0,0 +1,12 @@ |
|||
<template> |
|||
<div class="roles"> |
|||
roles |
|||
</div> |
|||
</template> |
|||
<script setup> |
|||
</script> |
|||
<style lang="less"> |
|||
.dashboard{ |
|||
|
|||
} |
|||
</style> |
|||
@ -0,0 +1,12 @@ |
|||
<template> |
|||
<div class="dashboard"> |
|||
users |
|||
</div> |
|||
</template> |
|||
<script setup> |
|||
</script> |
|||
<style lang="less"> |
|||
.dashboard{ |
|||
|
|||
} |
|||
</style> |
|||
Loading…
Reference in new issue