@@ -24,7 +24,6 @@ declare module 'vue' { | |||
ElBreadcrumbItem: typeof import('element-plus/es')['ElBreadcrumbItem'] | |||
ElButton: typeof import('element-plus/es')['ElButton'] | |||
ElCheckbox: typeof import('element-plus/es')['ElCheckbox'] | |||
ElCol: typeof import('element-plus/es')['ElCol'] | |||
ElColorPicker: typeof import('element-plus/es')['ElColorPicker'] | |||
ElContainer: typeof import('element-plus/es')['ElContainer'] | |||
ElDialog: typeof import('element-plus/es')['ElDialog'] | |||
@@ -43,13 +42,10 @@ declare module 'vue' { | |||
ElMain: typeof import('element-plus/es')['ElMain'] | |||
ElMenu: typeof import('element-plus/es')['ElMenu'] | |||
ElMenuItem: typeof import('element-plus/es')['ElMenuItem'] | |||
ElOption: typeof import('element-plus/es')['ElOption'] | |||
ElPagination: typeof import('element-plus/es')['ElPagination'] | |||
ElPopover: typeof import('element-plus/es')['ElPopover'] | |||
ElRadio: typeof import('element-plus/es')['ElRadio'] | |||
ElRow: typeof import('element-plus/es')['ElRow'] | |||
ElScrollbar: typeof import('element-plus/es')['ElScrollbar'] | |||
ElSelect: typeof import('element-plus/es')['ElSelect'] | |||
ElSpace: typeof import('element-plus/es')['ElSpace'] | |||
ElSubMenu: typeof import('element-plus/es')['ElSubMenu'] | |||
ElSwitch: typeof import('element-plus/es')['ElSwitch'] | |||
@@ -59,6 +55,8 @@ declare module 'vue' { | |||
ElTabs: typeof import('element-plus/es')['ElTabs'] | |||
ElTag: typeof import('element-plus/es')['ElTag'] | |||
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'] | |||
FormContainer: typeof import('./src/components/Form/FormContainer/index.vue')['default'] | |||
Grid: typeof import('./src/components/Grid/index.vue')['default'] | |||
@@ -2,7 +2,7 @@ | |||
<html lang="en"> | |||
<head> | |||
<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" /> | |||
<title><%- title %></title> | |||
<!-- <script src="https://unpkg.com/aliyun-rts-sdk@1.2.1/dist/aliyun-rts-sdk.js"></script> --> | |||
@@ -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> | |||
<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> | |||
</template> | |||
<script setup lang="ts"> | |||
@@ -1,12 +1,60 @@ | |||
.home { | |||
display: flex; | |||
align-items: center; | |||
justify-content: center; | |||
width: 100%; | |||
height: 100%; | |||
.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> | |||
<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> | |||
</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"> | |||
@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 | |||
!--> | |||
<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 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 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> | |||
</template> | |||
<script setup lang="tsx" name="sysSpa"> | |||
import VideoPlay from "@/components/VideoPlay/videoplay.vue"; | |||
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 { useHandleData } from "@/hooks/useHandleData"; | |||
import { ColumnProps, ProTableInstance } from "@/components/ProTable/interface"; | |||
import { useDictStore } from "@/stores/modules"; | |||
import Form from "./components/form.vue"; | |||
import { FormOptEnum, SysDictEnum, MenuTypeDictEnum } from "@/enums"; | |||
import './aliyun-rts-sdk.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); //是否显示表单 | |||
// 获取 ProTable 元素,调用其获取刷新数据方法(还能获取到当前查询参数,方便导出携带参数) | |||
@@ -72,7 +141,7 @@ | |||
// 表格配置项 | |||
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: "poiId", | |||
@@ -107,7 +176,6 @@ | |||
prop: "resWidth", | |||
label: "分辨率", | |||
render: (row) => { | |||
console.log(row,88) | |||
return row.row.resWidth + '*' + row.row.resHeight; | |||
} | |||
}, | |||
@@ -119,6 +187,7 @@ | |||
* @param ids id数组 | |||
*/ | |||
async function onDelete(ids: string[], msg: string) { | |||
return | |||
// 二次确认 => 请求api => 刷新表格 | |||
await useHandleData(monitorLIVEApi.delete, { ids }, msg); | |||
RefreshTable(); | |||
@@ -130,6 +199,16 @@ | |||
function RefreshTable() { | |||
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 = reactive({ | |||
@@ -305,6 +384,7 @@ | |||
<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 "./index.scss"; | |||
.detailpic { | |||
width: 800px; | |||
object-fit: cover; | |||
@@ -7,13 +7,13 @@ | |||
<div class="card content-main"> | |||
<el-row :gutter="20"> | |||
<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 :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 :span="24"> | |||
<div ref="chart3" style="width: 100%; height: 400px"></div> | |||
<div ref="chart3" style="width: 100%; height: 378px"></div> | |||
</el-col> | |||
</el-row> | |||
</div> | |||