yxq 1 month ago
parent
commit
086f40e4e6
14 changed files with 755 additions and 97 deletions
  1. +3
    -0
      SafeCampus.WEB/src/api/modules/usermanage/classManage.ts
  2. +4
    -0
      SafeCampus.WEB/src/api/modules/usermanage/dormitory.ts
  3. +8
    -0
      SafeCampus.WEB/src/api/modules/warn/zjrq.ts
  4. +25
    -2
      SafeCampus.WEB/src/components/Selectors/ClassUserselector/index.vue
  5. +46
    -48
      SafeCampus.WEB/src/views/home/index.vue
  6. +20
    -8
      SafeCampus.WEB/src/views/monitor/live/index.vue
  7. +600
    -0
      SafeCampus.WEB/src/views/monitor/live/index1.vue
  8. +1
    -8
      SafeCampus.WEB/src/views/userManage/classManage/index.vue
  9. +5
    -5
      SafeCampus.WEB/src/views/userManage/dormitory/components/formDormitory/index.vue
  10. +1
    -2
      SafeCampus.WEB/src/views/userManage/keyPersonnel/components/form/index.vue
  11. +1
    -2
      SafeCampus.WEB/src/views/userManage/personnel/components/form/index.vue
  12. +1
    -1
      SafeCampus.WEB/src/views/userManage/personnel/index.vue
  13. +20
    -17
      SafeCampus.WEB/src/views/violation/portrait/detail.vue
  14. +20
    -4
      SafeCampus.WEB/src/views/violation/portrait/index.vue

+ 3
- 0
SafeCampus.WEB/src/api/modules/usermanage/classManage.ts View File

@@ -26,6 +26,9 @@ const userManageClassManageApi = {
page(params: SysUserPersonnel.ClassPage) {
return http.get("queryAll", params);
},
getPageList(params: SysUserPersonnel.ClassPage) {
return http.get("getPageList", params);
},
/** 删除底库 */
delete(params: ReqId) {
return http.delete("deleteDfieldD", params);


+ 4
- 0
SafeCampus.WEB/src/api/modules/usermanage/dormitory.ts View File

@@ -78,6 +78,10 @@ const userManageDormitoryApi = {
/** 获取归寝时间 */
getReturnTime() {
return httpChamber.get("getReturnTime");
},
// 获取宿舍楼摄像头列表
getBuildCameraList() {
return http.get("getBuildCameraList");
}
};



+ 8
- 0
SafeCampus.WEB/src/api/modules/warn/zjrq.ts View File

@@ -45,6 +45,14 @@ const warnZJRQApi = {
/** 处理预警 */
handWarn(params: ReqId) {
return http.post("handWarn", params);
},
// 首页基础数据
basicInfo() {
return http.get("getBaseStatistics");
},
// 首页高危预警
highWarn() {
return http.get("getHighRisk");
}
};



+ 25
- 2
SafeCampus.WEB/src/components/Selectors/ClassUserselector/index.vue View File

@@ -67,7 +67,7 @@
<el-col :span="10">
<ProTable
ref="chooseTable"
:columns="columns"
:columns="columns2"
maxHeight="480"
:tool-button="true"
:data="chooseDataTmp"
@@ -170,7 +170,30 @@ const columns: ColumnProps<SysUser.SysUserInfo>[] = [
{ prop: "dormitoryName", label: "寝室" },
];

const columns2: ColumnProps<SysUser.SysUserInfo>[] = [
{ type: "selection", fixed: "left", width: 50 },
{ prop: "operation", label: "操作", width: 80, fixed: "left" },
{
prop: "faceUrl",
label: "人脸",
render: scope => {
return (
<img src={scope.row.faces.length > 0 ? scope.row.faces[0].faceUrl : ''} onClick={() => viewHeadImage(scope)} style='width:30px;height:30px;' alt=''/>
);
}
},
{
prop: "personName",
label: "姓名",
render: row => {
return row.row.name;
},
search: { el: "input", span: 2 }
},
{ prop: "personSetName", label: "班级" },
// { prop: "dormitoryName", label: "寝室" },
];
/** 显示选择器 */
function showSelector(data: SysUser.SysUserInfo[] = []) {
visible.value = true;


+ 46
- 48
SafeCampus.WEB/src/views/home/index.vue View File

@@ -16,7 +16,7 @@
</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 class="home-bg-content-item-value">{{ basicInfo.cameraCount }}</div>
</div>
</div></el-col
>
@@ -27,7 +27,7 @@
</div>
<div class="home-bg-content-item-content">
<div class="home-bg-content-item-title">预警信息总量</div>
<div class="home-bg-content-item-value">1972</div>
<div class="home-bg-content-item-value">{{ basicInfo.warnCount }}</div>
</div>
</div></el-col
>
@@ -38,7 +38,7 @@
</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 class="home-bg-content-item-value">{{ basicInfo.handCount }}</div>
</div>
</div></el-col
>
@@ -49,7 +49,7 @@
</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 class="home-bg-content-item-value">{{ basicInfo.teacherCount }}</div>
</div>
</div></el-col
>
@@ -86,7 +86,7 @@
<div>高危预警信息统计</div>
</div>
<div class="home-bg-content handleBox">
<ProTable ref="proTable" title="视频列表" :toolButton="false" :pagination="false" :columns="columns" :data="tableData"> </ProTable>
<ProTable ref="proTable" :toolButton="false" :pagination="false" :columns="columns" :data="highTabledata"> </ProTable>
</div>
</div>
</el-col>
@@ -108,7 +108,7 @@
<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 { warnZJRQApi } from "@/api";
import { ZJRQ } from "@/api/interface";
import { ColumnProps, ProTableInstance } from "@/components/ProTable/interface";
import { useDictStore } from "@/stores/modules";
@@ -121,9 +121,30 @@ const chart2 = ref(null);
const chart3 = ref(null);

onMounted(() => {
getBasic();
getHighWarin();
getDataChart();
getWeekData();
});
let basicInfo = reactive({
cameraCount: 0,
handCount: 0,
teacherCount: 0,
warnCount: 0
});

// 获取基础数据
function getBasic() {
warnZJRQApi.basicInfo().then((res: any) => {
if (res.code == 200) {
basicInfo.cameraCount = res.data.cameraCount;
basicInfo.handCount = res.data.handCount;
basicInfo.teacherCount = res.data.teacherCount;
basicInfo.warnCount = res.data.warnCount;
}
});
}

function getDataChart() {
setTimeout(async () => {
await statistionApi.warnstatistion({}).then(res => {
@@ -158,6 +179,7 @@ function getDataChart() {
});
});
}

function getCharts1(data: any) {
const chart = echarts.init(chart1.value);
const option = {
@@ -170,7 +192,7 @@ function getCharts1(data: any) {
// },
legend: {
orient: "vertical",
left: "right",
right: "0%",
top: "middle"
},
series: [
@@ -220,7 +242,7 @@ function getCharts2(data: any) {
// },
legend: {
orient: "vertical",
left: "right",
right: "0%",
top: "middle"
},
series: [
@@ -325,61 +347,37 @@ const dictStore = useDictStore();
// 表格配置项
const columns: ColumnProps<ZJRQ.WarnInfo>[] = [
{
prop: "type",
prop: "name",
label: "数据类型"
// render: () => {
// return "楼道";
// }
},
{
prop: "warntotal",
label: "预警总量"
prop: "day",
label: "今日预警"
// render: () => {
// return "楼道";
// }
},
{
prop: "lowrisk",
label: "低危信息 "
prop: "week",
label: "七日预警 "
},
{
prop: "highrisk",
label: "高危信息"
prop: "count",
label: "预警总量"
}
];
const tableData = ref([
{
type: "今日",
warntotal: "20",
lowrisk: "10",
highrisk: "10"
},
{
type: "本周",
warntotal: "50",
lowrisk: "20",
highrisk: "30"
},
{
type: "本月",
warntotal: "198",
lowrisk: "176",
highrisk: "22"
},
{
type: "上月",
warntotal: "10",
lowrisk: "5",
highrisk: "5"
},

{
type: "环比",
warntotal: "-9.07%",
lowrisk: "0%",
highrisk: "0%"
}
]);
let highTabledata = ref([]);
// 获取高危预警数据
function getHighWarin() {
warnZJRQApi.highWarn().then((res: any) => {
if (res.code == 200) {
highTabledata.value = res.data;
}
});
}
const tableLoading = ref(false);
</script>



+ 20
- 8
SafeCampus.WEB/src/views/monitor/live/index.vue View File

@@ -107,12 +107,12 @@
<div>
<div class="dialogHeader">
<div></div>
<div class="dialogBtn" @click="refreshUrl">
<!-- <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" /> -->
@@ -436,7 +436,7 @@ function onDetail(row: any) {
visible.value = true;
detailData.sensorId = row.sensorId;
detailData.title = row.sensorName + "(" + row.sensorId + ")";
getUrl();
getUrl(row.sensorId);
}
// 刷新
const showVideo = ref(false);
@@ -449,7 +449,8 @@ function refreshUrl() {
}, 1000);
}
let num = 1;
function getUrl() {

function getUrl(sensorId:any) {
detailData.videoType = "m3u8";
setTimeout(async () => {
await monitorLIVEApi.detail({ sensorId: detailData.sensorId }).then((res:any) => {
@@ -463,7 +464,18 @@ function getUrl() {
detailData.streamId = data.streamId;
detailData.videoToken = data.videoToken;
// getvideo1()
getvideo2();
let localurl = ''
if(sensorId == 'SXT001') {
localurl = 'http://123.57.209.16:8004/video/1.mp4'
getvideo2(localurl);
} else if(sensorId == 'SXT002'){
localurl = 'http://123.57.209.16:8004/video/5.mp4'
getvideo2(localurl);
} else if(sensorId == 'SXT003') {
localurl = 'http://123.57.209.16:8004/video/2.mp4'
getvideo2(localurl);
}
}
});
});
@@ -500,10 +512,10 @@ function getvideo1() {
// aliRts.startLiveStream(pullStreamUrl, mediaEle);
}
let player = ref<any>(null);
function getvideo2() {
function getvideo2(url:any) {
var options = {
id: "player-con",
source: detailData.videoUrl + "&subaudio=no&jitterbuffer=6000",
source: url,
// "rtsFallbackSource": "降级地址,如HLS",
width: "100%",
height: "500px",
@@ -549,7 +561,7 @@ const handleClose = () => {
visible.value = false;
detailData.videoUrl = "";
detailData.videoType = "";
stopUrl();
// stopUrl();
if (player.value) {
player.value.dispose();
}


+ 600
- 0
SafeCampus.WEB/src/views/monitor/live/index1.vue View File

@@ -0,0 +1,600 @@
<!--
* @Description: 监控管理
* @Author: wangwenpei
* @Date: 2024-07-18 15:44:05
!-->
<template>
<div class="main-box">
<div class="card treeBox">
<p class="title">摄像头分组管理</p>
<div class="btn">
<el-button icon="CirclePlus" @click="append('add', {})" type="primary">添加分组</el-button>
</div>
<div class="treeContent">
<el-input clearable v-model="filterText" style="width: 100%" placeholder="请输入关键字" />
<el-tree
style="max-width: 600px"
ref="treeRef"
:data="treeData"
node-key="id"
default-expand-all
:props="defaultProps"
:expand-on-click-node="false"
:check-on-click-node="true"
:highlight-current="true"
:filter-node-method="filterNode"
:current-node-key="defaultHighlightKey"
@node-click="handleNodeClick"
>
<template #default="{ node, data }">
<span class="custom-tree-node">
<span class="node-label" :title="node.label">{{ node.label }}</span>
<span v-if="data.id && data.id != '-1'">
<el-icon size="16" title="添加分组" @click.stop="append('addChild', data)"><CirclePlus /></el-icon>
<el-icon size="16" title="编辑分组" @click.stop="append('edit', data)" style="margin-left: 8px"><Edit /></el-icon>
<el-icon size="16" title="设置推送人" @click.stop="pushPerson(FormOptEnum.GroupPushPerson, data)" style="margin-left: 8px"
><UserFilled
/></el-icon>
<el-icon size="16" title="删除分组" @click.stop="remove(data.id, '删除该分组')" style="margin-left: 8px"><Delete /></el-icon>
</span>
</span>
</template>
</el-tree>
</div>
</div>
<div class="table-box">
<ProTable ref="proTable" title="视频列表" :columns="columns" :request-api="monitorLIVEApi.list">
<!-- 表格 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, '删除所选数据')"
/>
<el-button :disabled="!scope.isSelected" plain @click="omMove(FormOptEnum.ADD, scope.selectedListIds)" type="success">移动至分组</el-button>
</template>
<!-- 表格 菜单类型 按钮 -->
<!-- 操作 -->
<template #operation="scope">
<el-space>
<s-button link :opt="FormOptEnum.EDIT" @click="onOpen(FormOptEnum.EDIT, scope.row)">编辑</s-button>
<s-button link :opt="FormOptEnum.VIEW" @click="onDetail(scope.row)"> 查看 </s-button>
<!-- <s-button link :opt="FormOptEnum.DELETE" @click="onDelete([scope.row.id], `确定删除该摄像头吗?`)" />
<s-button link :opt="FormOptEnum.VIEW" @click="pushPerson(FormOptEnum.VideoPushPerson, scope.row)"> 推送人 </s-button> -->
<el-dropdown @command="handleCommand">
<el-link type="primary" :underline="false" :icon="ArrowDown"> 更多 </el-link>
<template #dropdown>
<el-dropdown-menu>
<el-dropdown-item :command="command(scope.row, cmdEnum.Delete)">
{{ cmdEnum.Delete }}
</el-dropdown-item>
<el-dropdown-item :command="command(scope.row, cmdEnum.pushPerson)">
{{ cmdEnum.pushPerson }}
</el-dropdown-item>
</el-dropdown-menu>
</template>
</el-dropdown>
</el-space>
</template>
</ProTable>
<!-- 添加分组弹框 -->
<el-dialog v-model="groupVisible" :title="groupTitle" width="600px" :before-close="closeGroup">
<el-form :model="groupForm" :rules="groupRules" ref="groupFormRef" label-width="80px">
<el-form-item label="分组名称" prop="name">
<el-input v-model="groupForm.name" placeholder="请输入分组名称"></el-input>
</el-form-item>
</el-form>

<template #footer>
<div class="dialog-footer">
<el-button type="primary" @click="onSubmit">提交</el-button>
<el-button @click="closeGroup">取消</el-button>
</div>
</template>
</el-dialog>
<!-- 新增/编辑表单 -->
<Form ref="formRef" />
<!-- 人员选择 -->
<userForm ref="userFormRef" />
<!-- 移动至分组 -->
<moveForm ref="moveFormRef" />
<!-- 视频详情 -->
<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>
<template #footer>
<div class="dialog-footer">
<el-button @click="handleClose">关闭</el-button>
</div>
</template>
</el-dialog>
</div>
</div>
</template>
<script setup lang="tsx" name="live">
import VideoPlay from "@/components/VideoPlay/videoplay.vue";
import { ElMessage, ElMessageBox, ElTree } from "element-plus";
import { ArrowDown,More } from "@element-plus/icons-vue";
import type Node from "element-plus/es/components/tree/src/model/node";
import { monitorLIVEApi, monitorLiveButtonCode,SysOrg,SysUserPersonnel } from "@/api";
import { sysCamera } 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 userForm from "./components/userForm.vue";
import moveForm from "./components/moveForm.vue";
// import { FormOptEnum, SysDictEnum, MenuTypeDictEnum } from "@/enums";
// import './aliyun-rts-sdk.js'
import "./ali.js";
enum FormOptEnum {
/** 新增 */
ADD = "新增",
/** 编辑 */
EDIT = "编辑",
/** 查看 */
VIEW = "查看",
/** 删除 */
DELETE = "删除",
// 分组推送人
GroupPushPerson = "分组推送人",
// 视频推送人
VideoPushPerson = "视频推送人",
// 移动
MOVE = "移动",
// 分组
GROUP = "分组"
}
/** 更多下拉菜单命令枚举 */
enum cmdEnum {
Delete = "删除",
pushPerson = "推送人"
}
/** 下拉菜单参数接口 */
interface Command {
row: SysUserPersonnel.SysUserPerInfo;
command: cmdEnum;
}

/**配置command的参数 */
function command(row: SysUserPersonnel.SysUserPerInfo, command: cmdEnum): Command {
return {
row: row,
command: command
};
}
function handleCommand(command: Command) {
switch (command.command) {
case cmdEnum.Delete:
ElMessageBox.confirm(`确定要删除此数据吗?`, "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning"
})
.then(() => {
onDelete([command.row.id])
})
.catch(() => {
})
break
case cmdEnum.pushPerson:
pushPerson(FormOptEnum.VideoPushPerson, command.row)
// userManagePersonnelApi.personUnBindDfie({
// personId:command.row.personId,
// personSetId: command.row.personSets[0].personSetId
// }).then(res=>{
// ElMessage.success('底库解绑成功');
// RefreshTable()
// })
break;
}
}
// 分组字段配置
const defaultProps = {
children: "children",
label: "name"
};
// 默认高亮
const defaultHighlightKey = ref("");

let treeDada1 = ref([
{
id: "",
name: "全部"
}
]);
const treeData = ref<any>([]);
var treeRef = ref<InstanceType<typeof ElTree>>();
// 获取摄像头分组
function getGroupList() {
monitorLIVEApi.groupList({}).then((res:any) => {
if (res.code == 200) {
treeData.value = [...treeDada1.value, ...res.data];
}
});
}

const groupVisible = ref(false); //是否显示表单
const groupTitle = ref("新增分组");
const groupForm = reactive({
name: "",
id: "",
parentId: ""
});
const groupFormRules = ref({
});
const groupRules = ref({
name: [{ required: true, message: "请输入分组名称", trigger: "blur" }]
});
const groupFormRef = ref<any>(null);
const closeGroup = () => {
groupVisible.value = false;
groupFormRef.value.resetFields();
groupForm.name = "";
groupForm.id = "";
groupForm.parentId = "";
};
const groupFormType = ref<any>(null);
// 新增编辑分组
const append = (type: string, data: Tree) => {
groupVisible.value = true;
groupFormType.value = type
if (type == "edit") {
groupTitle.value = "编辑分组";
groupForm.name = data.name;
groupForm.id = data.id;
} else if(type == "addChild") {
groupTitle.value = "新增分组";
groupForm.parentId = data.id
} else {
groupTitle.value = "新增分组";
}
};
// 删除分组
async function remove(id: string[], msg: string) {
await useHandleData(monitorLIVEApi.deleteGroup, { id }, msg);
getGroupList();
}
// 提交分组
const onSubmit = () => {
groupFormRef.value.validate((valid: any) => {
if (valid) {
let params: any = reactive({
id: "",
name: groupForm.name,
parentId: groupForm.parentId
});
console.log(groupFormType)
if (groupFormType.value == 'add') {
delete params.parentId;
monitorLIVEApi.addGroup(params).then((res:any) => {
if (res.code == 200) {
getGroupList();
closeGroup();
}
});
} else if(groupFormType.value == 'edit') {
params.id = groupForm.id;
delete params.parentId;
monitorLIVEApi.updateGroup(params).then((res:any) => {
if (res.code == 200) {
getGroupList();
closeGroup();
}
});
} else if(groupFormType.value == 'addChild') {
delete params.id;
monitorLIVEApi.addGroup(params).then((res:any) => {
if (res.code == 200) {
getGroupList();
closeGroup();
}
});
}
closeGroup();
} else {
return false;
}
});
};
// 摄像头分组过滤
interface Tree {
[key: string]: any;
id: any;
label: string;
children?: Tree[];
}
const filterText = ref("");

watch(filterText, val => {
treeRef.value!.filter(val);
});

const filterNode = (value: string, data: Tree) => {
if (!value) return true;
return data.name.includes(value);
};

const handleNodeClick = (data: Tree) => {
proTable.value!.pageable.pageNum = 1;
proTable.value!.searchParam.groupId = data.id;
proTable.value!.search();
};
const visible = ref(false); //是否显示表单

// 获取 ProTable 元素,调用其获取刷新数据方法(还能获取到当前查询参数,方便导出携带参数)
const proTable = ref<ProTableInstance>();
const dictStore = useDictStore();

// 表格配置项
const columns: ColumnProps<sysCamera.MonitorInfo>[] = [
{ type: "selection", fixed: "left", width: 80 },
{
prop: "sensorId",
label: "摄像头ID"
},
{
prop: "sensorName",
label: "摄像头名称"
},
{
prop: "fieldName",
label: "所属学校"
},
{
prop: "directUrlIp",
label: "设备ip"
},
{
prop: "resWidth",
label: "分辨率",
render: row => {
return row.row.resWidth + "*" + row.row.resHeight;
}
},
{ prop: "operation", label: "操作", width: 250, fixed: "right" }
];
// 移动分组禁用
const moveFormRef = ref<InstanceType<typeof Form> | null>(null);
function omMove(opt: FormOptEnum, record: {} | SysOrg.SysOrgInfo = {}) {
console.log(record,"record")

moveFormRef.value?.omMove({ opt: opt, records: record, successful: RefreshTable });
}
/**
* 删除
* @param ids id数组
*/
async function onDelete(ids: string[], msg: string) {
console.log(1)
return;
// 二次确认 => 请求api => 刷新表格
await useHandleData(monitorLIVEApi.delete, { ids }, msg);
RefreshTable();
}

/**
* 刷新表格
*/
function RefreshTable() {
proTable.value?.refresh();
}
function RefreshTables() {
proTable.value?.refresh();
getGroupList();
}
// 表单引用
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 });
}

// 人员选择
// 表单引用
const userFormRef = ref<InstanceType<typeof Form> | null>(null);
/**
* 打开表单
* @param opt 操作类型
* @param record 记录
*/
function pushPerson(opt: FormOptEnum, record: {} | SysOrg.SysOrgInfo = {}) {
userFormRef.value?.onOpen({ opt: opt, record: record, successful: RefreshTables });
}
// 详情数据
// let detailData: globalThis.Ref<{}>
let detailData = reactive({
title: "",
videoUrl: "",
sensorId: "",
streamId: "",
videoToken: "",
videoType: ""
});
function onDetail(row: any) {
visible.value = true;
detailData.sensorId = row.sensorId;
detailData.title = row.sensorName + "(" + row.sensorId + ")";
getUrl();
}
// 刷新
const showVideo = ref(false);
function refreshUrl() {
stopUrl();
showVideo.value = false;
setTimeout(() => {
showVideo.value = true;
getUrl();
}, 1000);
}
let num = 1;
function getUrl() {
detailData.videoType = "m3u8";
setTimeout(async () => {
await monitorLIVEApi.detail({ sensorId: detailData.sensorId }).then((res:any) => {
let { code, data } = res;

if (code == '200') {
// window.location.origin+
detailData.videoUrl = "";
detailData.videoUrl = data.rtsPullStreamUrls[0].url;
// detailData.videoUrl = data.pullStreamUrls[2].url;
detailData.streamId = data.streamId;
detailData.videoToken = data.videoToken;
// getvideo1()
getvideo2();
}
});
});
}
function getvideo1() {
let aliRts = new AliRTS();
let pullStreamUrl = detailData.videoUrl;
const mediaEle = document.querySelector("video");
aliRts.on("onError", err => {
console.log(`errorCode: ${err.errorCode}`);
console.log(`message: ${err.message}`);
});

const PLAY_EVENT = {
CANPLAY: "canplay",
WAITING: "waiting",
PLAYING: "playing"
};

aliRts.on("onPlayEvent", play => {
console.log(">>play.event:" + play.event);
if (play.event === PLAY_EVENT.CANPLAY) {
// 拉流可以播放
console.log("可以播放");
} else if (play.event === PLAY_EVENT.WAITING) {
// 拉流卡顿等待缓冲中 (仅Chrome)
console.log("拉流卡顿等待缓冲中");
} else if (play.event === PLAY_EVENT.PLAYING) {
// 拉流卡顿结束恢复播放 (仅Chrome)
console.log("拉流卡顿结束恢复播放");
}
});
aliRts.startLiveStream(pullStreamUrl, mediaEle);
// aliRts.startLiveStream(pullStreamUrl, mediaEle);
}
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 跳过检查,强制使用 RTS(有风险,需要自测保证)

/**
* RTS 拉流超时会默认重试
* 以下两个参数用来控制降级之前的重试策略,比如 3000 毫秒超时,重试一次,如果再拉不到流就降级,那么总共等待 6000 毫秒降级
**/
// RTS 多久拉不到流会重试,默认 3000 ms
rtsLoadDataTimeout: 1500,

// RTS 拉不到流重试的次数,默认 5,此参数建议设为 1,即重试 1 次后降级,可以减少降级等待时间
liveRetry: 1
};

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

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

player.value.on("error", function (event:any) {
console.log("[EVENT]error", event.paramData);
});
player.value.setVolume(0)
// 当RTS拉流成功时触发,通过订阅该事件,可以获取到RTS TraceId
player.value.on("rtsTraceId", function (data:any) {
console.log("[EVENT]rtsTraceId", data.paramData);
// event.paramData.traceId 拉流的TraceId
// event.paramData.source 当前RTS流的播放地址
});
}
const handleClose = () => {
visible.value = false;
detailData.videoUrl = "";
detailData.videoType = "";
stopUrl();
if (player.value) {
player.value.dispose();
}
};
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);
}
});
});
}

onMounted(() => {
getGroupList();
});
</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 "./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>

+ 1
- 8
SafeCampus.WEB/src/views/userManage/classManage/index.vue View File

@@ -6,14 +6,7 @@
<template>
<div class="main-box">
<div class="table-box">
<ProTable
ref="proTable"
:pagination="false"
title="班级管理"
:columns="columns"
rowKey="personSetId"
:request-api="userManageClassManageApi.page"
>
<ProTable ref="proTable" title="班级管理" :columns="columns" rowKey="personSetId" :request-api="userManageClassManageApi.getPageList">
<!-- 表格 header 按钮 -->
<template #tableHeader="scope">
<s-button suffix="班级" @click="addClass(FormOptEnum.ADD)" />


+ 5
- 5
SafeCampus.WEB/src/views/userManage/dormitory/components/formDormitory/index.vue View File

@@ -88,9 +88,9 @@ const sysDormitoryProps = reactive<FormProps.Base<SysDormitory.DormitoryInfo>>({
// 表单验证规则
const rules = reactive({
name: [required("请输入宿舍楼名称")],
gender: [required("请选择宿舍类型")],
insCameraId: [required("请选择进楼摄像头")],
outCameraId: [required("请选择出楼摄像头")]
gender: [required("请选择宿舍类型")]
// insCameraId: [required("请选择进楼摄像头")],
// outCameraId: [required("请选择出楼摄像头")]
});

/**
@@ -142,8 +142,8 @@ onMounted(() => {
getCreamaList();
});
const getCreamaList = () => {
monitorLIVEApi.list({ pageNum: 1, pageSize: 1000 }).then(res => {
creamaData.value = res.data.list;
userManageDormitoryApi.getBuildCameraList().then((res: any) => {
creamaData.value = res.data;
});
};
// 暴露给父组件的方法


+ 1
- 2
SafeCampus.WEB/src/views/userManage/keyPersonnel/components/form/index.vue View File

@@ -43,8 +43,7 @@ const sysUserProps = reactive<FormProps.Base<SysUserPersonnel.SysUserPerInfo>>({
disabled: false
});
const checkAgeNumber = (rule: any, value: any, callback: any) => {
if (value === "") callback("请输入年龄");
if (value > 100 || value < 0) {
if (value && (value > 100 || value <= 0)) {
callback(new Error("请输入正确的年龄(年龄范围1-100岁)"));
} else {
return callback();


+ 1
- 2
SafeCampus.WEB/src/views/userManage/personnel/components/form/index.vue View File

@@ -44,8 +44,7 @@ const sysUserProps = reactive<FormProps.Base<SysUserPersonnel.SysUserPerInfo>>({
disabled: false
});
const checkAgeNumber = (rule: any, value: any, callback: any) => {
if (value === "") callback("请输入年龄");
if (value > 100 || value < 0) {
if (value && (value > 100 || value <= 0)) {
callback(new Error("请输入正确的年龄(年龄范围1-100岁)"));
} else {
return callback();


+ 1
- 1
SafeCampus.WEB/src/views/userManage/personnel/index.vue View File

@@ -71,7 +71,7 @@ const columns: ColumnProps<SysUserPersonnel.SysUserPerInfo>[] = [
{
prop: "name",
label: "姓名",
search: {el:'input',span:1,}
search: {el:'input',span:1,key:'personName'}
},
{
prop: "personSetName",


+ 20
- 17
SafeCampus.WEB/src/views/violation/portrait/detail.vue View File

@@ -6,7 +6,7 @@
</div>
<div class="topContent">
<el-row>
<el-col :span="4" :offset="2">
<el-col :span="4" :offset="1">
<div class="left">
<el-image
class="avatar"
@@ -25,13 +25,13 @@
<Female class="gender GENDER_FEMALE" v-if="formData.gender == 'GENDER_FEMALE'"></Female>
</span>

<span class="personId" :title="formData.personId">编号:{{ formData.personId }}</span>
<!-- <span class="personId" :title="formData.personId">编号:{{ formData.personId }}</span> -->
<!-- <el-tag type="primary">学霸型</el-tag> -->
</div></el-col
>
<el-col :span="16">
<el-col :span="17">
<div class="right">
<el-row>
<el-row :gutter="20">
<el-col :span="6">
<span v-if="formData.name"
>姓名拼音:{{ pinyin(formData.name, { toneType: "none", type: "array" }).flat().join(" ") }}</span
@@ -42,11 +42,7 @@
>

<el-col :span="6">
<span
:title="formData.personId"
style="display: block; text-overflow: ellipsis; max-width: 100%; overflow: hidden; white-space: nowrap"
>编号:{{ formData.personId }}</span
></el-col
<span :title="formData.personId" class="ellipsis">编号:{{ formData.personId }}</span></el-col
>

<el-col :span="6"
@@ -57,20 +53,20 @@
>

<el-col :span="6"
><span>联系方式:{{ formData.phone }}</span>
><span :title="formData.phone" class="ellipsis">联系方式:{{ formData.phone }}</span>
</el-col>

<el-col :span="6"
><span>所属院系:{{ formData.depName }}</span>
><span :title="formData.depName" class="ellipsis">所属院系:{{ formData.depName }}</span>
</el-col>
<el-col :span="6"
><span>所属专业:{{ formData.majorName }}</span>
><span :title="formData.majorName" class="ellipsis">所属专业:{{ formData.majorName }}</span>
</el-col>
<el-col :span="6"
><span>所属班级:{{ formData.personSetName }}</span>
><span :title="formData.personSetName" class="ellipsis">所属班级:{{ formData.personSetName }}</span>
</el-col>
<el-col :span="6"
><span>寝室名称:{{ formData.dormitoryName }}</span>
><span :title="formData.dormitoryName" class="ellipsis">寝室名称:{{ formData.dormitoryName }}</span>
</el-col>
</el-row>
</div></el-col
@@ -631,13 +627,13 @@ onMounted(() => {
}
}
.personId {
display: block;
max-width: 90%;
margin-bottom: 10px;
overflow: hidden;
font-size: 14px;
display: block;
text-overflow: ellipsis;
overflow: hidden;
white-space: nowrap;
max-width: 90%;
}
}
.right {
@@ -647,6 +643,13 @@ onMounted(() => {
.el-col {
height: 50px;
line-height: 50px;
.ellipsis {
display: block;
max-width: 100%;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
}
}
}


+ 20
- 4
SafeCampus.WEB/src/views/violation/portrait/index.vue View File

@@ -67,16 +67,32 @@ const columns: ColumnProps[] = [
label: "姓名"
},
{
prop: "personId",
label: "人员ID"
prop: "personSetName",
label: "所属班级",
},
{
prop: "gender",
label: "性别",
enum: [
{
label: "男",
value: "GENDER_MALE"
},
{
label: "女",
value: "GENDER_FEMALE"
}],
},
{
prop: "phone",
label: "手机号"
},
{
prop: "personSetName",
label: "所属班级",
prop: "age",
label: "年龄",
render: scope => {
return scope.row.age ? scope.row.age : '--';
}
},
{ prop: "operation", label: "操作", width: 250, fixed: "right" }
];


Loading…
Cancel
Save