723第一次提交
This commit is contained in:
commit
283eedbcaa
|
@ -0,0 +1,14 @@
|
|||
/* eslint-env node */
|
||||
require('@rushstack/eslint-patch/modern-module-resolution')
|
||||
|
||||
module.exports = {
|
||||
root: true,
|
||||
'extends': [
|
||||
'plugin:vue/vue3-essential',
|
||||
'eslint:recommended',
|
||||
'@vue/eslint-config-typescript'
|
||||
],
|
||||
parserOptions: {
|
||||
ecmaVersion: 'latest'
|
||||
}
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
# Logs
|
||||
logs
|
||||
*.log
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
pnpm-debug.log*
|
||||
lerna-debug.log*
|
||||
|
||||
node_modules
|
||||
.DS_Store
|
||||
dist
|
||||
dist-ssr
|
||||
coverage
|
||||
*.local
|
||||
|
||||
/cypress/videos/
|
||||
/cypress/screenshots/
|
||||
|
||||
# Editor directories and files
|
||||
.vscode/*
|
||||
!.vscode/extensions.json
|
||||
.idea
|
||||
*.suo
|
||||
*.ntvs*
|
||||
*.njsproj
|
||||
*.sln
|
||||
*.sw?
|
||||
|
||||
*.tsbuildinfo
|
|
@ -0,0 +1,6 @@
|
|||
{
|
||||
"recommendations": [
|
||||
"Vue.volar",
|
||||
"dbaeumer.vscode-eslint"
|
||||
]
|
||||
}
|
|
@ -0,0 +1,39 @@
|
|||
# vue_one
|
||||
|
||||
This template should help get you started developing with Vue 3 in Vite.
|
||||
|
||||
## Recommended IDE Setup
|
||||
|
||||
[VSCode](https://code.visualstudio.com/) + [Volar](https://marketplace.visualstudio.com/items?itemName=Vue.volar) (and disable Vetur).
|
||||
|
||||
## Type Support for `.vue` Imports in TS
|
||||
|
||||
TypeScript cannot handle type information for `.vue` imports by default, so we replace the `tsc` CLI with `vue-tsc` for type checking. In editors, we need [Volar](https://marketplace.visualstudio.com/items?itemName=Vue.volar) to make the TypeScript language service aware of `.vue` types.
|
||||
|
||||
## Customize configuration
|
||||
|
||||
See [Vite Configuration Reference](https://vitejs.dev/config/).
|
||||
|
||||
## Project Setup
|
||||
|
||||
```sh
|
||||
npm install
|
||||
```
|
||||
|
||||
### Compile and Hot-Reload for Development
|
||||
|
||||
```sh
|
||||
npm run dev
|
||||
```
|
||||
|
||||
### Type-Check, Compile and Minify for Production
|
||||
|
||||
```sh
|
||||
npm run build
|
||||
```
|
||||
|
||||
### Lint with [ESLint](https://eslint.org/)
|
||||
|
||||
```sh
|
||||
npm run lint
|
||||
```
|
|
@ -0,0 +1,8 @@
|
|||
// vue3 报错提示 找不到模块“./XXX.vue”或其相应的类型声明
|
||||
// 报错原因:typescript 只能理解 .ts 文件,无法理解 .vue文件
|
||||
declare module '*.vue' {
|
||||
import type { DefineComponent } from 'vue'
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/ban-types
|
||||
const component: DefineComponent<{}, {}, any>
|
||||
export default component
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<link rel="icon" href="/favicon.ico">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Vite App</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
<script type="module" src="/src/main.ts"></script>
|
||||
</body>
|
||||
</html>
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,37 @@
|
|||
{
|
||||
"name": "vue_one",
|
||||
"version": "0.0.0",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
"build": "run-p type-check \"build-only {@}\" --",
|
||||
"preview": "vite preview",
|
||||
"build-only": "vite build",
|
||||
"type-check": "vue-tsc --build --force",
|
||||
"lint": "eslint . --ext .vue,.js,.jsx,.cjs,.mjs,.ts,.tsx,.cts,.mts --fix --ignore-path .gitignore"
|
||||
},
|
||||
"dependencies": {
|
||||
"axios": "^1.7.2",
|
||||
"echarts": "^5.5.1",
|
||||
"element-plus": "^2.7.6",
|
||||
"http-proxy-middleware": "^3.0.0",
|
||||
"vue": "^3.4.29",
|
||||
"vue-router": "^4.4.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@rushstack/eslint-patch": "^1.8.0",
|
||||
"@tsconfig/node20": "^20.1.4",
|
||||
"@types/node": "^20.14.10",
|
||||
"@vitejs/plugin-vue": "^5.0.5",
|
||||
"@vue/eslint-config-typescript": "^13.0.0",
|
||||
"@vue/tsconfig": "^0.5.1",
|
||||
"eslint": "^8.57.0",
|
||||
"eslint-plugin-vue": "^9.23.0",
|
||||
"npm-run-all2": "^6.2.0",
|
||||
"typescript": "~5.4.0",
|
||||
"vite": "^5.3.1",
|
||||
"vite-plugin-vue-setup-extend": "^0.4.0",
|
||||
"vue-tsc": "^2.0.21"
|
||||
}
|
||||
}
|
Binary file not shown.
After Width: | Height: | Size: 4.2 KiB |
|
@ -0,0 +1,105 @@
|
|||
<template>
|
||||
<div id="app">
|
||||
<el-header>
|
||||
<div class="logo">
|
||||
<span>管理平台</span>
|
||||
</div>
|
||||
<div class="nav-menu">
|
||||
<el-menu
|
||||
:default-active="activeIndex"
|
||||
class="el-menu-demo"
|
||||
mode="horizontal"
|
||||
router
|
||||
>
|
||||
<el-menu-item index="/">首页</el-menu-item>
|
||||
<el-menu-item index="/alert-management">告警管理</el-menu-item>
|
||||
<el-menu-item index="/real-time-monitoring">实时监测</el-menu-item>
|
||||
<el-menu-item index="/statistics-analysis">统计分析</el-menu-item>
|
||||
<!-- <el-menu-item index="/system-settings">系统设置</el-menu-item> -->
|
||||
<el-menu-item index="/test">系统设置</el-menu-item>
|
||||
</el-menu>
|
||||
</div>
|
||||
<div class="user-info">
|
||||
<span>线上轮巡</span>
|
||||
<span>|</span>
|
||||
<span>English</span>
|
||||
<span>|</span>
|
||||
<span>多云 35°C</span>
|
||||
<span>|</span>
|
||||
<el-dropdown>
|
||||
<span class="el-dropdown-link">
|
||||
test@qqqq.cn<i class="el-icon-arrow-down el-icon--right"></i>
|
||||
</span>
|
||||
<el-dropdown-menu>
|
||||
<el-dropdown-item>Profile</el-dropdown-item>
|
||||
<el-dropdown-item>Logout</el-dropdown-item>
|
||||
</el-dropdown-menu>
|
||||
</el-dropdown>
|
||||
</div>
|
||||
</el-header>
|
||||
<router-view />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
activeIndex: '/'
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
$route(to) {
|
||||
this.activeIndex = to.path
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.el-header {
|
||||
background-color: #1f2d3d;
|
||||
color: #fff;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 0 20px;
|
||||
}
|
||||
.logo {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-right: 10px; /* 添加适当的右边距 */
|
||||
}
|
||||
.logo img {
|
||||
height: 40px;
|
||||
margin-right: 10px;
|
||||
}
|
||||
.nav-menu {
|
||||
flex-grow: 1;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
margin-left: 110px; /* 添加适当的左边距 */
|
||||
margin-right: 100px; /* 添加适当的右边距 */
|
||||
}
|
||||
.el-menu-demo {
|
||||
background-color: transparent;
|
||||
color: #fff;
|
||||
display: flex;
|
||||
justify-content: space-between; /* 菜单项之间均匀分布 */
|
||||
flex-grow: 1;
|
||||
}
|
||||
.el-menu-demo .el-menu-item {
|
||||
padding: 0 20px; /* 减少 padding 以增加菜单项之间的间隔 */
|
||||
text-align: center;
|
||||
font-size: 16px;
|
||||
}
|
||||
.user-info {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
margin-left: 10px; /* 添加适当的左边距 */
|
||||
}
|
||||
.user-info span {
|
||||
color: #fff;
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,20 @@
|
|||
<template>
|
||||
<div class="about">
|
||||
<h1>关于</h1>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<scrip setup lang="ts" name="about">
|
||||
|
||||
</scrip>
|
||||
|
||||
|
||||
<style scoped>
|
||||
.about{
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
</style>
|
|
@ -0,0 +1,95 @@
|
|||
<template>
|
||||
<div>
|
||||
<el-card class="alert-card">
|
||||
<div class="alert-header">告警趋势</div>
|
||||
<el-tabs v-model="activeName" @tab-click="handleClick" class="alert-tabs">
|
||||
<el-tab-pane label="24小时" name="first">24小时数据展示</el-tab-pane>
|
||||
<el-tab-pane label="30天" name="second">30天数据展示</el-tab-pane>
|
||||
<el-tab-pane label="12月" name="third">12月数据展示</el-tab-pane>
|
||||
</el-tabs>
|
||||
<div id="alert-chart" class="chart-container"></div>
|
||||
</el-card>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import * as echarts from 'echarts';
|
||||
|
||||
export default {
|
||||
name: 'AlertChart',
|
||||
data() {
|
||||
return {
|
||||
activeName: 'first'
|
||||
};
|
||||
},
|
||||
mounted() {
|
||||
this.initChart();
|
||||
},
|
||||
methods: {
|
||||
handleClick(tab, event) {
|
||||
console.log(tab, event);
|
||||
// 根据选中的标签刷新图表数据
|
||||
this.initChart();
|
||||
},
|
||||
initChart() {
|
||||
var chartDom = document.getElementById('alert-chart');
|
||||
var myChart = echarts.init(chartDom);
|
||||
var option;
|
||||
|
||||
option = {
|
||||
xAxis: {
|
||||
type: 'category',
|
||||
boundaryGap: false,
|
||||
data: ['2024-07-08 00:00', '2024-07-08 08:00', '2024-07-08 16:00', '2024-07-09 00:00', '2024-07-09 08:00', '2024-07-09 16:00']
|
||||
},
|
||||
yAxis: {
|
||||
type: 'value'
|
||||
},
|
||||
series: [
|
||||
{
|
||||
data: [10, 22, 28, 43, 49, 62],
|
||||
type: 'line',
|
||||
areaStyle: {}
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
option && myChart.setOption(option);
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.alert-card {
|
||||
background-color: #2a3f54;
|
||||
color: #fff;
|
||||
padding: 20px;
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
.alert-header {
|
||||
font-size: 18px;
|
||||
font-weight: bold;
|
||||
margin-bottom: 20px;
|
||||
border-bottom: 1px solid #3a4b5c;
|
||||
padding-bottom: 10px;
|
||||
}
|
||||
|
||||
.alert-tabs {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.chart-container {
|
||||
width: 100%;
|
||||
height: 400px;
|
||||
}
|
||||
|
||||
.el-tabs__item {
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.el-tabs__active-bar {
|
||||
background-color: #409EFF;
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,252 @@
|
|||
<template>
|
||||
<div class="alert-management">
|
||||
<div class="breadcrumb">
|
||||
<el-breadcrumb separator=">">
|
||||
<el-breadcrumb-item>告警管理</el-breadcrumb-item>
|
||||
<el-breadcrumb-item>实时告警</el-breadcrumb-item>
|
||||
</el-breadcrumb>
|
||||
</div>
|
||||
<div class="alert-summary">
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="8">
|
||||
<div class="alert-card alert-pending">
|
||||
<div class="alert-card-header">告警数(待处理)</div>
|
||||
<div class="alert-card-content">{{ alerts.pending }}</div>
|
||||
</div>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<div class="alert-card alert-processing">
|
||||
<div class="alert-card-header">告警数(处理中)</div>
|
||||
<div class="alert-card-content">{{ alerts.processing }}</div>
|
||||
</div>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<div class="alert-card alert-completed">
|
||||
<div class="alert-card-header">告警数(已完成)</div>
|
||||
<div class="alert-card-content">{{ alerts.completed }}</div>
|
||||
</div>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</div>
|
||||
<div class="region-overview">
|
||||
<el-card>
|
||||
<div slot="header" class="card-header">
|
||||
<span>区域概况</span>
|
||||
</div>
|
||||
<el-table
|
||||
:data="tableData.slice((currentPage - 1) * pageSize, currentPage * pageSize)"
|
||||
style="width: 100%;"
|
||||
row-key="id"
|
||||
:tree-props="{ children: 'children', hasChildren: 'hasChildren' }"
|
||||
>
|
||||
<el-table-column prop="id" label="序号" width="50"></el-table-column>
|
||||
<el-table-column prop="region" label="区域名称" width="200"></el-table-column>
|
||||
<el-table-column prop="siteCount" label="站点数量" width="100"></el-table-column>
|
||||
<el-table-column prop="siteName" label="站点名称">
|
||||
<template v-slot="scope">
|
||||
<span v-if="scope.row.children"></span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="status" label="状态" width="100">
|
||||
<template v-slot="scope">
|
||||
<el-tag v-if="scope.row.status === '在线'" type="success">在线</el-tag>
|
||||
<el-tag v-else type="info">离线</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="cameraCount" label="摄像头数量" width="120"></el-table-column>
|
||||
<el-table-column prop="alertCount" label="告警数量" width="120"></el-table-column>
|
||||
<el-table-column label="操作" width="100">
|
||||
<template v-slot="scope">
|
||||
<el-button v-if="!scope.row.children" type="text" size="small">查看告警</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<div class="pagination">
|
||||
<el-pagination
|
||||
@size-change="handleSizeChange"
|
||||
@current-change="handleCurrentChange"
|
||||
:current-page="currentPage"
|
||||
:page-sizes="[5, 10, 20, 30]"
|
||||
:page-size="pageSize"
|
||||
layout="total, sizes, prev, pager, next, jumper"
|
||||
:total="total"
|
||||
></el-pagination>
|
||||
</div>
|
||||
</el-card>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'AlertManagement',
|
||||
data() {
|
||||
return {
|
||||
alerts: {
|
||||
pending: 1460,
|
||||
processing: 1,
|
||||
completed: 123830
|
||||
},
|
||||
tableData: [
|
||||
{
|
||||
id: 1,
|
||||
region: '安徽区域',
|
||||
siteCount: 2,
|
||||
children: [
|
||||
{
|
||||
id: 11,
|
||||
siteName: '天长吾悦广场',
|
||||
status: '在线',
|
||||
cameraCount: 20,
|
||||
alertCount: 6059
|
||||
},
|
||||
{
|
||||
id: 12,
|
||||
siteName: '颖上吾悦广场',
|
||||
status: '在线',
|
||||
cameraCount: 20,
|
||||
alertCount: 617
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
region: '东北区域',
|
||||
siteCount: 2,
|
||||
children: [
|
||||
{
|
||||
id: 21,
|
||||
siteName: '东北站点1',
|
||||
status: '在线',
|
||||
cameraCount: 15,
|
||||
alertCount: 200
|
||||
},
|
||||
{
|
||||
id: 22,
|
||||
siteName: '东北站点2',
|
||||
status: '离线',
|
||||
cameraCount: 18,
|
||||
alertCount: 150
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
region: '沪苏区域',
|
||||
siteCount: 1,
|
||||
children: [
|
||||
{
|
||||
id: 31,
|
||||
siteName: '沪苏站点',
|
||||
status: '在线',
|
||||
cameraCount: 10,
|
||||
alertCount: 300
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
region: '华北区域',
|
||||
siteCount: 5
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
region: '华南区域',
|
||||
siteCount: 2
|
||||
},
|
||||
{
|
||||
id: 6,
|
||||
region: '华中区域',
|
||||
siteCount: 10
|
||||
},
|
||||
{
|
||||
id: 7,
|
||||
region: '闽浙区域',
|
||||
siteCount: 2
|
||||
},
|
||||
{
|
||||
id: 8,
|
||||
region: '南京区域',
|
||||
siteCount: 1
|
||||
},
|
||||
{
|
||||
id: 9,
|
||||
region: '山东区域',
|
||||
siteCount: 7
|
||||
},
|
||||
{
|
||||
id: 10,
|
||||
region: '苏北区域',
|
||||
siteCount: 3
|
||||
}
|
||||
],
|
||||
currentPage: 1,
|
||||
pageSize: 5,
|
||||
total: 10
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
handleSizeChange(val) {
|
||||
this.pageSize = val;
|
||||
},
|
||||
handleCurrentChange(val) {
|
||||
this.currentPage = val;
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.alert-management {
|
||||
padding: 40px;
|
||||
background-color: #f5f7fa;
|
||||
}
|
||||
.breadcrumb {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
.alert-summary {
|
||||
background-color: #fff;
|
||||
padding: 20px;
|
||||
border-radius: 10px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
.alert-card {
|
||||
background-color: #fff;
|
||||
border-radius: 10px;
|
||||
text-align: center;
|
||||
padding: 20px;
|
||||
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
.alert-card-header {
|
||||
font-size: 16px;
|
||||
margin-bottom: 10px;
|
||||
color: #333;
|
||||
}
|
||||
.alert-card-content {
|
||||
font-size: 28px;
|
||||
font-weight: bold;
|
||||
color: #333;
|
||||
}
|
||||
.alert-pending {
|
||||
background: linear-gradient(135deg, #ff9a9e 0%, #fecfef 100%);
|
||||
}
|
||||
.alert-processing {
|
||||
background: linear-gradient(135deg, #a1c4fd 0%, #c2e9fb 100%);
|
||||
}
|
||||
.alert-completed {
|
||||
background: linear-gradient(135deg, #a18cd1 0%, #fbc2eb 100%);
|
||||
}
|
||||
.region-overview {
|
||||
background-color: #fff;
|
||||
padding: 20px;
|
||||
border-radius: 10px;
|
||||
}
|
||||
.card-header {
|
||||
font-size: 18px;
|
||||
font-weight: bold;
|
||||
}
|
||||
.pagination {
|
||||
margin-top: 20px;
|
||||
text-align: right;
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,17 @@
|
|||
<template>
|
||||
<div>
|
||||
<h2>摄像头管理</h2>
|
||||
<!-- 模拟静态数据内容 -->
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: "CameraManagement",
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
/* 添加需要的样式 */
|
||||
</style>
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
<template>
|
||||
<div>
|
||||
<h2>设备管理</h2>
|
||||
<!-- 模拟静态数据内容 -->
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: "DeviceManagement",
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
/* 添加需要的样式 */
|
||||
</style>
|
||||
|
|
@ -0,0 +1,288 @@
|
|||
<template>
|
||||
<div class="home">
|
||||
<div class="breadcrumb">
|
||||
<el-breadcrumb separator=">">
|
||||
<el-breadcrumb-item>主页</el-breadcrumb-item>
|
||||
</el-breadcrumb>
|
||||
</div>
|
||||
<el-row>
|
||||
<el-col :span="16">
|
||||
<div class="table-container">
|
||||
<el-table :data="paginatedData">
|
||||
<el-table-column prop="id" label="告警编号" width="140"></el-table-column>
|
||||
<el-table-column label="告警类型" width="140">
|
||||
<template v-slot="scope">
|
||||
<!-- {{ typeMapping[scope.row.types] || codenameTranslate(scope.row.types) }} -->
|
||||
{{ typeMapping[scope.row.types] }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="camera.name" label="告警位置" width="180"></el-table-column>
|
||||
<el-table-column label="告警时间" width="180">
|
||||
<template v-slot="scope">
|
||||
{{ formatDateTime(scope.row.started_at) }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="status" label="告警状态" width="140">
|
||||
<template v-slot="scope">
|
||||
<el-tag :type="scope.row.status === '已处理' ? 'success' : 'warning'">{{ scope.row.status }}</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" width="140">
|
||||
<template v-slot="scope">
|
||||
<el-button type="text" @click="handleView(scope.row)">查看</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</div>
|
||||
<div class="pagination-container">
|
||||
<el-pagination background layout="total, sizes, prev, pager, next, jumper" :total="tableData.length"
|
||||
:page-size="pageSize" :current-page.sync="currentPage" @current-change="handlePageChange"
|
||||
@size-change="handleSizeChange">
|
||||
</el-pagination>
|
||||
</div>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-dialog v-model="dialogVisible" title="告警详情" width="80%">
|
||||
<div>
|
||||
<el-row>
|
||||
<el-col :span="6">
|
||||
<p>告警编号: {{ selectedRow.id }}</p>
|
||||
</el-col>
|
||||
<el-col :span="6">
|
||||
<!-- <p>告警类型: {{ typeMapping[selectedRow.types] || codenameTranslate(selectedRow.types) }}</p> -->
|
||||
<p>告警类型: {{ typeMapping[selectedRow.types] }}</p>
|
||||
</el-col>
|
||||
<el-col :span="6">
|
||||
<p>告警位置: {{ selectedRow.camera.name }}</p>
|
||||
</el-col>
|
||||
<el-col :span="6">
|
||||
<p>告警时间: {{ selectedRow.formatted_started_at }}</p>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="6">
|
||||
<p>告警状态: <el-tag :type="selectedRow.status === '已处理' ? 'success' : 'warning'">{{ selectedRow.status }}</el-tag></p>
|
||||
</el-col>
|
||||
<el-col :span="6">
|
||||
<p>摄像头编号: {{ selectedRow.camera_id }}</p>
|
||||
</el-col>
|
||||
<el-col :span="6">
|
||||
<p>持续时间: {{ duration }}</p>
|
||||
</el-col>
|
||||
<el-col :span="6">
|
||||
<p>备注: {{ selectedRow.note }}</p>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<div class="event-media">
|
||||
<div v-for="medium in selectedRow.mediums" :key="medium.id" class="media-container">
|
||||
<div v-if="medium.name === 'video'" class="media-item video-item">
|
||||
<p>告警关联视频</p>
|
||||
<video :src="medium.file" controls></video>
|
||||
</div>
|
||||
<div v-if="medium.name === 'snapshot'" class="media-item image-item">
|
||||
<p>告警关联图片</p>
|
||||
<el-image :src="medium.file" fit="contain"></el-image>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<span slot="footer" class="dialog-footer">
|
||||
<div class=""></div>
|
||||
</span>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import * as echarts from 'echarts';
|
||||
import Statistics from '../components/Statistics.vue';
|
||||
import AlertChart from '../components/AlertChart.vue';
|
||||
import { login, getEvents, initCodeNameMap, codenameTranslate } from '../../superbox.js';
|
||||
|
||||
export default {
|
||||
name: 'Home',
|
||||
components: {
|
||||
Statistics,
|
||||
AlertChart,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
tableData: [],
|
||||
dialogVisible: false,
|
||||
selectedRow: {},
|
||||
mediums: {},
|
||||
duration: '',
|
||||
typeMapping: {
|
||||
'abnormal:525': '黑屏检测',
|
||||
'car_blocking:512': '车辆拥塞',
|
||||
'car_blocking:514': '违规停车',
|
||||
'escalator_status:518': '扶梯运行状态',
|
||||
'gathering:520': '人员密集',
|
||||
'gathering:521': '保洁点名',
|
||||
'intrude:513': '入侵检测',
|
||||
'long_term_door_status:526': '长期门状态检测',
|
||||
'lying_down:527': '人员倒地',
|
||||
'minizawu:531': '杂物堆积',
|
||||
'minizawu:532': '杂物堆积',
|
||||
'personnel_stay:535': '人员逗留',
|
||||
'vacant:524': '人员离岗',
|
||||
'zawu:516': '饮料垃圾检测',
|
||||
'zawu:517': '垃圾桶满溢',
|
||||
'zawu:519': '违规放置',
|
||||
'zawu:523': '绿化带垃圾检测',
|
||||
},
|
||||
statusMapping: {
|
||||
'': '待处理',
|
||||
'': '处理中',
|
||||
'': '已处理'
|
||||
},
|
||||
currentPage: 1,
|
||||
pageSize: 20,
|
||||
}
|
||||
},
|
||||
async created() {
|
||||
try {
|
||||
const token = await login('turingvideo', '1234qwer!');
|
||||
// await initCodeNameMap(token);
|
||||
this.tableData = await getEvents(token);
|
||||
console.log(this.tableData);
|
||||
} catch (error) {
|
||||
console.error("Error fetching events:", error);
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
paginatedData() {
|
||||
const start = (this.currentPage - 1) * this.pageSize;
|
||||
const end = start + this.pageSize;
|
||||
return this.tableData.slice(start, end);
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
handleView(row) {
|
||||
this.selectedRow = row;
|
||||
this.duration = this.calculateDuration(row.started_at, row.ended_at);
|
||||
row.formatted_started_at = this.formatDateTime(row.started_at);
|
||||
|
||||
// console.log("duration: ", row.started_at);
|
||||
// console.log("duration: ", row.ended_at);
|
||||
// console.log("duration: ", this.duration);
|
||||
this.dialogVisible = true;
|
||||
this.mediums = row.mediums || {};
|
||||
if (Array.isArray(row.mediums)) {
|
||||
row.mediums.forEach(medium => {
|
||||
// console.log("medium: ", medium.file);
|
||||
// console.log("medium: ", medium.id);
|
||||
});
|
||||
} else {
|
||||
// console.log("No mediums available");
|
||||
}
|
||||
},
|
||||
handlePageChange(page) {
|
||||
this.currentPage = page;
|
||||
},
|
||||
handleSizeChange(size) {
|
||||
this.pageSize = size;
|
||||
},
|
||||
calculateDuration(started_at, ended_at) {
|
||||
const start = new Date(started_at);
|
||||
const end = new Date(ended_at);
|
||||
const duration = end - start;
|
||||
const minutes = Math.floor(duration / 60000);
|
||||
const seconds = ((duration % 60000) / 1000).toFixed(0);
|
||||
return `${minutes}分${(seconds < 10 ? '0' : '')}${seconds}秒`;
|
||||
},
|
||||
formatDateTime(datetime) {
|
||||
const date = new Date(datetime);
|
||||
const year = date.getFullYear();
|
||||
const month = (date.getMonth() + 1).toString().padStart(2, '0');
|
||||
const day = date.getDate().toString().padStart(2, '0');
|
||||
const hours = date.getHours().toString().padStart(2, '0');
|
||||
const minutes = date.getMinutes().toString().padStart(2, '0');
|
||||
const seconds = date.getSeconds().toString().padStart(2, '0');
|
||||
return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.home {
|
||||
padding: 40px;
|
||||
background-color: #f5f7fa;
|
||||
}
|
||||
|
||||
.breadcrumb {
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
|
||||
.top-scroll {
|
||||
width: 100%;
|
||||
overflow-x: auto;
|
||||
}
|
||||
|
||||
.top-scroll-content {
|
||||
/* 高度滚动条显示出来默认值 */
|
||||
height: 1px;
|
||||
}
|
||||
|
||||
.table-container {
|
||||
width: 80%;
|
||||
max-height: 1000px;
|
||||
overflow-x: auto;
|
||||
padding-left: 7%;
|
||||
}
|
||||
|
||||
/* 弹窗> 显示左右等分*/
|
||||
.event-media {
|
||||
/* display: flex;
|
||||
flex-direction: column;
|
||||
gap: 10px;
|
||||
margin-top: 20px; */
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
/* 添加这个属性来左右等分 */
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.media-container {
|
||||
flex: 0 0 48%;
|
||||
/* 确保每块区域占据一行的48% */
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
/* 使内容在区域内居中 */
|
||||
margin-bottom: 20px;
|
||||
/* 添加底部间距,使多个元素之间有间隔 */
|
||||
box-sizing: border-box;
|
||||
/* 确保padding和border不会影响大小 */
|
||||
padding: 10px;
|
||||
/* 添加内边距,使内容不靠近边框 */
|
||||
}
|
||||
|
||||
.video-item video,
|
||||
.image-item img {
|
||||
width: 100%;
|
||||
/* 保证视频和图片在容器内等宽 */
|
||||
height: auto;
|
||||
/* 保证视频和图片比例正常 */
|
||||
border-radius: 8px;
|
||||
/* 圆润效果 */
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
|
||||
/* 阴影效果 */
|
||||
}
|
||||
|
||||
.video-item p,
|
||||
.image-item p {
|
||||
margin-bottom: 8px;
|
||||
text-align: center;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.pagination-container {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
margin-top: 20px;
|
||||
margin-right: 150px;
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,17 @@
|
|||
<template>
|
||||
<div>
|
||||
<h2>层级列表</h2>
|
||||
<!-- 模拟静态数据内容 -->
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: "LevelList",
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
/* 添加需要的样式 */
|
||||
</style>
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
<template>
|
||||
<div>
|
||||
<h2>层级树</h2>
|
||||
<!-- 模拟静态数据内容 -->
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: "LevelTree",
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
/* 添加需要的样式 */
|
||||
</style>
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
<template>
|
||||
<div>
|
||||
<el-card>
|
||||
<h2>当前位置:中国</h2>
|
||||
<!-- Add map implementation here -->
|
||||
</el-card>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'LocationMap'
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
/* Add your styles here */
|
||||
</style>
|
|
@ -0,0 +1,83 @@
|
|||
<!-- 测试 -->
|
||||
<template>
|
||||
<div>
|
||||
<button @click="loginAndGetToken">Login and Get Token</button>
|
||||
<button @click="withTokenGetCameras">Get Cameras with Token</button>
|
||||
<pre>Token: {{ token }}</pre>
|
||||
<pre>Cameras: {{ cameras }}</pre>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import axios from 'axios';
|
||||
import { ref } from 'vue';
|
||||
|
||||
export default {
|
||||
name: 'App',
|
||||
setup() {
|
||||
const token = ref('');
|
||||
const cameras = ref([]);
|
||||
|
||||
const api_base = "/api/v1";
|
||||
const api_login = api_base + "/auth/login";
|
||||
const api_cameras = api_base + "/camera/cameras";
|
||||
const username = "turingvideo";
|
||||
const password = "1234qwer!";
|
||||
|
||||
const loginAndGetToken = async () => {
|
||||
try {
|
||||
const res = await axios.post(api_login,
|
||||
{
|
||||
'username': username,
|
||||
'password': password,
|
||||
'cookieless': 'True'
|
||||
},
|
||||
{
|
||||
headers: {
|
||||
'Content-type': 'application/json'
|
||||
}
|
||||
}
|
||||
);
|
||||
console.log(res.data)
|
||||
token.value = res.data.ret.token;
|
||||
console.log('Token:', token.value);
|
||||
} catch (e) {
|
||||
console.log(e);
|
||||
}
|
||||
};
|
||||
|
||||
const withTokenGetCameras = async () => {
|
||||
try {
|
||||
if (!token.value) {
|
||||
console.error('No token available. Please login first.');
|
||||
return;
|
||||
}
|
||||
|
||||
const res = await axios.get(api_cameras, {
|
||||
headers: {
|
||||
'Content-type': 'application/json',
|
||||
'Authorization': `Bearer ${token.value}`,
|
||||
'Cookie': `jwt=${token.value}; sessionid=27iy45x18cq2uio2k2gnsl4a8s4si935`
|
||||
}
|
||||
});
|
||||
cameras.value = res.data;
|
||||
console.log('Cameras:', cameras.value);
|
||||
} catch (e) {
|
||||
console.log(e);
|
||||
}
|
||||
};
|
||||
|
||||
return {
|
||||
loginAndGetToken,
|
||||
withTokenGetCameras,
|
||||
token,
|
||||
cameras
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
</script>
|
||||
|
||||
<style>
|
||||
/* Add your styles here */
|
||||
</style>
|
|
@ -0,0 +1,313 @@
|
|||
<template>
|
||||
<div class="real-time-monitoring">
|
||||
<div class="breadcrumb">
|
||||
<el-breadcrumb separator=">">
|
||||
<el-breadcrumb-item>实时监测</el-breadcrumb-item>
|
||||
<el-breadcrumb-item>实时监测数据</el-breadcrumb-item>
|
||||
</el-breadcrumb>
|
||||
</div>
|
||||
<div class="alert-summary">
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="12">
|
||||
<div class="chart-container">
|
||||
<div class="chart-header">告警情况汇总</div>
|
||||
<div ref="cameraChart" class="chart"></div>
|
||||
<div class="chart-info">
|
||||
<div>摄像头数量</div>
|
||||
<div>
|
||||
<span class="status online">• 在线</span> 1885
|
||||
<span class="status offline">• 离线</span> 115
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<div class="chart-container">
|
||||
<div class="chart-header">站点数量</div>
|
||||
<div ref="siteChart" class="chart"></div>
|
||||
<div class="chart-info">
|
||||
<div>编制总数</div>
|
||||
<div>
|
||||
<span class="status online">• 在线</span> 47
|
||||
<span class="status offline">• 离线</span> 7
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</div>
|
||||
<div class="device-status">
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="8">
|
||||
<div class="status-card pending">
|
||||
<div class="status-header">待处理告警摄像头</div>
|
||||
<div class="status-content">{{ deviceStatus.pending }}</div>
|
||||
</div>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<div class="status-card total">
|
||||
<div class="status-header">累计产生告警摄像头</div>
|
||||
<div class="status-content">{{ deviceStatus.total }}</div>
|
||||
<div class="status-footer">
|
||||
<div>近7天产生告警摄像头 {{ deviceStatus.last7Days }}</div>
|
||||
<div>近30天产生告警摄像头 {{ deviceStatus.last30Days }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<div class="status-card inactive">
|
||||
<div class="status-header">非活跃摄像头(累计90天未产生告警)</div>
|
||||
<div class="status-content">{{ deviceStatus.inactive }}</div>
|
||||
</div>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</div>
|
||||
<div class="region-overview">
|
||||
<el-card>
|
||||
<div slot="header" class="card-header">
|
||||
<span>区域概况</span>
|
||||
</div>
|
||||
<el-table
|
||||
:data="pagedData"
|
||||
style="width: 100%;"
|
||||
row-key="id"
|
||||
height="400"
|
||||
>
|
||||
<el-table-column prop="id" label="序号" width="50"></el-table-column>
|
||||
<el-table-column prop="region" label="区域名称" width="200"></el-table-column>
|
||||
<el-table-column prop="siteCount" label="站点数量" width="100"></el-table-column>
|
||||
<el-table-column prop="cameraCount" label="摄像头数量" width="120"></el-table-column>
|
||||
<el-table-column label="操作" width="100">
|
||||
<template slot-scope="scope">
|
||||
<el-button type="text" size="small">查看站点</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<div class="pagination">
|
||||
<el-pagination
|
||||
@size-change="handleSizeChange"
|
||||
@current-change="handleCurrentChange"
|
||||
:current-page="currentPage"
|
||||
:page-sizes="[5, 10, 20, 30]"
|
||||
:page-size="pageSize"
|
||||
layout="total, sizes, prev, pager, next, jumper"
|
||||
:total="tableData.length"
|
||||
></el-pagination>
|
||||
</div>
|
||||
</el-card>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import * as echarts from 'echarts';
|
||||
|
||||
export default {
|
||||
name: 'RealTimeMonitoring',
|
||||
data() {
|
||||
return {
|
||||
deviceStatus: {
|
||||
pending: 100,
|
||||
total: 1104,
|
||||
last7Days: 125,
|
||||
last30Days: 185,
|
||||
inactive: 1738
|
||||
},
|
||||
tableData: [
|
||||
{ id: 1, region: '安徽区域', siteCount: 2, cameraCount: 40 },
|
||||
{ id: 2, region: '东北区域', siteCount: 2, cameraCount: 40 },
|
||||
{ id: 3, region: '沪苏区域', siteCount: 1, cameraCount: 311 },
|
||||
{ id: 4, region: '华北区域', siteCount: 5, cameraCount: 120 },
|
||||
{ id: 5, region: '华南区域', siteCount: 2, cameraCount: 60 },
|
||||
{ id: 6, region: '华中区域', siteCount: 10, cameraCount: 279 },
|
||||
{ id: 7, region: '闽浙区域', siteCount: 2, cameraCount: 20 },
|
||||
{ id: 8, region: '南京区域', siteCount: 1, cameraCount: 377 },
|
||||
{ id: 9, region: '山东区域', siteCount: 7, cameraCount: 193 },
|
||||
{ id: 10, region: '苏北区域', siteCount: 3, cameraCount: 100 }
|
||||
],
|
||||
currentPage: 1,
|
||||
pageSize: 5
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
pagedData() {
|
||||
const start = (this.currentPage - 1) * this.pageSize;
|
||||
const end = this.currentPage * this.pageSize;
|
||||
return this.tableData.slice(start, end);
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.initCameraChart();
|
||||
this.initSiteChart();
|
||||
},
|
||||
methods: {
|
||||
initCameraChart() {
|
||||
const cameraChart = echarts.init(this.$refs.cameraChart);
|
||||
const cameraOptions = {
|
||||
series: [
|
||||
{
|
||||
name: '摄像头数量',
|
||||
type: 'pie',
|
||||
radius: ['50%', '70%'],
|
||||
avoidLabelOverlap: false,
|
||||
label: {
|
||||
show: false,
|
||||
position: 'center'
|
||||
},
|
||||
emphasis: {
|
||||
label: {
|
||||
show: true,
|
||||
fontSize: '30',
|
||||
fontWeight: 'bold'
|
||||
}
|
||||
},
|
||||
labelLine: {
|
||||
show: false
|
||||
},
|
||||
data: [
|
||||
{ value: 1885, name: '在线' },
|
||||
{ value: 115, name: '离线' }
|
||||
]
|
||||
}
|
||||
]
|
||||
};
|
||||
cameraChart.setOption(cameraOptions);
|
||||
},
|
||||
initSiteChart() {
|
||||
const siteChart = echarts.init(this.$refs.siteChart);
|
||||
const siteOptions = {
|
||||
series: [
|
||||
{
|
||||
name: '站点数量',
|
||||
type: 'pie',
|
||||
radius: ['50%', '70%'],
|
||||
avoidLabelOverlap: false,
|
||||
label: {
|
||||
show: false,
|
||||
position: 'center'
|
||||
},
|
||||
emphasis: {
|
||||
label: {
|
||||
show: true,
|
||||
fontSize: '30',
|
||||
fontWeight: 'bold'
|
||||
}
|
||||
},
|
||||
labelLine: {
|
||||
show: false
|
||||
},
|
||||
data: [
|
||||
{ value: 47, name: '在线' },
|
||||
{ value: 7, name: '离线' }
|
||||
]
|
||||
}
|
||||
]
|
||||
};
|
||||
siteChart.setOption(siteOptions);
|
||||
},
|
||||
handleSizeChange(val) {
|
||||
this.pageSize = val;
|
||||
},
|
||||
handleCurrentChange(val) {
|
||||
this.currentPage = val;
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.real-time-monitoring {
|
||||
padding: 20px;
|
||||
background-color: #f5f7fa;
|
||||
}
|
||||
.breadcrumb {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
.alert-summary {
|
||||
background-color: #fff;
|
||||
padding: 20px;
|
||||
border-radius: 10px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
.chart-container {
|
||||
background-color: #fff;
|
||||
padding: 20px;
|
||||
border-radius: 10px;
|
||||
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
|
||||
text-align: center;
|
||||
}
|
||||
.chart-header {
|
||||
font-size: 18px;
|
||||
font-weight: bold;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
.chart {
|
||||
width: 100%;
|
||||
height: 300px;
|
||||
}
|
||||
.chart-info {
|
||||
margin-top: 10px;
|
||||
}
|
||||
.status {
|
||||
margin-right: 10px;
|
||||
}
|
||||
.status.online {
|
||||
color: #67c23a;
|
||||
}
|
||||
.status.offline {
|
||||
color: #f56c6c;
|
||||
}
|
||||
.device-status {
|
||||
background-color: #fff;
|
||||
padding: 20px;
|
||||
border-radius: 10px;
|
||||
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
.status-card {
|
||||
padding: 20px;
|
||||
border-radius: 10px;
|
||||
text-align: center;
|
||||
color: #fff;
|
||||
height: 200px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
}
|
||||
.status-card.pending {
|
||||
background: linear-gradient(135deg, #ff9a9e 0%, #fecfef 100%);
|
||||
}
|
||||
.status-card.total {
|
||||
background: linear-gradient(135deg, #a1c4fd 0%, #c2e9fb 100%);
|
||||
}
|
||||
.status-card.inactive {
|
||||
background: linear-gradient(135deg, #a18cd1 0%, #fbc2eb 100%);
|
||||
}
|
||||
.status-header {
|
||||
font-size: 16px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
.status-content {
|
||||
font-size: 28px;
|
||||
font-weight: bold;
|
||||
}
|
||||
.status-footer {
|
||||
margin-top: 10px;
|
||||
font-size: 14px;
|
||||
}
|
||||
.region-overview {
|
||||
background-color: #fff;
|
||||
padding: 20px;
|
||||
border-radius: 10px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
.card-header {
|
||||
font-size: 18px;
|
||||
font-weight: bold;
|
||||
}
|
||||
.pagination {
|
||||
margin-top: 20px;
|
||||
text-align: right;
|
||||
}
|
||||
</style>
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
<template>
|
||||
<div>
|
||||
<h2>区域1</h2>
|
||||
<!-- 模拟静态数据内容 -->
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: "Region1",
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
/* 添加需要的样式 */
|
||||
</style>
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
<template>
|
||||
<div>
|
||||
<h2>区域2</h2>
|
||||
<!-- 模拟静态数据内容 -->
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: "Region2",
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
/* 添加需要的样式 */
|
||||
</style>
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
<template>
|
||||
<div>
|
||||
<h2>服务器管理</h2>
|
||||
<!-- 模拟静态数据内容 -->
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: "ServerManagement",
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
/* 添加需要的样式 */
|
||||
</style>
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
<template>
|
||||
<div>
|
||||
<h2>站点管理</h2>
|
||||
<!-- 模拟静态数据内容 -->
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: "SiteManagement",
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
/* 添加需要的样式 */
|
||||
</style>
|
||||
|
|
@ -0,0 +1,101 @@
|
|||
<template>
|
||||
<div>
|
||||
<el-card class="stats-card">
|
||||
<div class="stats-header">布控情况</div>
|
||||
<el-row :gutter="20" class="stats-row">
|
||||
<el-col :span="8">
|
||||
<div class="stats-item">
|
||||
<div class="stats-title">布控区域数</div>
|
||||
<div class="stats-value">15</div>
|
||||
</div>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<div class="stats-item">
|
||||
<div class="stats-title">布控站点数</div>
|
||||
<div class="stats-value">54</div>
|
||||
<div class="stats-subvalue">7 异常站点</div>
|
||||
</div>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<div class="stats-item">
|
||||
<div class="stats-title">布控摄像头数</div>
|
||||
<div class="stats-value">2000</div>
|
||||
</div>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<div class="stats-divider"></div>
|
||||
<div class="stats-header">告警情况</div>
|
||||
<el-row :gutter="20" class="stats-row">
|
||||
<el-col :span="8">
|
||||
<div class="stats-item">
|
||||
<div class="stats-title">告警站点</div>
|
||||
<div class="stats-value">25</div>
|
||||
</div>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<div class="stats-item">
|
||||
<div class="stats-title">未完成告警</div>
|
||||
<div class="stats-value">1511</div>
|
||||
</div>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<div class="stats-item">
|
||||
<div class="stats-title">已完成告警</div>
|
||||
<div class="stats-value">123916</div>
|
||||
</div>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-card>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'Statistics'
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.stats-card {
|
||||
background-color: #2a3f54;
|
||||
color: #fff;
|
||||
padding: 20px;
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
.stats-header {
|
||||
font-size: 18px;
|
||||
font-weight: bold;
|
||||
margin-bottom: 20px;
|
||||
border-bottom: 1px solid #3a4b5c;
|
||||
padding-bottom: 10px;
|
||||
}
|
||||
|
||||
.stats-row {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.stats-item {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.stats-title {
|
||||
font-size: 16px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.stats-value {
|
||||
font-size: 24px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.stats-subvalue {
|
||||
font-size: 14px;
|
||||
color: #f39c12;
|
||||
}
|
||||
|
||||
.stats-divider {
|
||||
border-top: 1px solid #3a4b5c;
|
||||
margin: 20px 0;
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,376 @@
|
|||
<template>
|
||||
<div class="statistics-analysis">
|
||||
<div class="breadcrumb">
|
||||
<el-breadcrumb separator=">">
|
||||
<el-breadcrumb-item>统计分析</el-breadcrumb-item>
|
||||
</el-breadcrumb>
|
||||
</div>
|
||||
<div class="filter-form">
|
||||
<el-card>
|
||||
<div slot="header" class="card-header">
|
||||
<span>筛选条件</span>
|
||||
</div>
|
||||
<el-form :inline="true" :model="filterForm" class="demo-form-inline">
|
||||
<el-form-item label="所属站点:">
|
||||
<el-select v-model="filterForm.site" placeholder="全部">
|
||||
<el-option label="全部" value="all"></el-option>
|
||||
<el-option label="站点一" value="site1"></el-option>
|
||||
<el-option label="站点二" value="site2"></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="开始时间:">
|
||||
<el-date-picker v-model="filterForm.startDate" type="date" placeholder="选择日期"></el-date-picker>
|
||||
</el-form-item>
|
||||
<el-form-item label="结束时间:">
|
||||
<el-date-picker v-model="filterForm.endDate" type="date" placeholder="选择日期"></el-date-picker>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" @click="onSearch">查询</el-button>
|
||||
<el-button @click="onReset">清空</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-card>
|
||||
</div>
|
||||
<div class="device-management">
|
||||
<el-card>
|
||||
<div slot="header" class="card-header">
|
||||
<span>设备管理</span>
|
||||
</div>
|
||||
<el-row :gutter="10">
|
||||
<el-col :span="8">
|
||||
<div class="status-info">
|
||||
<div class="status-title">摄像头总数</div>
|
||||
<div class="status-value">{{ deviceData.totalCameras }}</div>
|
||||
</div>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<div class="status-info">
|
||||
<div class="status-title">在线</div>
|
||||
<div class="status-value">{{ deviceData.online }}</div>
|
||||
</div>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<div class="status-info">
|
||||
<div class="status-title">异常</div>
|
||||
<div class="status-value">{{ deviceData.abnormal }}</div>
|
||||
</div>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row :gutter="10" class="chart-row">
|
||||
<el-col :span="12">
|
||||
<div ref="statusPieChart" class="chart"></div>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<div class="status-percentage">
|
||||
<div><span class="dot online"></span> 在线 {{ deviceData.onlinePercentage }}%</div>
|
||||
<div><span class="dot abnormal"></span> 异常 {{ deviceData.abnormalPercentage }}%</div>
|
||||
</div>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<div class="chart-container">
|
||||
<div ref="distributionBarChart" class="chart"></div>
|
||||
</div>
|
||||
</el-card>
|
||||
</div>
|
||||
<div class="alert-management">
|
||||
<el-card>
|
||||
<div slot="header" class="card-header">
|
||||
<span>告警管理</span>
|
||||
</div>
|
||||
<el-row :gutter="10">
|
||||
<el-col :span="8">
|
||||
<div class="alert-info">
|
||||
<div class="alert-title">总告警数</div>
|
||||
<div class="alert-value">{{ alertData.totalAlerts }}</div>
|
||||
</div>
|
||||
</el-col>
|
||||
<el-col :span="4">
|
||||
<div class="alert-info pending">
|
||||
<div class="alert-title">待处理</div>
|
||||
<div class="alert-value">{{ alertData.pending }}</div>
|
||||
</div>
|
||||
</el-col>
|
||||
<el-col :span="4">
|
||||
<div class="alert-info processing">
|
||||
<div class="alert-title">处理中</div>
|
||||
<div class="alert-value">{{ alertData.processing }}</div>
|
||||
</div>
|
||||
</el-col>
|
||||
<el-col :span="4">
|
||||
<div class="alert-info completed">
|
||||
<div class="alert-title">已完成</div>
|
||||
<div class="alert-value">{{ alertData.completed }}</div>
|
||||
</div>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row :gutter="10" class="chart-row">
|
||||
<el-col :span="12">
|
||||
<div ref="alertPieChart" class="chart"></div>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<div ref="alertTrendChart" class="chart"></div>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-card>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import * as echarts from 'echarts';
|
||||
|
||||
export default {
|
||||
name: 'StatisticsAnalysis',
|
||||
data() {
|
||||
return {
|
||||
filterForm: {
|
||||
site: 'all',
|
||||
startDate: '',
|
||||
endDate: ''
|
||||
},
|
||||
deviceData: {
|
||||
totalCameras: 2000,
|
||||
online: 1885,
|
||||
abnormal: 115,
|
||||
onlinePercentage: 94,
|
||||
abnormalPercentage: 6,
|
||||
distribution: [
|
||||
{ name: '杂物堆积', value: 600 },
|
||||
{ name: '车辆拥堵', value: 500 },
|
||||
{ name: '违规停车', value: 400 },
|
||||
{ name: '饮料垃圾检测', value: 300 },
|
||||
{ name: '垃圾桶满溢', value: 200 },
|
||||
{ name: '入侵检测', value: 150 },
|
||||
{ name: '扶梯运行状态', value: 100 },
|
||||
{ name: '违规放置', value: 80 },
|
||||
{ name: '长期门状态检测', value: 70 },
|
||||
{ name: '人员密集', value: 60 },
|
||||
{ name: '保洁点名', value: 50 }
|
||||
]
|
||||
},
|
||||
alertData: {
|
||||
totalAlerts: 0,
|
||||
pending: 0,
|
||||
processing: 0,
|
||||
completed: 0
|
||||
}
|
||||
};
|
||||
},
|
||||
mounted() {
|
||||
this.initStatusPieChart();
|
||||
this.initDistributionBarChart();
|
||||
this.initAlertPieChart();
|
||||
this.initAlertTrendChart();
|
||||
},
|
||||
methods: {
|
||||
onSearch() {
|
||||
// 查询逻辑
|
||||
console.log('查询参数:', this.filterForm);
|
||||
},
|
||||
onReset() {
|
||||
this.filterForm = {
|
||||
site: 'all',
|
||||
startDate: '',
|
||||
endDate: ''
|
||||
};
|
||||
},
|
||||
initStatusPieChart() {
|
||||
const statusPieChart = echarts.init(this.$refs.statusPieChart);
|
||||
const options = {
|
||||
series: [
|
||||
{
|
||||
name: '设备状态分布',
|
||||
type: 'pie',
|
||||
radius: '50%',
|
||||
data: [
|
||||
{ value: this.deviceData.online, name: '在线' },
|
||||
{ value: this.deviceData.abnormal, name: '异常' }
|
||||
],
|
||||
label: {
|
||||
formatter: '{b}: {d}%'
|
||||
}
|
||||
}
|
||||
]
|
||||
};
|
||||
statusPieChart.setOption(options);
|
||||
},
|
||||
initDistributionBarChart() {
|
||||
const distributionBarChart = echarts.init(this.$refs.distributionBarChart);
|
||||
const options = {
|
||||
xAxis: {
|
||||
type: 'category',
|
||||
data: this.deviceData.distribution.map(item => item.name)
|
||||
},
|
||||
yAxis: {
|
||||
type: 'value'
|
||||
},
|
||||
series: [
|
||||
{
|
||||
data: this.deviceData.distribution.map(item => item.value),
|
||||
type: 'bar'
|
||||
}
|
||||
]
|
||||
};
|
||||
distributionBarChart.setOption(options);
|
||||
},
|
||||
initAlertPieChart() {
|
||||
const alertPieChart = echarts.init(this.$refs.alertPieChart);
|
||||
const options = {
|
||||
series: [
|
||||
{
|
||||
name: '告警事件分布',
|
||||
type: 'pie',
|
||||
radius: '50%',
|
||||
data: [
|
||||
{ value: this.alertData.pending, name: '待处理' },
|
||||
{ value: this.alertData.processing, name: '处理中' },
|
||||
{ value: this.alertData.completed, name: '已完成' }
|
||||
],
|
||||
label: {
|
||||
formatter: '{b}: {d}%'
|
||||
}
|
||||
}
|
||||
]
|
||||
};
|
||||
alertPieChart.setOption(options);
|
||||
},
|
||||
initAlertTrendChart() {
|
||||
const alertTrendChart = echarts.init(this.$refs.alertTrendChart);
|
||||
const options = {
|
||||
xAxis: {
|
||||
type: 'category',
|
||||
data: ['2024-07-16', '2024-07-17', '2024-07-18', '2024-07-19', '2024-07-20', '2024-07-21', '2024-07-22']
|
||||
},
|
||||
yAxis: {
|
||||
type: 'value'
|
||||
},
|
||||
series: [
|
||||
{
|
||||
name: '待处理',
|
||||
data: [0, 0, 0, 0, 0, 0, 0],
|
||||
type: 'line',
|
||||
smooth: true
|
||||
},
|
||||
{
|
||||
name: '处理中',
|
||||
data: [0, 0, 0, 0, 0, 0, 0],
|
||||
type: 'line',
|
||||
smooth: true
|
||||
},
|
||||
{
|
||||
name: '已完成',
|
||||
data: [0, 0, 0, 0, 0, 0, 0],
|
||||
type: 'line',
|
||||
smooth: true
|
||||
}
|
||||
]
|
||||
};
|
||||
alertTrendChart.setOption(options);
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.statistics-analysis {
|
||||
padding: 20px;
|
||||
background-color: #f5f7fa;
|
||||
}
|
||||
.breadcrumb {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
.filter-form {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
.card-header {
|
||||
font-size: 18px;
|
||||
font-weight: bold;
|
||||
}
|
||||
.demo-form-inline .el-form-item {
|
||||
margin-right: 20px;
|
||||
}
|
||||
.el-form-item .el-select,
|
||||
.el-form-item .el-date-picker {
|
||||
width: 200px;
|
||||
}
|
||||
.el-button {
|
||||
margin-right: 10px;
|
||||
}
|
||||
.device-management {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
.status-info {
|
||||
background-color: #fff;
|
||||
padding: 10px;
|
||||
border-radius: 10px;
|
||||
text-align: center;
|
||||
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
|
||||
height: 100px;
|
||||
}
|
||||
.status-title {
|
||||
font-size: 14px;
|
||||
color: #999;
|
||||
}
|
||||
.status-value {
|
||||
font-size: 20px;
|
||||
font-weight: bold;
|
||||
margin-top: 5px;
|
||||
}
|
||||
.chart-row {
|
||||
margin-top: 20px;
|
||||
}
|
||||
.chart {
|
||||
width: 100%;
|
||||
height: 200px;
|
||||
}
|
||||
.status-percentage {
|
||||
margin-top: 20px;
|
||||
font-size: 14px;
|
||||
text-align: center;
|
||||
}
|
||||
.status-percentage .dot {
|
||||
display: inline-block;
|
||||
width: 10px;
|
||||
height: 10px;
|
||||
border-radius: 50%;
|
||||
margin-right: 5px;
|
||||
}
|
||||
.status-percentage .online {
|
||||
background-color: #67c23a;
|
||||
}
|
||||
.status-percentage .abnormal {
|
||||
background-color: #f56c6c;
|
||||
}
|
||||
.chart-container {
|
||||
margin-top: 20px;
|
||||
}
|
||||
.alert-management {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
.alert-info {
|
||||
background-color: #fff;
|
||||
padding: 20px;
|
||||
border-radius: 10px;
|
||||
text-align: center;
|
||||
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
.alert-info.pending {
|
||||
background: linear-gradient(135deg, #64b5f6 0%, #bbdefb 100%);
|
||||
}
|
||||
.alert-info.processing {
|
||||
background: linear-gradient(135deg, #9575cd 0%, #d1c4e9 100%);
|
||||
}
|
||||
.alert-info.completed {
|
||||
background: linear-gradient(135deg, #81c784 0%, #c8e6c9 100%);
|
||||
}
|
||||
.alert-title {
|
||||
font-size: 14px;
|
||||
color: #999;
|
||||
}
|
||||
.alert-value {
|
||||
font-size: 20px;
|
||||
font-weight: bold;
|
||||
margin-top: 5px;
|
||||
}
|
||||
</style>
|
||||
|
|
@ -0,0 +1,71 @@
|
|||
<template>
|
||||
<div class="system-setting">
|
||||
<el-row>
|
||||
<el-col :span="3">
|
||||
<el-menu
|
||||
:default-openeds="['1', '2', '3', '4']"
|
||||
router
|
||||
class="el-menu-vertical-demo"
|
||||
background-color="#1f2d3d"
|
||||
text-color="#fff"
|
||||
active-text-color="#ffd04b"
|
||||
>
|
||||
<el-submenu index="1">
|
||||
<template slot="title">
|
||||
<i class="el-icon-menu"></i>
|
||||
<span>层级管理</span>
|
||||
</template>
|
||||
<el-menu-item index="/levelList">层级列表</el-menu-item>
|
||||
<el-menu-item index="/levelTree">层级树</el-menu-item>
|
||||
</el-submenu>
|
||||
<el-menu-item index="/siteManagement">
|
||||
<i class="el-icon-s-platform"></i>
|
||||
<span slot="title">站点管理</span>
|
||||
</el-menu-item>
|
||||
<el-submenu index="3">
|
||||
<template slot="title">
|
||||
<i class="el-icon-setting"></i>
|
||||
<span>设备管理</span>
|
||||
</template>
|
||||
<el-menu-item index="/serverManagement">服务器管理</el-menu-item>
|
||||
<el-menu-item index="/cameraManagement">摄像头管理</el-menu-item>
|
||||
</el-submenu>
|
||||
<el-menu-item index="/userManagement">
|
||||
<i class="el-icon-user"></i>
|
||||
<span slot="title">用户管理</span>
|
||||
</el-menu-item>
|
||||
</el-menu>
|
||||
</el-col>
|
||||
<el-col :span="21">
|
||||
<div class="router-view-container">
|
||||
<router-view></router-view>
|
||||
</div>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: "SystemSetting",
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.system-setting {
|
||||
height: 100%;
|
||||
}
|
||||
.el-menu-vertical-demo {
|
||||
height: 100%;
|
||||
border-right: none;
|
||||
}
|
||||
.router-view-container {
|
||||
margin: 20px 30px 20px 10px;
|
||||
padding: 20px;
|
||||
background-color: #fff;
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
|
||||
border-radius: 8px;
|
||||
height: calc(100vh - 100px); /* 调整高度以适应页面 */
|
||||
}
|
||||
</style>
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
<template>
|
||||
<div>
|
||||
<h2>用户管理</h2>
|
||||
<!-- 模拟静态数据内容 -->
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: "UserManagement",
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
/* 添加需要的样式 */
|
||||
</style>
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
|
||||
import {reactive} from "vue"
|
||||
import axios from "axios"
|
||||
|
||||
export default function (){
|
||||
|
||||
let dogList = reactive([
|
||||
'https://images.dog.ceo/breeds/pembroke/n02113023_1774.jpg'
|
||||
])
|
||||
async function addDog(){
|
||||
try {
|
||||
let result = await axios.get('https://dog.ceo/api/breeds/image/random')
|
||||
console.log(result.data.message)
|
||||
dogList.push(result.data.message)
|
||||
} catch (error) {
|
||||
console.log(error)
|
||||
}
|
||||
|
||||
}
|
||||
return {dogList,addDog}
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
import {ref,onMounted} from "vue"
|
||||
import axios from "axios"
|
||||
|
||||
export default function (){
|
||||
|
||||
let sum = ref(0)
|
||||
|
||||
function changeSum(){
|
||||
sum.value++
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
changeSum()
|
||||
})
|
||||
|
||||
return {sum,changeSum}
|
||||
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
import { createApp } from "vue";
|
||||
import App from "./App.vue";
|
||||
import router from "./router";
|
||||
import ElementPlus from 'element-plus'
|
||||
import 'element-plus/dist/index.css'
|
||||
import * as echarts from 'echarts'
|
||||
import axios from 'axios';
|
||||
|
||||
|
||||
|
||||
|
||||
const app = createApp(App)
|
||||
|
||||
app.use(ElementPlus)
|
||||
app.use(router)
|
||||
app.config.globalProperties.$echarts = echarts
|
||||
app.mount("#app");
|
|
@ -0,0 +1,75 @@
|
|||
// 第一步,引入createRouter
|
||||
import { createRouter, createWebHistory,createWebHashHistory} from 'vue-router'
|
||||
|
||||
// 引入路由组件
|
||||
import Home from '@/components/Home.vue'
|
||||
import About from '@/components/About.vue'
|
||||
import News from '@/components/News.vue'
|
||||
import AlertManagement from '@/components/AlertManagement.vue'
|
||||
import RealTimeMonitoring from '@/components/RealTimeMonitoring.vue'
|
||||
import StatisticsAnalysis from '@/components/StatisticsAnalysis.vue'
|
||||
import SystemSettings from '@/components/SystemSettings.vue'
|
||||
import LevelList from '@/components/LevelList.vue'
|
||||
import LevelTree from '@/components/LevelTree.vue'
|
||||
import Region1 from '@/components/Region1.vue'
|
||||
import Region2 from '@/components/Region2.vue'
|
||||
import SiteManagement from '@/components/SiteManagement.vue'
|
||||
import DeviceManagement from '@/components/DeviceManagement.vue'
|
||||
import ServerManagement from '@/components/ServerManagement.vue'
|
||||
import CameraManagement from '@/components/CameraManagement.vue'
|
||||
import UserManagement from '@/components/UserManagement.vue'
|
||||
|
||||
|
||||
// 第二步,创建路由求
|
||||
const router = createRouter({
|
||||
history: createWebHashHistory(),
|
||||
routes: [
|
||||
{ path: '/', component: Home },
|
||||
{ path: '/news', component: News },
|
||||
{ path: '/about', component: About },
|
||||
{ path: '/alert-management', name: 'AlertManagement', component: AlertManagement },
|
||||
{ path: '/real-time-monitoring', name: 'RealTimeMonitoring', component: RealTimeMonitoring },
|
||||
{ path: '/statistics-analysis', name: 'StatisticsAnalysis', component: StatisticsAnalysis },
|
||||
{ path: '/system-settings', name: 'SystemSettings', component: SystemSettings },
|
||||
{ path: '/levelList', name: 'LevelList', component: LevelList },
|
||||
{ path: '/region1', name: 'Region1', component: Region1 },
|
||||
{ path: '/region2', name: 'Region2', component: Region2 },
|
||||
{ path: '/siteManagement', name: 'SiteManagement', component: SiteManagement },
|
||||
{ path: '/deviceManagement', name: 'DeviceManagement', component: DeviceManagement },
|
||||
{ path: '/serverManagement', name: 'ServerManagement', component: ServerManagement },
|
||||
{ path: '/cameraManagement', name: 'CameraManagement', component: CameraManagement },
|
||||
{ path: '/userManagement', name: 'UserManagement', component: UserManagement },
|
||||
]
|
||||
})
|
||||
|
||||
// const routes = [
|
||||
// { path: '/', component: Home },
|
||||
// { path: '/news', component: News },
|
||||
// { path: '/about', component: About },
|
||||
// { path: '/alert-management', name: 'AlertManagement', component: AlertManagement },
|
||||
// { path: '/real-time-monitoring', name: 'RealTimeMonitoring', component: RealTimeMonitoring },
|
||||
// { path: '/statistics-analysis', name: 'StatisticsAnalysis', component: StatisticsAnalysis },
|
||||
// { path: '/system-settings', name: 'SystemSettings', component: SystemSettings },
|
||||
// { path: '/levelList', name: 'LevelList', component: LevelList },
|
||||
// { path: '/region1', name: 'Region1', component: Region1 },
|
||||
// { path: '/region2', name: 'Region2', component: Region2 },
|
||||
// { path: '/siteManagement', name: 'SiteManagement', component: SiteManagement },
|
||||
// { path: '/deviceManagement', name: 'DeviceManagement', component: DeviceManagement },
|
||||
// { path: '/serverManagement', name: 'ServerManagement', component: ServerManagement },
|
||||
// { path: '/cameraManagement', name: 'CameraManagement', component: CameraManagement },
|
||||
// { path: '/userManagement', name: 'UserManagement', component: UserManagement },
|
||||
|
||||
// ]
|
||||
|
||||
// const router = createRouter({
|
||||
// history: createWebHistory(),
|
||||
// routes
|
||||
// })
|
||||
|
||||
|
||||
// const routes = createRouter({
|
||||
// history: createWebHistory(process.env.BASE_URL),
|
||||
// router
|
||||
// })
|
||||
// 暴漏出去router
|
||||
export default router
|
|
@ -0,0 +1,158 @@
|
|||
import axios from "axios";
|
||||
|
||||
export const getSuperboxApiConfig = (address) => {
|
||||
const PORT = 8000;
|
||||
const BASE_ROUTE = "/api/v1";
|
||||
const LOGIN_ROUTE = BASE_ROUTE + "/auth/login";
|
||||
const LOGOUT_ROUTE = BASE_ROUTE + "/auth/logout";
|
||||
const CAMERA_ROUTE = BASE_ROUTE + "/camera/cameras";
|
||||
const EVENTS_ROUTE = BASE_ROUTE + "/event/events";
|
||||
const ALGORITHM_ROUTE = BASE_ROUTE + "/algorithms";
|
||||
|
||||
let addr = address;
|
||||
if (!addr) {
|
||||
addr = window.location.host.replace(/:\d+/, "");
|
||||
}
|
||||
const superboxAddress = "http://" + addr + ":" + PORT.toString();
|
||||
|
||||
return {
|
||||
base: superboxAddress + BASE_ROUTE,
|
||||
login: superboxAddress + LOGIN_ROUTE,
|
||||
logout: superboxAddress + LOGOUT_ROUTE,
|
||||
cameras: superboxAddress + CAMERA_ROUTE,
|
||||
events: superboxAddress + EVENTS_ROUTE,
|
||||
algorithms: superboxAddress + ALGORITHM_ROUTE,
|
||||
};
|
||||
/*return {
|
||||
base: "/api/v1",
|
||||
login: "/api/v1/auth/login",
|
||||
logout: "/api/v1/auth/logout",
|
||||
cameras: "/api/v1/camera/cameras",
|
||||
events: "/api/v1/event/events",
|
||||
};*/
|
||||
};
|
||||
|
||||
axios.defaults.withCredentials = true;
|
||||
export const login = (username, password, address = null) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
const api = getSuperboxApiConfig(address);
|
||||
axios
|
||||
.post(
|
||||
api.login,
|
||||
{
|
||||
username: username,
|
||||
password: password,
|
||||
cookieless: false,
|
||||
},
|
||||
{
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
}
|
||||
)
|
||||
.then((res) => {
|
||||
if (res.data.err.ec === 0) {
|
||||
resolve(res.data.ret.token);
|
||||
}
|
||||
reject(res.data.err);
|
||||
})
|
||||
.catch((err) => {
|
||||
reject(err);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
export const getCameras = (token, address = null) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
const api = getSuperboxApiConfig(address);
|
||||
axios
|
||||
.get(api.cameras, {
|
||||
withCredentials: true,
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
Authorization: `Bearer ${token}`,
|
||||
},
|
||||
})
|
||||
.then((res) => {
|
||||
if (res.data.err.ec === 0) {
|
||||
resolve(res.data.ret.results);
|
||||
}
|
||||
reject(res.data.err);
|
||||
})
|
||||
.catch((err) => {
|
||||
reject(err);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
export const getEvents = (token, address = null) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
const api = getSuperboxApiConfig(address);
|
||||
axios
|
||||
.get(api.events, {
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
Authorization: `Bearer ${token}`,
|
||||
},
|
||||
})
|
||||
.then((res) => {
|
||||
if (res.data.err.ec === 0) {
|
||||
resolve(res.data.ret.results);
|
||||
}
|
||||
reject(res.data.err);
|
||||
})
|
||||
.catch((err) => {
|
||||
reject(err);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
export const getAlgorithms = (token, address = null) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
const api = getSuperboxApiConfig(address);
|
||||
axios
|
||||
.get(api.algorithms, {
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
Authorization: `Bearer ${token}`,
|
||||
},
|
||||
})
|
||||
.then((res) => {
|
||||
if (res.data.err.ec === 0) {
|
||||
resolve(res.data.ret);
|
||||
}
|
||||
reject(res.data.err);
|
||||
})
|
||||
.catch((err) => {
|
||||
reject(err);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
var codeNameMap = {};
|
||||
|
||||
export const initCodeNameMap = async (token, address = null) => {
|
||||
try {
|
||||
const algorithms = await getAlgorithms(token, address);
|
||||
algorithms.forEach((algorithm) => {
|
||||
codeNameMap[algorithm.code_name] = algorithm.name;
|
||||
});
|
||||
return true;
|
||||
} catch (err) {
|
||||
console.log(err);
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
export const codenameTranslate = (codeName) => {
|
||||
return codeNameMap[codeName];
|
||||
};
|
||||
|
||||
export default {
|
||||
login,
|
||||
getCameras,
|
||||
getEvents,
|
||||
getSuperboxApiConfig,
|
||||
initCodeNameMap,
|
||||
codenameTranslate,
|
||||
};
|
|
@ -0,0 +1,14 @@
|
|||
{
|
||||
"extends": "@vue/tsconfig/tsconfig.dom.json",
|
||||
"include": ["env.d.ts", "src/**/*", "src/**/*.vue"],
|
||||
"exclude": ["src/**/__tests__/*"],
|
||||
"compilerOptions": {
|
||||
"composite": true,
|
||||
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo",
|
||||
|
||||
"baseUrl": ".",
|
||||
"paths": {
|
||||
"@/*": ["./src/*"]
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
{
|
||||
"files": [],
|
||||
"references": [
|
||||
{
|
||||
"path": "./tsconfig.node.json"
|
||||
},
|
||||
{
|
||||
"path": "./tsconfig.app.json"
|
||||
}
|
||||
],
|
||||
"compilerOptions": {
|
||||
"types": ["element-plus/global"]
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
{
|
||||
"extends": "@tsconfig/node20/tsconfig.json",
|
||||
"include": [
|
||||
"vite.config.*",
|
||||
"vitest.config.*",
|
||||
"cypress.config.*",
|
||||
"nightwatch.conf.*",
|
||||
"playwright.config.*"
|
||||
],
|
||||
"compilerOptions": {
|
||||
"composite": true,
|
||||
"noEmit": true,
|
||||
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo",
|
||||
|
||||
"module": "ESNext",
|
||||
"moduleResolution": "Bundler",
|
||||
"types": ["node"]
|
||||
}
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
import { defineConfig } from 'vite'
|
||||
import vue from '@vitejs/plugin-vue'
|
||||
import vueSetupExtend from 'vite-plugin-vue-setup-extend'
|
||||
import { fileURLToPath, URL } from 'node:url'
|
||||
import { createProxyMiddleware } from 'http-proxy-middleware'
|
||||
|
||||
|
||||
// https://vitejs.dev/config/
|
||||
export default defineConfig({
|
||||
plugins: [
|
||||
vue(),
|
||||
vueSetupExtend(),
|
||||
],
|
||||
resolve: {
|
||||
alias: {
|
||||
'@': fileURLToPath(new URL('./src', import.meta.url))
|
||||
}
|
||||
},
|
||||
server:{
|
||||
// host:'192.168.28.44',
|
||||
// host:'127.0.0.1',
|
||||
// host: '192.168.28.32',
|
||||
port: 8090,
|
||||
open:true,
|
||||
cors: true,
|
||||
// proxy: {
|
||||
// '/api': "192.168.28.44:8000"
|
||||
// }
|
||||
proxy: {
|
||||
'/api': {
|
||||
target: 'http://127.0.0.1:8000', // 目标 API 地址
|
||||
changeOrigin: true, // 开启跨域
|
||||
rewrite: path => path.replace('^/api/', '')
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
|
@ -0,0 +1,21 @@
|
|||
// vite.config.ts
|
||||
import { fileURLToPath, URL } from "node:url";
|
||||
import { defineConfig } from "file:///D:/java/demo/turing/vue_one/node_modules/vite/dist/node/index.js";
|
||||
import vue from "file:///D:/java/demo/turing/vue_one/node_modules/@vitejs/plugin-vue/dist/index.mjs";
|
||||
import vueSetupExtend from "file:///D:/java/demo/turing/vue_one/node_modules/vite-plugin-vue-setup-extend/dist/index.mjs";
|
||||
var __vite_injected_original_import_meta_url = "file:///D:/java/demo/turing/vue_one/vite.config.ts";
|
||||
var vite_config_default = defineConfig({
|
||||
plugins: [
|
||||
vue(),
|
||||
vueSetupExtend()
|
||||
],
|
||||
resolve: {
|
||||
alias: {
|
||||
"@": fileURLToPath(new URL("./src", __vite_injected_original_import_meta_url))
|
||||
}
|
||||
}
|
||||
});
|
||||
export {
|
||||
vite_config_default as default
|
||||
};
|
||||
//# sourceMappingURL=data:application/json;base64,ewogICJ2ZXJzaW9uIjogMywKICAic291cmNlcyI6IFsidml0ZS5jb25maWcudHMiXSwKICAic291cmNlc0NvbnRlbnQiOiBbImNvbnN0IF9fdml0ZV9pbmplY3RlZF9vcmlnaW5hbF9kaXJuYW1lID0gXCJEOlxcXFxqYXZhXFxcXGRlbW9cXFxcdHVyaW5nXFxcXHZ1ZV9vbmVcIjtjb25zdCBfX3ZpdGVfaW5qZWN0ZWRfb3JpZ2luYWxfZmlsZW5hbWUgPSBcIkQ6XFxcXGphdmFcXFxcZGVtb1xcXFx0dXJpbmdcXFxcdnVlX29uZVxcXFx2aXRlLmNvbmZpZy50c1wiO2NvbnN0IF9fdml0ZV9pbmplY3RlZF9vcmlnaW5hbF9pbXBvcnRfbWV0YV91cmwgPSBcImZpbGU6Ly8vRDovamF2YS9kZW1vL3R1cmluZy92dWVfb25lL3ZpdGUuY29uZmlnLnRzXCI7aW1wb3J0IHsgZmlsZVVSTFRvUGF0aCwgVVJMIH0gZnJvbSAnbm9kZTp1cmwnXG5cbmltcG9ydCB7IGRlZmluZUNvbmZpZyB9IGZyb20gJ3ZpdGUnXG5pbXBvcnQgdnVlIGZyb20gJ0B2aXRlanMvcGx1Z2luLXZ1ZSdcbmltcG9ydCB2dWVTZXR1cEV4dGVuZCBmcm9tICd2aXRlLXBsdWdpbi12dWUtc2V0dXAtZXh0ZW5kJ1xuXG4vLyBodHRwczovL3ZpdGVqcy5kZXYvY29uZmlnL1xuZXhwb3J0IGRlZmF1bHQgZGVmaW5lQ29uZmlnKHtcbiAgcGx1Z2luczogW1xuICAgIHZ1ZSgpLFxuICAgIHZ1ZVNldHVwRXh0ZW5kKCksXG4gIF0sXG4gIHJlc29sdmU6IHtcbiAgICBhbGlhczoge1xuICAgICAgJ0AnOiBmaWxlVVJMVG9QYXRoKG5ldyBVUkwoJy4vc3JjJywgaW1wb3J0Lm1ldGEudXJsKSlcbiAgICB9XG4gIH1cbn0pXG4iXSwKICAibWFwcGluZ3MiOiAiO0FBQTZRLFNBQVMsZUFBZSxXQUFXO0FBRWhULFNBQVMsb0JBQW9CO0FBQzdCLE9BQU8sU0FBUztBQUNoQixPQUFPLG9CQUFvQjtBQUo0SSxJQUFNLDJDQUEyQztBQU94TixJQUFPLHNCQUFRLGFBQWE7QUFBQSxFQUMxQixTQUFTO0FBQUEsSUFDUCxJQUFJO0FBQUEsSUFDSixlQUFlO0FBQUEsRUFDakI7QUFBQSxFQUNBLFNBQVM7QUFBQSxJQUNQLE9BQU87QUFBQSxNQUNMLEtBQUssY0FBYyxJQUFJLElBQUksU0FBUyx3Q0FBZSxDQUFDO0FBQUEsSUFDdEQ7QUFBQSxFQUNGO0FBQ0YsQ0FBQzsiLAogICJuYW1lcyI6IFtdCn0K
|
|
@ -0,0 +1,21 @@
|
|||
// vite.config.ts
|
||||
import { fileURLToPath, URL } from "node:url";
|
||||
import { defineConfig } from "file:///D:/java/demo/turing/vue_one/node_modules/vite/dist/node/index.js";
|
||||
import vue from "file:///D:/java/demo/turing/vue_one/node_modules/@vitejs/plugin-vue/dist/index.mjs";
|
||||
import vueSetupExtend from "file:///D:/java/demo/turing/vue_one/node_modules/vite-plugin-vue-setup-extend/dist/index.mjs";
|
||||
var __vite_injected_original_import_meta_url = "file:///D:/java/demo/turing/vue_one/vite.config.ts";
|
||||
var vite_config_default = defineConfig({
|
||||
plugins: [
|
||||
vue(),
|
||||
vueSetupExtend()
|
||||
],
|
||||
resolve: {
|
||||
alias: {
|
||||
"@": fileURLToPath(new URL("./src", __vite_injected_original_import_meta_url))
|
||||
}
|
||||
}
|
||||
});
|
||||
export {
|
||||
vite_config_default as default
|
||||
};
|
||||
//# sourceMappingURL=data:application/json;base64,ewogICJ2ZXJzaW9uIjogMywKICAic291cmNlcyI6IFsidml0ZS5jb25maWcudHMiXSwKICAic291cmNlc0NvbnRlbnQiOiBbImNvbnN0IF9fdml0ZV9pbmplY3RlZF9vcmlnaW5hbF9kaXJuYW1lID0gXCJEOlxcXFxqYXZhXFxcXGRlbW9cXFxcdHVyaW5nXFxcXHZ1ZV9vbmVcIjtjb25zdCBfX3ZpdGVfaW5qZWN0ZWRfb3JpZ2luYWxfZmlsZW5hbWUgPSBcIkQ6XFxcXGphdmFcXFxcZGVtb1xcXFx0dXJpbmdcXFxcdnVlX29uZVxcXFx2aXRlLmNvbmZpZy50c1wiO2NvbnN0IF9fdml0ZV9pbmplY3RlZF9vcmlnaW5hbF9pbXBvcnRfbWV0YV91cmwgPSBcImZpbGU6Ly8vRDovamF2YS9kZW1vL3R1cmluZy92dWVfb25lL3ZpdGUuY29uZmlnLnRzXCI7aW1wb3J0IHsgZmlsZVVSTFRvUGF0aCwgVVJMIH0gZnJvbSAnbm9kZTp1cmwnXG5cbmltcG9ydCB7IGRlZmluZUNvbmZpZyB9IGZyb20gJ3ZpdGUnXG5pbXBvcnQgdnVlIGZyb20gJ0B2aXRlanMvcGx1Z2luLXZ1ZSdcbmltcG9ydCB2dWVTZXR1cEV4dGVuZCBmcm9tICd2aXRlLXBsdWdpbi12dWUtc2V0dXAtZXh0ZW5kJ1xuXG4vLyBodHRwczovL3ZpdGVqcy5kZXYvY29uZmlnL1xuZXhwb3J0IGRlZmF1bHQgZGVmaW5lQ29uZmlnKHtcbiAgcGx1Z2luczogW1xuICAgIHZ1ZSgpLFxuICAgIHZ1ZVNldHVwRXh0ZW5kKCksXG4gIF0sXG4gIHJlc29sdmU6IHtcbiAgICBhbGlhczoge1xuICAgICAgJ0AnOiBmaWxlVVJMVG9QYXRoKG5ldyBVUkwoJy4vc3JjJywgaW1wb3J0Lm1ldGEudXJsKSlcbiAgICB9XG4gIH1cbn0pXG4iXSwKICAibWFwcGluZ3MiOiAiO0FBQTZRLFNBQVMsZUFBZSxXQUFXO0FBRWhULFNBQVMsb0JBQW9CO0FBQzdCLE9BQU8sU0FBUztBQUNoQixPQUFPLG9CQUFvQjtBQUo0SSxJQUFNLDJDQUEyQztBQU94TixJQUFPLHNCQUFRLGFBQWE7QUFBQSxFQUMxQixTQUFTO0FBQUEsSUFDUCxJQUFJO0FBQUEsSUFDSixlQUFlO0FBQUEsRUFDakI7QUFBQSxFQUNBLFNBQVM7QUFBQSxJQUNQLE9BQU87QUFBQSxNQUNMLEtBQUssY0FBYyxJQUFJLElBQUksU0FBUyx3Q0FBZSxDQUFDO0FBQUEsSUFDdEQ7QUFBQSxFQUNGO0FBQ0YsQ0FBQzsiLAogICJuYW1lcyI6IFtdCn0K
|
|
@ -0,0 +1,26 @@
|
|||
// vite.config.ts
|
||||
import { fileURLToPath, URL } from "node:url";
|
||||
import { defineConfig } from "file:///D:/java/demo/turing/vue_one/node_modules/vite/dist/node/index.js";
|
||||
import vue from "file:///D:/java/demo/turing/vue_one/node_modules/@vitejs/plugin-vue/dist/index.mjs";
|
||||
import vueSetupExtend from "file:///D:/java/demo/turing/vue_one/node_modules/vite-plugin-vue-setup-extend/dist/index.mjs";
|
||||
var __vite_injected_original_import_meta_url = "file:///D:/java/demo/turing/vue_one/vite.config.ts";
|
||||
var vite_config_default = defineConfig({
|
||||
plugins: [
|
||||
vue(),
|
||||
vueSetupExtend()
|
||||
],
|
||||
resolve: {
|
||||
alias: {
|
||||
"@": fileURLToPath(new URL("./src", __vite_injected_original_import_meta_url))
|
||||
}
|
||||
},
|
||||
server: {
|
||||
host: "127.0.0.1",
|
||||
port: 5137,
|
||||
open: true
|
||||
}
|
||||
});
|
||||
export {
|
||||
vite_config_default as default
|
||||
};
|
||||
//# sourceMappingURL=data:application/json;base64,ewogICJ2ZXJzaW9uIjogMywKICAic291cmNlcyI6IFsidml0ZS5jb25maWcudHMiXSwKICAic291cmNlc0NvbnRlbnQiOiBbImNvbnN0IF9fdml0ZV9pbmplY3RlZF9vcmlnaW5hbF9kaXJuYW1lID0gXCJEOlxcXFxqYXZhXFxcXGRlbW9cXFxcdHVyaW5nXFxcXHZ1ZV9vbmVcIjtjb25zdCBfX3ZpdGVfaW5qZWN0ZWRfb3JpZ2luYWxfZmlsZW5hbWUgPSBcIkQ6XFxcXGphdmFcXFxcZGVtb1xcXFx0dXJpbmdcXFxcdnVlX29uZVxcXFx2aXRlLmNvbmZpZy50c1wiO2NvbnN0IF9fdml0ZV9pbmplY3RlZF9vcmlnaW5hbF9pbXBvcnRfbWV0YV91cmwgPSBcImZpbGU6Ly8vRDovamF2YS9kZW1vL3R1cmluZy92dWVfb25lL3ZpdGUuY29uZmlnLnRzXCI7aW1wb3J0IHsgZmlsZVVSTFRvUGF0aCwgVVJMIH0gZnJvbSAnbm9kZTp1cmwnXG5cbmltcG9ydCB7IGRlZmluZUNvbmZpZyB9IGZyb20gJ3ZpdGUnXG5pbXBvcnQgdnVlIGZyb20gJ0B2aXRlanMvcGx1Z2luLXZ1ZSdcbmltcG9ydCB2dWVTZXR1cEV4dGVuZCBmcm9tICd2aXRlLXBsdWdpbi12dWUtc2V0dXAtZXh0ZW5kJ1xuXG4vLyBodHRwczovL3ZpdGVqcy5kZXYvY29uZmlnL1xuZXhwb3J0IGRlZmF1bHQgZGVmaW5lQ29uZmlnKHtcbiAgcGx1Z2luczogW1xuICAgIHZ1ZSgpLFxuICAgIHZ1ZVNldHVwRXh0ZW5kKCksXG4gIF0sXG4gIHJlc29sdmU6IHtcbiAgICBhbGlhczoge1xuICAgICAgJ0AnOiBmaWxlVVJMVG9QYXRoKG5ldyBVUkwoJy4vc3JjJywgaW1wb3J0Lm1ldGEudXJsKSlcbiAgICB9XG4gIH0sXG4gIHNlcnZlcjp7XG4gICAgaG9zdDonMTI3LjAuMC4xJyxcbiAgICBwb3J0OjUxMzcsXG4gICAgb3Blbjp0cnVlXG4gIH1cbn0pXG4iXSwKICAibWFwcGluZ3MiOiAiO0FBQTZRLFNBQVMsZUFBZSxXQUFXO0FBRWhULFNBQVMsb0JBQW9CO0FBQzdCLE9BQU8sU0FBUztBQUNoQixPQUFPLG9CQUFvQjtBQUo0SSxJQUFNLDJDQUEyQztBQU94TixJQUFPLHNCQUFRLGFBQWE7QUFBQSxFQUMxQixTQUFTO0FBQUEsSUFDUCxJQUFJO0FBQUEsSUFDSixlQUFlO0FBQUEsRUFDakI7QUFBQSxFQUNBLFNBQVM7QUFBQSxJQUNQLE9BQU87QUFBQSxNQUNMLEtBQUssY0FBYyxJQUFJLElBQUksU0FBUyx3Q0FBZSxDQUFDO0FBQUEsSUFDdEQ7QUFBQSxFQUNGO0FBQUEsRUFDQSxRQUFPO0FBQUEsSUFDTCxNQUFLO0FBQUEsSUFDTCxNQUFLO0FBQUEsSUFDTCxNQUFLO0FBQUEsRUFDUDtBQUNGLENBQUM7IiwKICAibmFtZXMiOiBbXQp9Cg==
|
Loading…
Reference in New Issue