@@ -1,5 +1,5 @@ | |||||
# title | # title | ||||
VITE_GLOB_APP_TITLE = 校园监控智能分析平台 | |||||
VITE_GLOB_APP_TITLE = AI监控预警分析平台 | |||||
# 本地运行端口号 | # 本地运行端口号 | ||||
VITE_PORT = 8848 | VITE_PORT = 8848 | ||||
@@ -1,5 +1,5 @@ | |||||
<!DOCTYPE html> | <!DOCTYPE html> | ||||
<html> | |||||
<html style="overflow: hidden;"> | |||||
<head> | <head> | ||||
<meta charset="utf-8"> | <meta charset="utf-8"> | ||||
@@ -27,12 +27,13 @@ | |||||
// 更多播放器配置请参考 https://player.alicdn.com/aliplayer/index.html | // 更多播放器配置请参考 https://player.alicdn.com/aliplayer/index.html | ||||
let rtsUrl = getUrlParams(location.href)['rtsUrl'] || '' | let rtsUrl = getUrlParams(location.href)['rtsUrl'] || '' | ||||
let height = getUrlParams(location.href)['height'] || "500px" | |||||
var options = { | var options = { | ||||
"id": "player-con", | "id": "player-con", | ||||
"source": rtsUrl, | "source": rtsUrl, | ||||
"rtsFallbackSource": "降级地址,如HLS", | "rtsFallbackSource": "降级地址,如HLS", | ||||
"width": "100%", | "width": "100%", | ||||
"height": "500px", | |||||
"height": height, | |||||
"autoplay": true, | "autoplay": true, | ||||
"isLive": true, | "isLive": true, | ||||
"playsinline": true, | "playsinline": true, | ||||
@@ -65,6 +66,9 @@ | |||||
// 当RTS拉流成功时触发,通过订阅该事件,可以获取到RTS TraceId | // 当RTS拉流成功时触发,通过订阅该事件,可以获取到RTS TraceId | ||||
player.on('rtsTraceId', function (data) { | player.on('rtsTraceId', function (data) { | ||||
console.log('[EVENT]rtsTraceId', data.paramData); | console.log('[EVENT]rtsTraceId', data.paramData); | ||||
player.setVolume(0) | |||||
let fullscreenBtn = document.querySelector('.prism-controlbar .prism-fullscreen-btn') | |||||
if(fullscreenBtn)fullscreenBtn.style.display = 'none' | |||||
// event.paramData.traceId 拉流的TraceId | // event.paramData.traceId 拉流的TraceId | ||||
// event.paramData.source 当前RTS流的播放地址 | // event.paramData.source 当前RTS流的播放地址 | ||||
}) | }) | ||||
@@ -0,0 +1,28 @@ | |||||
/** | |||||
* @description 学生归寝 | |||||
* @license Apache License Version 2.0 | |||||
* @Copyright (c) 2022-Now 少林寺驻北固山办事处大神父王喇嘛 | |||||
* @remarks | |||||
* SimpleAdmin 基于 Apache License Version 2.0 协议发布,可用于商业项目,但必须遵守以下补充条款: | |||||
* 1.请不要删除和修改根目录下的LICENSE文件。 | |||||
* 2.请不要删除和修改SimpleAdmin源码头部的版权声明。 | |||||
* 3.分发源码时候,请注明软件出处 https://gitee.com/dotnetmoyu/SimpleAdmin | |||||
* 4.基于本软件的作品,只能使用 SimpleAdmin 作为后台服务,除外情况不可商用且不允许二次分发或开源。 | |||||
* 5.请不得将本软件应用于危害国家安全、荣誉和利益的行为,不能以任何形式用于非法为目的的行为不要删除和修改作者声明。 | |||||
* 6.任何基于本软件而产生的一切法律纠纷和责任,均于我司无关 | |||||
*/ | |||||
import { ReqPage } from "@/api"; | |||||
/** | |||||
* @Description: 教师点名 | |||||
* @Author: yxq | |||||
* @Date: 2023-12-17 15:34:54 | |||||
*/ | |||||
export namespace AttendanceBehaviorTrace { | |||||
export interface Page extends ReqPage {} | |||||
/** 表单 */ | |||||
export interface behaviorTraceInfo { | |||||
} | |||||
} |
@@ -0,0 +1,17 @@ | |||||
/** | |||||
* @description | |||||
* @license Apache License Version 2.0 | |||||
* @Copyright (c) 2022-Now 少林寺驻北固山办事处大神父王喇嘛 | |||||
* @remarks | |||||
* SimpleAdmin 基于 Apache License Version 2.0 协议发布,可用于商业项目,但必须遵守以下补充条款: | |||||
* 1.请不要删除和修改根目录下的LICENSE文件。 | |||||
* 2.请不要删除和修改SimpleAdmin源码头部的版权声明。 | |||||
* 3.分发源码时候,请注明软件出处 https://gitee.com/dotnetmoyu/SimpleAdmin | |||||
* 4.基于本软件的作品,只能使用 SimpleAdmin 作为后台服务,除外情况不可商用且不允许二次分发或开源。 | |||||
* 5.请不得将本软件应用于危害国家安全、荣誉和利益的行为,不能以任何形式用于非法为目的的行为不要删除和修改作者声明。 | |||||
* 6.任何基于本软件而产生的一切法律纠纷和责任,均于我司无关 | |||||
* @see https://gitee.com/dotnetmoyu/SimpleAdmin | |||||
*/ | |||||
export * from "./passenger"; | |||||
export * from "./studentsReturn"; | |||||
export * from "./behaviorTrace"; |
@@ -0,0 +1,31 @@ | |||||
/** | |||||
* @description 用户管理接口 | |||||
* @license Apache License Version 2.0 | |||||
* @Copyright (c) 2022-Now 少林寺驻北固山办事处大神父王喇嘛 | |||||
* @remarks | |||||
* SimpleAdmin 基于 Apache License Version 2.0 协议发布,可用于商业项目,但必须遵守以下补充条款: | |||||
* 1.请不要删除和修改根目录下的LICENSE文件。 | |||||
* 2.请不要删除和修改SimpleAdmin源码头部的版权声明。 | |||||
* 3.分发源码时候,请注明软件出处 https://gitee.com/dotnetmoyu/SimpleAdmin | |||||
* 4.基于本软件的作品,只能使用 SimpleAdmin 作为后台服务,除外情况不可商用且不允许二次分发或开源。 | |||||
* 5.请不得将本软件应用于危害国家安全、荣誉和利益的行为,不能以任何形式用于非法为目的的行为不要删除和修改作者声明。 | |||||
* 6.任何基于本软件而产生的一切法律纠纷和责任,均于我司无关 | |||||
*/ | |||||
import { ReqPage } from "@/api"; | |||||
/** | |||||
* @Description: 客流查询 | |||||
* @Author: yxq | |||||
* @Date: 2023-12-17 15:34:54 | |||||
*/ | |||||
export namespace AttendancePassenger { | |||||
export interface Page extends ReqPage {} | |||||
/** 客流查询表单 */ | |||||
export interface PassengerInfo { | |||||
fenpianleixing:String, | |||||
shijianduan:any, | |||||
shexiangtou:any, | |||||
} | |||||
} |
@@ -0,0 +1,28 @@ | |||||
/** | |||||
* @description 学生归寝 | |||||
* @license Apache License Version 2.0 | |||||
* @Copyright (c) 2022-Now 少林寺驻北固山办事处大神父王喇嘛 | |||||
* @remarks | |||||
* SimpleAdmin 基于 Apache License Version 2.0 协议发布,可用于商业项目,但必须遵守以下补充条款: | |||||
* 1.请不要删除和修改根目录下的LICENSE文件。 | |||||
* 2.请不要删除和修改SimpleAdmin源码头部的版权声明。 | |||||
* 3.分发源码时候,请注明软件出处 https://gitee.com/dotnetmoyu/SimpleAdmin | |||||
* 4.基于本软件的作品,只能使用 SimpleAdmin 作为后台服务,除外情况不可商用且不允许二次分发或开源。 | |||||
* 5.请不得将本软件应用于危害国家安全、荣誉和利益的行为,不能以任何形式用于非法为目的的行为不要删除和修改作者声明。 | |||||
* 6.任何基于本软件而产生的一切法律纠纷和责任,均于我司无关 | |||||
*/ | |||||
import { ReqPage } from "@/api"; | |||||
/** | |||||
* @Description: 教师点名 | |||||
* @Author: yxq | |||||
* @Date: 2023-12-17 15:34:54 | |||||
*/ | |||||
export namespace AttendanceStudentsReturn { | |||||
export interface Page extends ReqPage {} | |||||
/** 表单 */ | |||||
export interface studentsReturnInfo { | |||||
} | |||||
} |
@@ -22,3 +22,4 @@ export * from "./auth"; | |||||
export * from "./warn"; | export * from "./warn"; | ||||
export * from "./usermanage"; | export * from "./usermanage"; | ||||
export * from "./monitor"; | export * from "./monitor"; | ||||
export * from "./attendance"; |
@@ -57,4 +57,11 @@ export namespace sysCamera { | |||||
id: number | string; | id: number | string; | ||||
name: string; | name: string; | ||||
} | } | ||||
// 设置推送人 | |||||
export interface setGroup { | |||||
/** groupId */ | |||||
groupId: number | string; | |||||
userId: number | string; | |||||
ids: number | string[]; | |||||
} | |||||
} | } |
@@ -0,0 +1,47 @@ | |||||
/** | |||||
* @description 单页管理接口 | |||||
* @license Apache License Version 2.0 | |||||
* @Copyright (c) 2022-Now 少林寺驻北固山办事处大神父王喇嘛 | |||||
* @remarks | |||||
* SimpleAdmin 基于 Apache License Version 2.0 协议发布,可用于商业项目,但必须遵守以下补充条款: | |||||
* 1.请不要删除和修改根目录下的LICENSE文件。 | |||||
* 2.请不要删除和修改SimpleAdmin源码头部的版权声明。 | |||||
* 3.分发源码时候,请注明软件出处 https://gitee.com/dotnetmoyu/SimpleAdmin | |||||
* 4.基于本软件的作品,只能使用 SimpleAdmin 作为后台服务,除外情况不可商用且不允许二次分发或开源。 | |||||
* 5.请不得将本软件应用于危害国家安全、荣誉和利益的行为,不能以任何形式用于非法为目的的行为不要删除和修改作者声明。 | |||||
* 6.任何基于本软件而产生的一切法律纠纷和责任,均于我司无关 | |||||
* @see https://gitee.com/dotnetmoyu/SimpleAdmin | |||||
*/ | |||||
import { moduleRequest } from "@/api/request"; | |||||
import { ReqId, SysUserPersonnel } from "@/api/interface"; | |||||
const http = moduleRequest("/business/dfieldApi/"); | |||||
/** | |||||
* @Description: 单页管理 | |||||
* @Author: SYY | |||||
* @Date: 2023-12-15 15:34:54 | |||||
*/ | |||||
const attendanceBehaviorTrace = { | |||||
/** 查询底库列表 */ | |||||
page(params: SysUserPersonnel.ClassPage) { | |||||
return http.get("test", params); | |||||
}, | |||||
/** 删除底库 */ | |||||
delete(params: ReqId) { | |||||
return http.delete("test", params); | |||||
}, | |||||
/** 创建底库 */ | |||||
add(params: SysUserPersonnel.ClassPage) { | |||||
return http.post("test", params); | |||||
}, | |||||
/** 更新底库 */ | |||||
update(params: SysUserPersonnel.ClassPage) { | |||||
return http.put("test", params); | |||||
}, | |||||
/** 轨迹详情 */ | |||||
detail(params: SysUserPersonnel.ClassPage) { | |||||
return http.get("test", params); | |||||
} | |||||
}; | |||||
export { attendanceBehaviorTrace }; |
@@ -0,0 +1,19 @@ | |||||
/** | |||||
* @description | |||||
* @license Apache License Version 2.0 | |||||
* @Copyright (c) 2022-Now 少林寺驻北固山办事处大神父王喇嘛 | |||||
* @remarks | |||||
* SimpleAdmin 基于 Apache License Version 2.0 协议发布,可用于商业项目,但必须遵守以下补充条款: | |||||
* 1.请不要删除和修改根目录下的LICENSE文件。 | |||||
* 2.请不要删除和修改SimpleAdmin源码头部的版权声明。 | |||||
* 3.分发源码时候,请注明软件出处 https://gitee.com/dotnetmoyu/SimpleAdmin | |||||
* 4.基于本软件的作品,只能使用 SimpleAdmin 作为后台服务,除外情况不可商用且不允许二次分发或开源。 | |||||
* 5.请不得将本软件应用于危害国家安全、荣誉和利益的行为,不能以任何形式用于非法为目的的行为不要删除和修改作者声明。 | |||||
* 6.任何基于本软件而产生的一切法律纠纷和责任,均于我司无关 | |||||
* @see https://gitee.com/dotnetmoyu/SimpleAdmin | |||||
*/ | |||||
export * from "./behaviorTrace"; | |||||
export * from "./passenger"; | |||||
export * from "./roolcall"; | |||||
export * from "./studentsReturn"; | |||||
@@ -0,0 +1,50 @@ | |||||
/** | |||||
* @description 单页管理接口 | |||||
* @license Apache License Version 2.0 | |||||
* @Copyright (c) 2022-Now 少林寺驻北固山办事处大神父王喇嘛 | |||||
* @remarks | |||||
* SimpleAdmin 基于 Apache License Version 2.0 协议发布,可用于商业项目,但必须遵守以下补充条款: | |||||
* 1.请不要删除和修改根目录下的LICENSE文件。 | |||||
* 2.请不要删除和修改SimpleAdmin源码头部的版权声明。 | |||||
* 3.分发源码时候,请注明软件出处 https://gitee.com/dotnetmoyu/SimpleAdmin | |||||
* 4.基于本软件的作品,只能使用 SimpleAdmin 作为后台服务,除外情况不可商用且不允许二次分发或开源。 | |||||
* 5.请不得将本软件应用于危害国家安全、荣誉和利益的行为,不能以任何形式用于非法为目的的行为不要删除和修改作者声明。 | |||||
* 6.任何基于本软件而产生的一切法律纠纷和责任,均于我司无关 | |||||
* @see https://gitee.com/dotnetmoyu/SimpleAdmin | |||||
*/ | |||||
import { moduleRequest } from "@/api/request"; | |||||
import { ReqId, AttendancePassenger } from "@/api/interface"; | |||||
const http = moduleRequest("/business/dfieldApi/"); | |||||
/** | |||||
* @Description: 单页管理 | |||||
* @Author: SYY | |||||
* @Date: 2023-12-15 15:34:54 | |||||
*/ | |||||
const attendancePassenger = { | |||||
/** 查询列表 */ | |||||
page(params: AttendancePassenger.PassengerInfo) { | |||||
return http.get("test", params); | |||||
}, | |||||
/** 删除 */ | |||||
delete(params: ReqId) { | |||||
return http.delete("test", params); | |||||
}, | |||||
/** 创建 */ | |||||
add(params: AttendancePassenger.PassengerInfo) { | |||||
return http.post("test", params); | |||||
}, | |||||
/** 详情 */ | |||||
detail(params: ReqId) { | |||||
return http.post("test", params); | |||||
}, | |||||
}; | |||||
const attendancePassengerBtnCode = { | |||||
/** 新增 */ | |||||
add: "attendancePassengerBtnCodeAdd", | |||||
/** 删除 */ | |||||
delete: "attendancePassengerBtnCodeDel" | |||||
}; | |||||
export { attendancePassenger,attendancePassengerBtnCode }; |
@@ -0,0 +1,49 @@ | |||||
/** | |||||
* @description 单页管理接口 | |||||
* @license Apache License Version 2.0 | |||||
* @Copyright (c) 2022-Now 少林寺驻北固山办事处大神父王喇嘛 | |||||
* @remarks | |||||
* SimpleAdmin 基于 Apache License Version 2.0 协议发布,可用于商业项目,但必须遵守以下补充条款: | |||||
* 1.请不要删除和修改根目录下的LICENSE文件。 | |||||
* 2.请不要删除和修改SimpleAdmin源码头部的版权声明。 | |||||
* 3.分发源码时候,请注明软件出处 https://gitee.com/dotnetmoyu/SimpleAdmin | |||||
* 4.基于本软件的作品,只能使用 SimpleAdmin 作为后台服务,除外情况不可商用且不允许二次分发或开源。 | |||||
* 5.请不得将本软件应用于危害国家安全、荣誉和利益的行为,不能以任何形式用于非法为目的的行为不要删除和修改作者声明。 | |||||
* 6.任何基于本软件而产生的一切法律纠纷和责任,均于我司无关 | |||||
* @see https://gitee.com/dotnetmoyu/SimpleAdmin | |||||
*/ | |||||
import { moduleRequest } from "@/api/request"; | |||||
const http = moduleRequest("/business/classRoomCallApi/"); | |||||
/** | |||||
* @Description: 教师点名 | |||||
* @Author: SYY | |||||
* @Date: 2023-12-15 15:34:54 | |||||
*/ | |||||
const attendanceRoolcallApi = { | |||||
// 获取列表 | |||||
page(params: any) { | |||||
return http.get("getPageList", params); | |||||
}, | |||||
/** 查询点名任务列表 */ | |||||
getTaskPageList(params: any) { | |||||
return http.get("getTaskPageList", params); | |||||
}, | |||||
/** 删除点名任务(删除关联点名数据) */ | |||||
delete(params: any) { | |||||
return http.delete("delete", params); | |||||
}, | |||||
/** 删除点名任务(只可删除待处理的任务) */ | |||||
remove(params: any) { | |||||
return http.delete("remove", params); | |||||
}, | |||||
/** 点名任务下发 */ | |||||
add(params: any) { | |||||
return http.post("taskSubmit", params); | |||||
}, | |||||
/** 修改点名任务 */ | |||||
update(params: any) { | |||||
return http.post("update", params); | |||||
} | |||||
}; | |||||
export { attendanceRoolcallApi }; |
@@ -0,0 +1,43 @@ | |||||
/** | |||||
* @description 学生归寝 | |||||
* @license Apache License Version 2.0 | |||||
* @Copyright (c) 2022-Now 少林寺驻北固山办事处大神父王喇嘛 | |||||
* @remarks | |||||
* SimpleAdmin 基于 Apache License Version 2.0 协议发布,可用于商业项目,但必须遵守以下补充条款: | |||||
* 1.请不要删除和修改根目录下的LICENSE文件。 | |||||
* 2.请不要删除和修改SimpleAdmin源码头部的版权声明。 | |||||
* 3.分发源码时候,请注明软件出处 https://gitee.com/dotnetmoyu/SimpleAdmin | |||||
* 4.基于本软件的作品,只能使用 SimpleAdmin 作为后台服务,除外情况不可商用且不允许二次分发或开源。 | |||||
* 5.请不得将本软件应用于危害国家安全、荣誉和利益的行为,不能以任何形式用于非法为目的的行为不要删除和修改作者声明。 | |||||
* 6.任何基于本软件而产生的一切法律纠纷和责任,均于我司无关 | |||||
* @see https://gitee.com/dotnetmoyu/SimpleAdmin | |||||
*/ | |||||
import { moduleRequest } from "@/api/request"; | |||||
import { ReqId, SysUserPersonnel } from "@/api/interface"; | |||||
const http = moduleRequest("/business/dfieldApi/"); | |||||
/** | |||||
* @Description: 单页管理 | |||||
* @Author: SYY | |||||
* @Date: 2023-12-15 15:34:54 | |||||
*/ | |||||
const attendanceStudentsReturn = { | |||||
/** 查询底库列表 */ | |||||
page(params: SysUserPersonnel.ClassPage) { | |||||
return http.get("test", params); | |||||
}, | |||||
/** 删除底库 */ | |||||
delete(params: ReqId) { | |||||
return http.delete("test", params); | |||||
}, | |||||
/** 创建底库 */ | |||||
add(params: SysUserPersonnel.ClassPage) { | |||||
return http.post("test", params); | |||||
}, | |||||
/** 更新底库 */ | |||||
update(params: SysUserPersonnel.ClassPage) { | |||||
return http.put("test", params); | |||||
} | |||||
}; | |||||
export { attendanceStudentsReturn }; |
@@ -20,3 +20,4 @@ export * from "./monitor"; | |||||
export * from "./sysconfig"; | export * from "./sysconfig"; | ||||
export * from "./statistion"; | export * from "./statistion"; | ||||
export * from "./usermanage"; | export * from "./usermanage"; | ||||
export * from "./attendance"; |
@@ -44,6 +44,18 @@ const monitorLIVEApi = { | |||||
setGroup(params: sysCamera.setGroup) { | setGroup(params: sysCamera.setGroup) { | ||||
return http2.post<ResPage<sysCamera.MonitorInfo>>("batchSetGroup", params); | return http2.post<ResPage<sysCamera.MonitorInfo>>("batchSetGroup", params); | ||||
}, | }, | ||||
// 根据分组批量设置推送人 | |||||
setPushPerson(params: sysCamera.setGroup) { | |||||
return http2.post<ResPage<sysCamera.MonitorInfo>>("batchSetPushPersonByGroup", params); | |||||
}, | |||||
// 对摄像头批量设置推送人 | |||||
setVideoPushPerson(params: sysCamera.setGroup) { | |||||
return http2.post<ResPage<sysCamera.MonitorInfo>>("batchSetPushPerson", params); | |||||
}, | |||||
// 对摄像头批量设置推送人 | |||||
setWarningPushPerson(params: sysCamera.setGroup) { | |||||
return http2.post<ResPage<sysCamera.MonitorInfo>>("batchSetPushPersonByWarn", params); | |||||
}, | |||||
// 获取摄像头分组树 | // 获取摄像头分组树 | ||||
groupList(params: sysCamera.Tree) { | groupList(params: sysCamera.Tree) { | ||||
return http3.get<ResPage<sysCamera.MonitorInfo>>("getNoPageList"); | return http3.get<ResPage<sysCamera.MonitorInfo>>("getNoPageList"); | ||||
@@ -18,7 +18,8 @@ import { FormOptEnum } from "@/enums"; | |||||
//接口 | //接口 | ||||
interface Props { | interface Props { | ||||
/** 操作 */ | /** 操作 */ | ||||
opt?: FormOptEnum; | |||||
// opt?: FormOptEnum; | |||||
opt?: any; | |||||
/** 前缀 */ | /** 前缀 */ | ||||
prefix?: string; | prefix?: string; | ||||
/** 标题 */ | /** 标题 */ | ||||
@@ -82,7 +82,7 @@ function getOrgTree() { | |||||
function changeOrg(value: number | string) { | function changeOrg(value: number | string) { | ||||
valueOrg.value = value; //更新当前选中的组织名称 | valueOrg.value = value; //更新当前选中的组织名称 | ||||
emit("update:orgValue", value); //更新父组件数据 | emit("update:orgValue", value); //更新父组件数据 | ||||
emit("change", treeRef.value.getCurrentNode().path); //触发change事件 | |||||
emit("change", treeRef.value.getCurrentNode().path, treeRef.value.getCurrentNode()); //触发change事件 | |||||
} | } | ||||
</script> | </script> | ||||
@@ -22,5 +22,13 @@ export enum FormOptEnum { | |||||
/** 查看 */ | /** 查看 */ | ||||
VIEW = "查看", | VIEW = "查看", | ||||
/** 删除 */ | /** 删除 */ | ||||
DELETE = "删除" | |||||
DELETE = "删除", | |||||
// 分组推送人 | |||||
GroupPushPerson = "分组推送人", | |||||
// 视频推送人 | |||||
VideoPushPerson = "视频推送人", | |||||
// 移动 | |||||
MOVE = "移动", | |||||
// 分组 | |||||
GROUP = "分组" | |||||
} | } |
@@ -37,7 +37,16 @@ export const staticRouter: RouteRecordRaw[] = [ | |||||
component: () => import("@/layouts/index.vue"), | component: () => import("@/layouts/index.vue"), | ||||
// component: () => import("@/layouts/indexAsync.vue"), | // component: () => import("@/layouts/indexAsync.vue"), | ||||
redirect: HOME_URL, | redirect: HOME_URL, | ||||
children: [] | |||||
children: [ | |||||
{ | |||||
meta: { | |||||
title: "学生点名详情" | |||||
}, | |||||
name: "学生点名详情", | |||||
path: "/roolcall/detail", | |||||
component: () => import("@/views/attendance/roolcall/detail.vue") | |||||
} | |||||
] | |||||
} | } | ||||
]; | ]; | ||||
@@ -29,6 +29,7 @@ declare namespace FormProps { | |||||
inline?: boolean; | inline?: boolean; | ||||
// 树数据 | // 树数据 | ||||
treeAllData?: Array<any>; | treeAllData?: Array<any>; | ||||
records: Array<any>; | |||||
/** 表单布局 */ | /** 表单布局 */ | ||||
successful?: () => void; | successful?: () => void; | ||||
} | } | ||||
@@ -323,3 +323,19 @@ export function findItemNested(enumData: any, callValue: any, value: string, chi | |||||
if (current[children]) return findItemNested(current[children], callValue, value, children); | if (current[children]) return findItemNested(current[children], callValue, value, children); | ||||
}, null); | }, null); | ||||
} | } | ||||
/** | |||||
* @description 时间戳转化为日期 | |||||
* */ | |||||
export function formatDate(timestamp:number) { | |||||
let date = new Date(timestamp); | |||||
let year = date.getFullYear(); | |||||
let month = "0" + (date.getMonth() + 1); // getMonth返回的月份是从0开始的 | |||||
let day = "0" + date.getDate(); | |||||
let hours = "0" + date.getHours(); | |||||
let minutes = "0" + date.getMinutes(); | |||||
let seconds = "0" + date.getSeconds(); | |||||
return year + "-" + month.substr(-2) + "-" + day.substr(-2) | |||||
+ " " + hours.substr(-2) + ":" + minutes.substr(-2) + ":" + seconds.substr(-2); | |||||
} |
@@ -0,0 +1,148 @@ | |||||
<!-- | |||||
* @Description: 行为轨迹 | |||||
* @Author: yxq | |||||
* @Date: 2023-12-15 15:45:59 | |||||
--> | |||||
<template> | |||||
<div> | |||||
<form-container v-model="visible" :title="`行为轨迹查看`" form-size="800px" @close="onClose"> | |||||
<ProTable ref="proTable" title="行为轨迹" height="500px" :data="tableData" :columns="columns"></ProTable> | |||||
<template #footer> | |||||
<el-button @click="onClose"> 关闭 </el-button> | |||||
</template> | |||||
</form-container> | |||||
<!-- 预览头像 --> | |||||
<el-dialog v-model="imgVisible" title="查看头像" width="830px"> | |||||
<div style="display: flex; align-items: center; justify-content: center"> | |||||
<img class="detailpic" :src="faceUrl" alt="" /> | |||||
</div> | |||||
</el-dialog> | |||||
</div> | |||||
</template> | |||||
<script setup lang="tsx" name="attendanceBehaviorTrace"> | |||||
import { AttendanceBehaviorTrace, attendanceBehaviorTrace } from "@/api"; | |||||
import { ColumnProps, ProTableInstance } from "@/components/ProTable/interface"; | |||||
import { FormOptEnum } from "@/enums"; | |||||
const visible = ref(false); //是否显示 | |||||
// 弹框参数 | |||||
const propsInfo = reactive<FormProps.Base<AttendanceBehaviorTrace.behaviorTraceInfo>>({ | |||||
opt: FormOptEnum.VIEW, //操作类型 | |||||
record: {}, //弹框数据 | |||||
disabled: false | |||||
}); | |||||
/** | |||||
* 打开弹框 | |||||
* @param props 弹框参数 | |||||
*/ | |||||
function onOpen(props: FormProps.Base<AttendanceBehaviorTrace.PassengerInfo>) { | |||||
Object.assign(propsInfo, props); //合并参数 | |||||
visible.value = true; //显示弹框 | |||||
if (props.record.id) { | |||||
//如果传了id,就去请求api获取record | |||||
attendanceBehaviorTrace.detail({ id: props.record.id }).then(res => { | |||||
propsInfo.record = res.data; | |||||
}); | |||||
} | |||||
} | |||||
const tableData = ref([ | |||||
{ | |||||
faces: [ | |||||
{ | |||||
faceUrl: | |||||
"http://deepvision.oss-cn-zhangjiakou.aliyuncs.com/dfield-cruising/online/person-set/quanjiang/DEMO00001/8746a847ecd64c1696b37f4cdf617a18/5dc35e4c7af84b3fb5aab70156574873.jpg?Expires=1721375257&OSSAccessKeyId=STS.NTfeBHwzU7kivsSS2EypREace&Signature=c1aTbDc1hNISq%2BV05o0slEfoCTI%3D&security-token=CAIS0wN1q6Ft5B2yfSjIr5fTLvj8mqV0gKmCdFXitzIQdf9%2BqqTIhzz2IHFMf3huCeodsv8%2BlGxS5%2FgelrpqVpZDR03Na8RHwrly1lv5O9KY4x49TRng0s%2FLI3OaLjKm9hi7AYygPgK0GJqEb1TDiVUto9%2FTfimjWFqIKICAjYUdAP0cQgi%2Fa0gwZrJRPRAwh8IGEnHTOP2xUHvtmXGCNFd0nQB%2BhGhjk7TdpPeR8R3Dllb35%2FYIroDqWPieYtJrIY10XqWBvqx%2FfbGT1zVLuVoYtvV6gaFc5zbcv9abRFVf4hiCP6%2Ff6MBuNw5%2Fae94efZNp%2BOukuZj6K6B1db7xhtVI%2BBOUiPZA4mr2IzdBeqvNNcwc7m8F1no9YjXbsGs9EEGGStLaVgVI4F8dyAhWEd9FWjgR%2FX5qAyQUGCKULOY1aw6651xwmjz8MCCT1r1GOTBindGasVnMxh5Z0JMjDK9aNkKfgFUbVJ8BrGTCIh%2FYx0bsq7yowDIEyp71TRMo%2Bbu%2FDBhIifKpO4VN7AxMup1DPwu2wNCxORK3yyybb5sa3aTR6942p%2F%2FF5VxFNPqOx1rmCMf4znuW4yrvNkAVvNcuIqdR8aLhaLIEbHzoKxuEKRnrfsIeBqAAUB%2FCKIuI1UaCj4LYX8DyIYOI8tUKFsMguPHpPENaK9Lcz5ZhB%2BrX6BcQfNWOLhDx7KyRE28vtEs2uolAhLTRaZsZFjbAZE5Ngt09%2FbSXdD%2FR%2BOlGMpQdp752x5lOlvPsJp1skuFLbramyqY4oj4tVwv1OLWpcsEc3AEosPalpAuIAA%3D" | |||||
}, | |||||
], | |||||
time:'2024-07-16 18:20:12', | |||||
name:'大厅(魔豆)', | |||||
}, | |||||
{ | |||||
faces: [ | |||||
{ | |||||
faceUrl: | |||||
"http://deepvision.oss-cn-zhangjiakou.aliyuncs.com/dfield-cruising/online/person-set/quanjiang/DEMO00001/8746a847ecd64c1696b37f4cdf617a18/5dc35e4c7af84b3fb5aab70156574873.jpg?Expires=1721375257&OSSAccessKeyId=STS.NTfeBHwzU7kivsSS2EypREace&Signature=c1aTbDc1hNISq%2BV05o0slEfoCTI%3D&security-token=CAIS0wN1q6Ft5B2yfSjIr5fTLvj8mqV0gKmCdFXitzIQdf9%2BqqTIhzz2IHFMf3huCeodsv8%2BlGxS5%2FgelrpqVpZDR03Na8RHwrly1lv5O9KY4x49TRng0s%2FLI3OaLjKm9hi7AYygPgK0GJqEb1TDiVUto9%2FTfimjWFqIKICAjYUdAP0cQgi%2Fa0gwZrJRPRAwh8IGEnHTOP2xUHvtmXGCNFd0nQB%2BhGhjk7TdpPeR8R3Dllb35%2FYIroDqWPieYtJrIY10XqWBvqx%2FfbGT1zVLuVoYtvV6gaFc5zbcv9abRFVf4hiCP6%2Ff6MBuNw5%2Fae94efZNp%2BOukuZj6K6B1db7xhtVI%2BBOUiPZA4mr2IzdBeqvNNcwc7m8F1no9YjXbsGs9EEGGStLaVgVI4F8dyAhWEd9FWjgR%2FX5qAyQUGCKULOY1aw6651xwmjz8MCCT1r1GOTBindGasVnMxh5Z0JMjDK9aNkKfgFUbVJ8BrGTCIh%2FYx0bsq7yowDIEyp71TRMo%2Bbu%2FDBhIifKpO4VN7AxMup1DPwu2wNCxORK3yyybb5sa3aTR6942p%2F%2FF5VxFNPqOx1rmCMf4znuW4yrvNkAVvNcuIqdR8aLhaLIEbHzoKxuEKRnrfsIeBqAAUB%2FCKIuI1UaCj4LYX8DyIYOI8tUKFsMguPHpPENaK9Lcz5ZhB%2BrX6BcQfNWOLhDx7KyRE28vtEs2uolAhLTRaZsZFjbAZE5Ngt09%2FbSXdD%2FR%2BOlGMpQdp752x5lOlvPsJp1skuFLbramyqY4oj4tVwv1OLWpcsEc3AEosPalpAuIAA%3D" | |||||
}, | |||||
], | |||||
time:'2024-07-16 18:20:12', | |||||
name:'教室(海康)', | |||||
}, | |||||
{ | |||||
faces: [ | |||||
{ | |||||
faceUrl: | |||||
"http://deepvision.oss-cn-zhangjiakou.aliyuncs.com/dfield-cruising/online/person-set/quanjiang/DEMO00001/8746a847ecd64c1696b37f4cdf617a18/5dc35e4c7af84b3fb5aab70156574873.jpg?Expires=1721375257&OSSAccessKeyId=STS.NTfeBHwzU7kivsSS2EypREace&Signature=c1aTbDc1hNISq%2BV05o0slEfoCTI%3D&security-token=CAIS0wN1q6Ft5B2yfSjIr5fTLvj8mqV0gKmCdFXitzIQdf9%2BqqTIhzz2IHFMf3huCeodsv8%2BlGxS5%2FgelrpqVpZDR03Na8RHwrly1lv5O9KY4x49TRng0s%2FLI3OaLjKm9hi7AYygPgK0GJqEb1TDiVUto9%2FTfimjWFqIKICAjYUdAP0cQgi%2Fa0gwZrJRPRAwh8IGEnHTOP2xUHvtmXGCNFd0nQB%2BhGhjk7TdpPeR8R3Dllb35%2FYIroDqWPieYtJrIY10XqWBvqx%2FfbGT1zVLuVoYtvV6gaFc5zbcv9abRFVf4hiCP6%2Ff6MBuNw5%2Fae94efZNp%2BOukuZj6K6B1db7xhtVI%2BBOUiPZA4mr2IzdBeqvNNcwc7m8F1no9YjXbsGs9EEGGStLaVgVI4F8dyAhWEd9FWjgR%2FX5qAyQUGCKULOY1aw6651xwmjz8MCCT1r1GOTBindGasVnMxh5Z0JMjDK9aNkKfgFUbVJ8BrGTCIh%2FYx0bsq7yowDIEyp71TRMo%2Bbu%2FDBhIifKpO4VN7AxMup1DPwu2wNCxORK3yyybb5sa3aTR6942p%2F%2FF5VxFNPqOx1rmCMf4znuW4yrvNkAVvNcuIqdR8aLhaLIEbHzoKxuEKRnrfsIeBqAAUB%2FCKIuI1UaCj4LYX8DyIYOI8tUKFsMguPHpPENaK9Lcz5ZhB%2BrX6BcQfNWOLhDx7KyRE28vtEs2uolAhLTRaZsZFjbAZE5Ngt09%2FbSXdD%2FR%2BOlGMpQdp752x5lOlvPsJp1skuFLbramyqY4oj4tVwv1OLWpcsEc3AEosPalpAuIAA%3D" | |||||
}, | |||||
], | |||||
time:'2024-07-16 18:20:12', | |||||
name:'大厅(魔豆)', | |||||
}, | |||||
{ | |||||
faces: [ | |||||
{ | |||||
faceUrl: | |||||
"http://deepvision.oss-cn-zhangjiakou.aliyuncs.com/dfield-cruising/online/person-set/quanjiang/DEMO00001/8746a847ecd64c1696b37f4cdf617a18/5dc35e4c7af84b3fb5aab70156574873.jpg?Expires=1721375257&OSSAccessKeyId=STS.NTfeBHwzU7kivsSS2EypREace&Signature=c1aTbDc1hNISq%2BV05o0slEfoCTI%3D&security-token=CAIS0wN1q6Ft5B2yfSjIr5fTLvj8mqV0gKmCdFXitzIQdf9%2BqqTIhzz2IHFMf3huCeodsv8%2BlGxS5%2FgelrpqVpZDR03Na8RHwrly1lv5O9KY4x49TRng0s%2FLI3OaLjKm9hi7AYygPgK0GJqEb1TDiVUto9%2FTfimjWFqIKICAjYUdAP0cQgi%2Fa0gwZrJRPRAwh8IGEnHTOP2xUHvtmXGCNFd0nQB%2BhGhjk7TdpPeR8R3Dllb35%2FYIroDqWPieYtJrIY10XqWBvqx%2FfbGT1zVLuVoYtvV6gaFc5zbcv9abRFVf4hiCP6%2Ff6MBuNw5%2Fae94efZNp%2BOukuZj6K6B1db7xhtVI%2BBOUiPZA4mr2IzdBeqvNNcwc7m8F1no9YjXbsGs9EEGGStLaVgVI4F8dyAhWEd9FWjgR%2FX5qAyQUGCKULOY1aw6651xwmjz8MCCT1r1GOTBindGasVnMxh5Z0JMjDK9aNkKfgFUbVJ8BrGTCIh%2FYx0bsq7yowDIEyp71TRMo%2Bbu%2FDBhIifKpO4VN7AxMup1DPwu2wNCxORK3yyybb5sa3aTR6942p%2F%2FF5VxFNPqOx1rmCMf4znuW4yrvNkAVvNcuIqdR8aLhaLIEbHzoKxuEKRnrfsIeBqAAUB%2FCKIuI1UaCj4LYX8DyIYOI8tUKFsMguPHpPENaK9Lcz5ZhB%2BrX6BcQfNWOLhDx7KyRE28vtEs2uolAhLTRaZsZFjbAZE5Ngt09%2FbSXdD%2FR%2BOlGMpQdp752x5lOlvPsJp1skuFLbramyqY4oj4tVwv1OLWpcsEc3AEosPalpAuIAA%3D" | |||||
}, | |||||
], | |||||
time:'2024-07-16 18:20:12', | |||||
name:'教室(海康)', | |||||
}, | |||||
{ | |||||
faces: [ | |||||
{ | |||||
faceUrl: | |||||
"http://deepvision.oss-cn-zhangjiakou.aliyuncs.com/dfield-cruising/online/person-set/quanjiang/DEMO00001/8746a847ecd64c1696b37f4cdf617a18/5dc35e4c7af84b3fb5aab70156574873.jpg?Expires=1721375257&OSSAccessKeyId=STS.NTfeBHwzU7kivsSS2EypREace&Signature=c1aTbDc1hNISq%2BV05o0slEfoCTI%3D&security-token=CAIS0wN1q6Ft5B2yfSjIr5fTLvj8mqV0gKmCdFXitzIQdf9%2BqqTIhzz2IHFMf3huCeodsv8%2BlGxS5%2FgelrpqVpZDR03Na8RHwrly1lv5O9KY4x49TRng0s%2FLI3OaLjKm9hi7AYygPgK0GJqEb1TDiVUto9%2FTfimjWFqIKICAjYUdAP0cQgi%2Fa0gwZrJRPRAwh8IGEnHTOP2xUHvtmXGCNFd0nQB%2BhGhjk7TdpPeR8R3Dllb35%2FYIroDqWPieYtJrIY10XqWBvqx%2FfbGT1zVLuVoYtvV6gaFc5zbcv9abRFVf4hiCP6%2Ff6MBuNw5%2Fae94efZNp%2BOukuZj6K6B1db7xhtVI%2BBOUiPZA4mr2IzdBeqvNNcwc7m8F1no9YjXbsGs9EEGGStLaVgVI4F8dyAhWEd9FWjgR%2FX5qAyQUGCKULOY1aw6651xwmjz8MCCT1r1GOTBindGasVnMxh5Z0JMjDK9aNkKfgFUbVJ8BrGTCIh%2FYx0bsq7yowDIEyp71TRMo%2Bbu%2FDBhIifKpO4VN7AxMup1DPwu2wNCxORK3yyybb5sa3aTR6942p%2F%2FF5VxFNPqOx1rmCMf4znuW4yrvNkAVvNcuIqdR8aLhaLIEbHzoKxuEKRnrfsIeBqAAUB%2FCKIuI1UaCj4LYX8DyIYOI8tUKFsMguPHpPENaK9Lcz5ZhB%2BrX6BcQfNWOLhDx7KyRE28vtEs2uolAhLTRaZsZFjbAZE5Ngt09%2FbSXdD%2FR%2BOlGMpQdp752x5lOlvPsJp1skuFLbramyqY4oj4tVwv1OLWpcsEc3AEosPalpAuIAA%3D" | |||||
}, | |||||
], | |||||
time:'2024-07-16 18:20:12', | |||||
name:'大厅(魔豆)', | |||||
} | |||||
]); | |||||
// 获取 ProTable 元素,调用其获取刷新数据方法(还能获取到当前查询参数,方便导出携带参数) | |||||
const proTable = ref<ProTableInstance>(); | |||||
// 表格配置项 | |||||
const columns: ColumnProps[] = [ | |||||
{ | |||||
prop: "time", | |||||
label: "经过摄像头时间" | |||||
}, | |||||
{ | |||||
prop: "name", | |||||
label: "摄像头名称", | |||||
}, | |||||
{ | |||||
prop: "faces", | |||||
label: "快照", | |||||
render: scope => { | |||||
return ( | |||||
<img | |||||
src={scope.row.faces.length > 0 ? scope.row.faces[0].faceUrl : ""} | |||||
onClick={() => viewHeadImage(scope)} | |||||
style="width:50px;height:50px;cursor:pointer" | |||||
alt="" | |||||
/> | |||||
); | |||||
} | |||||
} | |||||
]; | |||||
// 图片预览 | |||||
const imgVisible = ref(false); | |||||
const faceUrl = ref(''); | |||||
const viewHeadImage = (scope: any) => { | |||||
faceUrl.value = scope.row.faces[0].faceUrl; | |||||
imgVisible.value = true | |||||
}; | |||||
/** 关闭表单*/ | |||||
function onClose() { | |||||
visible.value = false; | |||||
} | |||||
// 暴露给父组件的方法 | |||||
defineExpose({ | |||||
onOpen | |||||
}); | |||||
</script> | |||||
<style lang="scss" scoped></style> | |||||
@@ -0,0 +1,139 @@ | |||||
<!-- | |||||
* @Description: 行为轨迹 | |||||
* @Author: yxq | |||||
* @Date: 2024-7-15 | |||||
--> | |||||
<template> | |||||
<div class="main-box"> | |||||
<TreeFilter | |||||
ref="treeFilter" | |||||
label="personSetName" | |||||
id="personSetId" | |||||
width="300px" | |||||
:show-all="true" | |||||
:request-api="userManageClassManageApi.page" | |||||
@change="changeTreeFilter" | |||||
> | |||||
<template v-slot:header> | |||||
<h4 style="margin: 0 0 15px; font-size: 18px; font-weight: bold; color: var(--el-color-info-dark-2); letter-spacing: 0.5px">所属班级</h4> | |||||
</template> | |||||
<template v-slot:label="{ row }"> | |||||
<span class="custom-tree-node"> | |||||
<span>{{ row.node.label }}</span> | |||||
</span> | |||||
</template> | |||||
</TreeFilter> | |||||
<div class="table-box"> | |||||
<ProTable ref="proTable" title="人员管理" :columns="columns" rowKey="personId" :request-api="userManagePersonnelApi.page"> | |||||
<!-- 表格操作栏 --> | |||||
<template #operation="scope"> | |||||
<el-space> | |||||
<s-button link prefix="轨迹" suffix="查看" :opt="FormOptEnum.VIEW" @click="onOpenDetail(FormOptEnum.VIEW, scope.row)" /> | |||||
</el-space> | |||||
</template> | |||||
</ProTable> | |||||
</div> | |||||
<!-- 预览头像 --> | |||||
<el-dialog v-model="visible" title="查看快照" width="830px" :before-close="handleClose"> | |||||
<div style="display: flex; align-items: center; justify-content: center"> | |||||
<img class="detailpic" :src="faceUrl" alt="" /> | |||||
</div> | |||||
</el-dialog> | |||||
<!-- 轨迹详情 --> | |||||
<TraceShow ref="detialRef" /> | |||||
</div> | |||||
</template> | |||||
<script setup lang="tsx" name="SysUserPersonnel"> | |||||
import { userManagePersonnelApi,SysUserPersonnel,userManageClassManageApi,userManageTeacherApi } from "@/api"; | |||||
import { FormOptEnum } from "@/enums"; | |||||
import { ColumnProps, ProTableInstance } from "@/components/ProTable/interface"; | |||||
import TreeFilter from "@/components/TreeFilter/index.vue"; | |||||
import { useUserStore } from "@/stores/modules"; | |||||
import TraceShow from "./components/traceShow/index.vue"; | |||||
// 获取 ProTable 元素,调用其获取刷新数据方法(还能获取到当前查询参数,方便导出携带参数) | |||||
const faceUrl = ref(''); | |||||
const visible = ref(false); //预览头像 | |||||
const proTable = ref<ProTableInstance>(); | |||||
const treeFilter = ref<InstanceType<typeof TreeFilter> | null>(null); | |||||
// 表格配置项 | |||||
const columns: ColumnProps<SysUserPersonnel.SysUserPerInfo>[] = [ | |||||
{ | |||||
prop: "faceUrl", | |||||
label: "人脸", | |||||
render: scope => { | |||||
return ( | |||||
<img src={scope.row.faces.length > 0 ? scope.row.faces[0].faceUrl : ''} onClick={() => viewHeadImage(scope)} style='width:50px;height:50px;' alt=''/> | |||||
); | |||||
} | |||||
}, | |||||
{ | |||||
prop: "name", | |||||
label: "姓名" | |||||
}, | |||||
{ | |||||
prop: "personId", | |||||
label: "人员ID" | |||||
}, | |||||
{ | |||||
prop: "phone", | |||||
label: "手机号" | |||||
}, | |||||
{ | |||||
prop: "personSets", | |||||
label: "所属班级", | |||||
render: scope => { | |||||
return scope.row.personSets.length > 0 ? scope.row.personSets[0].personSetName : '' | |||||
} | |||||
}, | |||||
{ prop: "operation", label: "操作", width: 250, fixed: "right" } | |||||
]; | |||||
const viewHeadImage = (scope: any) => { | |||||
faceUrl.value = scope.row.faces[0].faceUrl; | |||||
visible.value = true | |||||
}; | |||||
const handleClose = () => { | |||||
visible.value = false; | |||||
}; | |||||
// 刷新表格 | |||||
const RefreshTable = () => { | |||||
proTable.value?.refresh(); | |||||
treeFilter.value?.refresh(); //刷新树形筛选器 | |||||
} | |||||
/** 部门切换 */ | |||||
const personSetId = ref<number | string>() | |||||
function changeTreeFilter(val: number | string) { | |||||
personSetId.value = val | |||||
proTable.value!.pageable.pageNum = 1; | |||||
proTable.value!.searchParam.personSetId = val; | |||||
proTable.value!.search(); | |||||
} | |||||
const detialRef = ref<InstanceType<typeof TraceShow> | null>(null); | |||||
/** | |||||
* 详情 | |||||
* @param opt 操作类型 | |||||
* @param record 弹框数据 | |||||
*/ | |||||
function onOpenDetail(opt: FormOptEnum, record: {} | AttendanceStudentsReturn.studentsReturnInfo = {}) { | |||||
switch (opt) { | |||||
case FormOptEnum.VIEW: | |||||
detialRef.value?.onOpen({ opt: opt, record: record, successful: RefreshTable }); | |||||
break; | |||||
} | |||||
} | |||||
</script> | |||||
<style scoped lang="scss"> | |||||
.table-box { | |||||
width: 100%; | |||||
height: 100%; | |||||
} | |||||
.custom-tree-node { | |||||
display: flex; | |||||
flex: 1; | |||||
align-items: center; | |||||
justify-content: space-between; | |||||
padding-right: 8px; | |||||
font-size: 14px; | |||||
} | |||||
</style> |
@@ -0,0 +1,79 @@ | |||||
<!-- | |||||
* @Description: 行为轨迹 | |||||
* @Author: yxq | |||||
* @Date: 2023-12-15 15:45:59 | |||||
--> | |||||
<template> | |||||
<div> | |||||
<form-container v-model="visible" :title="`分片详情`" form-size="800px" @close="onClose"> | |||||
<ProTable ref="proTable" title="分片详情" height="500px" :data="tableData" :columns="columns"></ProTable> | |||||
<template #footer> | |||||
<el-button @click="onClose"> 关闭 </el-button> | |||||
</template> | |||||
</form-container> | |||||
</div> | |||||
</template> | |||||
<script setup lang="tsx" name="attendanceBehaviorTrace"> | |||||
import { AttendanceBehaviorTrace, attendanceBehaviorTrace } from "@/api"; | |||||
import { ColumnProps, ProTableInstance } from "@/components/ProTable/interface"; | |||||
import { FormOptEnum } from "@/enums"; | |||||
const visible = ref(false); //是否显示 | |||||
// 弹框参数 | |||||
const propsInfo = reactive<FormProps.Base<AttendanceBehaviorTrace.behaviorTraceInfo>>({ | |||||
opt: FormOptEnum.VIEW, //操作类型 | |||||
record: {}, //弹框数据 | |||||
disabled: false | |||||
}); | |||||
/** | |||||
* 打开弹框 | |||||
* @param props 弹框参数 | |||||
*/ | |||||
function onOpen(props: FormProps.Base<AttendanceBehaviorTrace.PassengerInfo>) { | |||||
Object.assign(propsInfo, props); //合并参数 | |||||
visible.value = true; //显示弹框 | |||||
if (props.record.id) { | |||||
//如果传了id,就去请求api获取record | |||||
attendanceBehaviorTrace.detail({ id: props.record.id }).then(res => { | |||||
propsInfo.record = res.data; | |||||
}); | |||||
} | |||||
} | |||||
const tableData = ref([ | |||||
{ | |||||
time:'2024-07-16 00:00:00', | |||||
name:'60', | |||||
}, | |||||
{ | |||||
time:'2024-07-17 00:00:00', | |||||
name:'40', | |||||
}, | |||||
]); | |||||
// 获取 ProTable 元素,调用其获取刷新数据方法(还能获取到当前查询参数,方便导出携带参数) | |||||
const proTable = ref<ProTableInstance>(); | |||||
// 表格配置项 | |||||
const columns: ColumnProps[] = [ | |||||
{ | |||||
prop: "time", | |||||
label: "时间" | |||||
}, | |||||
{ | |||||
prop: "name", | |||||
label: "人数", | |||||
}, | |||||
]; | |||||
/** 关闭表单*/ | |||||
function onClose() { | |||||
visible.value = false; | |||||
} | |||||
// 暴露给父组件的方法 | |||||
defineExpose({ | |||||
onOpen | |||||
}); | |||||
</script> | |||||
<style lang="scss" scoped></style> | |||||
@@ -0,0 +1,91 @@ | |||||
<!-- | |||||
* @Description: 客流查询 | |||||
* @Author: yxq | |||||
* @Date: 2023-12-17 15:45:50 | |||||
--> | |||||
<template> | |||||
<div> | |||||
<div> | |||||
<el-row :gutter="16"> | |||||
<el-col :span="24"> | |||||
<s-form-item label="查询时间段" prop="shijianduan"> | |||||
<el-date-picker | |||||
v-model="formInfo.shijianduan" | |||||
type="datetimerange" | |||||
range-separator="至" | |||||
start-placeholder="开始日期" | |||||
end-placeholder="结束日期" | |||||
> | |||||
</el-date-picker> | |||||
</s-form-item> | |||||
</el-col> | |||||
</el-row> | |||||
<el-row :gutter="16"> | |||||
<el-col :span="24"> | |||||
<s-form-item label="摄像头" prop="shexiangtou"> | |||||
<el-select v-model="formInfo.shexiangtou" multiple placeholder="摄像头"> | |||||
<el-option v-for="item in shexiangtouOptions" :key="item.value" :label="item.label" :value="item.value"> </el-option> | |||||
</el-select> | |||||
</s-form-item> | |||||
</el-col> | |||||
</el-row> | |||||
<el-row :gutter="16"> | |||||
<el-col :span="24"> | |||||
<s-form-item label="分片类型(天/小时)" prop="fenpianleixing"> | |||||
<s-radio-group v-model="formInfo.fenpianleixing" :options="fenpianleixingOptions" button /> | |||||
</s-form-item> | |||||
</el-col> | |||||
</el-row> | |||||
</div> | |||||
</div> | |||||
</template> | |||||
<script setup lang="ts"> | |||||
import { AttendancePassenger, monitorLIVEApi } from "@/api"; | |||||
// props | |||||
interface FormProps { | |||||
modelValue: Partial<AttendancePassenger.PassengerInfo>; | |||||
} | |||||
const emit = defineEmits(["update:modelValue"]); //定义emit | |||||
const props = defineProps<FormProps>(); //定义props | |||||
// 客流查询表单 | |||||
const formInfo = computed({ | |||||
get: () => props.modelValue, | |||||
set: val => emit("update:modelValue", val) | |||||
}); | |||||
console.log(props.modelValue); | |||||
// 分片类型 | |||||
const fenpianleixingOptions = ref([ | |||||
{ | |||||
label: "天", | |||||
value: "0" | |||||
}, | |||||
{ | |||||
label: "小时", | |||||
value: "1" | |||||
} | |||||
]); | |||||
// 摄像头 | |||||
let shexiangtouOptions = ref([]); | |||||
monitorLIVEApi.page({ pageSize: 100, pageNum: 1 }).then(res => { | |||||
if (res.code == 200) { | |||||
shexiangtouOptions.value = res.data.list.map(e => { | |||||
return { | |||||
value: e.sensorId, | |||||
label: e.sensorName | |||||
}; | |||||
}); | |||||
} | |||||
}); | |||||
onMounted(() => { | |||||
// 初始化 | |||||
formInfo.value.fenpianleixing = formInfo.value.fenpianleixing ? formInfo.value.fenpianleixing : fenpianleixingOptions.value[0].value; | |||||
}); | |||||
</script> | |||||
<style lang="scss" scoped> | |||||
:deep(.el-input__wrapper) { | |||||
width: 100% !important; | |||||
} | |||||
</style> |
@@ -0,0 +1,112 @@ | |||||
<!-- | |||||
* @Description: 表单 | |||||
* @Author: syy | |||||
* @Date: 2023-12-15 15:45:59 | |||||
--> | |||||
<template> | |||||
<div> | |||||
<form-container v-model="visible" :title="`${propsInfo.opt}查询`" form-size="600px" @close="onClose"> | |||||
<el-form | |||||
ref="formRef" | |||||
:rules="rules" | |||||
:disabled="propsInfo.disabled" | |||||
:model="propsInfo.record" | |||||
:hide-required-asterisk="propsInfo.disabled" | |||||
label-width="auto" | |||||
label-suffix=" :" | |||||
> | |||||
<el-tabs v-model="activeName"> | |||||
<Basic v-model="propsInfo.record"></Basic> | |||||
</el-tabs> | |||||
</el-form> | |||||
<template #footer> | |||||
<el-button @click="onClose"> 取消 </el-button> | |||||
<el-button v-show="!propsInfo.disabled" type="primary" @click="handleSubmit"> 确定 </el-button> | |||||
</template> | |||||
</form-container> | |||||
</div> | |||||
</template> | |||||
<script setup lang="ts"> | |||||
import { AttendancePassenger, attendancePassenger } from "@/api"; | |||||
import { FormOptEnum } from "@/enums"; | |||||
import { required } from "@/utils/formRules"; | |||||
import { FormInstance } from "element-plus"; | |||||
import Basic from "./form_basic.vue"; | |||||
import { formatDate } from "@/utils"; | |||||
const visible = ref(false); //是否显示表单 | |||||
const activeName = ref("basic"); | |||||
// 弹框参数 | |||||
const propsInfo = reactive<FormProps.Base<AttendancePassenger.PassengerInfo>>({ | |||||
opt: FormOptEnum.ADD, | |||||
record: {}, | |||||
disabled: false | |||||
}); | |||||
// 表单验证规则 | |||||
const rules = reactive({ | |||||
shijianduan: [ | |||||
required("请选择查询时间段"), | |||||
{ | |||||
validator: (rule, value, callback) => { | |||||
value = value.map(e => e.valueOf()); | |||||
if (86400000 * 7 < value[1] - value[0]) { | |||||
callback(new Error("时间跨度不能大于七天")); | |||||
} else { | |||||
callback(); | |||||
} | |||||
}, | |||||
trigger: "change" | |||||
} | |||||
], | |||||
shexiangtou: [required("请选择摄像头")] | |||||
}); | |||||
/** | |||||
* 打开表单 | |||||
* @param props 表单参数 | |||||
*/ | |||||
function onOpen(props: FormProps.Base<AttendancePassenger.PassengerInfo>) { | |||||
Object.assign(propsInfo, props); //合并参数 | |||||
if (props.opt == FormOptEnum.ADD) { | |||||
//如果是新增,设置默认值 | |||||
propsInfo.record.shijianduan = []; | |||||
propsInfo.record.shexiangtou = []; | |||||
} | |||||
visible.value = true; //显示表单 | |||||
if (props.record.id) { | |||||
//如果传了id,就去请求api获取record | |||||
attendancePassenger.detail({ id: props.record.id }).then(res => { | |||||
propsInfo.record = res.data; | |||||
}); | |||||
} | |||||
} | |||||
// 提交数据(新增/编辑) | |||||
const formRef = ref<FormInstance>(); | |||||
/** 提交表单 */ | |||||
async function handleSubmit() { | |||||
await attendancePassenger | |||||
.update(propsInfo.record) | |||||
.then(() => { | |||||
propsInfo.successful!(); //调用父组件的successful方法 | |||||
}) | |||||
.finally(() => { | |||||
onClose(); | |||||
}); | |||||
} | |||||
/** 关闭表单*/ | |||||
function onClose() { | |||||
visible.value = false; | |||||
activeName.value = "basic"; | |||||
} | |||||
// 暴露给父组件的方法 | |||||
defineExpose({ | |||||
onOpen | |||||
}); | |||||
</script> | |||||
<style lang="scss" scoped></style> |
@@ -0,0 +1,110 @@ | |||||
<!-- | |||||
* @Description: 客流查询 | |||||
* @Author: yxq | |||||
* @Date: 2024-7-17 | |||||
--> | |||||
<template> | |||||
<div class="table-box"> | |||||
<ProTable ref="proTable" title="查询管理" :columns="columns" :data="data"> | |||||
<!-- 表格 header 按钮 --> | |||||
<template #tableHeader> | |||||
<s-button v-auth="attendancePassengerBtnCode.add" type="primary" suffix="查询" @click="onOpen(FormOptEnum.ADD)" /> | |||||
</template> | |||||
<!-- 表格操作栏 --> | |||||
<template #operation="scope"> | |||||
<el-space> | |||||
<s-button link :opt="FormOptEnum.VIEW" prefix="分片" suffix="详情" @click="onOpen(FormOptEnum.VIEW, scope.row)" /> | |||||
</el-space> | |||||
</template> | |||||
</ProTable> | |||||
<Form ref="formRef" /> | |||||
<DetailTable ref="detailTableRef"></DetailTable> | |||||
</div> | |||||
</template> | |||||
<script setup lang="ts" name="AttendancePassenger"> | |||||
import { attendancePassenger, attendancePassengerBtnCode, AttendancePassenger } from "@/api"; | |||||
import { ColumnProps, ProTableInstance } from "@/components/ProTable/interface"; | |||||
import Form from "./components/form/index.vue"; | |||||
import DetailTable from "./components/detailTable/index.vue"; | |||||
import { FormOptEnum } from "@/enums"; | |||||
// 获取 ProTable 元素,调用其获取刷新数据方法(还能获取到当前查询参数,方便导出携带参数) | |||||
const proTable = ref<ProTableInstance>(); | |||||
const data = ref([ | |||||
{ | |||||
chaxunshijian: "2024-07-18 14:20:12", | |||||
kaishishijian: "2024-07-16 18:20:12", | |||||
jieshushijian: "2024-07-17 16:20:12", | |||||
shexiangtou: "大厅(魔豆)", | |||||
fenpianleiixng: "天", | |||||
tongjirenshu: "100", | |||||
fenpianshijian: "2024-07-17 16:20:12", | |||||
fenpianshuliang: "100" | |||||
}, | |||||
{ | |||||
chaxunshijian: "2024-06-19 14:20:12", | |||||
kaishishijian: "2024-05-16 18:20:12", | |||||
jieshushijian: "2024-05-17 16:20:12", | |||||
shexiangtou: "教室(海康)", | |||||
fenpianleiixng: "天", | |||||
tongjirenshu: "66", | |||||
fenpianshijian: "2024-07-17 16:20:12", | |||||
fenpianshuliang: "60" | |||||
} | |||||
]); | |||||
// 表格配置项 | |||||
const columns: ColumnProps<any>[] = [ | |||||
{ | |||||
prop: "chaxunshijian", | |||||
label: "查询时间" | |||||
}, | |||||
{ | |||||
prop: "kaishishijian", | |||||
label: "开始时间" | |||||
}, | |||||
{ | |||||
prop: "jieshushijian", | |||||
label: "结束时间" | |||||
}, | |||||
{ | |||||
prop: "shexiangtou", | |||||
label: "摄像头" | |||||
}, | |||||
{ | |||||
prop: "fenpianleiixng", | |||||
label: "分片类型" | |||||
}, | |||||
{ | |||||
prop: "tongjirenshu", | |||||
label: "总人数" | |||||
}, | |||||
{ prop: "operation", label: "操作", width: 250, fixed: "right" } | |||||
]; | |||||
// 表单引用 | |||||
const formRef = ref<InstanceType<typeof Form> | null>(null); | |||||
const detailTableRef = ref<InstanceType<typeof DetailTable> | null>(null); | |||||
/** | |||||
* 打开表单 | |||||
* @param opt 操作类型 | |||||
* @param record 记录 | |||||
*/ | |||||
function onOpen(opt: FormOptEnum, record: {} | AttendancePassenger.PassengerInfo = {}) { | |||||
switch (opt) { | |||||
case FormOptEnum.ADD: | |||||
formRef.value?.onOpen({ opt: opt, record: record, successful: RefreshTable }); | |||||
break; | |||||
case FormOptEnum.VIEW: | |||||
detailTableRef.value?.onOpen({ opt: opt, record: record, successful: RefreshTable }); | |||||
} | |||||
} | |||||
// 刷新表格 | |||||
const RefreshTable = () => { | |||||
proTable.value?.refresh(); | |||||
}; | |||||
</script> | |||||
<style scoped lang="scss"> | |||||
.table-box { | |||||
width: 100%; | |||||
height: 100%; | |||||
} | |||||
</style> | |||||
@@ -0,0 +1,160 @@ | |||||
<!-- | |||||
* @Description: 表单 | |||||
* @Author: syy | |||||
* @Date: 2023-12-15 15:45:59 | |||||
--> | |||||
<template> | |||||
<div> | |||||
<form-container v-model="visible" :title="`${sysUserProps.opt}点名`" form-size="900px" @close="onClose"> | |||||
<el-form | |||||
ref="sysUserFormRef" | |||||
:rules="rules" | |||||
:disabled="sysUserProps.disabled" | |||||
:model="sysUserProps.record" | |||||
:hide-required-asterisk="sysUserProps.disabled" | |||||
label-width="auto" | |||||
label-suffix=" :" | |||||
> | |||||
<div> | |||||
<el-row :gutter="16"> | |||||
<el-col :span="12"> | |||||
<s-form-item label="摄像头分组" prop="cameraGroudId"> | |||||
<org-selector | |||||
@change="handleChange" | |||||
v-model:org-value="sysUserProps.record.cameraGroudId" | |||||
:org-tree-api="monitorLIVEApi.groupList" | |||||
:show-all="false" | |||||
/></s-form-item> | |||||
</el-col> | |||||
<el-col :span="12"> | |||||
<s-form-item label="摄像头" prop="cameraId"> | |||||
<s-select v-model="sysUserProps.record.cameraId" :options="CameraList" label="sensorName" value="sensorId"></s-select> | |||||
</s-form-item> | |||||
</el-col> | |||||
</el-row> | |||||
<el-row :gutter="16"> | |||||
<el-col :span="12"> | |||||
<s-form-item label="所属班级" prop="personSetId"> | |||||
<s-select | |||||
v-model="sysUserProps.record.personSetId" | |||||
:options="sysUserProps.treeAllData" | |||||
label="personSetName" | |||||
value="personSetId" | |||||
></s-select> | |||||
</s-form-item> | |||||
</el-col> | |||||
<el-col :span="12"> | |||||
<s-form-item label="持续时间" prop="continueTime"> | |||||
<el-slider v-model="sysUserProps.record.continueTime" /> | |||||
</s-form-item> | |||||
</el-col> | |||||
</el-row> | |||||
<el-row :gutter="16"> | |||||
<el-col :span="12"> | |||||
<s-form-item label="相似度" prop="similarity"> | |||||
<el-slider v-model="sysUserProps.record.similarity" :min="0.3" :max="0.8" :step="0.01" /> | |||||
</s-form-item> | |||||
</el-col> | |||||
</el-row> | |||||
</div> | |||||
</el-form> | |||||
<template #footer> | |||||
<el-button @click="onClose"> 取消 </el-button> | |||||
<el-button v-show="!sysUserProps.disabled" type="primary" @click="handleSubmit"> 确定 </el-button> | |||||
</template> | |||||
</form-container> | |||||
</div> | |||||
</template> | |||||
<script setup lang="ts" name="SysUserPersonnelForm"> | |||||
import { attendanceRoolcallApi, userManagePersonnelApi, monitorLIVEApi } from "@/api"; | |||||
import { required } from "@/utils/formRules"; | |||||
import { FormInstance } from "element-plus"; | |||||
const visible = ref(false); //是否显示表单 | |||||
/** 表单操作类型枚举 */ | |||||
enum FormOptEnums { | |||||
/** 发起 */ | |||||
INITIATE = "发起" | |||||
} | |||||
// 表单参数 | |||||
const sysUserProps = reactive<FormProps.Base<any>>({ | |||||
opt: FormOptEnums.INITIATE, | |||||
record: {}, | |||||
treeAllData: [], | |||||
disabled: false | |||||
}); | |||||
const CameraList = ref<any>([]); | |||||
// 表单验证规则 | |||||
const rules = reactive({ | |||||
cameraGroudId: [required("请选择摄像头分组")], | |||||
similarity: [required("请选择相似度")], | |||||
cameraId: [required("请选择摄像头")], | |||||
continueTime: [required("请选择持续时间")], | |||||
personSetId: [required("请选择所属班级")] | |||||
}); | |||||
/** | |||||
* 打开表单 | |||||
* @param props 表单参数 | |||||
*/ | |||||
function onOpen(props: FormProps.Base<any>) { | |||||
Object.assign(sysUserProps, props); //合并参数 | |||||
if (props.opt == FormOptEnums.INITIATE) { | |||||
//如果是新增,设置默认值 | |||||
// sysUserProps.record.sortCode = 99; | |||||
} | |||||
visible.value = true; //显示表单 | |||||
if (props.record.personId) { | |||||
//如果传了id,就去请求api获取record | |||||
userManagePersonnelApi.detail({ id: props.record.personId }).then((res: any) => { | |||||
sysUserProps.record = res.data; | |||||
}); | |||||
} | |||||
} | |||||
const handleChange = async (val: any, data: any) => { | |||||
let res = await monitorLIVEApi.list({ pageNum: 1, pageSize: 1000, groupId: data.id }); | |||||
CameraList.value = res.data.list; | |||||
}; | |||||
// 提交数据(新增/编辑) | |||||
const sysUserFormRef = ref<FormInstance>(); | |||||
/** 提交表单 */ | |||||
async function handleSubmit() { | |||||
sysUserFormRef.value?.validate(async valid => { | |||||
if (!valid) return; //表单验证失败 | |||||
//提交表单 | |||||
if (sysUserProps.record.personId) { | |||||
await attendanceRoolcallApi | |||||
.update(sysUserProps.record) | |||||
.then(() => { | |||||
sysUserProps.successful!(); //调用父组件的successful方法 | |||||
}) | |||||
.finally(() => { | |||||
onClose(); | |||||
}); | |||||
} else { | |||||
await attendanceRoolcallApi | |||||
.add(sysUserProps.record) | |||||
.then(() => { | |||||
sysUserProps.successful!(); //调用父组件的successful方法 | |||||
}) | |||||
.finally(() => { | |||||
onClose(); | |||||
}); | |||||
} | |||||
}); | |||||
} | |||||
/** 关闭表单*/ | |||||
function onClose() { | |||||
visible.value = false; | |||||
} | |||||
// 暴露给父组件的方法 | |||||
defineExpose({ | |||||
onOpen | |||||
}); | |||||
</script> | |||||
<style lang="scss" scoped></style> |
@@ -0,0 +1,191 @@ | |||||
<template> | |||||
<div class="roolcallDetail"> | |||||
<div class="header"> | |||||
<el-row> | |||||
<el-col :span="18"> | |||||
<el-row> | |||||
<el-col :span="6"><el-text class="mx-1" type="primary" size="large">应到:8人</el-text></el-col> | |||||
<el-col :span="6"><el-text class="mx-1" type="success" size="large">实到:4</el-text> </el-col> | |||||
<el-col :span="6"> <el-text class="mx-1" type="warning" size="large">趴桌子:2</el-text></el-col> | |||||
<el-col :span="6"> | |||||
<el-text class="mx-1" type="info" size="large">未识别:{{ UnrecognizedD.length }}</el-text></el-col | |||||
> | |||||
</el-row> | |||||
</el-col> | |||||
</el-row> | |||||
</div> | |||||
<el-row :gutter="20"> | |||||
<el-col :span="18" | |||||
><el-row class="rowbg"> | |||||
<el-col :xl="4" :lg="4" :md="6" :sm="8" :xs="12" v-for="(item, index) in listData" :key="index" | |||||
><div class="grid-content"> | |||||
<div class="imgBox" :class="{ active: item.status === 1 ? true : false }"> | |||||
<img :src="item.faces[0].faceUrl" alt="" /> | |||||
</div> | |||||
<div class="info"> | |||||
<div class="desc"> | |||||
<span class="label">姓名:</span> | |||||
{{ item.name }} | |||||
</div> | |||||
<div class="desc"> | |||||
<span class="label">所属分组:</span> | |||||
{{ item.personSets[0].personSetName }} | |||||
</div> | |||||
</div> | |||||
</div></el-col | |||||
> | |||||
</el-row></el-col | |||||
> | |||||
<el-col :span="6"> | |||||
<div class="unrecognized"> | |||||
<div class="title">未识别人员</div> | |||||
<div class="imgBox" v-for="(item, index) in UnrecognizedD" :key="index"> | |||||
<img :src="item.faceUrl" alt="" /> | |||||
</div> | |||||
</div> | |||||
</el-col> | |||||
</el-row> | |||||
</div> | |||||
</template> | |||||
<script setup lang="ts" name="SysUserPersonnel"> | |||||
import { userManagePersonnelApi, attendanceRoolcallApi } from "@/api"; | |||||
const route = useRoute(); | |||||
const listData = ref<any>([]); //人员列表 | |||||
const HighlightData = ref<any>([]); //点名人员列表 | |||||
const UnrecognizedD = ref<any>([]); //未识别数据 | |||||
const getList = () => { | |||||
userManagePersonnelApi | |||||
.page({ | |||||
pageNum: 1, | |||||
pageSize: 1000, | |||||
personSetId: route.query.personSetId | |||||
}) | |||||
.then((res: any) => { | |||||
listData.value = res.data.list; | |||||
Highlight(); | |||||
}); | |||||
}; | |||||
const Highlight = () => { | |||||
attendanceRoolcallApi | |||||
.page({ | |||||
pageNum: 1, | |||||
pageSize: 1000, | |||||
taskId: route.query.taskId | |||||
}) | |||||
.then((res: any) => { | |||||
HighlightData.value = res.data.list; | |||||
listData.value | |||||
.map((item: any) => { | |||||
item.status = 0; | |||||
return item; | |||||
}) | |||||
.forEach((item: any) => { | |||||
HighlightData.value.forEach((item1: any) => { | |||||
if (item.personId === item1.personId) { | |||||
item.status = 1; | |||||
} | |||||
}); | |||||
}); | |||||
// 未识别人员摘取 | |||||
UnrecognizedD.value = []; | |||||
JSON.parse(JSON.stringify(HighlightData.value)).map((item: any) => { | |||||
if (!item.personId) { | |||||
UnrecognizedD.value.push(item); | |||||
} | |||||
}); | |||||
console.log(UnrecognizedD.value); | |||||
}); | |||||
}; | |||||
onMounted(() => { | |||||
getList(); | |||||
console.log(route.query); | |||||
}); | |||||
</script> | |||||
<style lang="scss" scoped> | |||||
.roolcallDetail { | |||||
.el-row { | |||||
width: 100%; | |||||
} | |||||
.header { | |||||
box-sizing: border-box; | |||||
display: flex; | |||||
align-items: center; | |||||
justify-content: space-between; | |||||
width: 100%; | |||||
height: 80px; | |||||
padding: 0 20px; | |||||
background: #ffffff; | |||||
.el-col { | |||||
text-align: center; | |||||
} | |||||
} | |||||
.rowbg { | |||||
width: 100%; | |||||
.el-col { | |||||
box-sizing: border-box; | |||||
height: 190px; | |||||
margin-bottom: 20px; | |||||
.grid-content { | |||||
box-sizing: border-box; | |||||
height: 100%; | |||||
padding: 15px; | |||||
margin: 10px; | |||||
background: #ffffff; | |||||
.imgBox { | |||||
display: flex; | |||||
align-items: center; | |||||
justify-content: center; | |||||
width: 100%; | |||||
height: 100px; | |||||
background: #f2f2f2; | |||||
opacity: 0.5; | |||||
&.active { | |||||
background: #79bbff45; | |||||
opacity: 1; | |||||
} | |||||
img { | |||||
max-height: 100%; | |||||
object-fit: cover; | |||||
} | |||||
} | |||||
.info { | |||||
height: 80px; | |||||
.label { | |||||
margin-right: 8px; | |||||
font-size: 14px; | |||||
color: #41465f; | |||||
opacity: 0.6; | |||||
} | |||||
.desc { | |||||
max-width: 100%; | |||||
margin-top: 10px; | |||||
overflow: hidden; | |||||
font-size: 14px; | |||||
color: #41465f; | |||||
text-overflow: ellipsis; | |||||
white-space: nowrap; | |||||
} | |||||
} | |||||
.btn { | |||||
display: flex; | |||||
align-items: center; | |||||
justify-content: space-between; | |||||
height: 40px; | |||||
font-size: 14px; | |||||
color: #41465f; | |||||
border-top: 1px solid #f3f3f3; | |||||
} | |||||
} | |||||
} | |||||
} | |||||
.unrecognized { | |||||
.title { | |||||
font-size: 18px; | |||||
font-weight: bold; | |||||
line-height: 50px; | |||||
color: #41465f; | |||||
text-align: center; | |||||
} | |||||
} | |||||
} | |||||
</style> |
@@ -0,0 +1,159 @@ | |||||
<!-- | |||||
* @Description: 教师点名 | |||||
* @Author: syy | |||||
* @Date: 2024-7-15 | |||||
--> | |||||
<template> | |||||
<div class="main-box"> | |||||
<TreeFilter | |||||
ref="treeFilter" | |||||
label="personSetName" | |||||
id="personSetId" | |||||
width="300px" | |||||
title="班级管理" | |||||
:show-all="true" | |||||
:request-api="userManageClassManageApi.page" | |||||
@change="changeTreeFilter" | |||||
> | |||||
<template v-slot:label="{ row }"> | |||||
<span class="custom-tree-node"> | |||||
<span>{{ row.node.label }} {{ row.node.userName ? `(${row.node.userName})` : "" }}</span> | |||||
</span> | |||||
</template> | |||||
</TreeFilter> | |||||
<div class="table-box"> | |||||
<ProTable ref="proTable" title="任务列表" :columns="columns" rowKey="id" :request-api="attendanceRoolcallApi.getTaskPageList"> | |||||
<!-- 表格 header 按钮 --> | |||||
<template #tableHeader="scope"> | |||||
<s-button :opt="FormOptEnums.INITIATE" @click="onOpen(FormOptEnums.INITIATE, { personSetId: personSetId }, treeFilter.treeAllData)" /> | |||||
<s-button | |||||
type="danger" | |||||
:opt="FormOptEnum.DELETE" | |||||
plain | |||||
suffix="点名任务" | |||||
:disabled="!scope.isSelected" | |||||
@click="onDelete(scope.selectedListIds, '删除点名任务')" | |||||
/> | |||||
</template> | |||||
<!-- 表格操作栏 --> | |||||
<template #operation="scope"> | |||||
<el-space> | |||||
<s-button link :opt="FormOptEnum.VIEW" @click="onView(scope.row)" /> | |||||
<s-button link :opt="FormOptEnum.DELETE" @click="onDelete([scope.row.personId], `删除点名任务`)" /> | |||||
</el-space> | |||||
</template> | |||||
</ProTable> | |||||
</div> | |||||
<!-- 发起新增/编辑表单 --> | |||||
<Form ref="formRef"></Form> | |||||
</div> | |||||
</template> | |||||
<script setup lang="tsx" name="SysUserPersonnel"> | |||||
import { attendanceRoolcallApi,userManagePersonnelApi,userManageClassManageApi} from "@/api"; | |||||
import { useHandleData } from "@/hooks/useHandleData"; | |||||
import { FormOptEnum } from "@/enums"; | |||||
import Form from "./components/form/index.vue"; | |||||
import { ColumnProps, ProTableInstance } from "@/components/ProTable/interface"; | |||||
import TreeFilter from "@/components/TreeFilter/index.vue"; | |||||
import { useRouter } from "vue-router"; | |||||
const router = useRouter(); | |||||
/** 表单操作类型枚举 */ | |||||
enum FormOptEnums { | |||||
/** 发起 */ | |||||
INITIATE = "发起", | |||||
/* 查看点名任务 */ | |||||
VIEWTASK = "查看", | |||||
/* 修改点名记录 */ | |||||
EDITTASK = "修改点名记录" | |||||
} | |||||
// 获取 ProTable 元素,调用其获取刷新数据方法(还能获取到当前查询参数,方便导出携带参数) | |||||
const visible = ref(false); //是否显示人员表单 | |||||
const proTable = ref<ProTableInstance>(); | |||||
const treeFilter = ref<any>(); | |||||
// 表格配置项 | |||||
const columns: ColumnProps[] = [ | |||||
{ type: "selection", fixed: "left", width: 50 }, | |||||
{ | |||||
prop: "cameraName", | |||||
label: "摄像头名称" | |||||
}, | |||||
{ | |||||
prop: "continueTime", | |||||
label: "持续时间" | |||||
}, | |||||
{ | |||||
prop: "similarity", | |||||
label: "相似度" | |||||
}, | |||||
{ prop: "operation", label: "操作", width: 250, fixed: "right" } | |||||
]; | |||||
const onView = (row: any) => { | |||||
router.push( { | |||||
path:'/roolcall/detail', | |||||
query: { | |||||
taskId: row.taskId, | |||||
personSetId:row.personSetId | |||||
} | |||||
}); | |||||
}; | |||||
// 发起任务表单引用 | |||||
const formRef = ref<InstanceType<typeof Form> | null>(null); | |||||
/** | |||||
* 打开表单 | |||||
* @param opt 操作类型 | |||||
* @param record 记录 | |||||
*/ | |||||
function onOpen(opt: FormOptEnums, record: {},treeAllData:any) { | |||||
formRef.value?.onOpen({ opt: opt, record: record,treeAllData:treeAllData, successful: RefreshTable }); | |||||
} | |||||
/** | |||||
* 任务删除 | |||||
* @param ids id数组 | |||||
*/ | |||||
async function onDelete(ids: string[], msg: string) { | |||||
if(ids.length === 0){ | |||||
ElMessage({ | |||||
message: '请选择要删除的人员', | |||||
type: 'warning' | |||||
}); | |||||
return | |||||
} | |||||
// 二次确认 => 请求api => 刷新表格 | |||||
await useHandleData(userManagePersonnelApi.delete, {id: ids.join(",") }, msg); | |||||
RefreshTable(); //刷新表格 | |||||
} | |||||
// 刷新表格 | |||||
const RefreshTable = () => { | |||||
proTable.value?.refresh(); | |||||
} | |||||
/** 班级切换 */ | |||||
const personSetId = ref<number | string>() | |||||
function changeTreeFilter(val: number | string) { | |||||
personSetId.value = val | |||||
proTable.value!.pageable.pageNum = 1; | |||||
proTable.value!.searchParam.personSetId = val; | |||||
proTable.value!.search(); | |||||
} | |||||
</script> | |||||
<style scoped lang="scss"> | |||||
.table-box { | |||||
width: 100%; | |||||
height: 100%; | |||||
} | |||||
.custom-tree-node { | |||||
display: flex; | |||||
flex: 1; | |||||
align-items: center; | |||||
justify-content: space-between; | |||||
padding-right: 8px; | |||||
font-size: 14px; | |||||
} | |||||
</style> |
@@ -0,0 +1,184 @@ | |||||
<!-- | |||||
* @Description: 人脸识别失败表格 | |||||
* @Author: yxq | |||||
* @Date: 2023-12-15 15:45:59 | |||||
--> | |||||
<template> | |||||
<div> | |||||
<form-container v-model="visible" row-key="id" :title="`${propsInfo.record.qinshibianhao}归寝确认`" form-size="800px" @close="onClose"> | |||||
<ProTable ref="noFaceTableRef" title="归寝确认" height="500px" :data="tableData" :columns="columns"> | |||||
<!-- 表格 header 按钮 --> | |||||
<template #tableHeader="scope"> | |||||
<s-button | |||||
type="primary" | |||||
:disabled="!scope.isSelected" | |||||
icon="check" | |||||
prefix="人工" | |||||
suffix="确认" | |||||
@click="personConfirm(scope.selectedListIds, '确认已归寝')" | |||||
/> | |||||
</template> | |||||
</ProTable> | |||||
<template #footer> | |||||
<el-button @click="onClose"> 关闭 </el-button> | |||||
</template> | |||||
</form-container> | |||||
<!-- 预览头像 --> | |||||
<el-dialog v-model="imgVisible" title="查看头像" width="830px"> | |||||
<div style="display: flex; align-items: center; justify-content: center"> | |||||
<img class="detailpic" :src="faceUrl" alt="" /> | |||||
</div> | |||||
</el-dialog> | |||||
</div> | |||||
</template> | |||||
<script setup lang="tsx" name="attendanceStudentsReturn"> | |||||
import { AttendanceStudentsReturn, attendanceStudentsReturn } from "@/api"; | |||||
import { ColumnProps, noFaceTableInstance } from "@/components/noFaceTableRef/interface"; | |||||
import { FormOptEnum } from "@/enums"; | |||||
import { useHandleData } from "@/hooks"; | |||||
const visible = ref(false); //是否显示 | |||||
// 弹框参数 | |||||
const propsInfo = reactive<FormProps.Base<AttendanceStudentsReturn.PassengerInfo>>({ | |||||
opt: FormOptEnum.VIEW, //操作类型 | |||||
record: {}, //弹框数据 | |||||
disabled: false | |||||
}); | |||||
/** | |||||
* 打开弹框 | |||||
* @param props 弹框参数 | |||||
*/ | |||||
function onOpen(props: FormProps.Base<AttendanceStudentsReturn.PassengerInfo>) { | |||||
Object.assign(propsInfo, props); //合并参数 | |||||
visible.value = true; //显示弹框 | |||||
if (props.record.id) { | |||||
//如果传了id,就去请求api获取record | |||||
attendanceStudentsReturn.detail({ id: props.record.id }).then(res => { | |||||
propsInfo.record = res.data; | |||||
}); | |||||
} | |||||
} | |||||
const tableData = ref([ | |||||
{ | |||||
id:'1', | |||||
studentname: "张三", | |||||
faces: [ | |||||
{ | |||||
faceUrl: | |||||
"http://deepvision.oss-cn-zhangjiakou.aliyuncs.com/dfield-cruising/online/person-set/quanjiang/DEMO00001/8746a847ecd64c1696b37f4cdf617a18/5dc35e4c7af84b3fb5aab70156574873.jpg?Expires=1721375257&OSSAccessKeyId=STS.NTfeBHwzU7kivsSS2EypREace&Signature=c1aTbDc1hNISq%2BV05o0slEfoCTI%3D&security-token=CAIS0wN1q6Ft5B2yfSjIr5fTLvj8mqV0gKmCdFXitzIQdf9%2BqqTIhzz2IHFMf3huCeodsv8%2BlGxS5%2FgelrpqVpZDR03Na8RHwrly1lv5O9KY4x49TRng0s%2FLI3OaLjKm9hi7AYygPgK0GJqEb1TDiVUto9%2FTfimjWFqIKICAjYUdAP0cQgi%2Fa0gwZrJRPRAwh8IGEnHTOP2xUHvtmXGCNFd0nQB%2BhGhjk7TdpPeR8R3Dllb35%2FYIroDqWPieYtJrIY10XqWBvqx%2FfbGT1zVLuVoYtvV6gaFc5zbcv9abRFVf4hiCP6%2Ff6MBuNw5%2Fae94efZNp%2BOukuZj6K6B1db7xhtVI%2BBOUiPZA4mr2IzdBeqvNNcwc7m8F1no9YjXbsGs9EEGGStLaVgVI4F8dyAhWEd9FWjgR%2FX5qAyQUGCKULOY1aw6651xwmjz8MCCT1r1GOTBindGasVnMxh5Z0JMjDK9aNkKfgFUbVJ8BrGTCIh%2FYx0bsq7yowDIEyp71TRMo%2Bbu%2FDBhIifKpO4VN7AxMup1DPwu2wNCxORK3yyybb5sa3aTR6942p%2F%2FF5VxFNPqOx1rmCMf4znuW4yrvNkAVvNcuIqdR8aLhaLIEbHzoKxuEKRnrfsIeBqAAUB%2FCKIuI1UaCj4LYX8DyIYOI8tUKFsMguPHpPENaK9Lcz5ZhB%2BrX6BcQfNWOLhDx7KyRE28vtEs2uolAhLTRaZsZFjbAZE5Ngt09%2FbSXdD%2FR%2BOlGMpQdp752x5lOlvPsJp1skuFLbramyqY4oj4tVwv1OLWpcsEc3AEosPalpAuIAA%3D" | |||||
}, | |||||
], | |||||
louceng:'3', | |||||
qinshi:'301', | |||||
}, | |||||
{ | |||||
id:'2', | |||||
studentname: "李四", | |||||
faces: [ | |||||
{ | |||||
faceUrl: | |||||
"http://deepvision.oss-cn-zhangjiakou.aliyuncs.com/dfield-cruising/online/person-set/quanjiang/DEMO00001/8746a847ecd64c1696b37f4cdf617a18/5dc35e4c7af84b3fb5aab70156574873.jpg?Expires=1721375257&OSSAccessKeyId=STS.NTfeBHwzU7kivsSS2EypREace&Signature=c1aTbDc1hNISq%2BV05o0slEfoCTI%3D&security-token=CAIS0wN1q6Ft5B2yfSjIr5fTLvj8mqV0gKmCdFXitzIQdf9%2BqqTIhzz2IHFMf3huCeodsv8%2BlGxS5%2FgelrpqVpZDR03Na8RHwrly1lv5O9KY4x49TRng0s%2FLI3OaLjKm9hi7AYygPgK0GJqEb1TDiVUto9%2FTfimjWFqIKICAjYUdAP0cQgi%2Fa0gwZrJRPRAwh8IGEnHTOP2xUHvtmXGCNFd0nQB%2BhGhjk7TdpPeR8R3Dllb35%2FYIroDqWPieYtJrIY10XqWBvqx%2FfbGT1zVLuVoYtvV6gaFc5zbcv9abRFVf4hiCP6%2Ff6MBuNw5%2Fae94efZNp%2BOukuZj6K6B1db7xhtVI%2BBOUiPZA4mr2IzdBeqvNNcwc7m8F1no9YjXbsGs9EEGGStLaVgVI4F8dyAhWEd9FWjgR%2FX5qAyQUGCKULOY1aw6651xwmjz8MCCT1r1GOTBindGasVnMxh5Z0JMjDK9aNkKfgFUbVJ8BrGTCIh%2FYx0bsq7yowDIEyp71TRMo%2Bbu%2FDBhIifKpO4VN7AxMup1DPwu2wNCxORK3yyybb5sa3aTR6942p%2F%2FF5VxFNPqOx1rmCMf4znuW4yrvNkAVvNcuIqdR8aLhaLIEbHzoKxuEKRnrfsIeBqAAUB%2FCKIuI1UaCj4LYX8DyIYOI8tUKFsMguPHpPENaK9Lcz5ZhB%2BrX6BcQfNWOLhDx7KyRE28vtEs2uolAhLTRaZsZFjbAZE5Ngt09%2FbSXdD%2FR%2BOlGMpQdp752x5lOlvPsJp1skuFLbramyqY4oj4tVwv1OLWpcsEc3AEosPalpAuIAA%3D" | |||||
}, | |||||
], | |||||
louceng:'3', | |||||
qinshi:'302', | |||||
}, | |||||
{ | |||||
id:'3', | |||||
studentname: "张三", | |||||
faces: [ | |||||
{ | |||||
faceUrl: | |||||
"http://deepvision.oss-cn-zhangjiakou.aliyuncs.com/dfield-cruising/online/person-set/quanjiang/DEMO00001/8746a847ecd64c1696b37f4cdf617a18/5dc35e4c7af84b3fb5aab70156574873.jpg?Expires=1721375257&OSSAccessKeyId=STS.NTfeBHwzU7kivsSS2EypREace&Signature=c1aTbDc1hNISq%2BV05o0slEfoCTI%3D&security-token=CAIS0wN1q6Ft5B2yfSjIr5fTLvj8mqV0gKmCdFXitzIQdf9%2BqqTIhzz2IHFMf3huCeodsv8%2BlGxS5%2FgelrpqVpZDR03Na8RHwrly1lv5O9KY4x49TRng0s%2FLI3OaLjKm9hi7AYygPgK0GJqEb1TDiVUto9%2FTfimjWFqIKICAjYUdAP0cQgi%2Fa0gwZrJRPRAwh8IGEnHTOP2xUHvtmXGCNFd0nQB%2BhGhjk7TdpPeR8R3Dllb35%2FYIroDqWPieYtJrIY10XqWBvqx%2FfbGT1zVLuVoYtvV6gaFc5zbcv9abRFVf4hiCP6%2Ff6MBuNw5%2Fae94efZNp%2BOukuZj6K6B1db7xhtVI%2BBOUiPZA4mr2IzdBeqvNNcwc7m8F1no9YjXbsGs9EEGGStLaVgVI4F8dyAhWEd9FWjgR%2FX5qAyQUGCKULOY1aw6651xwmjz8MCCT1r1GOTBindGasVnMxh5Z0JMjDK9aNkKfgFUbVJ8BrGTCIh%2FYx0bsq7yowDIEyp71TRMo%2Bbu%2FDBhIifKpO4VN7AxMup1DPwu2wNCxORK3yyybb5sa3aTR6942p%2F%2FF5VxFNPqOx1rmCMf4znuW4yrvNkAVvNcuIqdR8aLhaLIEbHzoKxuEKRnrfsIeBqAAUB%2FCKIuI1UaCj4LYX8DyIYOI8tUKFsMguPHpPENaK9Lcz5ZhB%2BrX6BcQfNWOLhDx7KyRE28vtEs2uolAhLTRaZsZFjbAZE5Ngt09%2FbSXdD%2FR%2BOlGMpQdp752x5lOlvPsJp1skuFLbramyqY4oj4tVwv1OLWpcsEc3AEosPalpAuIAA%3D" | |||||
}, | |||||
], | |||||
louceng:'4', | |||||
qinshi:'401', | |||||
}, | |||||
{ | |||||
id:'4', | |||||
studentname: "李四", | |||||
faces: [ | |||||
{ | |||||
faceUrl: | |||||
"http://deepvision.oss-cn-zhangjiakou.aliyuncs.com/dfield-cruising/online/person-set/quanjiang/DEMO00001/8746a847ecd64c1696b37f4cdf617a18/5dc35e4c7af84b3fb5aab70156574873.jpg?Expires=1721375257&OSSAccessKeyId=STS.NTfeBHwzU7kivsSS2EypREace&Signature=c1aTbDc1hNISq%2BV05o0slEfoCTI%3D&security-token=CAIS0wN1q6Ft5B2yfSjIr5fTLvj8mqV0gKmCdFXitzIQdf9%2BqqTIhzz2IHFMf3huCeodsv8%2BlGxS5%2FgelrpqVpZDR03Na8RHwrly1lv5O9KY4x49TRng0s%2FLI3OaLjKm9hi7AYygPgK0GJqEb1TDiVUto9%2FTfimjWFqIKICAjYUdAP0cQgi%2Fa0gwZrJRPRAwh8IGEnHTOP2xUHvtmXGCNFd0nQB%2BhGhjk7TdpPeR8R3Dllb35%2FYIroDqWPieYtJrIY10XqWBvqx%2FfbGT1zVLuVoYtvV6gaFc5zbcv9abRFVf4hiCP6%2Ff6MBuNw5%2Fae94efZNp%2BOukuZj6K6B1db7xhtVI%2BBOUiPZA4mr2IzdBeqvNNcwc7m8F1no9YjXbsGs9EEGGStLaVgVI4F8dyAhWEd9FWjgR%2FX5qAyQUGCKULOY1aw6651xwmjz8MCCT1r1GOTBindGasVnMxh5Z0JMjDK9aNkKfgFUbVJ8BrGTCIh%2FYx0bsq7yowDIEyp71TRMo%2Bbu%2FDBhIifKpO4VN7AxMup1DPwu2wNCxORK3yyybb5sa3aTR6942p%2F%2FF5VxFNPqOx1rmCMf4znuW4yrvNkAVvNcuIqdR8aLhaLIEbHzoKxuEKRnrfsIeBqAAUB%2FCKIuI1UaCj4LYX8DyIYOI8tUKFsMguPHpPENaK9Lcz5ZhB%2BrX6BcQfNWOLhDx7KyRE28vtEs2uolAhLTRaZsZFjbAZE5Ngt09%2FbSXdD%2FR%2BOlGMpQdp752x5lOlvPsJp1skuFLbramyqY4oj4tVwv1OLWpcsEc3AEosPalpAuIAA%3D" | |||||
}, | |||||
], | |||||
louceng:'3', | |||||
qinshi:'301', | |||||
}, | |||||
{ | |||||
id:'5', | |||||
studentname: "张三", | |||||
faces: [ | |||||
{ | |||||
faceUrl: | |||||
"http://deepvision.oss-cn-zhangjiakou.aliyuncs.com/dfield-cruising/online/person-set/quanjiang/DEMO00001/8746a847ecd64c1696b37f4cdf617a18/5dc35e4c7af84b3fb5aab70156574873.jpg?Expires=1721375257&OSSAccessKeyId=STS.NTfeBHwzU7kivsSS2EypREace&Signature=c1aTbDc1hNISq%2BV05o0slEfoCTI%3D&security-token=CAIS0wN1q6Ft5B2yfSjIr5fTLvj8mqV0gKmCdFXitzIQdf9%2BqqTIhzz2IHFMf3huCeodsv8%2BlGxS5%2FgelrpqVpZDR03Na8RHwrly1lv5O9KY4x49TRng0s%2FLI3OaLjKm9hi7AYygPgK0GJqEb1TDiVUto9%2FTfimjWFqIKICAjYUdAP0cQgi%2Fa0gwZrJRPRAwh8IGEnHTOP2xUHvtmXGCNFd0nQB%2BhGhjk7TdpPeR8R3Dllb35%2FYIroDqWPieYtJrIY10XqWBvqx%2FfbGT1zVLuVoYtvV6gaFc5zbcv9abRFVf4hiCP6%2Ff6MBuNw5%2Fae94efZNp%2BOukuZj6K6B1db7xhtVI%2BBOUiPZA4mr2IzdBeqvNNcwc7m8F1no9YjXbsGs9EEGGStLaVgVI4F8dyAhWEd9FWjgR%2FX5qAyQUGCKULOY1aw6651xwmjz8MCCT1r1GOTBindGasVnMxh5Z0JMjDK9aNkKfgFUbVJ8BrGTCIh%2FYx0bsq7yowDIEyp71TRMo%2Bbu%2FDBhIifKpO4VN7AxMup1DPwu2wNCxORK3yyybb5sa3aTR6942p%2F%2FF5VxFNPqOx1rmCMf4znuW4yrvNkAVvNcuIqdR8aLhaLIEbHzoKxuEKRnrfsIeBqAAUB%2FCKIuI1UaCj4LYX8DyIYOI8tUKFsMguPHpPENaK9Lcz5ZhB%2BrX6BcQfNWOLhDx7KyRE28vtEs2uolAhLTRaZsZFjbAZE5Ngt09%2FbSXdD%2FR%2BOlGMpQdp752x5lOlvPsJp1skuFLbramyqY4oj4tVwv1OLWpcsEc3AEosPalpAuIAA%3D" | |||||
}, | |||||
], | |||||
louceng:'5', | |||||
qinshi:'502', | |||||
} | |||||
]); | |||||
// 获取 noFaceTableRef 元素,调用其获取刷新数据方法(还能获取到当前查询参数,方便导出携带参数) | |||||
const noFaceTableRef = ref<noFaceTableInstance>(); | |||||
// 表格配置项 | |||||
const columns: ColumnProps[] = [ | |||||
{ type: "selection" }, | |||||
{ | |||||
prop: "louceng", | |||||
label: "楼层" | |||||
}, | |||||
{ | |||||
prop: "qinshi", | |||||
label: "寝室编号" | |||||
}, | |||||
{ | |||||
prop: "studentname", | |||||
label: "学生姓名" | |||||
}, | |||||
{ | |||||
prop: "faces", | |||||
label: "人脸", | |||||
render: scope => { | |||||
return ( | |||||
<img | |||||
src={scope.row.faces.length > 0 ? scope.row.faces[0].faceUrl : ""} | |||||
onClick={() => viewHeadImage(scope)} | |||||
style="width:50px;height:50px;cursor:pointer" | |||||
alt="" | |||||
/> | |||||
); | |||||
} | |||||
} | |||||
]; | |||||
// 图片预览 | |||||
const imgVisible = ref(false); | |||||
const faceUrl = ref(''); | |||||
const viewHeadImage = (scope: any) => { | |||||
faceUrl.value = scope.row.faces[0].faceUrl; | |||||
imgVisible.value = true | |||||
}; | |||||
/** 人工确认 */ | |||||
async function personConfirm(ids: string[], msg: string) { | |||||
await useHandleData(attendanceStudentsReturn.delete, {id: ids.toString() }, msg); | |||||
RefreshTable(); //刷新表格 | |||||
} | |||||
/** 关闭表单*/ | |||||
function onClose() { | |||||
visible.value = false; | |||||
} | |||||
// 刷新表格 | |||||
const RefreshTable = () => { | |||||
noFaceTableRef.value?.refresh(); | |||||
}; | |||||
// 暴露给父组件的方法 | |||||
defineExpose({ | |||||
onOpen | |||||
}); | |||||
</script> | |||||
<style lang="scss" scoped></style> | |||||
@@ -0,0 +1,96 @@ | |||||
<!-- | |||||
* @Description: 教师点名 | |||||
* @Author: yxq | |||||
* @Date: 2024-7-16 | |||||
--> | |||||
<template> | |||||
<div class="table-box"> | |||||
<ProTable ref="proTable" title="教师点名" :columns="columns" :data="data"> | |||||
<!-- 表格操作栏 --> | |||||
<template #operation="scope"> | |||||
<el-space> | |||||
<s-button | |||||
:disabled="!scope.row.noFaceNum" | |||||
link | |||||
prefix="人工" | |||||
:opt="FormOptEnum.EDIT" | |||||
suffix="确认" | |||||
@click="onOpen(FormOptEnum.VIEW, scope.row)" | |||||
/> | |||||
</el-space> | |||||
</template> | |||||
</ProTable> | |||||
<ReturnConfirm ref="ReturnConfirmRef" /> | |||||
</div> | |||||
</template> | |||||
<script setup lang="ts"> | |||||
import { attendanceStudentsReturn, AttendanceStudentsReturn } from "@/api"; | |||||
import { ColumnProps, ProTableInstance } from "@/components/ProTable/interface"; | |||||
import { FormOptEnum } from "@/enums"; | |||||
import ReturnConfirm from "./components/returnConfirm/index.vue"; | |||||
const data = ref([ | |||||
{ | |||||
louceng: "3", | |||||
qinshibianhao: "306", | |||||
qinshirenshu: "6", | |||||
guiqinNum: "5", | |||||
noFaceNum: "1" | |||||
}, | |||||
{ | |||||
louceng: "3", | |||||
qinshibianhao: "307", | |||||
qinshirenshu: "8", | |||||
guiqinNum: "6", | |||||
noFaceNum: "2" | |||||
} | |||||
]); | |||||
// 获取 ProTable 元素,调用其获取刷新数据方法(还能获取到当前查询参数,方便导出携带参数) | |||||
const proTable = ref<ProTableInstance>(); | |||||
// 表格配置项 | |||||
const columns: ColumnProps[] = [ | |||||
{ | |||||
prop: "louceng", | |||||
label: "楼层" | |||||
}, | |||||
{ | |||||
prop: "qinshibianhao", | |||||
label: "寝室编号" | |||||
}, | |||||
{ | |||||
prop: "qinshirenshu", | |||||
label: "寝室人数" | |||||
}, | |||||
{ | |||||
prop: "guiqinNum", | |||||
label: "归寝人数" | |||||
}, | |||||
{ | |||||
prop: "noFaceNum", | |||||
label: "未归寝人数" | |||||
}, | |||||
{ prop: "operation", label: "操作", width: 250, fixed: "right" } | |||||
]; | |||||
const ReturnConfirmRef = ref<InstanceType<typeof ReturnConfirm> | null>(null); | |||||
/** | |||||
* 人工确认 | |||||
* @param opt 操作类型 | |||||
* @param record 弹框数据 | |||||
*/ | |||||
function onOpen(opt: FormOptEnum, record: {} | AttendanceStudentsReturn.studentsReturnInfo = {}) { | |||||
switch (opt) { | |||||
case FormOptEnum.VIEW: | |||||
ReturnConfirmRef.value?.onOpen({ opt: opt, record: record, successful: RefreshTable }); | |||||
break; | |||||
} | |||||
} | |||||
// 刷新表格 | |||||
const RefreshTable = () => { | |||||
proTable.value?.refresh(); | |||||
}; | |||||
</script> | |||||
<style scoped lang="scss"> | |||||
.table-box { | |||||
width: 100%; | |||||
height: 100%; | |||||
} | |||||
</style> |
@@ -15,17 +15,20 @@ | |||||
label-width="auto" | label-width="auto" | ||||
label-suffix=" :" | label-suffix=" :" | ||||
> | > | ||||
<s-form-item label="摄像头名称" prop="name"> | |||||
<s-input v-model="orgProps.record.name"></s-input> | |||||
<s-form-item label="摄像头名称" prop="sensorName"> | |||||
<s-input v-model="orgProps.record.sensorName"></s-input> | |||||
</s-form-item> | </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 label="所属学校" prop="fieldName"> | |||||
<org-selector v-model:org-value="orgProps.record.fieldName" :org-tree-api="bizOrgApi.tree" :show-all="false" /> | |||||
</s-form-item> | </s-form-item> | ||||
<s-form-item label="设备IP" prop="codeip"> | |||||
<s-input v-model="orgProps.record.codeip" clearable></s-input> | |||||
<s-form-item label="设备IP" prop="directUrlIp"> | |||||
<s-input v-model="orgProps.record.directUrlIp" clearable></s-input> | |||||
</s-form-item> | </s-form-item> | ||||
<s-form-item label="分辨率" prop="status"> | |||||
<s-input v-model="orgProps.record.status" clearable></s-input> | |||||
<s-form-item label="分辨率(width)" prop="resWidth"> | |||||
<s-input v-model="orgProps.record.resWidth" clearable></s-input> | |||||
</s-form-item> | |||||
<s-form-item label="分辨率(height)" prop="resHeight"> | |||||
<s-input v-model="orgProps.record.resHeight" clearable></s-input> | |||||
</s-form-item> | </s-form-item> | ||||
</el-form> | </el-form> | ||||
<template #footer> | <template #footer> | ||||
@@ -50,7 +53,7 @@ const dictStore = useDictStore(); //字典仓库 | |||||
const statusOptions = dictStore.getDictList(SysDictEnum.COMMON_STATUS); | const statusOptions = dictStore.getDictList(SysDictEnum.COMMON_STATUS); | ||||
// 表单参数 | // 表单参数 | ||||
const orgProps = reactive<FormProps.Base<SysOrg.SysOrgInfo>>({ | |||||
const orgProps = reactive<FormProps.Base<any>>({ | |||||
opt: FormOptEnum.ADD, | opt: FormOptEnum.ADD, | ||||
record: {}, | record: {}, | ||||
disabled: false | disabled: false | ||||
@@ -58,10 +61,11 @@ const orgProps = reactive<FormProps.Base<SysOrg.SysOrgInfo>>({ | |||||
// 表单验证规则 | // 表单验证规则 | ||||
const rules = reactive({ | const rules = reactive({ | ||||
name: [required("请输入摄像头名称")], | |||||
parentId: [required("请选择所属学校")], | |||||
codeip: [required("请选择设备IP")], | |||||
status: [required("请输入分辨率")] | |||||
sensorName: [required("请输入摄像头名称")], | |||||
fieldName: [required("请选择所属学校")], | |||||
directUrlIp: [required("请选择设备IP")], | |||||
resWidth: [required("请输入分辨率(width)")], | |||||
resHeight: [required("请输入分辨率(height)")] | |||||
}); | }); | ||||
/** | /** | ||||
@@ -72,12 +76,14 @@ function onOpen(props: FormProps.Base<SysOrg.SysOrgInfo>) { | |||||
Object.assign(orgProps, props); //合并参数 | Object.assign(orgProps, props); //合并参数 | ||||
if (props.opt == FormOptEnum.ADD) { | if (props.opt == FormOptEnum.ADD) { | ||||
//如果是新增,设置默认值 | //如果是新增,设置默认值 | ||||
orgProps.record.sortCode = 99; | |||||
// orgProps.record.sortCode = 99; | |||||
// orgProps.record.status = statusOptions[0].value; | // orgProps.record.status = statusOptions[0].value; | ||||
} | } | ||||
visible.value = true; //显示表单 | visible.value = true; //显示表单 | ||||
if (props.record.id) { | if (props.record.id) { | ||||
orgProps.record = props.record; | |||||
//如果传了id,就去请求api获取record | //如果传了id,就去请求api获取record | ||||
return; | |||||
bizOrgApi.detail({ id: props.record.id }).then(res => { | bizOrgApi.detail({ id: props.record.id }).then(res => { | ||||
orgProps.record = res.data; | orgProps.record = res.data; | ||||
}); | }); | ||||
@@ -41,7 +41,7 @@ const dictStore = useDictStore(); //字典仓库 | |||||
const statusOptions = dictStore.getDictList(SysDictEnum.COMMON_STATUS); | const statusOptions = dictStore.getDictList(SysDictEnum.COMMON_STATUS); | ||||
// 表单参数 | // 表单参数 | ||||
const orgProps = reactive<FormProps.Base<SysOrg.SysOrgInfo>>({ | |||||
const orgProps = reactive<FormProps.Base<any>>({ | |||||
opt: FormOptEnum.ADD, | opt: FormOptEnum.ADD, | ||||
record: {}, | record: {}, | ||||
disabled: false, | disabled: false, | ||||
@@ -57,7 +57,7 @@ const rules = reactive({ | |||||
* 打开表单 | * 打开表单 | ||||
* @param props 表单参数 | * @param props 表单参数 | ||||
*/ | */ | ||||
function omMove(props: FormProps.Base<SysOrg.SysOrgInfo>) { | |||||
function omMove(props: FormProps.Base<any>) { | |||||
// 合并参数 | // 合并参数 | ||||
Object.assign(orgProps, props); //合并参数 | Object.assign(orgProps, props); //合并参数 | ||||
if (orgProps.opt == FormOptEnum.ADD) { | if (orgProps.opt == FormOptEnum.ADD) { | ||||
@@ -15,10 +15,10 @@ | |||||
label-width="auto" | label-width="auto" | ||||
label-suffix=" :" | label-suffix=" :" | ||||
> | > | ||||
<s-form-item label="指定分组推送人" prop="directorId"> | |||||
<s-form-item label="指定推送人" prop="userId"> | |||||
<el-button link type="primary" @click="showSelector">选择</el-button> | <el-button link type="primary" @click="showSelector">选择</el-button> | ||||
<el-tag v-if="liveUserProps.record.directorId" class="ml-3px" type="warning" closable @close="removeDirector">{{ | |||||
liveUserProps.record.directorInfo?.name | |||||
<el-tag v-if="liveUserProps.record.userId" class="ml-3px" type="warning" closable @close="removeDirector">{{ | |||||
liveUserProps.record.userInfo?.name | |||||
}}</el-tag> | }}</el-tag> | ||||
</s-form-item> | </s-form-item> | ||||
</el-form> | </el-form> | ||||
@@ -32,7 +32,7 @@ | |||||
</template> | </template> | ||||
<script setup lang="ts"> | <script setup lang="ts"> | ||||
import { SysOrg, SysUser, sysOrgApi, sysPositionApi, sysRoleApi, sysUserApi } from "@/api"; | |||||
import { SysOrg, SysUser, sysOrgApi, sysPositionApi, sysRoleApi, sysUserApi, monitorLIVEApi } from "@/api"; | |||||
import { FormOptEnum, SysDictEnum } from "@/enums"; | import { FormOptEnum, SysDictEnum } from "@/enums"; | ||||
import { required } from "@/utils/formRules"; | import { required } from "@/utils/formRules"; | ||||
import { FormInstance } from "element-plus"; | import { FormInstance } from "element-plus"; | ||||
@@ -43,7 +43,7 @@ const visible = ref(false); //是否显示表单 | |||||
const dictStore = useDictStore(); //字典仓库 | const dictStore = useDictStore(); //字典仓库 | ||||
// 表单参数 | // 表单参数 | ||||
const liveUserProps = reactive<FormProps.Base<SysOrg.SysOrgInfo>>({ | |||||
const liveUserProps = reactive<FormProps.Base<any>>({ | |||||
opt: FormOptEnum.ADD, | opt: FormOptEnum.ADD, | ||||
record: {}, | record: {}, | ||||
disabled: false | disabled: false | ||||
@@ -51,25 +51,27 @@ const liveUserProps = reactive<FormProps.Base<SysOrg.SysOrgInfo>>({ | |||||
// 表单验证规则 | // 表单验证规则 | ||||
const rules = reactive({ | const rules = reactive({ | ||||
directorId: [required("请选择指定分组推送人")] | |||||
userId: [required("请选择指定推送人")] | |||||
}); | }); | ||||
/** | /** | ||||
* 打开表单 | * 打开表单 | ||||
* @param props 表单参数 | * @param props 表单参数 | ||||
*/ | */ | ||||
function onOpen(props: FormProps.Base<SysOrg.SysOrgInfo>) { | |||||
function onOpen(props: FormProps.Base<any>) { | |||||
Object.assign(liveUserProps, props); //合并参数 | Object.assign(liveUserProps, props); //合并参数 | ||||
if (props.opt == FormOptEnum.ADD) { | if (props.opt == FormOptEnum.ADD) { | ||||
//如果是新增,设置默认值 | //如果是新增,设置默认值 | ||||
} | } | ||||
visible.value = true; //显示表单 | visible.value = true; //显示表单 | ||||
// if (props.record.id) { | |||||
// //如果传了id,就去请求api获取record | |||||
// sysOrgApi.detail({ id: props.record.id }).then(res => { | |||||
// liveUserProps.record = res.data; | |||||
// }); | |||||
// } | |||||
if (props.record.pushUserId) { | |||||
//如果传了id,就去请求api获取record | |||||
liveUserProps.record.userId = props.record.pushUserId; | |||||
liveUserProps.record.userInfo = props.record.sysUserItem; | |||||
// sysOrgApi.detail({ id: props.record.id }).then(res => { | |||||
// liveUserProps.record.userId = res.data; | |||||
// }); | |||||
} | |||||
} | } | ||||
// 提交数据(新增/编辑) | // 提交数据(新增/编辑) | ||||
@@ -78,45 +80,71 @@ const userFormRef = ref<FormInstance>(); | |||||
async function handleSubmit() { | async function handleSubmit() { | ||||
userFormRef.value?.validate(async valid => { | userFormRef.value?.validate(async valid => { | ||||
if (!valid) return; //表单验证失败 | if (!valid) return; //表单验证失败 | ||||
return; | |||||
//提交表单 | |||||
await sysOrgApi | |||||
.submitForm(liveUserProps.record, liveUserProps.record.id != undefined) | |||||
.then(() => { | |||||
liveUserProps.successful!(); //调用父组件的successful方法 | |||||
}) | |||||
.finally(() => { | |||||
onClose(); | |||||
}); | |||||
console.log(liveUserProps, 888); | |||||
let params: any = { | |||||
groupId: "", | |||||
userId: "", | |||||
ids: [] | |||||
}; | |||||
if (liveUserProps.opt == "分组推送人") { | |||||
params.groupId = liveUserProps.record.id; | |||||
params.userId = liveUserProps.record.userId; | |||||
//提交表单 | |||||
await monitorLIVEApi | |||||
.setPushPerson(params) | |||||
.then(() => { | |||||
liveUserProps.successful!(); //调用父组件的successful方法 | |||||
}) | |||||
.finally(() => { | |||||
onClose(); | |||||
}); | |||||
} else { | |||||
params.userId = liveUserProps.record.userId; | |||||
params.ids.push(liveUserProps.record.id); | |||||
//提交表单 | |||||
await monitorLIVEApi | |||||
.setVideoPushPerson(params) | |||||
.then(() => { | |||||
liveUserProps.successful!(); //调用父组件的successful方法 | |||||
}) | |||||
.finally(() => { | |||||
onClose(); | |||||
}); | |||||
// delete params. | |||||
} | |||||
// console.log(params); | |||||
// return; | |||||
}); | }); | ||||
} | } | ||||
/** 关闭表单*/ | /** 关闭表单*/ | ||||
function onClose() { | function onClose() { | ||||
visible.value = false; | visible.value = false; | ||||
liveUserProps.record.userId = null; | |||||
liveUserProps.record.userInfo = null; | |||||
} | } | ||||
const userSelectorRef = ref<UserSelectorInstance>(); //用户选择器引用 | const userSelectorRef = ref<UserSelectorInstance>(); //用户选择器引用 | ||||
/** 显示用户选择器 */ | /** 显示用户选择器 */ | ||||
function showSelector() { | function showSelector() { | ||||
//将liveUserProps.record.directorInfo转为 SysUser.SysUserInfo[]类型 | |||||
const directorInfo = liveUserProps.record.directorInfo ? [liveUserProps.record.directorInfo] : []; | |||||
userSelectorRef.value?.showSelector(directorInfo); | |||||
//将liveUserProps.record.userInfo转为 SysUser.SysUserInfo[]类型 | |||||
const userInfo = liveUserProps.record.userInfo ? [liveUserProps.record.userInfo] : []; | |||||
userSelectorRef.value?.showSelector(userInfo); | |||||
} | } | ||||
/** 选择用户 */ | /** 选择用户 */ | ||||
function handleChooseUser(data: SysUser.SysUserInfo[]) { | function handleChooseUser(data: SysUser.SysUserInfo[]) { | ||||
// 选择用户后,将用户id赋值给liveUserProps.record.directorId | |||||
// 选择用户后,将用户id赋值给liveUserProps.record.userId | |||||
if (data.length > 0) { | if (data.length > 0) { | ||||
liveUserProps.record.directorId = data[0].id; | |||||
liveUserProps.record.directorInfo = data[0]; | |||||
liveUserProps.record.userId = data[0].id; | |||||
liveUserProps.record.userInfo = data[0]; | |||||
} | } | ||||
} | } | ||||
/** 移除主管 */ | /** 移除主管 */ | ||||
function removeDirector() { | function removeDirector() { | ||||
liveUserProps.record.directorId = null; | |||||
liveUserProps.record.directorInfo = null; | |||||
liveUserProps.record.userId = null; | |||||
liveUserProps.record.userInfo = null; | |||||
} | } | ||||
// 暴露给父组件的方法 | // 暴露给父组件的方法 | ||||
defineExpose({ | defineExpose({ | ||||
@@ -11,7 +11,7 @@ | |||||
<el-button icon="CirclePlus" @click="append('add', {})" type="primary">添加分组</el-button> | <el-button icon="CirclePlus" @click="append('add', {})" type="primary">添加分组</el-button> | ||||
</div> | </div> | ||||
<div class="treeContent"> | <div class="treeContent"> | ||||
<el-input v-model="filterText" style="width: 240px" placeholder="请输入关键字" /> | |||||
<el-input clearable v-model="filterText" style="width: 100%" placeholder="请输入关键字" /> | |||||
<el-tree | <el-tree | ||||
style="max-width: 600px" | style="max-width: 600px" | ||||
ref="treeRef" | ref="treeRef" | ||||
@@ -30,9 +30,11 @@ | |||||
<span class="custom-tree-node"> | <span class="custom-tree-node"> | ||||
<span class="node-label" :title="node.label">{{ node.label }}</span> | <span class="node-label" :title="node.label">{{ node.label }}</span> | ||||
<span v-if="data.id && data.id != '-1'"> | <span v-if="data.id && data.id != '-1'"> | ||||
<el-icon size="16" title="添加" @click.stop="append('add', data)"><CirclePlus /></el-icon> | |||||
<!-- <el-icon size="16" title="添加" @click.stop="append('add', 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="append('edit', data)" style="margin-left: 8px"><Edit /></el-icon> | ||||
<el-icon size="16" title="设置推送人" @click.stop="pushPerson('push', data)" style="margin-left: 8px"><UserFilled /></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> | <el-icon size="16" title="删除" @click.stop="remove(data.id, '删除该分组')" style="margin-left: 8px"><Delete /></el-icon> | ||||
</span> | </span> | ||||
</span> | </span> | ||||
@@ -58,10 +60,25 @@ | |||||
<!-- 表格 菜单类型 按钮 --> | <!-- 表格 菜单类型 按钮 --> | ||||
<!-- 操作 --> | <!-- 操作 --> | ||||
<template #operation="scope"> | <template #operation="scope"> | ||||
<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(scope.row)"> 推送人 </s-button> | |||||
<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> | </template> | ||||
</ProTable> | </ProTable> | ||||
<!-- 添加分组弹框 --> | <!-- 添加分组弹框 --> | ||||
@@ -111,21 +128,84 @@ | |||||
</div> | </div> | ||||
</div> | </div> | ||||
</template> | </template> | ||||
<script setup lang="tsx" name="sysSpa"> | |||||
<script setup lang="tsx" name="live"> | |||||
import VideoPlay from "@/components/VideoPlay/videoplay.vue"; | import VideoPlay from "@/components/VideoPlay/videoplay.vue"; | ||||
import { ElMessage, ElMessageBox, ElTree } from "element-plus"; | 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 type Node from "element-plus/es/components/tree/src/model/node"; | ||||
import { monitorLIVEApi, monitorLiveButtonCode } from "@/api"; | |||||
import { ZJRQ } from "@/api/interface"; | |||||
import { monitorLIVEApi, monitorLiveButtonCode,SysOrg,SysUserPersonnel } from "@/api"; | |||||
import { sysCamera } 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 Form from "./components/form.vue"; | ||||
import userForm from "./components/userForm.vue"; | import userForm from "./components/userForm.vue"; | ||||
import moveForm from "./components/moveForm.vue"; | import moveForm from "./components/moveForm.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"; | ||||
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 = { | const defaultProps = { | ||||
children: "children", | children: "children", | ||||
@@ -228,17 +308,10 @@ const filterNode = (value: string, data: Tree) => { | |||||
}; | }; | ||||
const handleNodeClick = (data: Tree) => { | const handleNodeClick = (data: Tree) => { | ||||
console.log(data); | |||||
// personSetId.value = val | |||||
proTable.value!.pageable.pageNum = 1; | proTable.value!.pageable.pageNum = 1; | ||||
proTable.value!.searchParam.groupId = data.id; | proTable.value!.searchParam.groupId = data.id; | ||||
proTable.value!.search(); | proTable.value!.search(); | ||||
}; | }; | ||||
// 设置分组推送人 | |||||
// async function pushPerson(type:string,data: Tree) { | |||||
// } | |||||
const visible = ref(false); //是否显示表单 | const visible = ref(false); //是否显示表单 | ||||
// 获取 ProTable 元素,调用其获取刷新数据方法(还能获取到当前查询参数,方便导出携带参数) | // 获取 ProTable 元素,调用其获取刷新数据方法(还能获取到当前查询参数,方便导出携带参数) | ||||
@@ -246,7 +319,7 @@ const proTable = ref<ProTableInstance>(); | |||||
const dictStore = useDictStore(); | const dictStore = useDictStore(); | ||||
// 表格配置项 | // 表格配置项 | ||||
const columns: ColumnProps<ZJRQ.WarnInfo>[] = [ | |||||
const columns: ColumnProps<sysCamera.MonitorInfo>[] = [ | |||||
{ type: "selection", fixed: "left", width: 80 }, | { type: "selection", fixed: "left", width: 80 }, | ||||
{ | { | ||||
prop: "sensorId", | prop: "sensorId", | ||||
@@ -285,6 +358,7 @@ function omMove(opt: FormOptEnum, record: {} | SysOrg.SysOrgInfo = {}) { | |||||
* @param ids id数组 | * @param ids id数组 | ||||
*/ | */ | ||||
async function onDelete(ids: string[], msg: string) { | async function onDelete(ids: string[], msg: string) { | ||||
console.log(1) | |||||
return; | return; | ||||
// 二次确认 => 请求api => 刷新表格 | // 二次确认 => 请求api => 刷新表格 | ||||
await useHandleData(monitorLIVEApi.delete, { ids }, msg); | await useHandleData(monitorLIVEApi.delete, { ids }, msg); | ||||
@@ -403,7 +477,7 @@ function getvideo2() { | |||||
source: detailData.videoUrl + "&subaudio=no&jitterbuffer=6000", | source: detailData.videoUrl + "&subaudio=no&jitterbuffer=6000", | ||||
// "rtsFallbackSource": "降级地址,如HLS", | // "rtsFallbackSource": "降级地址,如HLS", | ||||
width: "100%", | width: "100%", | ||||
height: "600px", | |||||
height: "500px", | |||||
autoplay: true, | autoplay: true, | ||||
isLive: true, | isLive: true, | ||||
playsinline: true, | playsinline: true, | ||||
@@ -434,7 +508,7 @@ function getvideo2() { | |||||
player.value.on("error", function (event:any) { | player.value.on("error", function (event:any) { | ||||
console.log("[EVENT]error", event.paramData); | console.log("[EVENT]error", event.paramData); | ||||
}); | }); | ||||
player.value.setVolume(0) | |||||
// 当RTS拉流成功时触发,通过订阅该事件,可以获取到RTS TraceId | // 当RTS拉流成功时触发,通过订阅该事件,可以获取到RTS TraceId | ||||
player.value.on("rtsTraceId", function (data:any) { | player.value.on("rtsTraceId", function (data:any) { | ||||
console.log("[EVENT]rtsTraceId", data.paramData); | console.log("[EVENT]rtsTraceId", data.paramData); | ||||
@@ -0,0 +1,138 @@ | |||||
<!-- | |||||
* @Description: 表单 | |||||
* @Author: huguodong | |||||
* @Date: 2023-12-15 15:45:28 | |||||
!--> | |||||
<template> | |||||
<div> | |||||
<form-container v-model="visible" title="人员选择" form-size="600px"> | |||||
<el-form | |||||
ref="userFormRef" | |||||
:rules="rules" | |||||
:disabled="liveUserProps.disabled" | |||||
:model="liveUserProps.record" | |||||
:hide-required-asterisk="liveUserProps.disabled" | |||||
label-width="auto" | |||||
label-suffix=" :" | |||||
> | |||||
<s-form-item label="指定推送人" prop="userId"> | |||||
<el-button link type="primary" @click="showSelector">选择</el-button> | |||||
<el-tag v-if="liveUserProps.record.userId" class="ml-3px" type="warning" closable @close="removeDirector">{{ | |||||
liveUserProps.record.userInfo?.name | |||||
}}</el-tag> | |||||
</s-form-item> | |||||
</el-form> | |||||
<template #footer> | |||||
<el-button @click="onClose"> 取消 </el-button> | |||||
<el-button v-show="!liveUserProps.disabled" type="primary" @click="handleSubmit"> 确定 </el-button> | |||||
</template> | |||||
</form-container> | |||||
<user-selector ref="userSelectorRef" :org-tree-api="sysOrgApi.tree" :user-selector-api="sysUserApi.selector" @successful="handleChooseUser" /> | |||||
</div> | |||||
</template> | |||||
<script setup lang="ts"> | |||||
import { SysOrg, SysUser, sysOrgApi, sysPositionApi, sysRoleApi, sysUserApi, monitorLIVEApi } from "@/api"; | |||||
import { FormOptEnum, SysDictEnum } from "@/enums"; | |||||
import { required } from "@/utils/formRules"; | |||||
import { FormInstance } from "element-plus"; | |||||
import { useDictStore } from "@/stores/modules"; | |||||
import { UserSelectorInstance } from "@/components/Selectors/UserSelector/interface"; | |||||
const visible = ref(false); //是否显示表单 | |||||
const dictStore = useDictStore(); //字典仓库 | |||||
// 表单参数 | |||||
const liveUserProps = reactive<FormProps.Base<any>>({ | |||||
opt: FormOptEnum.ADD, | |||||
record: {}, | |||||
disabled: false | |||||
}); | |||||
// 表单验证规则 | |||||
const rules = reactive({ | |||||
userId: [required("请选择指定推送人")] | |||||
}); | |||||
/** | |||||
* 打开表单 | |||||
* @param props 表单参数 | |||||
*/ | |||||
function onOpen(props: FormProps.Base<any>) { | |||||
Object.assign(liveUserProps, props); //合并参数 | |||||
if (props.opt == FormOptEnum.ADD) { | |||||
//如果是新增,设置默认值 | |||||
} | |||||
visible.value = true; //显示表单 | |||||
if (props.record.pushUserId) { | |||||
//如果传了id,就去请求api获取record | |||||
liveUserProps.record.userId = props.record.pushUserId; | |||||
liveUserProps.record.userInfo = props.record.sysUserItem; | |||||
// sysOrgApi.detail({ id: props.record.id }).then(res => { | |||||
// liveUserProps.record.userId = res.data; | |||||
// }); | |||||
} | |||||
} | |||||
// 提交数据(新增/编辑) | |||||
const userFormRef = ref<FormInstance>(); | |||||
/** 提交表单 */ | |||||
async function handleSubmit() { | |||||
userFormRef.value?.validate(async valid => { | |||||
if (!valid) return; //表单验证失败 | |||||
let params: any = { | |||||
warnCode: "", | |||||
userId: "" | |||||
}; | |||||
if (liveUserProps.opt == "预警推送人") { | |||||
params.warnCode = liveUserProps.record.warnCode; | |||||
params.userId = liveUserProps.record.userId; | |||||
//提交表单 | |||||
await monitorLIVEApi | |||||
.setWarningPushPerson(params) | |||||
.then(() => { | |||||
liveUserProps.successful!(); //调用父组件的successful方法 | |||||
}) | |||||
.finally(() => { | |||||
onClose(); | |||||
}); | |||||
} | |||||
}); | |||||
} | |||||
/** 关闭表单*/ | |||||
function onClose() { | |||||
visible.value = false; | |||||
liveUserProps.record.userId = null; | |||||
liveUserProps.record.userInfo = null; | |||||
} | |||||
const userSelectorRef = ref<UserSelectorInstance>(); //用户选择器引用 | |||||
/** 显示用户选择器 */ | |||||
function showSelector() { | |||||
//将liveUserProps.record.userInfo转为 SysUser.SysUserInfo[]类型 | |||||
const userInfo = liveUserProps.record.userInfo ? [liveUserProps.record.userInfo] : []; | |||||
userSelectorRef.value?.showSelector(userInfo); | |||||
} | |||||
/** 选择用户 */ | |||||
function handleChooseUser(data: SysUser.SysUserInfo[]) { | |||||
// 选择用户后,将用户id赋值给liveUserProps.record.userId | |||||
if (data.length > 0) { | |||||
liveUserProps.record.userId = data[0].id; | |||||
liveUserProps.record.userInfo = data[0]; | |||||
} | |||||
} | |||||
/** 移除主管 */ | |||||
function removeDirector() { | |||||
liveUserProps.record.userId = null; | |||||
liveUserProps.record.userInfo = null; | |||||
} | |||||
// 暴露给父组件的方法 | |||||
defineExpose({ | |||||
onOpen | |||||
}); | |||||
</script> | |||||
<style lang="scss" scoped></style> |
@@ -5,16 +5,32 @@ | |||||
!--> | !--> | ||||
<template> | <template> | ||||
<div class="abilityBox"> | <div class="abilityBox"> | ||||
<TreeFilter ref="treeFilter" label="name" id="id" width="300px" :request-api="monitorLIVEApi.groupList" @change="changeGroup"> </TreeFilter> | |||||
<TreeFilter ref="treeFilter" title="摄像头分组" label="name" id="id" width="300px" :request-api="monitorLIVEApi.groupList" @change="changeGroup"> | |||||
</TreeFilter> | |||||
<TreeFilter ref="treeFilters" label="sensorName" id="sensorId" :isData="true" width="300px" :data="videoList" @change="changeVideo"> </TreeFilter> | |||||
<TreeFilter | |||||
ref="treeFilters" | |||||
title="摄像头列表" | |||||
label="sensorName" | |||||
id="sensorId" | |||||
:isData="true" | |||||
width="300px" | |||||
:data="videoList" | |||||
@change="changeVideo" | |||||
> | |||||
</TreeFilter> | |||||
<div class="card content-main"> | <div class="card content-main"> | ||||
<el-collapse accordion> | <el-collapse accordion> | ||||
<el-collapse-item :name="ins" v-for="(item, ins) in warnGroupList" :key="item.cameraId[0]"> | <el-collapse-item :name="ins" v-for="(item, ins) in warnGroupList" :key="item.cameraId[0]"> | ||||
<template #title> | <template #title> | ||||
<div class="collapse-title" @click.stop=""> | <div class="collapse-title" @click.stop=""> | ||||
<div class="titlemodel">{{ item.name }} {{ item.cameraId[0] }}</div> | |||||
<div class="titlemodel"> | |||||
<div style="width: 220px; text-align: left">{{ item.name }} {{ item.cameraId[0] }}</div> | |||||
<div style="margin-left: 20px"> | |||||
<el-button @click="pushPerson(FormOptEnum.VideoPushPerson, item)" type="primary" size="small">设置推送人</el-button> | |||||
</div> | |||||
</div> | |||||
<div class="btns"> | <div class="btns"> | ||||
<el-switch v-model="item.state" @change="stateChange" /> | <el-switch v-model="item.state" @change="stateChange" /> | ||||
</div> | </div> | ||||
@@ -29,12 +45,12 @@ | |||||
</div> | </div> | ||||
</div> --> | </div> --> | ||||
<el-row :gutter="20"> | <el-row :gutter="20"> | ||||
<el-col :span="6" v-for="(v, index) in item.subset" :key="v.code"> | |||||
<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"> | ||||
<div class="modellabel">{{ v.name }}</div> | <div class="modellabel">{{ v.name }}</div> | ||||
<div class="btns"> | <div class="btns"> | ||||
<el-switch v-model="v.state" @change="stateChange" /> | |||||
<el-switch :disabled="item.state == false" v-model="v.state" @change="stateChange" /> | |||||
</div> | </div> | ||||
</div> | </div> | ||||
</el-col> | </el-col> | ||||
@@ -43,35 +59,52 @@ | |||||
</el-collapse-item> | </el-collapse-item> | ||||
</el-collapse> | </el-collapse> | ||||
</div> | </div> | ||||
<!-- 人员选择 --> | |||||
<userForm ref="userFormRef" /> | |||||
</div> | </div> | ||||
</template> | </template> | ||||
<script setup lang="tsx" name="sysSpa"> | |||||
<script setup lang="tsx" name="ability"> | |||||
import { ref, watch, provide, onMounted, unref, computed, reactive } from "vue"; | import { ref, watch, provide, onMounted, unref, computed, reactive } from "vue"; | ||||
import TreeFilter from "@/components/TreeFilter/index.vue"; | import TreeFilter from "@/components/TreeFilter/index.vue"; | ||||
import { ElMessage } from "element-plus"; | import { ElMessage } from "element-plus"; | ||||
import { abilityApi, userManageClassManageApi, monitorLIVEApi } from "@/api"; | |||||
import { abilityApi, userManageClassManageApi, monitorLIVEApi,SysOrg } from "@/api"; | |||||
// import { FormOptEnum, SysDictEnum, MenuTypeDictEnum } from "@/enums"; | |||||
import userForm from "./components/userForm.vue"; | |||||
const value = ref(true); | |||||
enum FormOptEnum { | |||||
/** 新增 */ | |||||
ADD = "新增", | |||||
/** 编辑 */ | |||||
EDIT = "编辑", | |||||
/** 查看 */ | |||||
VIEW = "查看", | |||||
/** 删除 */ | |||||
DELETE = "删除", | |||||
// 分组推送人 | |||||
GroupPushPerson = "分组推送人", | |||||
// 视频推送人 | |||||
VideoPushPerson = "视频推送人", | |||||
// 移动 | |||||
MOVE = "移动", | |||||
// 分组 | |||||
GROUP = "分组" | |||||
} | |||||
onMounted(() => { | onMounted(() => { | ||||
// 在这里执行其他需要在组件挂载后运行的代码 | // 在这里执行其他需要在组件挂载后运行的代码 | ||||
getwarnGroup(); | getwarnGroup(); | ||||
getVideoList() | |||||
getVideoList('') | |||||
}); | }); | ||||
const treeFilter = ref<InstanceType<typeof TreeFilter> | null>(null); | const treeFilter = ref<InstanceType<typeof TreeFilter> | null>(null); | ||||
const treeFilters = ref<InstanceType<typeof TreeFilter> | null>(null); | const treeFilters = ref<InstanceType<typeof TreeFilter> | null>(null); | ||||
function changeGroup(val: number | string) { | function changeGroup(val: number | string) { | ||||
console.log(val) | |||||
// personSetId.value = val | |||||
// proTable.value!.pageable.pageNum = 1; | |||||
// proTable.value!.searchParam.personSetId = val; | |||||
// proTable.value!.search(); | |||||
// getVideoList(val.id) | |||||
getVideoList(val) | |||||
} | } | ||||
const videoList = ref<any>(); | const videoList = ref<any>(); | ||||
function getVideoList() { | |||||
function getVideoList(id:any) { | |||||
console.log(id,11) | |||||
setTimeout(async () => { | setTimeout(async () => { | ||||
await monitorLIVEApi.list({ pageNum: 1, pageSize: 1000 }).then(res => { | |||||
await monitorLIVEApi.list({ pageNum: 1, pageSize: 1000, groupId:id }).then(res => { | |||||
videoList.value = res.data.list; | videoList.value = res.data.list; | ||||
}); | }); | ||||
}); | }); | ||||
@@ -87,10 +120,10 @@ function changeVideo(val: number | string) { | |||||
// 获取配置树 | // 获取配置树 | ||||
// 获取配置树 | // 获取配置树 | ||||
let warnGroupList = ref([]); | |||||
let warnGroupList = ref<any>([]); | |||||
function getwarnGroup() { | function getwarnGroup() { | ||||
setTimeout(async () => { | setTimeout(async () => { | ||||
await abilityApi.warnGroup({}).then(res => { | |||||
await abilityApi.warnGroup({}).then((res:any) => { | |||||
let { code, data } = res; | let { code, data } = res; | ||||
if (code == 200) { | if (code == 200) { | ||||
warnGroupList.value = data; | warnGroupList.value = data; | ||||
@@ -99,11 +132,15 @@ function getwarnGroup() { | |||||
}); | }); | ||||
}); | }); | ||||
} | } | ||||
const userFormRef = ref<any>(null); | |||||
function pushPerson(opt: FormOptEnum, record: {} | SysOrg.SysOrgInfo = {}) { | |||||
userFormRef.value?.onOpen({ opt: opt, record: record, successful: getwarnGroup }); | |||||
} | |||||
// 开关 | // 开关 | ||||
function stateChange() { | function stateChange() { | ||||
let params: string = JSON.stringify(warnGroupList.value); | let params: string = JSON.stringify(warnGroupList.value); | ||||
setTimeout(async () => { | setTimeout(async () => { | ||||
await abilityApi.setWarnGroup({ configJson: params }).then(res => { | |||||
await abilityApi.setWarnGroup({ configJson: params }).then((res:any) => { | |||||
let { code, data, msg } = res; | let { code, data, msg } = res; | ||||
if (code == 200 && data) { | if (code == 200 && data) { | ||||
// warnGroupList.value = data; | // warnGroupList.value = data; | ||||
@@ -137,6 +174,8 @@ function stateChange() { | |||||
justify-content: space-between; | justify-content: space-between; | ||||
order: 1; | order: 1; | ||||
.titlemodel { | .titlemodel { | ||||
display: flex; | |||||
align-items: center; | |||||
margin-right: 40px; | margin-right: 40px; | ||||
font-size: 18px; | font-size: 18px; | ||||
} | } | ||||
@@ -30,7 +30,7 @@ | |||||
</el-row> | </el-row> | ||||
<el-row :gutter="16"> | <el-row :gutter="16"> | ||||
<el-col :span="24"> | <el-col :span="24"> | ||||
<s-form-item label="上传服装" prop="faces"> | |||||
<s-form-item label="上传服装" prop="clothUrl"> | |||||
<el-upload | <el-upload | ||||
class="avatar-uploader" | class="avatar-uploader" | ||||
action="/api/business/clothApi/uploadFile" | action="/api/business/clothApi/uploadFile" | ||||
@@ -60,7 +60,7 @@ | |||||
<!-- 预览头像 --> | <!-- 预览头像 --> | ||||
<el-dialog v-model="visible" title="查看头像" width="830px" :before-close="handleClose"> | <el-dialog v-model="visible" title="查看头像" width="830px" :before-close="handleClose"> | ||||
<div style="display: flex; align-items: center; justify-content: center"> | <div style="display: flex; align-items: center; justify-content: center"> | ||||
<img style="max-width: 100%" class="detailpic" :src="faceUrl" alt="" /> | |||||
<img style="max-width: 100%; max-height: 600px" class="detailpic" :src="faceUrl" alt="" /> | |||||
</div> | </div> | ||||
<template #footer> | <template #footer> | ||||
<div class="dialog-footer"> | <div class="dialog-footer"> | ||||
@@ -57,7 +57,7 @@ | |||||
<!-- 预览头像 --> | <!-- 预览头像 --> | ||||
<el-dialog v-model="visible" title="查看头像" width="830px" :before-close="handleClose"> | <el-dialog v-model="visible" title="查看头像" width="830px" :before-close="handleClose"> | ||||
<div style="display: flex; align-items: center; justify-content: center"> | <div style="display: flex; align-items: center; justify-content: center"> | ||||
<img class="detailpic" :src="faceUrl" alt="" style="max-width: 100%" /> | |||||
<img class="detailpic" :src="faceUrl" alt="" style="max-width: 100%; max-height: 600px" /> | |||||
</div> | </div> | ||||
</el-dialog> | </el-dialog> | ||||
</div> | </div> | ||||
@@ -109,7 +109,7 @@ | |||||
<!-- 预览头像 --> | <!-- 预览头像 --> | ||||
<el-dialog v-model="visible" title="查看头像" width="830px" :before-close="handleClose"> | <el-dialog v-model="visible" title="查看头像" width="830px" :before-close="handleClose"> | ||||
<div style="display: flex; align-items: center; justify-content: center"> | <div style="display: flex; align-items: center; justify-content: center"> | ||||
<img class="detailpic" :src="faceUrl" alt="" /> | |||||
<img style="max-width: 100%; max-height: 600px" class="detailpic" :src="faceUrl" alt="" /> | |||||
</div> | </div> | ||||
</el-dialog> | </el-dialog> | ||||
</div> | </div> | ||||