@@ -24,7 +24,6 @@ declare module 'vue' { | |||||
ElBreadcrumbItem: typeof import('element-plus/es')['ElBreadcrumbItem'] | ElBreadcrumbItem: typeof import('element-plus/es')['ElBreadcrumbItem'] | ||||
ElButton: typeof import('element-plus/es')['ElButton'] | ElButton: typeof import('element-plus/es')['ElButton'] | ||||
ElCheckbox: typeof import('element-plus/es')['ElCheckbox'] | ElCheckbox: typeof import('element-plus/es')['ElCheckbox'] | ||||
ElCol: typeof import('element-plus/es')['ElCol'] | |||||
ElColorPicker: typeof import('element-plus/es')['ElColorPicker'] | ElColorPicker: typeof import('element-plus/es')['ElColorPicker'] | ||||
ElContainer: typeof import('element-plus/es')['ElContainer'] | ElContainer: typeof import('element-plus/es')['ElContainer'] | ||||
ElDialog: typeof import('element-plus/es')['ElDialog'] | ElDialog: typeof import('element-plus/es')['ElDialog'] | ||||
@@ -43,13 +42,10 @@ declare module 'vue' { | |||||
ElMain: typeof import('element-plus/es')['ElMain'] | ElMain: typeof import('element-plus/es')['ElMain'] | ||||
ElMenu: typeof import('element-plus/es')['ElMenu'] | ElMenu: typeof import('element-plus/es')['ElMenu'] | ||||
ElMenuItem: typeof import('element-plus/es')['ElMenuItem'] | ElMenuItem: typeof import('element-plus/es')['ElMenuItem'] | ||||
ElOption: typeof import('element-plus/es')['ElOption'] | |||||
ElPagination: typeof import('element-plus/es')['ElPagination'] | ElPagination: typeof import('element-plus/es')['ElPagination'] | ||||
ElPopover: typeof import('element-plus/es')['ElPopover'] | ElPopover: typeof import('element-plus/es')['ElPopover'] | ||||
ElRadio: typeof import('element-plus/es')['ElRadio'] | ElRadio: typeof import('element-plus/es')['ElRadio'] | ||||
ElRow: typeof import('element-plus/es')['ElRow'] | |||||
ElScrollbar: typeof import('element-plus/es')['ElScrollbar'] | ElScrollbar: typeof import('element-plus/es')['ElScrollbar'] | ||||
ElSelect: typeof import('element-plus/es')['ElSelect'] | |||||
ElSpace: typeof import('element-plus/es')['ElSpace'] | ElSpace: typeof import('element-plus/es')['ElSpace'] | ||||
ElSubMenu: typeof import('element-plus/es')['ElSubMenu'] | ElSubMenu: typeof import('element-plus/es')['ElSubMenu'] | ||||
ElSwitch: typeof import('element-plus/es')['ElSwitch'] | ElSwitch: typeof import('element-plus/es')['ElSwitch'] | ||||
@@ -59,6 +55,8 @@ declare module 'vue' { | |||||
ElTabs: typeof import('element-plus/es')['ElTabs'] | ElTabs: typeof import('element-plus/es')['ElTabs'] | ||||
ElTag: typeof import('element-plus/es')['ElTag'] | ElTag: typeof import('element-plus/es')['ElTag'] | ||||
ElTooltip: typeof import('element-plus/es')['ElTooltip'] | ElTooltip: typeof import('element-plus/es')['ElTooltip'] | ||||
ElTree: typeof import('element-plus/es')['ElTree'] | |||||
ElTreeSelect: typeof import('element-plus/es')['ElTreeSelect'] | |||||
ESign: typeof import('./src/components/ESign/index.vue')['default'] | ESign: typeof import('./src/components/ESign/index.vue')['default'] | ||||
FormContainer: typeof import('./src/components/Form/FormContainer/index.vue')['default'] | FormContainer: typeof import('./src/components/Form/FormContainer/index.vue')['default'] | ||||
Grid: typeof import('./src/components/Grid/index.vue')['default'] | Grid: typeof import('./src/components/Grid/index.vue')['default'] | ||||
@@ -2,7 +2,7 @@ | |||||
<html lang="en"> | <html lang="en"> | ||||
<head> | <head> | ||||
<meta charset="UTF-8" /> | <meta charset="UTF-8" /> | ||||
<link rel="icon" href="/qjkj.ico" /> | |||||
<link rel="icon" href="/api/sys/ico" /> | |||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> | <meta name="viewport" content="width=device-width, initial-scale=1.0" /> | ||||
<title><%- title %></title> | <title><%- title %></title> | ||||
<!-- <script src="https://unpkg.com/aliyun-rts-sdk@1.2.1/dist/aliyun-rts-sdk.js"></script> --> | <!-- <script src="https://unpkg.com/aliyun-rts-sdk@1.2.1/dist/aliyun-rts-sdk.js"></script> --> | ||||
@@ -51,6 +51,11 @@ export interface ReqId { | |||||
/** id */ | /** id */ | ||||
id: number | string; | id: number | string; | ||||
} | } | ||||
/** id请求参数 */ | |||||
export interface ReqPersonId { | |||||
/** id */ | |||||
personId: number | string; | |||||
} | |||||
/** id请求参数 */ | /** id请求参数 */ | ||||
export interface ReqstartId { | export interface ReqstartId { | ||||
@@ -68,7 +73,6 @@ export interface ReqstopId { | |||||
} | } | ||||
export interface setWarn { | export interface setWarn { | ||||
configJson: string; | configJson: string; | ||||
} | } | ||||
@@ -36,5 +36,22 @@ const monitorLIVEApi = { | |||||
}, | }, | ||||
}; | }; | ||||
/** | |||||
* @Description: 监控管理按钮权限码 | |||||
* @Author: huguodong | |||||
* @Date: 2024-02-20 09:51:15 | |||||
*/ | |||||
const monitorLiveButtonCode = { | |||||
/** 新增监控 */ | |||||
add: "monitorLiveAdd", | |||||
/** 编辑监控 */ | |||||
edit: "monitorLiveEdit", | |||||
/** 删除监控 */ | |||||
delete: "monitorLiveDelete", | |||||
/** 批量删除监控 */ | |||||
batchDelete: "monitorLiveBatchDelete", | |||||
/** 复制监控 */ | |||||
copy: "monitorLiveCopy" | |||||
}; | |||||
export { monitorLIVEApi }; | |||||
export { monitorLIVEApi, monitorLiveButtonCode }; |
@@ -1,7 +1,7 @@ | |||||
<template> | <template> | ||||
<div class="footer flx-center"> | <div class="footer flx-center"> | ||||
<!-- <a :href="props.sysCopyrightUrl" target="_blank"> {{ props.sysCopyright }} </a> | |||||
<a v-for="link in props.footerLinks" :key="link.name" :href="link.url" target="_blank" class="mx-1"> | {{ link.name }}</a> --> | |||||
<a :href="props.sysCopyrightUrl" target="_blank"> {{ props.sysCopyright }} </a> | |||||
<a v-for="link in props.footerLinks" :key="link.name" :href="link.url" target="_blank" class="mx-1"> | {{ link.name }}</a> | |||||
</div> | </div> | ||||
</template> | </template> | ||||
<script setup lang="ts"> | <script setup lang="ts"> | ||||
@@ -1,12 +1,60 @@ | |||||
.home { | .home { | ||||
display: flex; | |||||
align-items: center; | |||||
justify-content: center; | |||||
width: 100%; | width: 100%; | ||||
height: 100%; | height: 100%; | ||||
.home-bg { | .home-bg { | ||||
width: 70%; | |||||
max-width: 1200px; | |||||
margin-bottom: 20px; | |||||
margin-bottom: 15px; | |||||
height: 390px; | |||||
// height: 424px; | |||||
.home-bg-title { | |||||
display: flex; | |||||
height: 50px; | |||||
align-items: center; | |||||
div:first-child { | |||||
height: 15px; | |||||
width: 4px; | |||||
background: #3a84ff; | |||||
margin-right: 10px; | |||||
} | |||||
div:nth-child(2) { | |||||
font-size: 20px; | |||||
font-weight: 600; | |||||
margin-left: 10px; | |||||
} | |||||
} | |||||
.home-bg-content { | |||||
height: calc(100% - 50px); | |||||
.home-bg-content-item { | |||||
margin-left: 15px; | |||||
margin-top: 60px; | |||||
display: flex; | |||||
align-items: center; | |||||
.home-bg-content-item-icon { | |||||
margin-right: 15px; | |||||
width: 70px; | |||||
height: 70px; | |||||
img { | |||||
width: 100%; | |||||
height: 100%; | |||||
} | |||||
} | |||||
.home-bg-content-item-content { | |||||
.home-bg-content-item-title { | |||||
} | |||||
.home-bg-content-item-value { | |||||
margin-top: 10px; | |||||
font-size: 20px; | |||||
font-weight: 600; | |||||
// color: #3a84ff; | |||||
} | |||||
} | |||||
} | |||||
} | |||||
.handleBox ::v-deep(.card) { | |||||
padding:0; | |||||
} | |||||
} | |||||
.topCard { | |||||
height: 355px; | |||||
} | } | ||||
} | } |
@@ -1,10 +1,387 @@ | |||||
<template> | <template> | ||||
<div class="home card"> | |||||
<img class="home-bg" src="@/assets/images/welcome.png" alt="welcome" /> | |||||
<div class="home"> | |||||
<el-row :gutter="20"> | |||||
<el-col :xs="24" :sm="24" :md="12" :lg="12" :xl="8"> | |||||
<div class="home-bg card"> | |||||
<div class="home-bg-title"> | |||||
<div></div> | |||||
<div>基础数据</div> | |||||
</div> | |||||
<div class="home-bg-content"> | |||||
<el-row :gutter="20"> | |||||
<el-col :span="12" | |||||
><div class="home-bg-content-item"> | |||||
<div class="home-bg-content-item-icon"> | |||||
<img src="@/assets/images/home/carame.png" alt="" /> | |||||
</div> | |||||
<div class="home-bg-content-item-content"> | |||||
<div class="home-bg-content-item-title">摄像头数量</div> | |||||
<div class="home-bg-content-item-value">3</div> | |||||
</div> | |||||
</div></el-col | |||||
> | |||||
<el-col :span="12" | |||||
><div class="home-bg-content-item"> | |||||
<div class="home-bg-content-item-icon"> | |||||
<img src="@/assets/images/home/warn.png" alt="" /> | |||||
</div> | |||||
<div class="home-bg-content-item-content"> | |||||
<div class="home-bg-content-item-title">告警信息总量</div> | |||||
<div class="home-bg-content-item-value">197218</div> | |||||
</div> | |||||
</div></el-col | |||||
> | |||||
<el-col :span="12" | |||||
><div class="home-bg-content-item"> | |||||
<div class="home-bg-content-item-icon"> | |||||
<img src="@/assets/images/home/handle.png" alt="" /> | |||||
</div> | |||||
<div class="home-bg-content-item-content"> | |||||
<div class="home-bg-content-item-title">处理意见提交</div> | |||||
<div class="home-bg-content-item-value">40</div> | |||||
</div> | |||||
</div></el-col | |||||
> | |||||
<el-col :span="12" | |||||
><div class="home-bg-content-item"> | |||||
<div class="home-bg-content-item-icon"> | |||||
<img src="@/assets/images/home/participation.png" alt="" /> | |||||
</div> | |||||
<div class="home-bg-content-item-content"> | |||||
<div class="home-bg-content-item-title">参与安防教师</div> | |||||
<div class="home-bg-content-item-value">22</div> | |||||
</div> | |||||
</div></el-col | |||||
> | |||||
</el-row> | |||||
</div> | |||||
</div> | |||||
</el-col> | |||||
<el-col :xs="24" :sm="24" :md="12" :lg="12" :xl="8"> | |||||
<div class="home-bg card"> | |||||
<div class="home-bg-title"> | |||||
<div></div> | |||||
<div>今日告警情况</div> | |||||
</div> | |||||
<div class="home-bg-content"> | |||||
<div ref="chart1" style="width: 100%; height: 100%"></div> | |||||
</div> | |||||
</div> | |||||
</el-col> | |||||
<el-col :xs="24" :sm="24" :md="12" :lg="12" :xl="8"> | |||||
<div class="home-bg card"> | |||||
<div class="home-bg-title"> | |||||
<div></div> | |||||
<div>今日处理情况</div> | |||||
</div> | |||||
<div class="home-bg-content"> | |||||
<div ref="chart2" style="width: 100%; height: 100%"></div> | |||||
</div> | |||||
</div> | |||||
</el-col> | |||||
<el-col :xs="24" :sm="24" :md="12" :lg="12" :xl="8"> | |||||
<div class="home-bg card"> | |||||
<div class="home-bg-title"> | |||||
<div></div> | |||||
<div>高危预警信息统计</div> | |||||
</div> | |||||
<div class="home-bg-content handleBox"> | |||||
<ProTable ref="proTable" title="视频列表" :toolButton="false" :pagination="false" :columns="columns" :data="tableData"> </ProTable> | |||||
</div> | |||||
</div> | |||||
</el-col> | |||||
<el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="16"> | |||||
<div class="home-bg card"> | |||||
<div class="home-bg-title"> | |||||
<div></div> | |||||
<div>统计分析</div> | |||||
</div> | |||||
<div class="home-bg-content handleBox"> | |||||
<div ref="chart3" style="width: 100%; height: 100%"></div> | |||||
</div> | |||||
</div> | |||||
</el-col> | |||||
</el-row> | |||||
</div> | </div> | ||||
</template> | </template> | ||||
<script setup lang="ts" name="home"></script> | |||||
<script setup lang="ts" name="home"> | |||||
import { ref, watch, provide, onMounted, unref, computed, reactive } from "vue"; | |||||
import { ElMessage } from "element-plus"; | |||||
import { monitorLIVEApi } from "@/api"; | |||||
import { ZJRQ } from "@/api/interface"; | |||||
import { ColumnProps, ProTableInstance } from "@/components/ProTable/interface"; | |||||
import { useDictStore } from "@/stores/modules"; | |||||
import { statistionApi } from "@/api"; | |||||
import * as echarts from "echarts"; | |||||
const value = ref(true); | |||||
const chart1 = ref(null); | |||||
const chart2 = ref(null); | |||||
const chart3 = ref(null); | |||||
onMounted(() => { | |||||
getDataChart(); | |||||
getWeekData(); | |||||
}); | |||||
function getDataChart() { | |||||
setTimeout(async () => { | |||||
await statistionApi.warnstatistion({}).then(res => { | |||||
let { code, data } = res; | |||||
if (code == 200) { | |||||
let chartData1 = data.alarm.map(item => { | |||||
return { | |||||
value: item.count, | |||||
name: item.name | |||||
}; | |||||
}); | |||||
let chartData2 = data.hand.map(item => { | |||||
return { | |||||
value: item.count, | |||||
name: item.name | |||||
}; | |||||
}); | |||||
// let chartData = [ | |||||
// { | |||||
// name: "1", | |||||
// value: 100 | |||||
// }, | |||||
// { | |||||
// name: "2", | |||||
// value: 200 | |||||
// } | |||||
// ]; | |||||
getCharts1(chartData1); | |||||
getCharts2(chartData2); | |||||
} | |||||
}); | |||||
}); | |||||
} | |||||
function getCharts1(data) { | |||||
const chart = echarts.init(chart1.value); | |||||
const option = { | |||||
tooltip: { | |||||
trigger: "item" | |||||
}, | |||||
// legend: { | |||||
// top: "5%", | |||||
// left: "center" | |||||
// }, | |||||
legend: { | |||||
orient: "vertical", | |||||
left: "right", | |||||
top: "middle" | |||||
}, | |||||
series: [ | |||||
{ | |||||
name: "今日告警情况", | |||||
type: "pie", | |||||
radius: ["60%", "90%"], | |||||
avoidLabelOverlap: false, | |||||
itemStyle: { | |||||
borderRadius: 10, | |||||
borderColor: "#fff", | |||||
borderWidth: 2 | |||||
}, | |||||
label: { | |||||
show: false, | |||||
position: "center" | |||||
}, | |||||
emphasis: { | |||||
label: { | |||||
show: true, | |||||
fontSize: 25, | |||||
fontWeight: "bold" | |||||
} | |||||
}, | |||||
labelLine: { | |||||
show: false | |||||
}, | |||||
data | |||||
} | |||||
] | |||||
}; | |||||
chart.setOption(option); | |||||
window.addEventListener("resize", function () { | |||||
chart.resize(); | |||||
}); | |||||
} | |||||
function getCharts2(data) { | |||||
const chartstation = echarts.init(chart2.value); | |||||
const option = { | |||||
tooltip: { | |||||
trigger: "item" | |||||
}, | |||||
// legend: { | |||||
// top: "5%", | |||||
// left: "center" | |||||
// }, | |||||
legend: { | |||||
orient: "vertical", | |||||
left: "right", | |||||
top: "middle" | |||||
}, | |||||
series: [ | |||||
{ | |||||
name: "今日处理情况", | |||||
type: "pie", | |||||
radius: ["60%", "90%"], | |||||
avoidLabelOverlap: false, | |||||
itemStyle: { | |||||
borderRadius: 10, | |||||
borderColor: "#fff", | |||||
borderWidth: 2 | |||||
}, | |||||
label: { | |||||
show: false, | |||||
position: "center" | |||||
}, | |||||
emphasis: { | |||||
label: { | |||||
show: true, | |||||
fontSize: 25, | |||||
fontWeight: "bold" | |||||
} | |||||
}, | |||||
labelLine: { | |||||
show: false | |||||
}, | |||||
data | |||||
} | |||||
] | |||||
}; | |||||
chartstation.setOption(option); | |||||
window.addEventListener("resize", function () { | |||||
chartstation.resize(); | |||||
}); | |||||
} | |||||
function getWeekData() { | |||||
setTimeout(async () => { | |||||
await statistionApi.weekstatistion({}).then(res => { | |||||
let { code, data } = res; | |||||
if (code == 200) { | |||||
// let chartData = data; | |||||
let time = data.dataX; | |||||
let chartData = data.dataY.map(item => { | |||||
return { | |||||
data: item.data, | |||||
name: item.name, | |||||
type: "bar", | |||||
barWidth: "12px", // 设置柱子粗细 | |||||
itemStyle: { | |||||
normal: { | |||||
barBorderRadius: [30, 30, 0, 0] | |||||
} | |||||
} | |||||
}; | |||||
}); | |||||
getCharts3(time, chartData); | |||||
} | |||||
}); | |||||
}); | |||||
} | |||||
function getCharts3(time, data) { | |||||
const chartstation3 = echarts.init(chart3.value); | |||||
const option = { | |||||
tooltip: { | |||||
trigger: "axis", | |||||
axisPointer: { | |||||
type: "shadow" | |||||
} | |||||
}, | |||||
legend: {}, | |||||
grid: { | |||||
left: "3%", | |||||
right: "4%", | |||||
bottom: "3%", | |||||
containLabel: true | |||||
}, | |||||
yAxis: { | |||||
type: "value", | |||||
boundaryGap: [0, 0.01] | |||||
}, | |||||
xAxis: { | |||||
type: "category", | |||||
data: time | |||||
}, | |||||
series: data | |||||
}; | |||||
chartstation3.setOption(option); | |||||
window.addEventListener("resize", function () { | |||||
chartstation3.resize(); | |||||
}); | |||||
} | |||||
// 获取 ProTable 元素,调用其获取刷新数据方法(还能获取到当前查询参数,方便导出携带参数) | |||||
const proTable = ref<ProTableInstance>(); | |||||
const dictStore = useDictStore(); | |||||
// 表格配置项 | |||||
const columns: ColumnProps<ZJRQ.WarnInfo>[] = [ | |||||
{ | |||||
prop: "type", | |||||
label: "数据类型" | |||||
// render: () => { | |||||
// return "楼道"; | |||||
// } | |||||
}, | |||||
{ | |||||
prop: "warntotal", | |||||
label: "告警总量" | |||||
// render: () => { | |||||
// return "楼道"; | |||||
// } | |||||
}, | |||||
{ | |||||
prop: "lowrisk", | |||||
label: "低危信息 " | |||||
}, | |||||
{ | |||||
prop: "highrisk", | |||||
label: "高危信息" | |||||
} | |||||
]; | |||||
const tableData = ref([ | |||||
{ | |||||
type: "今日", | |||||
warntotal: "828", | |||||
lowrisk: "675", | |||||
highrisk: "153" | |||||
}, | |||||
{ | |||||
type: "本周", | |||||
warntotal: "828", | |||||
lowrisk: "675", | |||||
highrisk: "153" | |||||
}, | |||||
{ | |||||
type: "本月", | |||||
warntotal: "19813", | |||||
lowrisk: "17671", | |||||
highrisk: "2129" | |||||
}, | |||||
{ | |||||
type: "上月", | |||||
warntotal: "21789", | |||||
lowrisk: "0", | |||||
highrisk: "0" | |||||
}, | |||||
{ | |||||
type: "环比", | |||||
warntotal: "-9.07%", | |||||
lowrisk: "0%", | |||||
highrisk: "0%" | |||||
} | |||||
]); | |||||
const tableLoading = ref(false); | |||||
</script> | |||||
<style scoped lang="scss"> | <style scoped lang="scss"> | ||||
@import "./index.scss"; | @import "./index.scss"; | ||||
@@ -0,0 +1,118 @@ | |||||
<!-- | |||||
* @Description: 表单 | |||||
* @Author: huguodong | |||||
* @Date: 2023-12-15 15:45:28 | |||||
!--> | |||||
<template> | |||||
<div> | |||||
<form-container v-model="visible" :title="`${orgProps.opt}监控`" form-size="600px"> | |||||
<el-form | |||||
ref="liveFormRef" | |||||
:rules="rules" | |||||
:disabled="orgProps.disabled" | |||||
:model="orgProps.record" | |||||
:hide-required-asterisk="orgProps.disabled" | |||||
label-width="auto" | |||||
label-suffix=" :" | |||||
> | |||||
<s-form-item label="摄像头名称" prop="name"> | |||||
<s-input v-model="orgProps.record.name"></s-input> | |||||
</s-form-item> | |||||
<s-form-item label="所属学校" prop="parentId"> | |||||
<org-selector v-model:org-value="orgProps.record.parentId" :org-tree-api="bizOrgApi.tree" :show-all="false" /> | |||||
</s-form-item> | |||||
<s-form-item label="设备IP" prop="codeip"> | |||||
<s-input v-model="orgProps.record.codeip" clearable></s-input> | |||||
</s-form-item> | |||||
<s-form-item label="分辨率" prop="status"> | |||||
<s-input v-model="orgProps.record.status" clearable></s-input> | |||||
</s-form-item> | |||||
</el-form> | |||||
<template #footer> | |||||
<el-button @click="onClose"> 取消 </el-button> | |||||
<el-button v-show="!orgProps.disabled" type="primary" @click="handleSubmit"> 确定 </el-button> | |||||
</template> | |||||
</form-container> | |||||
</div> | |||||
</template> | |||||
<script setup lang="ts"> | |||||
import { SysOrg, SysUser, bizOrgApi, bizPositionApi, sysRoleApi, bizUserApi } from "@/api"; | |||||
import { FormOptEnum, SysDictEnum } from "@/enums"; | |||||
import { required } from "@/utils/formRules"; | |||||
import { FormInstance } from "element-plus"; | |||||
import { useDictStore } from "@/stores/modules"; | |||||
const visible = ref(false); //是否显示表单 | |||||
const dictStore = useDictStore(); //字典仓库 | |||||
// 通用状态选项 | |||||
const statusOptions = dictStore.getDictList(SysDictEnum.COMMON_STATUS); | |||||
// 表单参数 | |||||
const orgProps = reactive<FormProps.Base<SysOrg.SysOrgInfo>>({ | |||||
opt: FormOptEnum.ADD, | |||||
record: {}, | |||||
disabled: false | |||||
}); | |||||
// 表单验证规则 | |||||
const rules = reactive({ | |||||
name: [required("请输入摄像头名称")], | |||||
parentId: [required("请选择所属学校")], | |||||
codeip: [required("请选择设备IP")], | |||||
status: [required("请输入分辨率")] | |||||
}); | |||||
/** | |||||
* 打开表单 | |||||
* @param props 表单参数 | |||||
*/ | |||||
function onOpen(props: FormProps.Base<SysOrg.SysOrgInfo>) { | |||||
Object.assign(orgProps, props); //合并参数 | |||||
if (props.opt == FormOptEnum.ADD) { | |||||
//如果是新增,设置默认值 | |||||
orgProps.record.sortCode = 99; | |||||
// orgProps.record.status = statusOptions[0].value; | |||||
} | |||||
visible.value = true; //显示表单 | |||||
if (props.record.id) { | |||||
//如果传了id,就去请求api获取record | |||||
bizOrgApi.detail({ id: props.record.id }).then(res => { | |||||
orgProps.record = res.data; | |||||
}); | |||||
} | |||||
} | |||||
// 提交数据(新增/编辑) | |||||
const liveFormRef = ref<FormInstance>(); | |||||
/** 提交表单 */ | |||||
async function handleSubmit() { | |||||
liveFormRef.value?.validate(async valid => { | |||||
if (!valid) return; //表单验证失败 | |||||
console.log(orgProps); | |||||
return; | |||||
//提交表单 | |||||
await bizOrgApi | |||||
.submitForm(orgProps.record, orgProps.record.id != undefined) | |||||
.then(() => { | |||||
orgProps.successful!(); //调用父组件的successful方法 | |||||
}) | |||||
.finally(() => { | |||||
onClose(); | |||||
}); | |||||
}); | |||||
} | |||||
/** 关闭表单*/ | |||||
function onClose() { | |||||
visible.value = false; | |||||
} | |||||
// 暴露给父组件的方法 | |||||
defineExpose({ | |||||
onOpen | |||||
}); | |||||
</script> | |||||
<style lang="scss" scoped></style> |
@@ -0,0 +1,38 @@ | |||||
.filter { | |||||
box-sizing: border-box; | |||||
width: 280px; | |||||
height: 100%; | |||||
padding: 18px; | |||||
margin-right: 10px; | |||||
.title { | |||||
margin: 0 0 15px; | |||||
font-size: 18px; | |||||
font-weight: bold; | |||||
color: var(--el-color-info-dark-2); | |||||
letter-spacing: 0.5px; | |||||
} | |||||
.el-input { | |||||
margin: 0 0 15px; | |||||
} | |||||
.el-scrollbar { | |||||
:deep(.el-tree) { | |||||
height: 80%; | |||||
overflow: auto; | |||||
.el-tree-node__content { | |||||
height: 33px; | |||||
} | |||||
} | |||||
:deep(.el-tree--highlight-current) { | |||||
.el-tree-node.is-current > .el-tree-node__content { | |||||
background-color: var(--el-color-primary); | |||||
.el-tree-node__label, | |||||
.el-tree-node__expand-icon { | |||||
color: white; | |||||
} | |||||
.is-leaf { | |||||
color: transparent; | |||||
} | |||||
} | |||||
} | |||||
} | |||||
} |
@@ -4,66 +4,135 @@ | |||||
* @Date: 2023-12-15 15:44:05 | * @Date: 2023-12-15 15:44:05 | ||||
!--> | !--> | ||||
<template> | <template> | ||||
<div class="table-box"> | |||||
<ProTable ref="proTable" title="视频列表" :columns="columns" :request-api="monitorLIVEApi.page"> | |||||
<!-- 表格 header 按钮 --> | |||||
<!-- 表格 菜单类型 按钮 --> | |||||
<template #menuType="scope"> | |||||
<el-space wrap> | |||||
<el-tag v-if="scope.row.menuType === MenuTypeDictEnum.MENU" type="success">{{ | |||||
dictStore.dictTranslation(SysDictEnum.MENU_TYPE, MenuTypeDictEnum.MENU) | |||||
}}</el-tag> | |||||
<el-tag v-else-if="scope.row.menuType === MenuTypeDictEnum.LINK" type="warning">{{ | |||||
dictStore.dictTranslation(SysDictEnum.MENU_TYPE, MenuTypeDictEnum.LINK) | |||||
}}</el-tag> | |||||
<el-tag v-else type="info">{{ dictStore.dictTranslation(SysDictEnum.MENU_TYPE, scope.row.menuType) }}</el-tag> | |||||
<el-tag v-if="scope.row.isHome === true" type="danger">首页</el-tag> | |||||
</el-space> | |||||
</template> | |||||
<!-- 操作 --> | |||||
<template #operation="scope"> | |||||
<s-button link :opt="FormOptEnum.VIEW" @click="onDetail(scope.row)"> 查看 </s-button> | |||||
<!-- <s-button link :opt="FormOptEnum.EDIT" @click="onOpen(FormOptEnum.EDIT, scope.row)">处理</s-button> | |||||
<s-button link :opt="FormOptEnum.DELETE" @click="onDelete([scope.row.id], `确定删除该预警吗?`)" /> --> | |||||
</template> | |||||
</ProTable> | |||||
<el-dialog v-model="visible" :title="detailData.title" width="830px" :before-close="handleClose"> | |||||
<div> | |||||
<div class="dialogHeader"> | |||||
<div></div> | |||||
<div class="dialogBtn" @click="refreshUrl"> | |||||
<el-icon color="#409efc" :size="20"> | |||||
<Refresh /> | |||||
</el-icon> | |||||
<div>刷新视频</div> | |||||
<div class="main-box"> | |||||
<div class="custom-tree-container card filter"> | |||||
<p>摄像头分组管理</p> | |||||
<el-tree style="max-width: 600px" :data="dataSource" node-key="id" default-expand-all :expand-on-click-node="false"> | |||||
<template #default="{ node, data }"> | |||||
<span class="custom-tree-node"> | |||||
<span>{{ node.label }}</span> | |||||
<span> | |||||
<a @click="append(data)"> Append </a> | |||||
<a style="margin-left: 8px" @click="remove(node, data)"> Delete </a> | |||||
</span> | |||||
</span> | |||||
</template> | |||||
</el-tree> | |||||
</div> | |||||
<div class="table-box"> | |||||
<ProTable ref="proTable" title="视频列表" :columns="columns" :request-api="monitorLIVEApi.page"> | |||||
<!-- 表格 header 按钮 --> | |||||
<template #tableHeader="scope"> | |||||
<s-button v-auth="monitorLiveButtonCode.add" suffix="摄像头" @click="onOpen(FormOptEnum.ADD)" /> | |||||
<s-button | |||||
type="danger" | |||||
plain | |||||
suffix="摄像头" | |||||
:opt="FormOptEnum.DELETE" | |||||
:disabled="!scope.isSelected" | |||||
@click="onDelete(scope.selectedListIds, '删除所选数据')" | |||||
/> | |||||
</template> | |||||
<!-- 表格 菜单类型 按钮 --> | |||||
<template #menuType="scope"> | |||||
<el-space wrap> | |||||
<el-tag v-if="scope.row.menuType === MenuTypeDictEnum.MENU" type="success">{{ | |||||
dictStore.dictTranslation(SysDictEnum.MENU_TYPE, MenuTypeDictEnum.MENU) | |||||
}}</el-tag> | |||||
<el-tag v-else-if="scope.row.menuType === MenuTypeDictEnum.LINK" type="warning">{{ | |||||
dictStore.dictTranslation(SysDictEnum.MENU_TYPE, MenuTypeDictEnum.LINK) | |||||
}}</el-tag> | |||||
<el-tag v-else type="info">{{ dictStore.dictTranslation(SysDictEnum.MENU_TYPE, scope.row.menuType) }}</el-tag> | |||||
<el-tag v-if="scope.row.isHome === true" type="danger">首页</el-tag> | |||||
</el-space> | |||||
</template> | |||||
<!-- 操作 --> | |||||
<template #operation="scope"> | |||||
<s-button link :opt="FormOptEnum.VIEW" @click="onDetail(scope.row)"> 查看 </s-button> | |||||
<s-button link :opt="FormOptEnum.EDIT" @click="onOpen(FormOptEnum.EDIT, scope.row)">编辑</s-button> | |||||
<s-button link :opt="FormOptEnum.DELETE" @click="onDelete([scope.row.id], `确定删除该摄像头吗?`)" /> | |||||
</template> | |||||
</ProTable> | |||||
<!-- 新增/编辑表单 --> | |||||
<Form ref="formRef" /> | |||||
<el-dialog v-model="visible" :title="detailData.title" width="830px" :before-close="handleClose"> | |||||
<div> | |||||
<div class="dialogHeader"> | |||||
<div></div> | |||||
<div class="dialogBtn" @click="refreshUrl"> | |||||
<el-icon color="#409efc" :size="20"> | |||||
<Refresh /> | |||||
</el-icon> | |||||
<div>刷新视频</div> | |||||
</div> | |||||
</div> | </div> | ||||
<div v-if="visible || showVideo" class="prism-player" id="player-con"></div> | |||||
<!-- <VideoPlay :videoUrl="detailData.videoUrl" :videoType="detailData.videoType" /> --> | |||||
<!-- <video style="width: 100%; height: 500px" id="video" controls muted="false"></video> --> | |||||
<!-- <iframe src="/static/artcvideo.html" width="100%" height="600px" ref="iframeDom"></iframe> --> | |||||
</div> | </div> | ||||
<div v-if="visible || showVideo" class="prism-player" id="player-con"></div> | |||||
<!-- <VideoPlay :videoUrl="detailData.videoUrl" :videoType="detailData.videoType" /> --> | |||||
<!-- <video style="width: 100%; height: 500px" id="video" controls muted="false"></video> --> | |||||
<!-- <iframe src="/static/artcvideo.html" width="100%" height="600px" ref="iframeDom"></iframe> --> | |||||
</div> | |||||
<template #footer> | |||||
<div class="dialog-footer"> | |||||
<el-button @click="handleClose">关闭</el-button> | |||||
</div> | |||||
</template> | |||||
</el-dialog> | |||||
<template #footer> | |||||
<div class="dialog-footer"> | |||||
<el-button @click="handleClose">关闭</el-button> | |||||
</div> | |||||
</template> | |||||
</el-dialog> | |||||
</div> | |||||
</div> | </div> | ||||
</template> | </template> | ||||
<script setup lang="tsx" name="sysSpa"> | <script setup lang="tsx" name="sysSpa"> | ||||
import VideoPlay from "@/components/VideoPlay/videoplay.vue"; | import VideoPlay from "@/components/VideoPlay/videoplay.vue"; | ||||
import { ElMessage } from "element-plus"; | import { ElMessage } from "element-plus"; | ||||
import { monitorLIVEApi } from "@/api"; | |||||
import type Node from 'element-plus/es/components/tree/src/model/node' | |||||
import { monitorLIVEApi, monitorLiveButtonCode } from "@/api"; | |||||
import { ZJRQ } from "@/api/interface"; | import { ZJRQ } from "@/api/interface"; | ||||
import { useHandleData } from "@/hooks/useHandleData"; | import { useHandleData } from "@/hooks/useHandleData"; | ||||
import { ColumnProps, ProTableInstance } from "@/components/ProTable/interface"; | import { ColumnProps, ProTableInstance } from "@/components/ProTable/interface"; | ||||
import { useDictStore } from "@/stores/modules"; | import { useDictStore } from "@/stores/modules"; | ||||
import Form from "./components/form.vue"; | |||||
import { FormOptEnum, SysDictEnum, MenuTypeDictEnum } from "@/enums"; | import { FormOptEnum, SysDictEnum, MenuTypeDictEnum } from "@/enums"; | ||||
import './aliyun-rts-sdk.js' | import './aliyun-rts-sdk.js' | ||||
import './ali.js' | import './ali.js' | ||||
interface Tree { | |||||
id: number | |||||
label: string | |||||
children?: Tree[] | |||||
} | |||||
let id = 1000 | |||||
const append = (data: Tree) => { | |||||
const newChild = { id: id++, label: 'testtest', children: [] } | |||||
if (!data.children) { | |||||
data.children = [] | |||||
} | |||||
data.children.push(newChild) | |||||
dataSource.value = [...dataSource.value] | |||||
} | |||||
const remove = (node: Node, data: Tree) => { | |||||
const parent = node.parent | |||||
const children: Tree[] = parent.data.children || parent.data | |||||
const index = children.findIndex((d) => d.id === data.id) | |||||
children.splice(index, 1) | |||||
dataSource.value = [...dataSource.value] | |||||
} | |||||
const dataSource = ref<Tree[]>([ | |||||
{ | |||||
id: 1, | |||||
label: 'Level one 1', | |||||
}, | |||||
{ | |||||
id: 2, | |||||
label: 'Level one 2', | |||||
}, | |||||
{ | |||||
id: 3, | |||||
label: 'Level one 3', | |||||
}, | |||||
]) | |||||
const visible = ref(false); //是否显示表单 | const visible = ref(false); //是否显示表单 | ||||
// 获取 ProTable 元素,调用其获取刷新数据方法(还能获取到当前查询参数,方便导出携带参数) | // 获取 ProTable 元素,调用其获取刷新数据方法(还能获取到当前查询参数,方便导出携带参数) | ||||
@@ -72,7 +141,7 @@ | |||||
// 表格配置项 | // 表格配置项 | ||||
const columns: ColumnProps<ZJRQ.WarnInfo>[] = [ | const columns: ColumnProps<ZJRQ.WarnInfo>[] = [ | ||||
// { type: "selection", fixed: "left", width: 80 }, | |||||
{ type: "selection", fixed: "left", width: 80 }, | |||||
// { prop: "searchKey", label: "关键字", search: { el: "input" }, isShow: false }, | // { prop: "searchKey", label: "关键字", search: { el: "input" }, isShow: false }, | ||||
// { | // { | ||||
// prop: "poiId", | // prop: "poiId", | ||||
@@ -107,7 +176,6 @@ | |||||
prop: "resWidth", | prop: "resWidth", | ||||
label: "分辨率", | label: "分辨率", | ||||
render: (row) => { | render: (row) => { | ||||
console.log(row,88) | |||||
return row.row.resWidth + '*' + row.row.resHeight; | return row.row.resWidth + '*' + row.row.resHeight; | ||||
} | } | ||||
}, | }, | ||||
@@ -119,6 +187,7 @@ | |||||
* @param ids id数组 | * @param ids id数组 | ||||
*/ | */ | ||||
async function onDelete(ids: string[], msg: string) { | async function onDelete(ids: string[], msg: string) { | ||||
return | |||||
// 二次确认 => 请求api => 刷新表格 | // 二次确认 => 请求api => 刷新表格 | ||||
await useHandleData(monitorLIVEApi.delete, { ids }, msg); | await useHandleData(monitorLIVEApi.delete, { ids }, msg); | ||||
RefreshTable(); | RefreshTable(); | ||||
@@ -130,6 +199,16 @@ | |||||
function RefreshTable() { | function RefreshTable() { | ||||
proTable.value?.refresh(); | proTable.value?.refresh(); | ||||
} | } | ||||
// 表单引用 | |||||
const formRef = ref<InstanceType<typeof Form> | null>(null); | |||||
/** | |||||
* 打开表单 | |||||
* @param opt 操作类型 | |||||
* @param record 记录 | |||||
*/ | |||||
function onOpen(opt: FormOptEnum, record: {} | SysOrg.SysOrgInfo = {}) { | |||||
formRef.value?.onOpen({ opt: opt, record: record, successful: RefreshTable }); | |||||
} | |||||
// 详情数据 | // 详情数据 | ||||
// let detailData: globalThis.Ref<{}> | // let detailData: globalThis.Ref<{}> | ||||
let detailData = reactive({ | let detailData = reactive({ | ||||
@@ -305,6 +384,7 @@ | |||||
<style lang="scss" scoped> | <style lang="scss" scoped> | ||||
@import url("https://g.alicdn.com/apsara-media-box/imp-web-player/2.16.3/skins/default/aliplayer-min.css"); | @import url("https://g.alicdn.com/apsara-media-box/imp-web-player/2.16.3/skins/default/aliplayer-min.css"); | ||||
@import "./index.scss"; | |||||
.detailpic { | .detailpic { | ||||
width: 800px; | width: 800px; | ||||
object-fit: cover; | object-fit: cover; | ||||
@@ -7,13 +7,13 @@ | |||||
<div class="card content-main"> | <div class="card content-main"> | ||||
<el-row :gutter="20"> | <el-row :gutter="20"> | ||||
<el-col :xs="24" :sm="24" :md="12" :lg="12" :xl="12"> | <el-col :xs="24" :sm="24" :md="12" :lg="12" :xl="12"> | ||||
<div ref="chart1" style="width: 600px; height: 400px"></div> | |||||
<div ref="chart1" style="width: 600px; height: 378px"></div> | |||||
</el-col> | </el-col> | ||||
<el-col :xs="24" :sm="24" :md="12" :lg="12" :xl="12"> | <el-col :xs="24" :sm="24" :md="12" :lg="12" :xl="12"> | ||||
<div ref="chart2" style="width: 600px; height: 400px"></div> | |||||
<div ref="chart2" style="width: 600px; height: 378px"></div> | |||||
</el-col> | </el-col> | ||||
<el-col :span="24"> | <el-col :span="24"> | ||||
<div ref="chart3" style="width: 100%; height: 400px"></div> | |||||
<div ref="chart3" style="width: 100%; height: 378px"></div> | |||||
</el-col> | </el-col> | ||||
</el-row> | </el-row> | ||||
</div> | </div> | ||||