Commit 1ed690be authored by lei's avatar lei

add:视频分析任务、算法配置、报警日志、报警提醒、首页

parent 8cbad040
<svg viewBox="0 0 160 160" xmlns="http://www.w3.org/2000/svg"><path d="M81.28 55.9c-.1-11.67-2.93-22.55-9.37-32.38-1-1.5-2.14-2.86-2.5-4.71a8.1 8.1 0 014-8.61 7.89 7.89 0 019.3 1.23 35.999 35.999 0 015.9 8.83 75.18 75.18 0 018.44 28.58 83.211 83.211 0 01-5.23 36.74 102.983 102.983 0 01-3 7.28 1.2 1.2 0 000 1.41c9.58 13.3 21.76 23 37.85 27.24a54.37 54.37 0 0019.68 1.57 7.72 7.72 0 018.36 6.9 7.903 7.903 0 01-6.7 9 64.744 64.744 0 01-23-1.33 77.68 77.68 0 01-36.93-19.88 93.628 93.628 0 01-11.91-13.71 2.18 2.18 0 00-2.3-1.06 72.744 72.744 0 00-27.38 7.55c-11.6 6-20.67 14.58-26.4 26.45a10.134 10.134 0 01-3.7 4.7 8 8 0 01-9.19-.7 7.86 7.86 0 01-2.36-9.28 60.324 60.324 0 018.72-14.52c12.2-15.43 28.21-24.59 47.32-28.57A85.085 85.085 0 0173.07 87c.524.015 1-.307 1.18-.8a76.06 76.06 0 006.53-22.3c.351-2.652.518-5.325.5-8z" fill="#646cff"/><path d="M136.26 108.34a44.742 44.742 0 01-11.13-2.87 46.108 46.108 0 01-19.66-13.76 8 8 0 015.72-13.22 7.93 7.93 0 016.54 2.93 33.27 33.27 0 0018.87 10.75c1.546.155 3.058.553 4.48 1.18a8.08 8.08 0 013.84 9.21c-.92 3.52-4.13 5.81-8.66 5.78zm-80.6-75.02a7.61 7.61 0 016.64 5 49.139 49.139 0 013.64 17 46.33 46.33 0 01-2.46 17.28c-2 5.77-8.24 7.79-12.89 4.15a8.1 8.1 0 01-2.39-9 31.679 31.679 0 001.68-12.36 35.77 35.77 0 00-2.43-11c-2.1-5.45 1.75-11.07 8.21-11.07zm22.26 93.25a8 8 0 01-6.68 7.86 32.88 32.88 0 00-19.7 12.19 8.13 8.13 0 01-11.21 1.62 8 8 0 01-1.41-11.58A51.043 51.043 0 0154 123.81a45.842 45.842 0 0114-5.1c5.35-1.04 9.91 2.56 9.92 7.86z" fill="#646cff"/></svg>
src/assets/logo/logo.png

5.53 KB | W: | H:

src/assets/logo/logo.png

10.4 KB | W: | H:

src/assets/logo/logo.png
src/assets/logo/logo.png
src/assets/logo/logo.png
src/assets/logo/logo.png
  • 2-up
  • Swipe
  • Onion skin
@import './variables.scss'; @import "./variables.scss";
@import './mixin.scss'; @import "./mixin.scss";
@import './transition.scss'; @import "./transition.scss";
@import './element-ui.scss'; @import "./element-ui.scss";
@import './sidebar.scss'; @import "./sidebar.scss";
@import './btn.scss'; @import "./btn.scss";
body { body {
height: 100%; height: 100%;
-moz-osx-font-smoothing: grayscale; -moz-osx-font-smoothing: grayscale;
-webkit-font-smoothing: antialiased; -webkit-font-smoothing: antialiased;
text-rendering: optimizeLegibility; text-rendering: optimizeLegibility;
font-family: Helvetica Neue, Helvetica, PingFang SC, Hiragino Sans GB, Microsoft YaHei, Arial, sans-serif; font-family: Helvetica Neue, Helvetica, PingFang SC, Hiragino Sans GB,
Microsoft YaHei, Arial, sans-serif;
} }
label { label {
...@@ -104,7 +105,8 @@ aside { ...@@ -104,7 +105,8 @@ aside {
display: block; display: block;
line-height: 32px; line-height: 32px;
font-size: 16px; font-size: 16px;
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen, Ubuntu, Cantarell, "Fira Sans", "Droid Sans", "Helvetica Neue", sans-serif; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen,
Ubuntu, Cantarell, "Fira Sans", "Droid Sans", "Helvetica Neue", sans-serif;
color: #2c3e50; color: #2c3e50;
-webkit-font-smoothing: antialiased; -webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale; -moz-osx-font-smoothing: grayscale;
...@@ -123,14 +125,19 @@ aside { ...@@ -123,14 +125,19 @@ aside {
.app-container { .app-container {
padding: 20px; padding: 20px;
} }
.Pd20 {
padding: 20px;
background: #fff;
position: relative;
height: calc(100vh - 125px);
}
.components-container { .components-container {
margin: 30px 50px; margin: 30px 50px;
position: relative; position: relative;
} }
.text-center { .text-center {
text-align: center text-align: center;
} }
.sub-navbar { .sub-navbar {
...@@ -141,7 +148,13 @@ aside { ...@@ -141,7 +148,13 @@ aside {
text-align: right; text-align: right;
padding-right: 20px; padding-right: 20px;
transition: 600ms ease position; transition: 600ms ease position;
background: linear-gradient(90deg, rgba(32, 182, 249, 1) 0%, rgba(32, 182, 249, 1) 0%, rgba(33, 120, 241, 1) 100%, rgba(33, 120, 241, 1) 100%); background: linear-gradient(
90deg,
rgba(32, 182, 249, 1) 0%,
rgba(32, 182, 249, 1) 0%,
rgba(33, 120, 241, 1) 100%,
rgba(33, 120, 241, 1) 100%
);
.subtitle { .subtitle {
font-size: 20px; font-size: 20px;
......
<template> <template>
<div class="navbar"> <div class="navbar">
<hamburger id="hamburger-container" :is-active="sidebar.opened" class="hamburger-container" @toggleClick="toggleSideBar" /> <hamburger
id="hamburger-container"
<breadcrumb v-if="!topNav" id="breadcrumb-container" class="breadcrumb-container" /> :is-active="sidebar.opened"
class="hamburger-container"
@toggleClick="toggleSideBar"
/>
<breadcrumb
v-if="!topNav"
id="breadcrumb-container"
class="breadcrumb-container"
/>
<top-nav v-if="topNav" id="topmenu-container" class="topmenu-container" /> <top-nav v-if="topNav" id="topmenu-container" class="topmenu-container" />
<div class="right-menu"> <div class="right-menu">
<template v-if="device!=='mobile'"> <template v-if="device !== 'mobile'">
<search id="header-search" class="right-menu-item" /> <search id="header-search" class="right-menu-item" />
<el-tooltip content="源码地址" effect="dark" placement="bottom">
<ruo-yi-git id="ruoyi-git" class="right-menu-item hover-effect" />
</el-tooltip>
<el-tooltip content="文档地址" effect="dark" placement="bottom">
<ruo-yi-doc id="ruoyi-doc" class="right-menu-item hover-effect" />
</el-tooltip>
<screenfull id="screenfull" class="right-menu-item hover-effect" /> <screenfull id="screenfull" class="right-menu-item hover-effect" />
<el-tooltip content="可视化大屏" effect="dark" placement="bottom">
<i
class="el-icon-monitor right-menu-item hover-effect"
style="font-size: 28px; line-height: 46px"
@click="$router.push('/screen')"
></i>
</el-tooltip>
<el-tooltip content="布局大小" effect="dark" placement="bottom"> <el-tooltip content="布局大小" effect="dark" placement="bottom">
<size-select id="size-select" class="right-menu-item hover-effect" /> <size-select id="size-select" class="right-menu-item hover-effect" />
</el-tooltip> </el-tooltip>
</template> </template>
<el-dropdown class="avatar-container right-menu-item hover-effect" trigger="click"> <el-dropdown
class="avatar-container right-menu-item hover-effect"
trigger="click"
>
<div class="avatar-wrapper"> <div class="avatar-wrapper">
<img :src="avatar" class="user-avatar"> <img :src="avatar" class="user-avatar" />
<i class="el-icon-caret-bottom" /> <i class="el-icon-caret-bottom" />
</div> </div>
<el-dropdown-menu slot="dropdown"> <el-dropdown-menu slot="dropdown">
...@@ -47,15 +55,15 @@ ...@@ -47,15 +55,15 @@
</template> </template>
<script> <script>
import { mapGetters } from 'vuex' import { mapGetters } from "vuex";
import Breadcrumb from '@/components/Breadcrumb' import Breadcrumb from "@/components/Breadcrumb";
import TopNav from '@/components/TopNav' import TopNav from "@/components/TopNav";
import Hamburger from '@/components/Hamburger' import Hamburger from "@/components/Hamburger";
import Screenfull from '@/components/Screenfull' import Screenfull from "@/components/Screenfull";
import SizeSelect from '@/components/SizeSelect' import SizeSelect from "@/components/SizeSelect";
import Search from '@/components/HeaderSearch' import Search from "@/components/HeaderSearch";
import RuoYiGit from '@/components/RuoYi/Git' import RuoYiGit from "@/components/RuoYi/Git";
import RuoYiDoc from '@/components/RuoYi/Doc' import RuoYiDoc from "@/components/RuoYi/Doc";
export default { export default {
components: { components: {
...@@ -66,48 +74,46 @@ export default { ...@@ -66,48 +74,46 @@ export default {
SizeSelect, SizeSelect,
Search, Search,
RuoYiGit, RuoYiGit,
RuoYiDoc RuoYiDoc,
}, },
computed: { computed: {
...mapGetters([ ...mapGetters(["sidebar", "avatar", "device"]),
'sidebar',
'avatar',
'device'
]),
setting: { setting: {
get() { get() {
return this.$store.state.settings.showSettings return this.$store.state.settings.showSettings;
}, },
set(val) { set(val) {
this.$store.dispatch('settings/changeSetting', { this.$store.dispatch("settings/changeSetting", {
key: 'showSettings', key: "showSettings",
value: val value: val,
}) });
} },
}, },
topNav: { topNav: {
get() { get() {
return this.$store.state.settings.topNav return this.$store.state.settings.topNav;
} },
} },
}, },
methods: { methods: {
toggleSideBar() { toggleSideBar() {
this.$store.dispatch('app/toggleSideBar') this.$store.dispatch("app/toggleSideBar");
}, },
logout() { logout() {
this.$confirm('确定注销并退出系统吗?', '提示', { this.$confirm("确定注销并退出系统吗?", "提示", {
confirmButtonText: '确定', confirmButtonText: "确定",
cancelButtonText: '取消', cancelButtonText: "取消",
type: 'warning' type: "warning",
}).then(() => {
this.$store.dispatch('LogOut').then(() => {
location.href = '/index'
}) })
}).catch(() => {}) .then(() => {
} this.$store.dispatch("LogOut").then(() => {
} location.href = "/index";
} });
})
.catch(() => {});
},
},
};
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
...@@ -116,18 +122,18 @@ export default { ...@@ -116,18 +122,18 @@ export default {
overflow: hidden; overflow: hidden;
position: relative; position: relative;
background: #fff; background: #fff;
box-shadow: 0 1px 4px rgba(0,21,41,.08); box-shadow: 0 1px 4px rgba(0, 21, 41, 0.08);
.hamburger-container { .hamburger-container {
line-height: 46px; line-height: 46px;
height: 100%; height: 100%;
float: left; float: left;
cursor: pointer; cursor: pointer;
transition: background .3s; transition: background 0.3s;
-webkit-tap-highlight-color:transparent; -webkit-tap-highlight-color: transparent;
&:hover { &:hover {
background: rgba(0, 0, 0, .025) background: rgba(0, 0, 0, 0.025);
} }
} }
...@@ -164,10 +170,10 @@ export default { ...@@ -164,10 +170,10 @@ export default {
&.hover-effect { &.hover-effect {
cursor: pointer; cursor: pointer;
transition: background .3s; transition: background 0.3s;
&:hover { &:hover {
background: rgba(0, 0, 0, .025) background: rgba(0, 0, 0, 0.025);
} }
} }
} }
......
...@@ -46,6 +46,11 @@ export const constantRoutes = [ ...@@ -46,6 +46,11 @@ export const constantRoutes = [
component: () => import('@/views/login'), component: () => import('@/views/login'),
hidden: true hidden: true
}, },
{
path: '/screen',
component: () => import('@/views/Screen'),
hidden: true
},
{ {
path: '/register', path: '/register',
component: () => import('@/views/register'), component: () => import('@/views/register'),
......
<template> <template>
<div class="app-container">报警日志</div> <div class="app-container">
<div class="Pd20">
<el-form :model="form" :inline="true" size="mini">
<el-form-item>
<el-select v-model="form.cameraName" placeholder="监控点位" clearable>
<el-option
v-for="(item, index) in cameraAdderss"
:key="index"
:value="item.address"
:label="item.name"
></el-option>
</el-select>
</el-form-item>
<el-form-item>
<el-select
v-model="form.algorithmLevel"
placeholder="算法报警等级"
clearable
>
<el-option
v-for="(item, index) in dict.type.algorithm_level"
:key="index"
:value="item.value"
:label="item.label"
></el-option>
</el-select>
</el-form-item>
<el-form-item>
<el-select
v-model="form.alarmStatus"
placeholder="报警处理状态"
clearable
>
<el-option :value="3" label="待处理"></el-option>
<el-option :value="1" label="正确报警"></el-option>
<el-option :value="0" label="错误报警"></el-option>
</el-select>
</el-form-item>
<el-form-item>
<el-input
v-model="form.algorithmName"
placeholder="算法名称"
></el-input>
</el-form-item>
<el-form-item>
<el-button type="primary" size="mini" @click="search">
<i class="el-icon-search el-icon--left"></i>
搜索
</el-button>
</el-form-item>
</el-form>
<el-table :data="tableList">
<el-table-column
label="摄像头ID"
prop="id"
align="center"
></el-table-column>
<el-table-column
label="视频分析任务名称"
prop="videoAnlysisTasksName"
align="center"
></el-table-column>
<el-table-column
label="摄像头名称"
prop="cameraName"
align="center"
></el-table-column>
<el-table-column
label="报警图片"
prop="alarmImg"
align="center"
></el-table-column>
<el-table-column
label="报警时间"
prop="alarmTime"
align="center"
></el-table-column>
<el-table-column
label="算法名称"
prop="algorithmName"
align="center"
></el-table-column>
<el-table-column
label="算法报警等级"
prop="algorithmLevel"
align="center"
>
<template slot-scope="scope">
<dict-tag
:options="dict.type.algorithm_level"
:value="scope.row.algorithmLevel"
/>
</template>
</el-table-column>
<el-table-column label="报警处理状态" align="center">
<template slot-scope="scope">
{{ scope.row.alarmStatus === 0 ? "错误报警" : "正确报警" }}
</template>
</el-table-column>
<el-table-column label="操作" align="center" width="200px">
<template slot-scope="scope">
<el-button type="text" size="mini" @click="editBut(scope.row)">
正确报警
</el-button>
<el-button type="text" size="mini" @click="editBut(scope.row)">
错误报警
</el-button>
<el-button type="text" size="mini" @click="deleteBut(scope.row)">
<i class="el-icon-delete el-icon--left"></i>
删除
</el-button>
</template>
</el-table-column>
</el-table>
<pagination
v-show="total > 0"
:total="total"
:page.sync="queryParams.pageNum"
:limit.sync="queryParams.pageSize"
@pagination="getList"
/>
</div>
</div>
</template> </template>
<script> <script>
export default { export default {
dicts: ["algorithm_level"],
name: "Alarmlog", name: "Alarmlog",
props: {}, props: {},
components: {}, components: {},
data() { data() {
return {}; return {
form: {
id: 1, // 摄像头ID
videoAnlysisTasksName: "", // 视频分析任务名称
cameraName: "", // 摄像头名称
alarmImg: "", // 报警图片
alarmTime: "", // 报警时间
algorithmName: "", // 算法名称
algorithmLevel: 1, // 算法报警等级
alarmStatus: 0, // 报警处理状态
},
tableList: [
{
id: 1, // 摄像头ID
videoAnlysisTasksName: "yi", // 视频分析任务名称
cameraName: "er", // 摄像头名称
alarmImg: "1121", // 报警图片
alarmTime: "1212", // 报警时间
algorithmName: "1212", // 算法名称
algorithmLevel: 1, // 算法报警等级
alarmStatus: 0, // 报警处理状态
},
],
cameraAdderss: [
{
name: "摄像头1", // 摄像头名称
address: "地址一", // 摄像头地址
},
], // 摄像头地址
total: 0, // 总数量
queryParams: {
pageNum: 1, // 当前页码
pageSize: 10, // 每页显示的数量
},
};
}, },
computed: {}, computed: {},
watch: {}, watch: {},
created() {}, created() {},
mounted() {}, mounted() {},
methods: {}, methods: {
// 搜索
search() {},
// 删除
deleteBut(row) {
this.$confirm("确认删除吗?", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning",
});
},
// 编辑
editBut(row) {},
// 获取数据列表
getList() {},
},
}; };
</script> </script>
......
<template> <template>
<div class="app-container">报警提醒</div> <div class="app-container">
<el-row type="flex" :gutter="10">
<el-col :span="8">
<el-card
shadow="hover"
:body-style="{ padding: '20px', height: 'calc(100vh - 200px)' }"
>
<p slot="header"><b>报警弹窗及语音提醒</b></p>
<div>
<p>
选择开启提醒的算法 共
{{ selectedAlarmList.length }} 个算法开启提醒
</p>
<el-select
v-model="selectedAlarmList"
multiple
style="width: 100%"
placeholder="请选择"
>
<el-option
v-for="item in alarmOptions"
:key="item.value"
:label="item.label"
:value="item.value"
>
</el-option>
</el-select>
<p>提醒方式</p>
<p>
<span>系统报警语音</span>
<el-switch
v-model="systemAlarmAudio"
active-color="#13ce66"
inactive-color="#ff4949"
>
</el-switch>
</p>
<p>
<span>系统报警弹窗</span>
<el-switch
v-model="systemAlarmWidow"
active-color="#13ce66"
inactive-color="#ff4949"
>
</el-switch>
</p>
<p>显示方式</p>
</div>
</el-card>
</el-col>
<el-col :span="16">
<el-card
shadow="hover"
:body-style="{ padding: '20px', height: 'calc(100vh - 200px)' }"
>
<p slot="header"><b>提醒语音管理</b></p>
<el-table
:data="tableData"
style="width: 100%"
:row-style="{ textAlign: 'center' }"
>
<el-table-column prop="id" label="算法ID"></el-table-column>
<el-table-column
prop="algorithmName"
label="算法名称"
></el-table-column>
<el-table-column label="算法等级">
<template slot-scope="scope">
<dict-tag
:options="dict.type.algorithm_level"
:value="scope.row.algorithmLevel"
/>
</template>
</el-table-column>
<el-table-column
prop="alarmAudio"
label="报警语音"
></el-table-column>
<el-table-column label="操作" width="200">
<template slot-scope="scope">
<el-button
size="mini"
type="text"
@click="handleEdit(scope.row)"
>
<i class="el-icon-video-play"></i>
试听
</el-button>
<el-button
size="mini"
type="text"
@click="handleUpload(scope.row)"
>
<i class="el-icon-upload"></i>
替换/上传
</el-button>
<el-button
size="mini"
type="text"
@click="handleDelete(scope.row)"
>
<i class="el-icon-delete"></i>
删除
</el-button>
</template>
</el-table-column>
</el-table>
<pagination
v-show="total > 0"
:total="total"
:page.sync="queryParams.pageNum"
:limit.sync="queryParams.pageSize"
@pagination="getList"
/>
</el-card>
</el-col>
</el-row>
</div>
</template> </template>
<script> <script>
export default { export default {
dicts: ["algorithm_level"],
name: "Alarmreminder", name: "Alarmreminder",
props: {}, props: {},
components: {}, components: {},
data() { data() {
return {}; return {
tableData: [
{
id: "1",
algorithmName: "算法1",
algorithmLevel: 1,
alarmAudio: "audio1.mp3",
},
],
total: 0, // 总记录数
queryParams: {
pageNum: 1, // 当前页码
pageSize: 10, // 每页显示的记录数
},
selectedAlarmList: [], // 选中的报警算法列表
alarmOptions: [
{ value: "1", label: "算法1" },
{ value: "2", label: "算法2" },
{ value: "3", label: "算法3" },
],
systemAlarmAudio: false, // 系统报警语音
systemAlarmWidow: false, // 系统报警弹窗
};
}, },
computed: {}, computed: {},
watch: {}, watch: {},
created() {}, created() {},
mounted() {}, mounted() {},
methods: {}, methods: {
//获取数据列表
getList() {},
//编辑
handleEdit(row) {
console.log("编辑:", row);
},
//删除
handleDelete(row) {
console.log("删除:", row);
},
//上传
handleUpload(row) {
console.log("上传:", row);
},
},
}; };
</script> </script>
......
<template> <template>
<div class="app-container">算法配置</div> <div class="app-container">
<div class="Pd20">
<span style="font-size: 20px">全部算法</span>
<el-table
:data="tableList"
style="width: 100%; margin-top: 20px"
empty-text
>
<el-table-column
prop="name"
align="center"
label="算法ID"
></el-table-column>
<el-table-column
prop="address"
align="center"
label="算法版本"
></el-table-column>
<el-table-column
prop="videoAdress"
label="算法名称"
align="center"
></el-table-column>
<el-table-column
prop="imageUrl"
align="center"
label="算法等级"
></el-table-column>
<el-table-column label="操作" width="200" align="center">
<template slot-scope="scope">
<el-button type="text" size="mini" @click="tableEdit(scope.row)">
编辑
</el-button>
</template>
</el-table-column>
</el-table>
<pagination
v-show="total > 0"
:total="total"
:page.sync="queryParams.pageNum"
:limit.sync="queryParams.pageSize"
@pagination="getList"
/>
</div>
</div>
</template> </template>
<script> <script>
...@@ -8,14 +52,33 @@ export default { ...@@ -8,14 +52,33 @@ export default {
props: {}, props: {},
components: {}, components: {},
data() { data() {
return {}; return {
tableList: [], //表格数据
total: 0, //总条数
queryParams: {
//查询参数
pageNum: 1,
pageSize: 10,
},
};
}, },
computed: {}, computed: {},
watch: {}, watch: {},
created() {}, created() {},
mounted() {}, mounted() {},
methods: {}, methods: {
//编辑
tableEdit(row) {},
getList() {
//获取列表
},
},
}; };
</script> </script>
<style scoped lang="scss"></style> <style scoped lang="scss">
.Pd20 {
padding: 20px;
background: #fff;
}
</style>
<template>
<v-scale-screen
ref="scale-screen"
width="1920"
height="1080"
:fullScreen="true"
>
<div class="">这里是大屏</div>
</v-scale-screen>
</template>
<script>
export default {
name: "Screen",
props: {},
components: {},
data() {
return {};
},
computed: {},
watch: {},
created() {},
mounted() {},
methods: {},
};
</script>
<style scoped lang="scss"></style>
<template> <template>
<div class="app-container">视频分析任务</div> <div class="app-container">
<div class="Pd20">
<el-row type="flex" :gutter="10">
<el-col :span="6">
<el-button type="primary" plain size="mini" @click="drawer = true">
<i class="el-icon-plus el-icon--left"></i>
创建视频分析任务
</el-button>
</el-col>
<el-col :span="6"> </el-col>
<el-col :span="6"> </el-col>
<el-col :span="6" :offset="6">
<el-input
v-model="searchValue"
size="mini"
style="width: 160px"
clearable
placeholder="请输入内容"
></el-input>
<el-button
type="primary"
size="mini"
@click="search"
style="margin-left: 10px"
>
<i class="el-icon-search el-icon--left"></i>
搜索
</el-button>
</el-col>
</el-row>
<el-table :data="tableList" class="Mt20">
<el-table-column
label="任务ID"
align="center"
prop="id"
></el-table-column>
<el-table-column
label="任务名称"
align="center"
prop="name"
></el-table-column>
<el-table-column
label="关联算法"
align="center"
prop="aboutAslgorithm"
></el-table-column>
<el-table-column label="任务启用状态" align="center">
<template slot-scope="scope">
<el-switch
v-model="scope.row.status"
active-color="#13ce66"
inactive-color="#ff4949"
></el-switch>
</template>
</el-table-column>
<el-table-column label="操作" align="center">
<template slot-scope="scope">
<el-button
type="text"
size="mini"
@click="() => editBut(scope.row)"
>
编辑
</el-button>
<el-button
type="text"
class="danger"
size="mini"
@click="() => deleteBut(scope.row)"
>
删除
</el-button>
</template>
</el-table-column>
</el-table>
<pagination
v-show="total > 0"
:total="total"
:page.sync="queryParams.pageNum"
:limit.sync="queryParams.pageSize"
@pagination="getList"
/>
<el-drawer :visible.sync="drawer" size="80%" :wrapperClosable="false">
<span slot="title">创建视频分析任务</span>
<add-video-anlysis-tasks
:editData="currentRow"
@close-drawer="closeDrawer()"
></add-video-anlysis-tasks>
</el-drawer>
</div>
</div>
</template> </template>
<script> <script>
import addVideoAnlysisTasks from "@/views/VideoAnalysisTasks/modules/addVideoAnlysisTasks.vue";
export default { export default {
name: "VideoAnalysisTasks", name: "VideoAnalysisTasks",
props: {}, props: {},
components: {}, components: { "add-video-anlysis-tasks": addVideoAnlysisTasks },
data() { data() {
return {}; return {
searchValue: "", // 搜索框的值
tableList: [
{
id: 1,
name: "视频分析任务1",
aboutAslgorithm: "这是一个视频分析任务",
status: 0, // 0:禁用 1:启用
},
],
queryParams: {
pageNum: 1, // 当前页码
pageSize: 10, // 每页显示的数量
},
total: 0, // 总数量
/* 创建摄像头相关 */
drawer: false, // 控制弹窗的显示
currentRow: null, // 当前行数据存储
};
}, },
computed: {}, computed: {},
watch: {}, watch: {},
created() {}, created() {},
mounted() {}, mounted() {},
methods: {}, methods: {
// 新增
append() {
this.currentRow = ""; // 存储当前行数据
this.drawer = true; // 打开抽屉
},
// 搜索
search() {},
// 分页
getList() {},
// 删除
deleteBut(row) {
this.$confirm("确认删除吗?", "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning",
});
},
// 编辑
editBut(row) {
this.currentRow = row; // 存储当前行数据
this.drawer = true; // 打开抽屉
},
// 关闭抽屉
closeDrawer() {
this.drawer = false; // 关闭抽屉
//需要重新获取列表数据
this.getList();
},
},
}; };
</script> </script>
<style scoped lang="scss"></style> <style scoped lang="scss">
.Pd20 {
padding: 20px;
background: #fff;
position: relative;
height: calc(100vh - 125px);
}
.Mt20 {
margin-top: 20px;
}
.danger {
color: #f5222d;
}
.active {
color: #52c41a;
}
::v-deep .el-drawer__header {
margin-bottom: 0;
}
</style>
<template>
<div style="padding: 20px">
<el-form :model="form" :rules="formRules" ref="taskForm">
<el-form-item prop="videoTasksName" label="算法名称">
<el-input
v-model="form.videoTasksName"
size="mini"
style="width: 200px"
clearable
placeholder="请输入算法名称"
></el-input>
</el-form-item>
</el-form>
<el-row :gutter="10" type="flex">
<el-col :span="8">
<el-card
shadow="hover"
:body-style="{ padding: '20px', height: 'calc(100vh - 280px)' }"
>
<span slot="header"
>选择算法
<p>
已选则 <span class="number">{{ checkAnalysisList.length }}</span
>个算法
</p>
</span>
<div>
<el-checkbox-group v-model="checkAnalysisList" size="small">
<!-- 自定义复选框组件 -->
<div
class="custom-checkbox"
:class="{
'is-checked': checkAnalysisList.some(
(val) => item.id === val.id
),
}"
@click="handleCheckboxChange(item)"
v-for="(item, index) in analysisList"
:key="index"
>
<div class="checkbox-inner">
<i
v-show="checkAnalysisList.some((val) => item.id === val.id)"
class="el-icon-check"
></i>
</div>
<div class="checkbox-content">
<p>{{ item.name }}</p>
<span>ID : {{ item.id }} </span>
<span>版本 {{ item.version }} </span>
</div>
</div>
</el-checkbox-group>
</div>
</el-card>
</el-col>
<el-col :span="8">
<el-card
shadow="hover"
:body-style="{ padding: '20px', height: 'calc(100vh - 280px)' }"
>
<span slot="header"
>选择摄像头
<p>
已选则<span class="number">{{ checkCameraList.length }}</span
>个摄像头
</p>
</span>
<div>
<el-table :data="cameraList" @selection-change="cameraChange">
<el-table-column type="selection" width="55"> </el-table-column>
<el-table-column label="名称" prop="name"></el-table-column>
<el-table-column label="地址" prop="address"></el-table-column>
</el-table>
</div>
</el-card>
</el-col>
<el-col :span="8">
<el-card
shadow="hover"
:body-style="{ padding: '20px', height: 'calc(100vh - 280px)' }"
>
<span slot="header"
>视频分析任务内容
<p>
<el-button type="primary" plain size="mini" @click="submitForm()">
<i class="el-icon-switch-button el-icon--left"></i>
创建任务
</el-button>
<el-button type="primary" size="mini" @click="submitForm()">
<i class="el-icon-finished el-icon--left"></i>
立即启用
</el-button>
</p>
</span>
<div>
<transition-group name="list" tag="div">
<div
class="custom-checkbox"
v-for="(item, index) in checkAnalysisList"
:key="index"
>
<div class="checkbox-content">
<p>{{ item.name }}</p>
<el-tag
v-for="tag in item.checkCameraList"
:key="tag.name"
closable
size="mini"
@close="deleteTag(item, tag)"
:type="tag.type"
>
{{ tag.name }}
</el-tag>
<p>
<span>ID : {{ item.id }} </span>
<span>版本 {{ item.version }} </span>
</p>
</div>
</div>
</transition-group>
</div>
</el-card>
</el-col>
</el-row>
</div>
</template>
<script>
export default {
name: "addVideoAnlysisTasks",
props: {
editData: {
type: Object,
default: () => null,
},
},
components: {},
data() {
return {
form: {
videoTasksName: "", // 将原videoTasksName移到form对象中
},
formRules: {
videoTasksName: [
{ required: true, message: "算法名称不能为空", trigger: "blur" },
{
min: 2,
max: 20,
message: "长度在 2 到 20 个字符",
trigger: "blur",
},
],
},
checkAnalysisList: [], // 选中的算法名称
// 算法列表
analysisList: [
{
id: 1,
name: "摄像头挪移角度识别检测算无模型",
version: "v1.0",
checkCameraList: [],
},
{
id: 2,
name: "巡检人员长时间停留训练版",
version: "v1.0",
checkCameraList: [],
},
{
id: 3,
name: "长时间无人巡检训练版",
version: "v1.0",
checkCameraList: [],
},
],
cameraList: [
{
id: 1,
name: "摄像头1",
address: "地址一",
},
{
id: 2,
name: "摄像头2",
address: "地址2",
},
{
id: 3,
name: "摄像头3",
address: "地址3",
},
],
checkCameraList: [], // 选中的摄像头
};
},
computed: {},
watch: {
editData: {
immediate: true,
handler(newVal) {
if (newVal) {
console.log(newVal);
// 填充表单数据
this.form.videoTasksName = newVal.name;
// 其他字段赋值...
}
},
},
},
created() {},
mounted() {},
methods: {
// 修改后的复选框点击方法
handleCheckboxChange(item) {
const index = this.checkAnalysisList.findIndex((i) => i.id === item.id);
if (index > -1) {
this.checkAnalysisList.splice(index, 1);
} else {
// 新增时初始化摄像头列表
this.checkAnalysisList.push({
...item,
checkCameraList: [],
});
}
// 同步更新树形选择
this.$nextTick(() => {});
},
// 摄像头选择
cameraChange(val) {
console.log(val);
this.checkCameraList = val;
const selectedCamera = val.map((item) => ({
name: item.name,
type: "success", // 可以根据需要设置不同的标签类型
}));
// 为每个算法项添加摄像头列表
this.checkAnalysisList.forEach((item) => {
item.checkCameraList = [...selectedCamera];
});
},
// 删除标签
deleteTag(item, tag) {
const index = item.checkCameraList.findIndex((i) => i.name === tag.name);
if (index > -1) {
item.checkCameraList.splice(index, 1);
}
console.log(this.checkAnalysisList);
},
//提交
// 在提交时触发验证
submitForm() {
this.$refs.taskForm.validate((valid) => {
if (valid) {
// 执行提交操作
this.$emit("close-drawer");
} else {
return false;
}
});
},
},
};
</script>
<style scoped lang="scss">
// 自定义复选框样式
.custom-checkbox {
display: flex;
align-items: center;
padding: 8px;
margin: 4px 0;
border: 1px solid #dcdfe6;
border-radius: 4px;
position: relative;
cursor: pointer;
transition: all 0.4s;
&:hover {
border-color: #409eff;
}
&.is-checked {
border-color: #409eff;
background-color: #f5f7fa;
// 新增内部框体选中样式
.checkbox-inner {
border-color: #409eff;
background-color: #409eff;
i {
color: #fff;
}
}
}
.checkbox-inner {
width: 16px;
height: 16px;
border: 1px solid #dcdfe6;
border-radius: 2px;
margin-right: 8px;
position: relative;
background: #fff;
transition: all 0.2s; // 添加过渡动画
i {
position: absolute;
left: 50%;
top: 55%; // 微调垂直居中
transform: translate(-50%, -50%);
color: #409eff;
font-weight: bold;
font-size: 14px; // 增大图标尺寸
}
}
.checkbox-content {
p {
margin: 0 0 4px 0;
font-size: 14px;
}
span {
font-size: 12px;
color: #909399;
margin-right: 8px;
}
}
}
// 新增动画样式
.list-enter-active {
transition: all 0.5s ease;
}
.list-leave-active {
transition: all 0.3s ease;
position: absolute;
}
.list-enter {
opacity: 0;
transform: translateX(-30px);
}
.list-leave-to {
opacity: 0;
}
.number {
color: rgb(24, 114, 240);
font-size: 25px;
}
</style>
<template> <template>
<div class="dashboard-editor-container"> <div class="app-container">
<el-row :gutter="15" type="flex">
<panel-group @handleSetLineChartData="handleSetLineChartData" /> <el-col :span="5">
<el-card
<el-row style="background:#fff;padding:16px 16px 0;margin-bottom:32px;"> shadow="hover"
<line-chart :chart-data="lineChartData" /> :body-style="{ padding: '20px', height: 'calc(100vh - 200px)' }"
</el-row> >
</el-card>
<el-row :gutter="32">
<el-col :xs="24" :sm="24" :lg="8">
<div class="chart-wrapper">
<raddar-chart />
</div>
</el-col> </el-col>
<el-col :xs="24" :sm="24" :lg="8"> <el-col :span="13">
<div class="chart-wrapper"> <el-card
<pie-chart /> shadow="hover"
</div> :body-style="{ padding: '20px', height: 'calc(100vh - 200px)' }"
>
</el-card>
</el-col> </el-col>
<el-col :xs="24" :sm="24" :lg="8"> <el-col :span="6">
<div class="chart-wrapper"> <el-card
<bar-chart /> shadow="hover"
</div> :body-style="{ padding: '20px', height: 'calc(100vh - 200px)' }"
>
</el-card>
</el-col> </el-col>
</el-row> </el-row>
</div> </div>
</template> </template>
<script> <script>
import PanelGroup from './dashboard/PanelGroup'
import LineChart from './dashboard/LineChart'
import RaddarChart from './dashboard/RaddarChart'
import PieChart from './dashboard/PieChart'
import BarChart from './dashboard/BarChart'
const lineChartData = {
newVisitis: {
expectedData: [100, 120, 161, 134, 105, 160, 165],
actualData: [120, 82, 91, 154, 162, 140, 145]
},
messages: {
expectedData: [200, 192, 120, 144, 160, 130, 140],
actualData: [180, 160, 151, 106, 145, 150, 130]
},
purchases: {
expectedData: [80, 100, 121, 104, 105, 90, 100],
actualData: [120, 90, 100, 138, 142, 130, 130]
},
shoppings: {
expectedData: [130, 140, 141, 142, 145, 150, 160],
actualData: [120, 82, 91, 154, 162, 140, 130]
}
}
export default { export default {
name: 'Index', name: "Index",
components: { components: {},
PanelGroup,
LineChart,
RaddarChart,
PieChart,
BarChart
},
data() { data() {
return { return {};
lineChartData: lineChartData.newVisitis
}
}, },
methods: { methods: {},
handleSetLineChartData(type) { };
this.lineChartData = lineChartData[type]
}
}
}
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
.dashboard-editor-container { .app-container {
padding: 32px; padding-right: 0;
background-color: rgb(240, 242, 245);
position: relative;
.chart-wrapper {
background: #fff;
padding: 16px 16px 0;
margin-bottom: 32px;
}
}
@media (max-width:1024px) {
.chart-wrapper {
padding: 8px;
}
} }
</style> </style>
...@@ -29,6 +29,10 @@ module.exports = { ...@@ -29,6 +29,10 @@ module.exports = {
productionSourceMap: false, productionSourceMap: false,
transpileDependencies: ['quill'], transpileDependencies: ['quill'],
// webpack-dev-server 相关配置 // webpack-dev-server 相关配置
hot: true,
headers: {
'Cache-Control': 'no-store'
},
devServer: { devServer: {
host: '0.0.0.0', host: '0.0.0.0',
port: port, port: port,
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment