20 changed files with 939 additions and 78 deletions
@ -1,59 +1,189 @@ |
|||||
import { createRouter, createWebHashHistory } from 'vue-router' |
import { createRouter, createWebHashHistory } from 'vue-router' |
||||
|
|
||||
const router = createRouter({ |
const router = createRouter({ |
||||
history: createWebHashHistory(import.meta.env.BASE_URL), |
history: createWebHashHistory(import.meta.env.BASE_URL), |
||||
routes: [ |
routes: [ |
||||
|
{ |
||||
|
path: '/', |
||||
|
name: 'home', |
||||
|
// 自动引导到 /editor
|
||||
|
component: () => import('@/views/HomeView.vue'), |
||||
|
children: [ |
||||
{ |
{ |
||||
path: '/', |
path: '/dashboard', |
||||
name: 'home', |
name: 'dashboard', |
||||
// 自动引导到 /editor
|
meta: { |
||||
redirect: '/editor' |
title: '仪表盘' |
||||
|
}, |
||||
|
component: () => import('@/views/dashboard/index.vue') |
||||
}, |
}, |
||||
{ |
{ |
||||
path: '/login', |
path: '/modelingSimulation', |
||||
name: 'login', |
name: 'modelingSimulation', |
||||
component: () => import('@/views/Login.vue') |
meta: { |
||||
|
title: '建模仿真控制平台' |
||||
|
}, |
||||
|
component: () => import('@/views/modelingSimulation/index.vue') |
||||
}, |
}, |
||||
{ |
{ |
||||
path: '/tp', |
path: '/taskManagement', |
||||
name: 'tp', |
name: 'taskManagement', |
||||
component: () => import('@/components/ThreePerfView.vue') |
children:[ |
||||
|
{ |
||||
|
path: '/taskQuery', |
||||
|
name: 'taskQuery', |
||||
|
meta: { |
||||
|
title: '任务查询' |
||||
|
}, |
||||
|
component: () => import('@/views/taskManagement/taskQuery.vue') |
||||
|
}, |
||||
|
{ |
||||
|
path: '/automatedPresentation', |
||||
|
name: 'automatedPresentation', |
||||
|
meta: { |
||||
|
title: '自动演示管理' |
||||
|
}, |
||||
|
component: () => import('@/views/taskManagement/automatedPresentation.vue') |
||||
|
} |
||||
|
] |
||||
}, |
}, |
||||
{ |
{ |
||||
path: '/editor', |
path: '/log', |
||||
name: 'editor', |
name: 'log', |
||||
// component: HomeView,
|
children:[ |
||||
component: () => import('../editor/ModelMain.vue') |
{ |
||||
|
path: '/upstream', |
||||
|
name: 'upstream', |
||||
|
meta: { |
||||
|
title: '上游接口日志' |
||||
|
}, |
||||
|
component: () => import('@/views/log/upstream.vue') |
||||
|
}, |
||||
|
{ |
||||
|
path: '/device', |
||||
|
name: 'device', |
||||
|
meta: { |
||||
|
title: '设备报文日志' |
||||
|
}, |
||||
|
component: () => import('@/views/log/device.vue') |
||||
|
} |
||||
|
] |
||||
}, |
}, |
||||
{ |
{ |
||||
path: '/about', |
path: '/device', |
||||
name: 'about', |
name: 'device', |
||||
// route level code-splitting
|
children:[ |
||||
// this generates a separate chunk (About.[hash].js) for this route
|
{ |
||||
// which is lazy-loaded when the route is visited.
|
path: '/points', |
||||
component: () => import('../views/AboutView.vue') |
name: 'points', |
||||
|
meta: { |
||||
|
title: '点位管理' |
||||
|
}, |
||||
|
component: () => import('@/views/device/points.vue') |
||||
|
}, |
||||
|
{ |
||||
|
path: '/locations', |
||||
|
name: 'locations', |
||||
|
meta: { |
||||
|
title: '货位管理' |
||||
|
}, |
||||
|
component: () => import('@/views/device/locations.vue') |
||||
|
}, |
||||
|
{ |
||||
|
path: '/vehicles', |
||||
|
name: 'vehicles', |
||||
|
meta: { |
||||
|
title: '车辆管理' |
||||
|
}, |
||||
|
component: () => import('@/views/device/vehicles.vue') |
||||
|
}, |
||||
|
{ |
||||
|
path: '/chargers', |
||||
|
name: 'chargers', |
||||
|
meta: { |
||||
|
title: '充电位管理' |
||||
|
}, |
||||
|
component: () => import('@/views/device/chargers.vue') |
||||
|
} |
||||
|
] |
||||
}, |
}, |
||||
|
|
||||
{ |
{ |
||||
path: '/DataForm01', |
path: '/inventory', |
||||
name: 'DataForm01', |
name: 'inventory', |
||||
component: () => import('@/pages/DataForm01.vue') |
children:[ |
||||
|
{ |
||||
|
path: '/query', |
||||
|
name: 'query', |
||||
|
meta: { |
||||
|
title: '库存查询' |
||||
|
}, |
||||
|
component: () => import('@/views/inventory/query.vue') |
||||
|
}, |
||||
|
{ |
||||
|
path: '/account', |
||||
|
name: 'account', |
||||
|
meta: { |
||||
|
title: '帐页查询' |
||||
|
}, |
||||
|
component: () => import('@/views/inventory/account.vue') |
||||
|
} |
||||
|
] |
||||
}, |
}, |
||||
{ |
{ |
||||
path: '/JsDemo', |
path: '/user', |
||||
name: 'JsDemo', |
name: 'user', |
||||
component: () => import('@/pages/JsDemo.vue') |
children:[ |
||||
}, |
{ |
||||
] |
path: '/users', |
||||
}) |
name: 'users', |
||||
|
meta: { |
||||
|
title: '用户管理' |
||||
|
}, |
||||
|
component: () => import('@/views/user/users.vue') |
||||
|
}, |
||||
|
{ |
||||
|
path: '/roles', |
||||
|
name: 'roles', |
||||
|
meta: { |
||||
|
title: '角色管理' |
||||
|
}, |
||||
|
component: () => import('@/views/user/roles.vue') |
||||
|
} |
||||
|
] |
||||
|
} |
||||
|
] |
||||
|
}, |
||||
|
{ |
||||
|
path: '/tp', |
||||
|
name: 'tp', |
||||
|
component: () => import('@/components/ThreePerfView.vue') |
||||
|
}, |
||||
|
{ |
||||
|
path: '/editor', |
||||
|
name: 'editor', |
||||
|
// component: HomeView,
|
||||
|
component: () => import('../editor/ModelMain.vue') |
||||
|
}, |
||||
|
{ |
||||
|
path: '/about', |
||||
|
name: 'about', |
||||
|
// route level code-splitting
|
||||
|
// this generates a separate chunk (About.[hash].js) for this route
|
||||
|
// which is lazy-loaded when the route is visited.
|
||||
|
component: () => import('../views/AboutView.vue') |
||||
|
}, |
||||
|
|
||||
router.beforeEach((to, from) => { |
{ |
||||
if (to.name !== "login" && !window.globalConfig.user) { |
path: '/DataForm01', |
||||
return { name: "login" }; |
name: 'DataForm01', |
||||
} |
component: () => import('@/pages/DataForm01.vue') |
||||
// if (to.name === "login" && window.globalConfig.user) {
|
}, |
||||
// return { name: "home" };
|
{ |
||||
// }
|
path: '/JsDemo', |
||||
|
name: 'JsDemo', |
||||
|
component: () => import('@/pages/JsDemo.vue') |
||||
|
}, |
||||
|
] |
||||
}) |
}) |
||||
|
|
||||
export default router |
export default router |
||||
|
|||||
@ -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> |
<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> |
</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(() => { |
<script setup> |
||||
|
import { ref, computed, onMounted} from 'vue' |
||||
// 测试 lodash |
import {useRoute} from "vue-router"; |
||||
const arr = [1, 2, 3] |
import Sidebar from './Sidebar.vue' |
||||
console.log(_.reverse(arr)) |
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() |
function toggleCollapse() { |
||||
const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000) |
collapsed.value = !collapsed.value |
||||
|
} |
||||
|
|
||||
const renderer = new THREE.WebGLRenderer() |
// 判断是否是移动设备 |
||||
threeDomElement.value.appendChild(renderer.domElement) |
function checkIsMobile() { |
||||
renderer.setSize(window.innerWidth, window.innerHeight) |
isMobile.value = window.innerWidth < 768 |
||||
|
if (isMobile.value) { |
||||
|
collapsed.value = true // 强制移动端默认关闭 |
||||
|
} |
||||
|
} |
||||
|
|
||||
const geometry = new THREE.BoxGeometry() |
onMounted(() => { |
||||
const material = new THREE.MeshBasicMaterial({ color: 0x00ff00 }) |
checkIsMobile() |
||||
const cube = new THREE.Mesh(geometry, material) |
window.addEventListener('resize', checkIsMobile) |
||||
scene.add(cube) |
}) |
||||
|
|
||||
camera.position.z = 5 |
</script> |
||||
|
|
||||
function animate() { |
<style scoped lang="less"> |
||||
requestAnimationFrame(animate) |
.layout { |
||||
cube.rotation.x += 0.01 |
height: 100vh; |
||||
cube.rotation.y += 0.01 |
|
||||
renderer.render(scene, camera) |
|
||||
} |
} |
||||
|
.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 |
.el-aside[style*='transform: translateX(0px)'] { |
||||
const gui = new GUI() |
transform: translateX(0); |
||||
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() |
|
||||
}) |
|
||||
|
|
||||
</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