Sfoglia il codice sorgente

系统配置添加额为功能

master
suyanyan 2 mesi fa
parent
commit
49f2031238
10 ha cambiato i file con 430 aggiunte e 23 eliminazioni
  1. +9
    -1
      SafeCampus.WEB/src/api/modules/monitor/live.ts
  2. +4
    -0
      SafeCampus.WEB/src/api/modules/sysconfig/ability.ts
  3. +15
    -1
      SafeCampus.WEB/src/components/Form/FormContainer/index.vue
  4. +25
    -4
      SafeCampus.WEB/src/views/monitor/live/index.vue
  5. +123
    -0
      SafeCampus.WEB/src/views/sysconfig/ability/components/cameraForm.vue
  6. +3
    -3
      SafeCampus.WEB/src/views/sysconfig/ability/components/userForm.vue
  7. +202
    -0
      SafeCampus.WEB/src/views/sysconfig/ability/components/viewMonitor.vue
  8. +45
    -8
      SafeCampus.WEB/src/views/sysconfig/ability/index.vue
  9. +2
    -4
      SafeCampus.WEB/src/views/warn/zjrq/index.vue
  10. +2
    -2
      monitorMobile/pages/earlyWarning/detail.vue

+ 9
- 1
SafeCampus.WEB/src/api/modules/monitor/live.ts Vedi File

@@ -17,7 +17,7 @@ import { ReqstartId, ResPage, sysCamera, ReqstopId } from "@/api/interface";
const http = moduleRequest("/business/deviceApi/");
const http2 = moduleRequest("/business/cameraInfo/");
const http3 = moduleRequest("/business/cameraGroup/");
const http4 = moduleRequest("/business/warn/");
/**
* @Description: 单页管理
* @Author: wangwenpei
@@ -56,6 +56,14 @@ const monitorLIVEApi = {
setWarningPushPerson(params: sysCamera.setGroup) {
return http2.post<ResPage<sysCamera.MonitorInfo>>("batchSetPushPersonByWarn", params);
},
/* 设置推送人 */
setPushPersonByWarn(params: sysCamera.setGroup) {
return http4.post<ResPage<sysCamera.MonitorInfo>>("setPushPersonByWarn", params);
},
// 数据同步
setdat() {
return http2.post<any>("dat");
},
// 获取摄像头分组树
groupList(params: sysCamera.Tree) {
return http3.get<ResPage<sysCamera.MonitorInfo>>("getNoPageList");


+ 4
- 0
SafeCampus.WEB/src/api/modules/sysconfig/ability.ts Vedi File

@@ -39,6 +39,10 @@ const abilityApi = {
return http1.download("reportExport", params, {
showHeader: true
});
},
// 获取订阅配置
getFuncConf(params: any) {
return http.get("getFuncConf", params);
}
};



+ 15
- 1
SafeCampus.WEB/src/components/Form/FormContainer/index.vue Vedi File

@@ -10,7 +10,17 @@
<template v-for="slotKey in slotKeys" #[slotKey]> <slot :name="slotKey" /></template>
</el-drawer>
<!-- 对话框 -->
<el-dialog v-else top="50px" :visible="visible" :destroy-on-close="true" draggable v-bind="$attrs" @close="close" :width="formProps.formSize">
<el-dialog
v-else
top="50px"
:visible="visible"
:close-on-click-modal="formProps.closeOnClickModal"
:destroy-on-close="true"
draggable
v-bind="$attrs"
@close="close"
:width="formProps.formSize"
>
<template v-for="slotKey in slotKeys" #[slotKey]> <slot :name="slotKey" /></template>
</el-dialog>
</div>
@@ -29,6 +39,10 @@ const formProps = defineProps({
formSize: {
type: String,
default: "600px"
},
closeOnClickModal: {
type: Boolean,
default: true
}
});



+ 25
- 4
SafeCampus.WEB/src/views/monitor/live/index.vue Vedi File

@@ -57,6 +57,10 @@
/>
<el-button :disabled="!scope.isSelected" plain @click="omMove(FormOptEnum.ADD, scope.selectedListIds)" type="success">移动至分组</el-button>
</template>
<!-- 表格工具按钮 -->
<template #toolButton>
<el-button :icon="Refresh" circle @click="getTableList" />
</template>
<!-- 表格 菜单类型 按钮 -->
<!-- 操作 -->
<template #operation="scope">
@@ -72,9 +76,9 @@
<el-dropdown-item :command="command(scope.row, cmdEnum.Delete)">
{{ cmdEnum.Delete }}
</el-dropdown-item>
<el-dropdown-item :command="command(scope.row, cmdEnum.pushPerson)">
<!-- <el-dropdown-item :command="command(scope.row, cmdEnum.pushPerson)">
{{ cmdEnum.pushPerson }}
</el-dropdown-item>
</el-dropdown-item> -->
</el-dropdown-menu>
</template>
</el-dropdown>
@@ -141,6 +145,7 @@ import { useDictStore } from "@/stores/modules";
import Form from "./components/form.vue";
import userForm from "./components/userForm.vue";
import moveForm from "./components/moveForm.vue";
import { Refresh } from "@element-plus/icons-vue";
// import { FormOptEnum, SysDictEnum, MenuTypeDictEnum } from "@/enums";
// import './aliyun-rts-sdk.js'
import "./ali.js";
@@ -369,6 +374,17 @@ const columns: ColumnProps<sysCamera.MonitorInfo>[] = [
return row.row.resWidth + "*" + row.row.resHeight;
}
},
{
prop: "deviceStatus",
label: "在线状态",
render: row => {
if(row.row.deviceStatus){
return (<el-tag type="success">在线</el-tag>)
}else{
return (<el-tag type="danger">离线</el-tag>)
}
}
},
{ prop: "operation", label: "操作", width: 250, fixed: "right" }
];
// 移动分组禁用
@@ -472,7 +488,7 @@ function getvideo1() {
let aliRts = new AliRTS();
let pullStreamUrl = detailData.videoUrl;
const mediaEle = document.querySelector("video");
aliRts.on("onError", err => {
aliRts.on("onError", (err: any) => {
console.log(`errorCode: ${err.errorCode}`);
console.log(`message: ${err.message}`);
});
@@ -574,7 +590,12 @@ function stopUrl() {
});
});
}

// 自定义刷新事件
function getTableList(){
monitorLIVEApi.setdat().then((res:any) => {
RefreshTable();
})
}
onMounted(() => {
getGroupList();
});


+ 123
- 0
SafeCampus.WEB/src/views/sysconfig/ability/components/cameraForm.vue Vedi File

@@ -0,0 +1,123 @@
<!--
* @Description: 表单
* @Author: syy
* @Date: 2023-12-15 15:45:59
-->
<template>
<div>
<form-container v-model="visible" :title="`${detailData.data.name}-关联摄像头`" :closeOnClickModal="false" form-size="800px" @close="onClose">
<el-transfer
v-model="modelvalue"
:data="tableData"
filterable
:titles="['待选择摄像头', '已选择摄像头']"
:props="{
key: 'id',
label: 'name'
}"
>
<template #default="{ option }">
<span>{{ option.id }} - {{ option.name }}</span>
</template>
<template #left-empty>
<el-empty :image-size="60" description="No data" />
</template>
<template #right-empty>
<el-empty :image-size="60" description="No data" />
</template>
</el-transfer>
<template #footer>
<el-button @click="onClose"> 取消 </el-button>
<el-button type="primary" @click="handleSubmit" :disabled="modelvalue.length == 0"> 确定 </el-button>
</template>
</form-container>
</div>
</template>

<script setup lang="ts" name="SysUserPerformClass">
import { ref, reactive } from "vue";
import { abilityApi } from "@/api";
const visible = ref(false); //是否显示表单
const modelvalue = ref<any>([]);
const tableData = ref<any>([]);
let detailData: any = reactive({
parentCode: "",
code: "",
parentData: {},
data: {}
});
// 表单参数
const sysUserProps = reactive<any>({
opt: "关联摄像头",
record: {},
disabled: false
});
/**
* 打开表单
* @param props 表单参数
*/

function onOpen(props: any) {
tableData.value = [];
Object.assign(sysUserProps, props); //合并参数
visible.value = true; //显示表单
sysUserProps.record = props.record;
detailData.parentData = props.record.parentData;
detailData.data = props.record.data;
modelvalue.value = detailData.data.cameraId;
getCameraList();
//获取专业数据
}
function getCameraList() {
abilityApi.getFuncConf({ subsetCode: detailData.data.code }).then((res: any) => {
tableData.value = res.data;
});
}
/** 提交表单 */
function handleSubmit() {
let submitForm: any = [];
// 过滤
tableData.value.map((item: any) => {
modelvalue.value.map((key: any) => {
if (item.id == key) {
submitForm.push(item);
}
});
});
let cameraId: any = [];
let cameraName: any = [];
for (let i = 0; i < submitForm.length; i++) {
cameraId.push(submitForm[i].id);
cameraName.push(submitForm[i].name);
}
detailData.parentData.subset.map((item: any) => {
if (item.code == detailData.data.code) {
item.cameraId = cameraId;
item.cameraName = cameraName;
}
});
console.log(detailData.parentData);
let params: string = JSON.stringify([detailData.parentData]);
abilityApi.setWarnGroup({ configJson: params }).then((res: any) => {
let { code, data, msg } = res;
if (code == 200 && data) {
ElMessage.success(msg);
onClose();
sysUserProps.successful!();
}
});
}
/** 关闭表单*/
function onClose() {
visible.value = false;
}
// 暴露给父组件的方法
defineExpose({
onOpen
});
</script>
<style lang="scss" scoped>
:deep(.el-transfer-panel) {
width: 299px !important;
}
</style>

+ 3
- 3
SafeCampus.WEB/src/views/sysconfig/ability/components/userForm.vue Vedi File

@@ -84,12 +84,12 @@ async function handleSubmit() {
warnCode: "",
userId: ""
};
if (liveUserProps.opt == "预警推送人") {
params.warnCode = liveUserProps.record.warnCode;
if (liveUserProps.opt == "视频推送人") {
params.warnCode = liveUserProps.record.code;
params.userId = liveUserProps.record.userId;
//提交表单
await monitorLIVEApi
.setWarningPushPerson(params)
.setPushPersonByWarn(params)
.then(() => {
liveUserProps.successful!(); //调用父组件的successful方法
})


+ 202
- 0
SafeCampus.WEB/src/views/sysconfig/ability/components/viewMonitor.vue Vedi File

@@ -0,0 +1,202 @@
<!--
* @Description: 表单
* @Author: syy
* @Date: 2023-12-15 15:45:59
-->
<template>
<div>
<form-container v-model="visibleClass" :title="`${sysUserProps.opt}监控`" form-size="800px" @close="onClose">
<el-table :data="tableData" style="width: 100%">
<el-table-column label="摄像头名称" prop="cameraName" />
<el-table-column align="right">
<template #default="scope">
<el-button size="small" @click="handleView(scope.row)"> 查看 </el-button>
</template>
</el-table-column>
</el-table>
</form-container>
<!-- 视频详情 -->
<el-dialog v-model="visibleDialog" :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="visibleDialog || showVideo" class="prism-player" id="player-con"></div>
</div>
<template #footer>
<div class="dialog-footer">
<el-button @click="handleClose">关闭</el-button>
</div>
</template>
</el-dialog>
</div>
</template>

<script setup lang="ts" name="SysUserPerformClass">
import { ref, reactive } from "vue";
import { monitorLIVEApi } from "@/api";
import { FormOptEnum } from "@/enums";
import "@/views/monitor/live/ali.js";
let detailData = reactive({
title: "",
videoUrl: "",
sensorId: "",
streamId: "",
videoToken: "",
videoType: ""
});
const visibleClass = ref(false); //是否显示表单
const visibleDialog = ref(false); //是否显示弹窗
// 表单参数
const sysUserProps = reactive<any>({
opt: FormOptEnum.ADD,
record: {},
disabled: false
});

/**
* 打开表单
* @param props 表单参数
*/
let tableData = ref<any>([]);
function onOpen(props: any) {
tableData.value = [];
Object.assign(sysUserProps, props); //合并参数
visibleClass.value = true; //显示表单
sysUserProps.record = props.record;
for (let i = 0; i < props.record.cameraId.length; i++) {
let obj: any = {};
obj["cameraId"] = props.record.cameraId[i];
obj["cameraName"] = props.record.cameraName[i];
tableData.value.push(obj);
}
console.log(tableData.value);
//获取专业数据
}
/** 关闭表单*/
function onClose() {
visibleClass.value = false;
}

// 刷新
const showVideo = ref(false);
function refreshUrl() {
stopUrl();
showVideo.value = false;
setTimeout(() => {
showVideo.value = true;
getUrl();
}, 1000);
}
function stopUrl() {
detailData.videoUrl = "";
if (player.value) {
player.value.dispose();
}
let params = {
sensorId: detailData.sensorId,
streamId: detailData.streamId,
videoToken: detailData.videoToken
};
setTimeout(async () => {
await monitorLIVEApi.stopUrl(params).then((res: any) => {
let { code, data, msg } = res;
if (code == 200) {
// ElMessage.success(msg);
}
});
});
}
function handleView(row: any) {
detailData.sensorId = row.cameraId;
detailData.title = row.cameraName + "(" + row.cameraId + ")";
visibleDialog.value = true;
getUrl();
}
function getUrl() {
detailData.videoType = "m3u8";
setTimeout(async () => {
await monitorLIVEApi.detail({ sensorId: detailData.sensorId }).then((res: any) => {
let { code, data } = res;
if (code == "200") {
detailData.videoUrl = "";
detailData.videoUrl = data.rtsPullStreamUrls[0].url;
detailData.streamId = data.streamId;
detailData.videoToken = data.videoToken;
getvideo2();
}
});
});
}

let player = ref<any>(null);
function getvideo2() {
var options = {
id: "player-con",
source: detailData.videoUrl + "&subaudio=no&jitterbuffer=6000",
// "rtsFallbackSource": "降级地址,如HLS",
width: "100%",
height: "500px",
autoplay: true,
isLive: true,
playsinline: true,
skipRtsSupportCheck: false, // 对于不在 https://help.aliyun.com/document_detail/397569.html 中的浏览器,可以传 true 跳过检
rtsLoadDataTimeout: 1500,
liveRetry: 1
};

player.value = new Aliplayer(options, function () {});

// 降级时会触发此事件
player.value.on("rtsFallback", function (event: any) {
console.log("[EVENT]rtsFallback", event.paramData);
});

player.value.on("error", function (event: any) {
console.log("[EVENT]error", event.paramData);
});
player.value.setVolume(0);
player.value.on("rtsTraceId", function (data: any) {
console.log("[EVENT]rtsTraceId", data.paramData);
});
}
const handleClose = () => {
visibleDialog.value = false;
detailData.videoUrl = "";
detailData.videoType = "";
stopUrl();
if (player.value) {
player.value.dispose();
}
};

// 暴露给父组件的方法
defineExpose({
onOpen
});
</script>

<style lang="scss" scoped>
@import "https://g.alicdn.com/apsara-media-box/imp-web-player/2.16.3/skins/default/aliplayer-min.css";
@import "@/views/monitor/live/index.scss";
.dialogHeader {
display: flex;
align-items: center;
justify-content: space-between;
margin: 20px;
font-size: 18px;
color: #409efc;
cursor: pointer;
.dialogBtn {
display: flex;
align-items: center;
justify-content: space-between;
}
}
</style>

+ 45
- 8
SafeCampus.WEB/src/views/sysconfig/ability/index.vue Vedi File

@@ -36,9 +36,11 @@
<div class="collapse-title" @click.stop="">
<div class="titlemodel">
<div style="width: 220px; text-align: left">{{ item.name }}</div>
<div style="margin-left: 20px">
<div style="margin: 0 20px">
<el-button @click="pushPerson(FormOptEnum.VideoPushPerson, item)" type="primary" size="small">设置推送人</el-button>
</div>

<el-tag type="info" v-if="item.pushUserId">{{ item.pushUserName }}({{ item.pushPhone }})</el-tag>
</div>
<div class="btns">
<el-switch v-model="item.state" @change="stateChange" />
@@ -55,12 +57,22 @@
</div> -->
<el-row :gutter="20">
<el-col :xs="24" :sm="24" :md="24" :lg="12" :xl="6" v-for="v in item.subset" :key="v.code">
<div class="contentinfo">
<div class="contentinfo" style="position: relative">
<div class="modellabel">{{ v.name }}</div>

<div class="btns">
<div class="btns" :style="{ justifyContent: v.cameraId.length > 0 ? 'space-between' : 'flex-end' }">
<el-button v-if="v.cameraId.length > 0" @click="viewMonitor(FormOptEnum.VIEW, v)" type="info" plain size="small"
>查看监控</el-button
>
<el-switch :disabled="item.state == false" v-model="v.state" @change="stateChange" />
</div>
<el-icon
color="#409efc"
:size="20"
style="position: absolute; top: 10px; right: 10px"
@click="addCamera(FormOptEnum.ADD, v, item)"
>
<Plus />
</el-icon>
</div>
</el-col>
</el-row>
@@ -70,18 +82,24 @@
</div>
<!-- 人员选择 -->
<userForm ref="userFormRef" />
<!-- 班级新增/编辑表单 -->
<viewMonitorForm ref="formRefC" />
<!-- 关联摄像头 -->
<cameraForm ref="cameraformRefC" />
</div>
</div>
</template>

<script setup lang="tsx" name="ability">
import { ref, watch, provide, onMounted, unref, computed, reactive } from "vue";
import { ref, onMounted } from "vue";
import TreeFilter from "@/components/TreeFilter/index.vue";
import { ElMessage } from "element-plus";
import { abilityApi, userManageClassManageApi, monitorLIVEApi,SysOrg } from "@/api";
import { abilityApi, monitorLIVEApi,SysOrg } from "@/api";
// import { FormOptEnum, SysDictEnum, MenuTypeDictEnum } from "@/enums";
import userForm from "./components/userForm.vue";

import viewMonitorForm from "./components/viewMonitor.vue";
import cameraForm from "./components/cameraForm.vue";
import { Plus} from "@element-plus/icons-vue";
enum FormOptEnum {
/** 新增 */
ADD = "新增",
@@ -150,6 +168,8 @@ function pushPerson(opt: FormOptEnum, record: {} | SysOrg.SysOrgInfo = {}) {
}
// 开关
function stateChange() {
console.log(warnGroupList.value);
let params: string = JSON.stringify(warnGroupList.value);
setTimeout(async () => {
await abilityApi.setWarnGroup({ configJson: params }).then((res:any) => {
@@ -162,6 +182,20 @@ function stateChange() {
});
});
}
// 查看监控
const formRefC = ref<any>(null);
function viewMonitor(opt: any, record: {}) {
formRefC.value?.onOpen({ opt: opt, record: JSON.parse(JSON.stringify(record))});
}
// 关联摄像头
const cameraformRefC = ref<any>(null);
function addCamera(opt: any, record: {}, option: {}) {
cameraformRefC.value?.onOpen({ opt: opt, record: {
data:JSON.parse(JSON.stringify(record)),
parentData:option
},successful: getwarnGroup});
}

</script>

<style lang="scss" scoped>
@@ -207,9 +241,12 @@ function stateChange() {
font-size: 16px;
}
.btns {
// text-align: right;
display: flex;
align-items: center;
justify-content: space-between;
margin-top: 20px;
margin-right: 0;
text-align: right;
}
}
}


+ 2
- 4
SafeCampus.WEB/src/views/warn/zjrq/index.vue Vedi File

@@ -86,19 +86,17 @@
<div class="linebox">预警时间:{{ detailData.tick }}</div>
</el-col>

<el-col :span="12">
<!-- <el-col :span="12">
<div class="linebox">
复核视频:
<span style="cursor: pointer" v-if="detailData.videoUrl" @click="onPlay(detailData.videoUrl)">
<el-icon color="#409efc" :size="20">
<VideoCamera />
</el-icon>
<!-- <el-icon><VideoCamera /></el-icon> -->
</span>
<span v-else>暂无数据</span>
<!-- {{ detailData.videoUrl }} -->
</div>
</el-col>
</el-col> -->
<el-col :span="12">
<div class="linebox">处理时间:{{ detailData.handTime ? detailData.handTime : "暂无数据" }}</div>
</el-col>


+ 2
- 2
monitorMobile/pages/earlyWarning/detail.vue Vedi File

@@ -58,7 +58,7 @@
{{ detailData.tick || "--" }}
</view>
</view>
<view class="cli">
<!-- <view class="cli">
<view class="labelBox">
复核视频:
</view>
@@ -67,7 +67,7 @@
@click="seeVideo(detailData.videoUrl)">查看视频</text>
<text v-else>--</text>
</view>
</view>
</view> -->
<view class="cli">
<view class="labelBox">
处理时间:


Caricamento…
Annulla
Salva