@@ -24,7 +24,6 @@ declare module 'vue' { | |||||
ElBreadcrumbItem: typeof import('element-plus/es')['ElBreadcrumbItem'] | ElBreadcrumbItem: typeof import('element-plus/es')['ElBreadcrumbItem'] | ||||
ElButton: typeof import('element-plus/es')['ElButton'] | ElButton: typeof import('element-plus/es')['ElButton'] | ||||
ElCheckbox: typeof import('element-plus/es')['ElCheckbox'] | ElCheckbox: typeof import('element-plus/es')['ElCheckbox'] | ||||
ElCol: typeof import('element-plus/es')['ElCol'] | |||||
ElColorPicker: typeof import('element-plus/es')['ElColorPicker'] | ElColorPicker: typeof import('element-plus/es')['ElColorPicker'] | ||||
ElContainer: typeof import('element-plus/es')['ElContainer'] | ElContainer: typeof import('element-plus/es')['ElContainer'] | ||||
ElDialog: typeof import('element-plus/es')['ElDialog'] | ElDialog: typeof import('element-plus/es')['ElDialog'] | ||||
@@ -43,13 +42,10 @@ declare module 'vue' { | |||||
ElMain: typeof import('element-plus/es')['ElMain'] | ElMain: typeof import('element-plus/es')['ElMain'] | ||||
ElMenu: typeof import('element-plus/es')['ElMenu'] | ElMenu: typeof import('element-plus/es')['ElMenu'] | ||||
ElMenuItem: typeof import('element-plus/es')['ElMenuItem'] | ElMenuItem: typeof import('element-plus/es')['ElMenuItem'] | ||||
ElOption: typeof import('element-plus/es')['ElOption'] | |||||
ElPagination: typeof import('element-plus/es')['ElPagination'] | ElPagination: typeof import('element-plus/es')['ElPagination'] | ||||
ElPopover: typeof import('element-plus/es')['ElPopover'] | ElPopover: typeof import('element-plus/es')['ElPopover'] | ||||
ElRadio: typeof import('element-plus/es')['ElRadio'] | ElRadio: typeof import('element-plus/es')['ElRadio'] | ||||
ElRow: typeof import('element-plus/es')['ElRow'] | |||||
ElScrollbar: typeof import('element-plus/es')['ElScrollbar'] | ElScrollbar: typeof import('element-plus/es')['ElScrollbar'] | ||||
ElSelect: typeof import('element-plus/es')['ElSelect'] | |||||
ElSpace: typeof import('element-plus/es')['ElSpace'] | ElSpace: typeof import('element-plus/es')['ElSpace'] | ||||
ElSubMenu: typeof import('element-plus/es')['ElSubMenu'] | ElSubMenu: typeof import('element-plus/es')['ElSubMenu'] | ||||
ElSwitch: typeof import('element-plus/es')['ElSwitch'] | ElSwitch: typeof import('element-plus/es')['ElSwitch'] | ||||
@@ -59,6 +55,8 @@ declare module 'vue' { | |||||
ElTabs: typeof import('element-plus/es')['ElTabs'] | ElTabs: typeof import('element-plus/es')['ElTabs'] | ||||
ElTag: typeof import('element-plus/es')['ElTag'] | ElTag: typeof import('element-plus/es')['ElTag'] | ||||
ElTooltip: typeof import('element-plus/es')['ElTooltip'] | ElTooltip: typeof import('element-plus/es')['ElTooltip'] | ||||
ElTree: typeof import('element-plus/es')['ElTree'] | |||||
ElTreeSelect: typeof import('element-plus/es')['ElTreeSelect'] | |||||
ESign: typeof import('./src/components/ESign/index.vue')['default'] | ESign: typeof import('./src/components/ESign/index.vue')['default'] | ||||
FormContainer: typeof import('./src/components/Form/FormContainer/index.vue')['default'] | FormContainer: typeof import('./src/components/Form/FormContainer/index.vue')['default'] | ||||
Grid: typeof import('./src/components/Grid/index.vue')['default'] | Grid: typeof import('./src/components/Grid/index.vue')['default'] | ||||
@@ -2,7 +2,7 @@ | |||||
<html lang="en"> | <html lang="en"> | ||||
<head> | <head> | ||||
<meta charset="UTF-8" /> | <meta charset="UTF-8" /> | ||||
<link rel="icon" href="/qjkj.ico" /> | |||||
<link rel="icon" href="/api/sys/ico" /> | |||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> | <meta name="viewport" content="width=device-width, initial-scale=1.0" /> | ||||
<title><%- title %></title> | <title><%- title %></title> | ||||
<!-- <script src="https://unpkg.com/aliyun-rts-sdk@1.2.1/dist/aliyun-rts-sdk.js"></script> --> | <!-- <script src="https://unpkg.com/aliyun-rts-sdk@1.2.1/dist/aliyun-rts-sdk.js"></script> --> | ||||
@@ -0,0 +1,86 @@ | |||||
<!DOCTYPE html> | |||||
<html> | |||||
<head> | |||||
<meta charset="utf-8"> | |||||
<meta http-equiv="x-ua-compatible" content="IE=edge"> | |||||
<meta name="viewport" | |||||
content="width=device-width, height=device-height, initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no" /> | |||||
<title>Aliplayer Rts Demo</title> | |||||
<link rel="stylesheet" | |||||
href="https://g.alicdn.com/apsara-media-box/imp-web-player/2.16.3/skins/default/aliplayer-min.css" /> | |||||
<script type="text/javascript" charset="utf-8" | |||||
src="https://g.alicdn.com/apsara-media-box/imp-web-player/2.16.3/aliplayer-min.js"></script> | |||||
</head> | |||||
<body style="margin: 0;"> | |||||
<div class="prism-player" id="player-con"></div> | |||||
<script> | |||||
// 使用: /static/rtsPlayer.html?rtsUrl= | |||||
/** | |||||
* 播放器默认播放 source 提供的 rts 拉流地址,如果失败,则会自动降级至 rtsFallbackSource 提供的拉流地址(如 HLS 地址)。 | |||||
* 可能的降级场景包括: | |||||
* 1. 浏览器不支持 RTS,直接降级 | |||||
* 2. RTS 信令请求失败(拉流地址无效、https配置无效、RTS配置无效等),直接降级 | |||||
* 3. RTS 起播超时或中途断流,按自定义策略重试失败后降级 | |||||
**/ | |||||
// 更多播放器配置请参考 https://player.alicdn.com/aliplayer/index.html | |||||
let rtsUrl = getUrlParams(location.href)['rtsUrl'] || '' | |||||
var options = { | |||||
"id": "player-con", | |||||
"source": rtsUrl, | |||||
"rtsFallbackSource": "降级地址,如HLS", | |||||
"width": "100%", | |||||
"height": "500px", | |||||
"autoplay": true, | |||||
"isLive": true, | |||||
"playsinline": true, | |||||
"skipRtsSupportCheck": false, // 对于不在 https://help.aliyun.com/document_detail/397569.html 中的浏览器,可以传 true 跳过检查,强制使用 RTS(有风险,需要自测保证) | |||||
/** | |||||
* RTS 拉流超时会默认重试 | |||||
* 以下两个参数用来控制降级之前的重试策略,比如 3000 毫秒超时,重试一次,如果再拉不到流就降级,那么总共等待 6000 毫秒降级 | |||||
**/ | |||||
// RTS 多久拉不到流会重试,默认 3000 ms | |||||
// rtsLoadDataTimeout: 2000, | |||||
// RTS 拉不到流重试的次数,默认 5,此参数建议设为 1,即重试 1 次后降级,可以减少降级等待时间 | |||||
liveRetry: 1, | |||||
}; | |||||
var player = new Aliplayer(options, function () {/* player ready */ }); | |||||
// 降级时会触发此事件 | |||||
player.on('rtsFallback', function (event) { | |||||
console.log('[EVENT]rtsFallback', event.paramData); | |||||
// event.paramData.reason 降级的原因 | |||||
// event.paramData.fallbackUrl 降级到的地址 | |||||
}) | |||||
player.on('error', function (event) { | |||||
console.log('[EVENT]error', event.paramData); | |||||
}) | |||||
// 当RTS拉流成功时触发,通过订阅该事件,可以获取到RTS TraceId | |||||
player.on('rtsTraceId', function (data) { | |||||
console.log('[EVENT]rtsTraceId', data.paramData); | |||||
// event.paramData.traceId 拉流的TraceId | |||||
// event.paramData.source 当前RTS流的播放地址 | |||||
}) | |||||
function getUrlParams(url) { | |||||
const reg = /(\w+)=([^&]+)/g; | |||||
const params = {}; | |||||
let match; | |||||
while ((match = reg.exec(url)) !== null) { | |||||
params[match[1]] = match[2]; | |||||
} | |||||
return params; | |||||
} | |||||
</script> | |||||
</body> |
@@ -51,6 +51,11 @@ export interface ReqId { | |||||
/** id */ | /** id */ | ||||
id: number | string; | id: number | string; | ||||
} | } | ||||
/** id请求参数 */ | |||||
export interface ReqPersonId { | |||||
/** id */ | |||||
personId: number | string; | |||||
} | |||||
/** id请求参数 */ | /** id请求参数 */ | ||||
export interface ReqstartId { | export interface ReqstartId { | ||||
@@ -68,7 +73,6 @@ export interface ReqstopId { | |||||
} | } | ||||
export interface setWarn { | export interface setWarn { | ||||
configJson: string; | configJson: string; | ||||
} | } | ||||
@@ -20,3 +20,4 @@ export * from "./audit"; | |||||
export * from "./organization"; | export * from "./organization"; | ||||
export * from "./auth"; | export * from "./auth"; | ||||
export * from "./warn"; | export * from "./warn"; | ||||
export * from "./usermanage"; |
@@ -0,0 +1,15 @@ | |||||
/** | |||||
* @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 "./personnel"; |
@@ -0,0 +1,67 @@ | |||||
/** | |||||
* @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: syy | |||||
* @Date: 2023-12-15 15:34:54 | |||||
*/ | |||||
export namespace SysUserPersonnel { | |||||
export interface Page extends ReqPage {} | |||||
/** 底库信息 */ | |||||
export interface ClassPage { | |||||
personSetId?: string | number | undefined; | |||||
personSetName?: string | undefined; | |||||
id?: string | undefined; | |||||
name?: string | undefined; | |||||
personId?: string | undefined | number; | |||||
} | |||||
/** 人脸信息 */ | |||||
export interface SysUserAvatar { | |||||
/** 人脸 */ | |||||
personId?: string | undefined | number; | |||||
faceId?: string | number; | |||||
faceUrl: string; | |||||
uid?: string | number; | |||||
} | |||||
// 人脸删除 | |||||
export interface SysUserFace { | |||||
personId: string | undefined; | |||||
faceIds: Array<string | number>; | |||||
} | |||||
/** 用户信息 */ | |||||
export interface SysUserPerInfo { | |||||
/** 人员id */ | |||||
personId?: string; | |||||
/** 姓名 */ | |||||
name?: string; | |||||
/** 年龄 */ | |||||
age?: number | string; | |||||
/** 性别 */ | |||||
gender?: string; | |||||
/** 手机 */ | |||||
phone?: string; | |||||
/** 扩展字段 */ | |||||
extData?: string; | |||||
/** 人脸 */ | |||||
faces: Array<SysUserAvatar>; | |||||
/** 分组 */ | |||||
personSets: Array<ClassPage>; | |||||
personSetId?: number | string; | |||||
} | |||||
} |
@@ -19,4 +19,4 @@ export * from "./warn"; | |||||
export * from "./monitor"; | export * from "./monitor"; | ||||
export * from "./sysconfig"; | export * from "./sysconfig"; | ||||
export * from "./statistion"; | export * from "./statistion"; | ||||
export * from "./usermanage"; |
@@ -36,5 +36,22 @@ const monitorLIVEApi = { | |||||
}, | }, | ||||
}; | }; | ||||
/** | |||||
* @Description: 监控管理按钮权限码 | |||||
* @Author: huguodong | |||||
* @Date: 2024-02-20 09:51:15 | |||||
*/ | |||||
const monitorLiveButtonCode = { | |||||
/** 新增监控 */ | |||||
add: "monitorLiveAdd", | |||||
/** 编辑监控 */ | |||||
edit: "monitorLiveEdit", | |||||
/** 删除监控 */ | |||||
delete: "monitorLiveDelete", | |||||
/** 批量删除监控 */ | |||||
batchDelete: "monitorLiveBatchDelete", | |||||
/** 复制监控 */ | |||||
copy: "monitorLiveCopy" | |||||
}; | |||||
export { monitorLIVEApi }; | |||||
export { monitorLIVEApi, monitorLiveButtonCode }; |
@@ -0,0 +1,52 @@ | |||||
/** | |||||
* @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 userManageClassManageApi = { | |||||
/** 查询底库列表 */ | |||||
page(params: SysUserPersonnel.ClassPage) { | |||||
return http.get("queryAll", params); | |||||
}, | |||||
/** 删除底库 */ | |||||
delete(params: ReqId) { | |||||
return http.delete("deleteDfieldD", params); | |||||
}, | |||||
/** 创建底库 */ | |||||
add(params: SysUserPersonnel.ClassPage) { | |||||
return http.post("createDfieldA", params); | |||||
}, | |||||
/** 更新底库 */ | |||||
update(params: SysUserPersonnel.ClassPage) { | |||||
return http.put("updateDfieldU", params); | |||||
} | |||||
}; | |||||
const userClassButtonCode = { | |||||
/** 新增人员 */ | |||||
add: "userManageClassManageAdd", | |||||
/** 删除人员 */ | |||||
edit: "userManageClassManageEdit", | |||||
/** 删除人员 */ | |||||
delete: "userManageClassManageDelete" | |||||
}; | |||||
export { userManageClassManageApi, userClassButtonCode }; |
@@ -0,0 +1,16 @@ | |||||
/** | |||||
* @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 "./personnel"; | |||||
export * from "./classManage"; |
@@ -0,0 +1,72 @@ | |||||
/** | |||||
* @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, ResPage, ReqPersonId, SysUserPersonnel } from "@/api/interface"; | |||||
const http = moduleRequest("/business/personApi/"); | |||||
/** | |||||
* @Description: 单页管理 | |||||
* @Author: SYY | |||||
* @Date: 2023-12-15 15:34:54 | |||||
*/ | |||||
const userManagePersonnelApi = { | |||||
/** 获取单页分页 */ | |||||
page(params: SysUserPersonnel.Page) { | |||||
return http.post("pageQuery", params); | |||||
}, | |||||
/** 获取单页详情 */ | |||||
detail(params: ReqId) { | |||||
return http.get("getPersionById", params); | |||||
}, | |||||
/** 删除人员 */ | |||||
delete(params: ReqId) { | |||||
return http.delete("deletePersonD", params); | |||||
}, | |||||
/** 新增人员 */ | |||||
add(params: SysUserPersonnel.SysUserPerInfo) { | |||||
return http.post("createPersonA", params); | |||||
}, | |||||
/** 修改人员 */ | |||||
update(params: SysUserPersonnel.SysUserPerInfo) { | |||||
return http.put("updatePersionU", params); | |||||
}, | |||||
/** 添加人脸 */ | |||||
addFace(params: SysUserPersonnel.SysUserAvatar) { | |||||
return http.post("addFaceA", params); | |||||
}, | |||||
/** 删除人脸 */ | |||||
deleteFace(params: SysUserPersonnel.SysUserFace) { | |||||
return http.post("deleteFaceD", params); | |||||
}, | |||||
/**底库绑定 */ | |||||
personBindDfie(params: SysUserPersonnel.ClassPage) { | |||||
return http.post("personBindDfie", params); | |||||
}, | |||||
/**底库解绑*/ | |||||
personUnBindDfie(params: SysUserPersonnel.ClassPage) { | |||||
return http.post("personUnBindDfie", params); | |||||
} | |||||
}; | |||||
const userPerButtonCode = { | |||||
/** 新增人员 */ | |||||
add: "userManagePersonnelAdd", | |||||
/** 删除人员 */ | |||||
edit: "userManagePersonnelEdit", | |||||
/** 删除人员 */ | |||||
delete: "userManagePersonnelDelete" | |||||
}; | |||||
export { userManagePersonnelApi, userPerButtonCode }; |
@@ -38,6 +38,10 @@ const warnZJRQApi = { | |||||
warnGroup(params: ReqId) { | warnGroup(params: ReqId) { | ||||
return http.get("getInfo", params); | return http.get("getInfo", params); | ||||
}, | }, | ||||
/** 获取告警分组 */ | |||||
warnType(params: ReqId) { | |||||
return http.get("getAlarmType", params); | |||||
}, | |||||
}; | }; | ||||
export { warnZJRQApi }; | export { warnZJRQApi }; |
@@ -0,0 +1,246 @@ | |||||
<!-- | |||||
* @Description: 用户选择器 | |||||
* @Author: huguodong | |||||
* @Date: 2023-12-15 15:40:45 | |||||
!--> | |||||
<template> | |||||
<form-container v-model="visible" :title="`${userName}选择`" form-size="90%" v-bind="$attrs"> | |||||
<div class="-mt-15px min-h-350px"> | |||||
<el-row :gutter="12" justify="space-between"> | |||||
<el-col :span="4"> | |||||
<el-tabs v-model="activeName" type="card" stretch class="min-h-350px"> | |||||
<el-tab-pane :label="`${orgName}`" class="ml-5px mr-5px" name="org"> | |||||
<el-scrollbar max-height="650px"> | |||||
<TreeFilter | |||||
label="name" | |||||
class="filterWidth" | |||||
:title="`${orgName}列表`" | |||||
:show-all="!biz" | |||||
:default-expand-all="false" | |||||
:request-api="orgTreeApi" | |||||
@change="changeOrgTreeFilter" | |||||
/> | |||||
</el-scrollbar> | |||||
</el-tab-pane> | |||||
<!-- <el-tab-pane v-if="positionTreeApi" :label="`${positionName}`" class="ml-5px mr-5px" name="pos"> | |||||
<el-scrollbar max-height="650px"> | |||||
<TreeFilter | |||||
label="name" | |||||
class="filterWidth" | |||||
:title="`${positionName}列表`" | |||||
:show-all="!biz" | |||||
:default-expand-all="false" | |||||
:request-api="positionTreeApi" | |||||
@change="changePositionTreeFilter" | |||||
/> | |||||
</el-scrollbar> | |||||
</el-tab-pane> | |||||
<el-tab-pane v-if="roleTreeApi" label="角色" class="ml-5px mr-5px" name="role"> | |||||
<el-scrollbar max-height="650px"> | |||||
<TreeFilter | |||||
label="name" | |||||
class="filterWidth" | |||||
title="角色列表" | |||||
:show-all="!biz" | |||||
:default-expand-all="false" | |||||
:request-api="roleTreeApi" | |||||
@change="changeRoleTreeFilter" | |||||
/> | |||||
</el-scrollbar> | |||||
</el-tab-pane> --> | |||||
</el-tabs> | |||||
</el-col> | |||||
<el-col :span="10"> | |||||
<ProTable ref="userTable" :columns="columns" :tool-button="false" :init-param="initParam" :request-api="userSelectorApi"> | |||||
<!-- 表格 header 按钮 --> | |||||
<template #tableHeader="scope"> | |||||
<el-button type="primary" @click="addRecords(userTable!.tableData)">添加当前</el-button> | |||||
<el-button type="primary" plain :disabled="!scope.isSelected" @click="addRecords(scope.selectedList)">添加选中</el-button> | |||||
</template> | |||||
<!-- 操作 --> | |||||
<template #operation="scope"> | |||||
<el-button type="primary" link :icon="Plus" plain @click="addRecords([scope.row])">添加</el-button> | |||||
</template> | |||||
</ProTable> | |||||
</el-col> | |||||
<el-col :span="10"> | |||||
<ProTable ref="chooseTable" :columns="columns" :tool-button="true" :data="chooseDataTmp" @search="searchRecords" @reset="resetRecords"> | |||||
<!-- 表格 header 按钮 --> | |||||
<template #tableHeader="scope"> | |||||
<el-button type="danger" @click="delRecords(chooseTable!.tableData)">删除当前</el-button> | |||||
<el-button type="danger" plain :disabled="!scope.isSelected" @click="delRecords(scope.selectedList)">删除选中</el-button> | |||||
</template> | |||||
<template #toolButton> | |||||
<span>已选择:{{ chooseData.length }}人</span> | |||||
<span v-if="maxCount">,最多选择:{{ maxCount }}人</span> | |||||
</template> | |||||
<!-- 操作 --> | |||||
<template #operation="scope"> | |||||
<el-button type="danger" link :icon="Delete" plain @click="delRecords([scope.row])">删除</el-button> | |||||
</template> | |||||
</ProTable> | |||||
</el-col> | |||||
</el-row> | |||||
</div> | |||||
<template #footer> | |||||
<div class="mt-20px"> | |||||
<el-button @click="onClose"> 取消 </el-button> | |||||
<el-button type="primary" @click="handleOk"> 确定 </el-button> | |||||
</div> | |||||
</template> | |||||
</form-container> | |||||
</template> | |||||
<script setup lang="ts" name="UserSelector"> | |||||
import { SysUser, SysPosition, SysRole } from "@/api"; | |||||
import { UserSelectProps, UserSelectTableInitParams } from "./interface"; | |||||
import { ColumnProps, ProTableInstance } from "@/components/ProTable/interface"; | |||||
import { ElMessage } from "element-plus"; | |||||
import { Plus, Delete } from "@element-plus/icons-vue"; | |||||
const activeName = ref("org"); | |||||
const emit = defineEmits({ successful: null }); // 自定义事件 | |||||
// const handleClick = (tab: TabsPaneContext, event: Event) => { | |||||
// console.log(tab, event); | |||||
// }; | |||||
const visible = ref(false); //是否显示 | |||||
// 定义组件props | |||||
const props = withDefaults(defineProps<UserSelectProps>(), { | |||||
multiple: false, | |||||
biz: false | |||||
}); | |||||
// 根据是否业务显示不同名称 | |||||
const userName = props.biz ? "人员" : "用户"; | |||||
const positionName = props.biz ? "职位" : "岗位"; | |||||
const orgName = props.biz ? "机构" : "班级"; | |||||
// 如果表格需要初始化请求参数,直接定义传给 ProTable(之后每次请求都会自动带上该参数,此参数更改之后也会一直带上,改变此参数会自动刷新表格数据) | |||||
const initParam = reactive<UserSelectTableInitParams>({}); | |||||
// 获取 userTable 元素,调用其获取刷新数据方法(还能获取到当前查询参数,方便导出携带参数) | |||||
const userTable = ref<ProTableInstance>(); | |||||
// 获取 chooseTable 元素,调用其获取刷新数据方法(还能获取到当前查询参数,方便导出携带参数) | |||||
const chooseTable = ref<ProTableInstance>(); | |||||
// 表格配置项 | |||||
const columns: ColumnProps<SysUser.SysUserInfo>[] = [ | |||||
{ type: "selection", fixed: "left", width: 50 }, | |||||
{ prop: "operation", label: "操作", width: 80, fixed: "left" }, | |||||
{ prop: "account", label: "账号", search: { el: "input", span: 2 } }, | |||||
{ prop: "name", label: "姓名" } | |||||
]; | |||||
/** 显示选择器 */ | |||||
function showSelector(data: SysUser.SysUserInfo[] = []) { | |||||
visible.value = true; | |||||
chooseDataTmp.value = data; | |||||
chooseData.value = data; | |||||
} | |||||
/** 关闭选择器 */ | |||||
function onClose() { | |||||
visible.value = false; | |||||
chooseDataTmp.value = []; | |||||
chooseData.value = []; | |||||
} | |||||
/** 提交数据 */ | |||||
function handleOk() { | |||||
visible.value = false; | |||||
emit("successful", chooseData.value); | |||||
} | |||||
/** 部门切换 */ | |||||
function changeOrgTreeFilter(val: number | string) { | |||||
userTable.value!.pageable.pageNum = 1; | |||||
if (val != "") { | |||||
// 如果传入的val不为空 | |||||
initParam.orgId = val; | |||||
} else { | |||||
initParam.orgId = null; | |||||
} | |||||
} | |||||
/** 职位切换 */ | |||||
function changePositionTreeFilter(val: number | string, data: SysPosition.SysPositionTree) { | |||||
userTable.value!.pageable.pageNum = 1; | |||||
if (data.isPosition) { | |||||
// 如果是职位 | |||||
initParam.positionId = val; | |||||
} else { | |||||
initParam.positionId = null; | |||||
} | |||||
} | |||||
/** 角色切换 */ | |||||
function changeRoleTreeFilter(val: number | string, data: SysRole.SysRoleTree) { | |||||
userTable.value!.pageable.pageNum = 1; | |||||
if (data.isRole) { | |||||
// 如果是角色 | |||||
initParam.roleId = val; | |||||
} else { | |||||
// 置空 | |||||
initParam.roleId = null; | |||||
} | |||||
} | |||||
const chooseData = ref<SysUser.SysUserInfo[]>([]); //选择的数据 | |||||
const chooseDataTmp = ref<SysUser.SysUserInfo[]>([]); //临时选择的数据 | |||||
/** 添加记录 */ | |||||
function addRecords(records: any[]) { | |||||
//如果不是多选,判断是否已经添加了 | |||||
if (!props.multiple) { | |||||
if (chooseData.value.length > 0 || records.length > 1) { | |||||
ElMessage.warning("只可选择一条"); | |||||
return; | |||||
} | |||||
chooseData.value = records; | |||||
chooseDataTmp.value = chooseData.value; | |||||
} else { | |||||
//如果是多选,先判断已添加列表是否有重复,有则过滤掉,没有则直接添加 | |||||
records = records.filter(item => !chooseData.value.find(it => it.id == item.id)); | |||||
if (props.maxCount && props.maxCount < records.length + chooseData.value.length) { | |||||
ElMessage.warning("最多选择" + props.maxCount + "条"); | |||||
return; | |||||
} | |||||
chooseData.value = chooseData.value.concat(records); //添加到已选中列表 | |||||
chooseDataTmp.value = chooseData.value; | |||||
} | |||||
chooseTable.value?.refresh(); //刷新表格 | |||||
} | |||||
/** 删除记录 */ | |||||
function delRecords(records: any[]) { | |||||
chooseData.value = chooseData.value.filter(item => !records.includes(item)); //过滤掉已选中的 | |||||
chooseDataTmp.value = chooseData.value; | |||||
chooseTable.value?.refresh(); //刷新表格 | |||||
} | |||||
/** 搜索记录 */ | |||||
function searchRecords() { | |||||
if (chooseTable.value?.searchParam?.account) { | |||||
//搜索account符合的记录 | |||||
chooseDataTmp.value = chooseDataTmp.value.filter(item => item.account.includes(chooseTable.value?.searchParam.account)); //过滤掉已选中的 | |||||
chooseTable.value?.refresh(); //刷新表格 | |||||
} | |||||
} | |||||
/** 重置记录 */ | |||||
function resetRecords() { | |||||
chooseDataTmp.value = chooseData.value; | |||||
chooseTable.value?.refresh(); //刷新表格 | |||||
} | |||||
// 暴露方法 | |||||
defineExpose({ showSelector }); | |||||
</script> | |||||
<style lang="scss" scoped> | |||||
.filterWidth { | |||||
width: 100%; | |||||
} | |||||
:deep(.el-tabs--border-card > .el-tabs__content) { | |||||
padding: 5px; | |||||
} | |||||
:deep(.table-main) { | |||||
height: 90%; | |||||
} | |||||
</style> |
@@ -0,0 +1,48 @@ | |||||
/** | |||||
* @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 UserSelector from "./index.vue"; | |||||
/** 用户选择器属性 */ | |||||
export interface UserSelectProps { | |||||
/** 组织树api */ | |||||
orgTreeApi: (data?: any) => Promise<any>; | |||||
/** 职位选择api */ | |||||
positionTreeApi?: (data?: any) => Promise<any>; | |||||
/** 角色选择api */ | |||||
roleTreeApi?: (data?: any) => Promise<any>; | |||||
/** 用户选择api */ | |||||
userSelectorApi: (data?: any) => Promise<any>; | |||||
/** 是否多选 */ | |||||
multiple?: boolean; | |||||
/** 最大用户数 */ | |||||
maxCount?: number; | |||||
/** 是否是业务 */ | |||||
biz?: boolean; | |||||
} | |||||
/** 用户选择器表格初始化参数 */ | |||||
export interface UserSelectTableInitParams { | |||||
/** 组织ID */ | |||||
orgId?: number | string | null; | |||||
/** 职位ID */ | |||||
positionId?: number | string | null; | |||||
/** 角色ID */ | |||||
roleId?: number | string | null; | |||||
} | |||||
/** | |||||
* @description 用户选择器实例类型 | |||||
*/ | |||||
export type UserSelectorInstance = Omit<InstanceType<typeof UserSelector>, keyof ComponentPublicInstance | keyof UserSelectProps>; |
@@ -1,9 +1,11 @@ | |||||
<template> | <template> | ||||
<div class="card filter"> | |||||
<div class="card filter" :style="{ width: width }"> | |||||
<h4 v-if="title" class="title sle"> | <h4 v-if="title" class="title sle"> | ||||
{{ title }} | {{ title }} | ||||
</h4> | </h4> | ||||
<slot name="header"></slot> | |||||
<el-input v-model="filterText" placeholder="输入关键字进行过滤" clearable /> | <el-input v-model="filterText" placeholder="输入关键字进行过滤" clearable /> | ||||
<el-scrollbar :style="{ height: title ? `calc(100% - 95px)` : `calc(100% - 56px)` }"> | <el-scrollbar :style="{ height: title ? `calc(100% - 95px)` : `calc(100% - 56px)` }"> | ||||
<el-tree | <el-tree | ||||
ref="treeRef" | ref="treeRef" | ||||
@@ -24,8 +26,8 @@ | |||||
@check="handleCheckChange" | @check="handleCheckChange" | ||||
> | > | ||||
<template #default="scope"> | <template #default="scope"> | ||||
<span class="el-tree-node__label"> | |||||
<slot :row="scope"> | |||||
<span class="el-tree-node__label" style="width: 100%"> | |||||
<slot :row="scope" name="label"> | |||||
{{ scope.node.label }} | {{ scope.node.label }} | ||||
</slot> | </slot> | ||||
</span> | </span> | ||||
@@ -53,6 +55,7 @@ interface TreeFilterProps { | |||||
checkStrictly?: boolean; // 是否开启子节点和父节点不关联 ==> 非必传,默认为 false | checkStrictly?: boolean; // 是否开启子节点和父节点不关联 ==> 非必传,默认为 false | ||||
topName?: string; // 顶级分类名称 ==> 非必传,默认为 “全部” | topName?: string; // 顶级分类名称 ==> 非必传,默认为 “全部” | ||||
showAll?: boolean; // 是否显示全部选项 ==> 非必传,默认为 true | showAll?: boolean; // 是否显示全部选项 ==> 非必传,默认为 true | ||||
width: string; | |||||
} | } | ||||
const props = withDefaults(defineProps<TreeFilterProps>(), { | const props = withDefaults(defineProps<TreeFilterProps>(), { | ||||
id: "id", | id: "id", | ||||
@@ -1,7 +1,7 @@ | |||||
<template> | <template> | ||||
<div class="footer flx-center"> | <div class="footer flx-center"> | ||||
<!-- <a :href="props.sysCopyrightUrl" target="_blank"> {{ props.sysCopyright }} </a> | |||||
<a v-for="link in props.footerLinks" :key="link.name" :href="link.url" target="_blank" class="mx-1"> | {{ link.name }}</a> --> | |||||
<a :href="props.sysCopyrightUrl" target="_blank"> {{ props.sysCopyright }} </a> | |||||
<a v-for="link in props.footerLinks" :key="link.name" :href="link.url" target="_blank" class="mx-1"> | {{ link.name }}</a> | |||||
</div> | </div> | ||||
</template> | </template> | ||||
<script setup lang="ts"> | <script setup lang="ts"> | ||||
@@ -249,13 +249,25 @@ | |||||
/* el-dialog */ | /* el-dialog */ | ||||
.el-dialog { | .el-dialog { | ||||
padding: 0 !important; | |||||
.el-dialog__header { | .el-dialog__header { | ||||
padding: 15px 20px; | |||||
padding: 16px; | |||||
margin: 0; | margin: 0; | ||||
border-bottom: 1px solid var(--el-border-color-lighter); | border-bottom: 1px solid var(--el-border-color-lighter); | ||||
.el-dialog__title { | .el-dialog__title { | ||||
font-size: 17px; | font-size: 17px; | ||||
} | } | ||||
.el-dialog__headerbtn { | |||||
top: 6px; | |||||
} | |||||
} | |||||
.el-dialog__body { | |||||
padding: 20px; | |||||
} | |||||
.el-dialog__footer { | |||||
box-sizing: border-box; | |||||
padding: 15px 16px; | |||||
border-top: 1px solid var(--el-border-color-lighter); | |||||
} | } | ||||
} | } | ||||
@@ -1,12 +1,60 @@ | |||||
.home { | .home { | ||||
display: flex; | |||||
align-items: center; | |||||
justify-content: center; | |||||
width: 100%; | width: 100%; | ||||
height: 100%; | height: 100%; | ||||
.home-bg { | .home-bg { | ||||
width: 70%; | |||||
max-width: 1200px; | |||||
margin-bottom: 20px; | |||||
margin-bottom: 15px; | |||||
height: 390px; | |||||
// height: 424px; | |||||
.home-bg-title { | |||||
display: flex; | |||||
height: 50px; | |||||
align-items: center; | |||||
div:first-child { | |||||
height: 15px; | |||||
width: 4px; | |||||
background: #3a84ff; | |||||
margin-right: 10px; | |||||
} | |||||
div:nth-child(2) { | |||||
font-size: 20px; | |||||
font-weight: 600; | |||||
margin-left: 10px; | |||||
} | |||||
} | |||||
.home-bg-content { | |||||
height: calc(100% - 50px); | |||||
.home-bg-content-item { | |||||
margin-left: 15px; | |||||
margin-top: 60px; | |||||
display: flex; | |||||
align-items: center; | |||||
.home-bg-content-item-icon { | |||||
margin-right: 15px; | |||||
width: 70px; | |||||
height: 70px; | |||||
img { | |||||
width: 100%; | |||||
height: 100%; | |||||
} | |||||
} | |||||
.home-bg-content-item-content { | |||||
.home-bg-content-item-title { | |||||
} | |||||
.home-bg-content-item-value { | |||||
margin-top: 10px; | |||||
font-size: 20px; | |||||
font-weight: 600; | |||||
// color: #3a84ff; | |||||
} | |||||
} | |||||
} | |||||
} | |||||
.handleBox ::v-deep(.card) { | |||||
padding:0; | |||||
} | |||||
} | |||||
.topCard { | |||||
height: 355px; | |||||
} | } | ||||
} | } |
@@ -1,10 +1,387 @@ | |||||
<template> | <template> | ||||
<div class="home card"> | |||||
<img class="home-bg" src="@/assets/images/welcome.png" alt="welcome" /> | |||||
<div class="home"> | |||||
<el-row :gutter="20"> | |||||
<el-col :xs="24" :sm="24" :md="12" :lg="12" :xl="8"> | |||||
<div class="home-bg card"> | |||||
<div class="home-bg-title"> | |||||
<div></div> | |||||
<div>基础数据</div> | |||||
</div> | |||||
<div class="home-bg-content"> | |||||
<el-row :gutter="20"> | |||||
<el-col :span="12" | |||||
><div class="home-bg-content-item"> | |||||
<div class="home-bg-content-item-icon"> | |||||
<img src="@/assets/images/home/carame.png" alt="" /> | |||||
</div> | |||||
<div class="home-bg-content-item-content"> | |||||
<div class="home-bg-content-item-title">摄像头数量</div> | |||||
<div class="home-bg-content-item-value">3</div> | |||||
</div> | |||||
</div></el-col | |||||
> | |||||
<el-col :span="12" | |||||
><div class="home-bg-content-item"> | |||||
<div class="home-bg-content-item-icon"> | |||||
<img src="@/assets/images/home/warn.png" alt="" /> | |||||
</div> | |||||
<div class="home-bg-content-item-content"> | |||||
<div class="home-bg-content-item-title">告警信息总量</div> | |||||
<div class="home-bg-content-item-value">197218</div> | |||||
</div> | |||||
</div></el-col | |||||
> | |||||
<el-col :span="12" | |||||
><div class="home-bg-content-item"> | |||||
<div class="home-bg-content-item-icon"> | |||||
<img src="@/assets/images/home/handle.png" alt="" /> | |||||
</div> | |||||
<div class="home-bg-content-item-content"> | |||||
<div class="home-bg-content-item-title">处理意见提交</div> | |||||
<div class="home-bg-content-item-value">40</div> | |||||
</div> | |||||
</div></el-col | |||||
> | |||||
<el-col :span="12" | |||||
><div class="home-bg-content-item"> | |||||
<div class="home-bg-content-item-icon"> | |||||
<img src="@/assets/images/home/participation.png" alt="" /> | |||||
</div> | |||||
<div class="home-bg-content-item-content"> | |||||
<div class="home-bg-content-item-title">参与安防教师</div> | |||||
<div class="home-bg-content-item-value">22</div> | |||||
</div> | |||||
</div></el-col | |||||
> | |||||
</el-row> | |||||
</div> | |||||
</div> | |||||
</el-col> | |||||
<el-col :xs="24" :sm="24" :md="12" :lg="12" :xl="8"> | |||||
<div class="home-bg card"> | |||||
<div class="home-bg-title"> | |||||
<div></div> | |||||
<div>今日告警情况</div> | |||||
</div> | |||||
<div class="home-bg-content"> | |||||
<div ref="chart1" style="width: 100%; height: 100%"></div> | |||||
</div> | |||||
</div> | |||||
</el-col> | |||||
<el-col :xs="24" :sm="24" :md="12" :lg="12" :xl="8"> | |||||
<div class="home-bg card"> | |||||
<div class="home-bg-title"> | |||||
<div></div> | |||||
<div>今日处理情况</div> | |||||
</div> | |||||
<div class="home-bg-content"> | |||||
<div ref="chart2" style="width: 100%; height: 100%"></div> | |||||
</div> | |||||
</div> | |||||
</el-col> | |||||
<el-col :xs="24" :sm="24" :md="12" :lg="12" :xl="8"> | |||||
<div class="home-bg card"> | |||||
<div class="home-bg-title"> | |||||
<div></div> | |||||
<div>高危预警信息统计</div> | |||||
</div> | |||||
<div class="home-bg-content handleBox"> | |||||
<ProTable ref="proTable" title="视频列表" :toolButton="false" :pagination="false" :columns="columns" :data="tableData"> </ProTable> | |||||
</div> | |||||
</div> | |||||
</el-col> | |||||
<el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="16"> | |||||
<div class="home-bg card"> | |||||
<div class="home-bg-title"> | |||||
<div></div> | |||||
<div>统计分析</div> | |||||
</div> | |||||
<div class="home-bg-content handleBox"> | |||||
<div ref="chart3" style="width: 100%; height: 100%"></div> | |||||
</div> | |||||
</div> | |||||
</el-col> | |||||
</el-row> | |||||
</div> | </div> | ||||
</template> | </template> | ||||
<script setup lang="ts" name="home"></script> | |||||
<script setup lang="ts" name="home"> | |||||
import { ref, watch, provide, onMounted, unref, computed, reactive } from "vue"; | |||||
import { ElMessage } from "element-plus"; | |||||
import { monitorLIVEApi } from "@/api"; | |||||
import { ZJRQ } from "@/api/interface"; | |||||
import { ColumnProps, ProTableInstance } from "@/components/ProTable/interface"; | |||||
import { useDictStore } from "@/stores/modules"; | |||||
import { statistionApi } from "@/api"; | |||||
import * as echarts from "echarts"; | |||||
const value = ref(true); | |||||
const chart1 = ref(null); | |||||
const chart2 = ref(null); | |||||
const chart3 = ref(null); | |||||
onMounted(() => { | |||||
getDataChart(); | |||||
getWeekData(); | |||||
}); | |||||
function getDataChart() { | |||||
setTimeout(async () => { | |||||
await statistionApi.warnstatistion({}).then(res => { | |||||
let { code, data } = res; | |||||
if (code == 200) { | |||||
let chartData1 = data.alarm.map(item => { | |||||
return { | |||||
value: item.count, | |||||
name: item.name | |||||
}; | |||||
}); | |||||
let chartData2 = data.hand.map(item => { | |||||
return { | |||||
value: item.count, | |||||
name: item.name | |||||
}; | |||||
}); | |||||
// let chartData = [ | |||||
// { | |||||
// name: "1", | |||||
// value: 100 | |||||
// }, | |||||
// { | |||||
// name: "2", | |||||
// value: 200 | |||||
// } | |||||
// ]; | |||||
getCharts1(chartData1); | |||||
getCharts2(chartData2); | |||||
} | |||||
}); | |||||
}); | |||||
} | |||||
function getCharts1(data) { | |||||
const chart = echarts.init(chart1.value); | |||||
const option = { | |||||
tooltip: { | |||||
trigger: "item" | |||||
}, | |||||
// legend: { | |||||
// top: "5%", | |||||
// left: "center" | |||||
// }, | |||||
legend: { | |||||
orient: "vertical", | |||||
left: "right", | |||||
top: "middle" | |||||
}, | |||||
series: [ | |||||
{ | |||||
name: "今日告警情况", | |||||
type: "pie", | |||||
radius: ["60%", "90%"], | |||||
avoidLabelOverlap: false, | |||||
itemStyle: { | |||||
borderRadius: 10, | |||||
borderColor: "#fff", | |||||
borderWidth: 2 | |||||
}, | |||||
label: { | |||||
show: false, | |||||
position: "center" | |||||
}, | |||||
emphasis: { | |||||
label: { | |||||
show: true, | |||||
fontSize: 25, | |||||
fontWeight: "bold" | |||||
} | |||||
}, | |||||
labelLine: { | |||||
show: false | |||||
}, | |||||
data | |||||
} | |||||
] | |||||
}; | |||||
chart.setOption(option); | |||||
window.addEventListener("resize", function () { | |||||
chart.resize(); | |||||
}); | |||||
} | |||||
function getCharts2(data) { | |||||
const chartstation = echarts.init(chart2.value); | |||||
const option = { | |||||
tooltip: { | |||||
trigger: "item" | |||||
}, | |||||
// legend: { | |||||
// top: "5%", | |||||
// left: "center" | |||||
// }, | |||||
legend: { | |||||
orient: "vertical", | |||||
left: "right", | |||||
top: "middle" | |||||
}, | |||||
series: [ | |||||
{ | |||||
name: "今日处理情况", | |||||
type: "pie", | |||||
radius: ["60%", "90%"], | |||||
avoidLabelOverlap: false, | |||||
itemStyle: { | |||||
borderRadius: 10, | |||||
borderColor: "#fff", | |||||
borderWidth: 2 | |||||
}, | |||||
label: { | |||||
show: false, | |||||
position: "center" | |||||
}, | |||||
emphasis: { | |||||
label: { | |||||
show: true, | |||||
fontSize: 25, | |||||
fontWeight: "bold" | |||||
} | |||||
}, | |||||
labelLine: { | |||||
show: false | |||||
}, | |||||
data | |||||
} | |||||
] | |||||
}; | |||||
chartstation.setOption(option); | |||||
window.addEventListener("resize", function () { | |||||
chartstation.resize(); | |||||
}); | |||||
} | |||||
function getWeekData() { | |||||
setTimeout(async () => { | |||||
await statistionApi.weekstatistion({}).then(res => { | |||||
let { code, data } = res; | |||||
if (code == 200) { | |||||
// let chartData = data; | |||||
let time = data.dataX; | |||||
let chartData = data.dataY.map(item => { | |||||
return { | |||||
data: item.data, | |||||
name: item.name, | |||||
type: "bar", | |||||
barWidth: "12px", // 设置柱子粗细 | |||||
itemStyle: { | |||||
normal: { | |||||
barBorderRadius: [30, 30, 0, 0] | |||||
} | |||||
} | |||||
}; | |||||
}); | |||||
getCharts3(time, chartData); | |||||
} | |||||
}); | |||||
}); | |||||
} | |||||
function getCharts3(time, data) { | |||||
const chartstation3 = echarts.init(chart3.value); | |||||
const option = { | |||||
tooltip: { | |||||
trigger: "axis", | |||||
axisPointer: { | |||||
type: "shadow" | |||||
} | |||||
}, | |||||
legend: {}, | |||||
grid: { | |||||
left: "3%", | |||||
right: "4%", | |||||
bottom: "3%", | |||||
containLabel: true | |||||
}, | |||||
yAxis: { | |||||
type: "value", | |||||
boundaryGap: [0, 0.01] | |||||
}, | |||||
xAxis: { | |||||
type: "category", | |||||
data: time | |||||
}, | |||||
series: data | |||||
}; | |||||
chartstation3.setOption(option); | |||||
window.addEventListener("resize", function () { | |||||
chartstation3.resize(); | |||||
}); | |||||
} | |||||
// 获取 ProTable 元素,调用其获取刷新数据方法(还能获取到当前查询参数,方便导出携带参数) | |||||
const proTable = ref<ProTableInstance>(); | |||||
const dictStore = useDictStore(); | |||||
// 表格配置项 | |||||
const columns: ColumnProps<ZJRQ.WarnInfo>[] = [ | |||||
{ | |||||
prop: "type", | |||||
label: "数据类型" | |||||
// render: () => { | |||||
// return "楼道"; | |||||
// } | |||||
}, | |||||
{ | |||||
prop: "warntotal", | |||||
label: "告警总量" | |||||
// render: () => { | |||||
// return "楼道"; | |||||
// } | |||||
}, | |||||
{ | |||||
prop: "lowrisk", | |||||
label: "低危信息 " | |||||
}, | |||||
{ | |||||
prop: "highrisk", | |||||
label: "高危信息" | |||||
} | |||||
]; | |||||
const tableData = ref([ | |||||
{ | |||||
type: "今日", | |||||
warntotal: "828", | |||||
lowrisk: "675", | |||||
highrisk: "153" | |||||
}, | |||||
{ | |||||
type: "本周", | |||||
warntotal: "828", | |||||
lowrisk: "675", | |||||
highrisk: "153" | |||||
}, | |||||
{ | |||||
type: "本月", | |||||
warntotal: "19813", | |||||
lowrisk: "17671", | |||||
highrisk: "2129" | |||||
}, | |||||
{ | |||||
type: "上月", | |||||
warntotal: "21789", | |||||
lowrisk: "0", | |||||
highrisk: "0" | |||||
}, | |||||
{ | |||||
type: "环比", | |||||
warntotal: "-9.07%", | |||||
lowrisk: "0%", | |||||
highrisk: "0%" | |||||
} | |||||
]); | |||||
const tableLoading = ref(false); | |||||
</script> | |||||
<style scoped lang="scss"> | <style scoped lang="scss"> | ||||
@import "./index.scss"; | @import "./index.scss"; | ||||
@@ -0,0 +1,118 @@ | |||||
<!-- | |||||
* @Description: 表单 | |||||
* @Author: huguodong | |||||
* @Date: 2023-12-15 15:45:28 | |||||
!--> | |||||
<template> | |||||
<div> | |||||
<form-container v-model="visible" :title="`${orgProps.opt}监控`" form-size="600px"> | |||||
<el-form | |||||
ref="liveFormRef" | |||||
:rules="rules" | |||||
:disabled="orgProps.disabled" | |||||
:model="orgProps.record" | |||||
:hide-required-asterisk="orgProps.disabled" | |||||
label-width="auto" | |||||
label-suffix=" :" | |||||
> | |||||
<s-form-item label="摄像头名称" prop="name"> | |||||
<s-input v-model="orgProps.record.name"></s-input> | |||||
</s-form-item> | |||||
<s-form-item label="所属学校" prop="parentId"> | |||||
<org-selector v-model:org-value="orgProps.record.parentId" :org-tree-api="bizOrgApi.tree" :show-all="false" /> | |||||
</s-form-item> | |||||
<s-form-item label="设备IP" prop="codeip"> | |||||
<s-input v-model="orgProps.record.codeip" clearable></s-input> | |||||
</s-form-item> | |||||
<s-form-item label="分辨率" prop="status"> | |||||
<s-input v-model="orgProps.record.status" clearable></s-input> | |||||
</s-form-item> | |||||
</el-form> | |||||
<template #footer> | |||||
<el-button @click="onClose"> 取消 </el-button> | |||||
<el-button v-show="!orgProps.disabled" type="primary" @click="handleSubmit"> 确定 </el-button> | |||||
</template> | |||||
</form-container> | |||||
</div> | |||||
</template> | |||||
<script setup lang="ts"> | |||||
import { SysOrg, SysUser, bizOrgApi, bizPositionApi, sysRoleApi, bizUserApi } from "@/api"; | |||||
import { FormOptEnum, SysDictEnum } from "@/enums"; | |||||
import { required } from "@/utils/formRules"; | |||||
import { FormInstance } from "element-plus"; | |||||
import { useDictStore } from "@/stores/modules"; | |||||
const visible = ref(false); //是否显示表单 | |||||
const dictStore = useDictStore(); //字典仓库 | |||||
// 通用状态选项 | |||||
const statusOptions = dictStore.getDictList(SysDictEnum.COMMON_STATUS); | |||||
// 表单参数 | |||||
const orgProps = reactive<FormProps.Base<SysOrg.SysOrgInfo>>({ | |||||
opt: FormOptEnum.ADD, | |||||
record: {}, | |||||
disabled: false | |||||
}); | |||||
// 表单验证规则 | |||||
const rules = reactive({ | |||||
name: [required("请输入摄像头名称")], | |||||
parentId: [required("请选择所属学校")], | |||||
codeip: [required("请选择设备IP")], | |||||
status: [required("请输入分辨率")] | |||||
}); | |||||
/** | |||||
* 打开表单 | |||||
* @param props 表单参数 | |||||
*/ | |||||
function onOpen(props: FormProps.Base<SysOrg.SysOrgInfo>) { | |||||
Object.assign(orgProps, props); //合并参数 | |||||
if (props.opt == FormOptEnum.ADD) { | |||||
//如果是新增,设置默认值 | |||||
orgProps.record.sortCode = 99; | |||||
// orgProps.record.status = statusOptions[0].value; | |||||
} | |||||
visible.value = true; //显示表单 | |||||
if (props.record.id) { | |||||
//如果传了id,就去请求api获取record | |||||
bizOrgApi.detail({ id: props.record.id }).then(res => { | |||||
orgProps.record = res.data; | |||||
}); | |||||
} | |||||
} | |||||
// 提交数据(新增/编辑) | |||||
const liveFormRef = ref<FormInstance>(); | |||||
/** 提交表单 */ | |||||
async function handleSubmit() { | |||||
liveFormRef.value?.validate(async valid => { | |||||
if (!valid) return; //表单验证失败 | |||||
console.log(orgProps); | |||||
return; | |||||
//提交表单 | |||||
await bizOrgApi | |||||
.submitForm(orgProps.record, orgProps.record.id != undefined) | |||||
.then(() => { | |||||
orgProps.successful!(); //调用父组件的successful方法 | |||||
}) | |||||
.finally(() => { | |||||
onClose(); | |||||
}); | |||||
}); | |||||
} | |||||
/** 关闭表单*/ | |||||
function onClose() { | |||||
visible.value = false; | |||||
} | |||||
// 暴露给父组件的方法 | |||||
defineExpose({ | |||||
onOpen | |||||
}); | |||||
</script> | |||||
<style lang="scss" scoped></style> |
@@ -0,0 +1,106 @@ | |||||
<!-- | |||||
* @Description: 表单 | |||||
* @Author: huguodong | |||||
* @Date: 2023-12-15 15:45:28 | |||||
!--> | |||||
<template> | |||||
<div> | |||||
<form-container v-model="visible" title="选择分组" form-size="600px"> | |||||
<el-form | |||||
ref="liveFormRef" | |||||
:rules="rules" | |||||
:disabled="orgProps.disabled" | |||||
:model="orgProps.record" | |||||
:hide-required-asterisk="orgProps.disabled" | |||||
label-width="auto" | |||||
label-suffix=" :" | |||||
> | |||||
<s-form-item label="所属学校" prop="parentId"> | |||||
<org-selector v-model:org-value="orgProps.record.parentId" :org-tree-api="bizOrgApi.tree" :show-all="false" /> | |||||
</s-form-item> | |||||
</el-form> | |||||
<template #footer> | |||||
<el-button @click="onClose"> 取消 </el-button> | |||||
<el-button v-show="!orgProps.disabled" type="primary" @click="handleSubmit"> 确定 </el-button> | |||||
</template> | |||||
</form-container> | |||||
</div> | |||||
</template> | |||||
<script setup lang="ts"> | |||||
import { SysOrg, SysUser, bizOrgApi, bizPositionApi, sysRoleApi, bizUserApi } from "@/api"; | |||||
import { FormOptEnum, SysDictEnum } from "@/enums"; | |||||
import { required } from "@/utils/formRules"; | |||||
import { FormInstance } from "element-plus"; | |||||
import { useDictStore } from "@/stores/modules"; | |||||
const visible = ref(false); //是否显示表单 | |||||
const dictStore = useDictStore(); //字典仓库 | |||||
// 通用状态选项 | |||||
const statusOptions = dictStore.getDictList(SysDictEnum.COMMON_STATUS); | |||||
// 表单参数 | |||||
const orgProps = reactive<FormProps.Base<SysOrg.SysOrgInfo>>({ | |||||
opt: FormOptEnum.ADD, | |||||
record: {}, | |||||
disabled: false | |||||
}); | |||||
// 表单验证规则 | |||||
const rules = reactive({ | |||||
parentId: [required("请选择所属学校")] | |||||
}); | |||||
/** | |||||
* 打开表单 | |||||
* @param props 表单参数 | |||||
*/ | |||||
function omMove(props: FormProps.Base<SysOrg.SysOrgInfo>) { | |||||
Object.assign(orgProps, props); //合并参数 | |||||
if (props.opt == FormOptEnum.ADD) { | |||||
//如果是新增,设置默认值 | |||||
orgProps.record.sortCode = 99; | |||||
// orgProps.record.status = statusOptions[0].value; | |||||
} | |||||
visible.value = true; //显示表单 | |||||
if (props.record.id) { | |||||
//如果传了id,就去请求api获取record | |||||
bizOrgApi.detail({ id: props.record.id }).then(res => { | |||||
orgProps.record = res.data; | |||||
}); | |||||
} | |||||
} | |||||
// 提交数据(新增/编辑) | |||||
const liveFormRef = ref<FormInstance>(); | |||||
/** 提交表单 */ | |||||
async function handleSubmit() { | |||||
liveFormRef.value?.validate(async valid => { | |||||
if (!valid) return; //表单验证失败 | |||||
console.log(orgProps); | |||||
return; | |||||
//提交表单 | |||||
await bizOrgApi | |||||
.submitForm(orgProps.record, orgProps.record.id != undefined) | |||||
.then(() => { | |||||
orgProps.successful!(); //调用父组件的successful方法 | |||||
}) | |||||
.finally(() => { | |||||
onClose(); | |||||
}); | |||||
}); | |||||
} | |||||
/** 关闭表单*/ | |||||
function onClose() { | |||||
visible.value = false; | |||||
} | |||||
// 暴露给父组件的方法 | |||||
defineExpose({ | |||||
omMove | |||||
}); | |||||
</script> | |||||
<style lang="scss" scoped></style> |
@@ -0,0 +1,127 @@ | |||||
<!-- | |||||
* @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="directorId"> | |||||
<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> | |||||
</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 } 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<SysOrg.SysOrgInfo>>({ | |||||
opt: FormOptEnum.ADD, | |||||
record: {}, | |||||
disabled: false | |||||
}); | |||||
// 表单验证规则 | |||||
const rules = reactive({ | |||||
directorId: [required("请选择指定分组推送人")] | |||||
}); | |||||
/** | |||||
* 打开表单 | |||||
* @param props 表单参数 | |||||
*/ | |||||
function onOpen(props: FormProps.Base<SysOrg.SysOrgInfo>) { | |||||
Object.assign(liveUserProps, props); //合并参数 | |||||
if (props.opt == FormOptEnum.ADD) { | |||||
//如果是新增,设置默认值 | |||||
} | |||||
visible.value = true; //显示表单 | |||||
// if (props.record.id) { | |||||
// //如果传了id,就去请求api获取record | |||||
// sysOrgApi.detail({ id: props.record.id }).then(res => { | |||||
// liveUserProps.record = res.data; | |||||
// }); | |||||
// } | |||||
} | |||||
// 提交数据(新增/编辑) | |||||
const userFormRef = ref<FormInstance>(); | |||||
/** 提交表单 */ | |||||
async function handleSubmit() { | |||||
userFormRef.value?.validate(async valid => { | |||||
if (!valid) return; //表单验证失败 | |||||
return; | |||||
//提交表单 | |||||
await sysOrgApi | |||||
.submitForm(liveUserProps.record, liveUserProps.record.id != undefined) | |||||
.then(() => { | |||||
liveUserProps.successful!(); //调用父组件的successful方法 | |||||
}) | |||||
.finally(() => { | |||||
onClose(); | |||||
}); | |||||
}); | |||||
} | |||||
/** 关闭表单*/ | |||||
function onClose() { | |||||
visible.value = false; | |||||
} | |||||
const userSelectorRef = ref<UserSelectorInstance>(); //用户选择器引用 | |||||
/** 显示用户选择器 */ | |||||
function showSelector() { | |||||
//将liveUserProps.record.directorInfo转为 SysUser.SysUserInfo[]类型 | |||||
const directorInfo = liveUserProps.record.directorInfo ? [liveUserProps.record.directorInfo] : []; | |||||
userSelectorRef.value?.showSelector(directorInfo); | |||||
} | |||||
/** 选择用户 */ | |||||
function handleChooseUser(data: SysUser.SysUserInfo[]) { | |||||
// 选择用户后,将用户id赋值给liveUserProps.record.directorId | |||||
if (data.length > 0) { | |||||
liveUserProps.record.directorId = data[0].id; | |||||
liveUserProps.record.directorInfo = data[0]; | |||||
} | |||||
} | |||||
/** 移除主管 */ | |||||
function removeDirector() { | |||||
liveUserProps.record.directorId = null; | |||||
liveUserProps.record.directorInfo = null; | |||||
} | |||||
// 暴露给父组件的方法 | |||||
defineExpose({ | |||||
onOpen | |||||
}); | |||||
</script> | |||||
<style lang="scss" scoped></style> |
@@ -0,0 +1,78 @@ | |||||
ul,li { | |||||
list-style: none; | |||||
padding: 0; | |||||
margin: 0; | |||||
} | |||||
.treeBox { | |||||
box-sizing: border-box; | |||||
width: 280px; | |||||
height: 100%; | |||||
padding: 14px; | |||||
margin-right: 10px; | |||||
flex-shrink: 1; | |||||
.title { | |||||
margin: 0 0 15px; | |||||
font-size: 18px; | |||||
font-weight: bold; | |||||
color: var(--el-color-info-dark-2); | |||||
letter-spacing: 0.5px; | |||||
} | |||||
.btn { | |||||
} | |||||
.treeContent { | |||||
padding: 10px 0; | |||||
// height: calc(100% - 100px); | |||||
// overflow: auto; | |||||
.el-tree-node__content { | |||||
height: 33px; | |||||
} | |||||
.custom-tree-node { | |||||
flex: 1; | |||||
display: flex; | |||||
align-items: center; | |||||
justify-content: space-between; | |||||
font-size: 14px; | |||||
padding-right: 8px; | |||||
.node-label { | |||||
width: 100px; | |||||
overflow: hidden; | |||||
text-overflow: ellipsis; | |||||
white-space: nowrap; | |||||
font-size: 16px; | |||||
} | |||||
} | |||||
:deep(.el-tree-node__content) { | |||||
height: 50px; | |||||
} | |||||
} | |||||
.el-input { | |||||
margin: 0 0 15px; | |||||
} | |||||
.el-scrollbar { | |||||
:deep(.el-tree) { | |||||
height: 80%; | |||||
overflow: auto; | |||||
.el-tree-node__content { | |||||
height: 33px; | |||||
} | |||||
} | |||||
:deep(.el-tree--highlight-current) { | |||||
.el-tree-node.is-current > .el-tree-node__content { | |||||
background-color: var(--el-color-primary); | |||||
.el-tree-node__label, | |||||
.el-tree-node__expand-icon { | |||||
color: white; | |||||
} | |||||
.is-leaf { | |||||
color: transparent; | |||||
} | |||||
} | |||||
} | |||||
} | |||||
} | |||||
.table-box { | |||||
width: calc(100% - 280px); | |||||
} |
@@ -4,66 +4,236 @@ | |||||
* @Date: 2023-12-15 15:44:05 | * @Date: 2023-12-15 15:44:05 | ||||
!--> | !--> | ||||
<template> | <template> | ||||
<div class="table-box"> | |||||
<ProTable ref="proTable" title="视频列表" :columns="columns" :request-api="monitorLIVEApi.page"> | |||||
<!-- 表格 header 按钮 --> | |||||
<div class="main-box"> | |||||
<div class="card treeBox"> | |||||
<p class="title">摄像头分组管理</p> | |||||
<div class="btn"> | |||||
<el-button @click="append('add', {})" type="primary">添加分组</el-button> | |||||
</div> | |||||
<!-- <div class="treeContent"> | |||||
<ul class="treeList" v-for="(item, i) in treeData" :key="i"> | |||||
<li class="treeItem"> | |||||
<div class="treeLabel">{{ item.label }}</div> | |||||
<div class="treeBtn"> | |||||
<el-icon><Edit /></el-icon> | |||||
<el-icon><Delete /></el-icon> | |||||
</div> | |||||
</li> | |||||
</ul> | |||||
</div> --> | |||||
<div class="treeContent"> | |||||
<el-tree | |||||
style="max-width: 600px" | |||||
:data="treeData" | |||||
node-key="id" | |||||
default-expand-all | |||||
:expand-on-click-node="false" | |||||
:check-on-click-node="true" | |||||
:highlight-current="true" | |||||
@node-click="handleNodeClick" | |||||
> | |||||
<template #default="{ node, data }"> | |||||
<span class="custom-tree-node"> | |||||
<span class="node-label" :title="node.label">{{ node.label }}</span> | |||||
<span v-if="data.id && data.id != '-1'"> | |||||
<el-icon size="16" @click.stop="append('edit', data)"><Edit /></el-icon> | |||||
<el-icon size="16" @click.stop="pushPerson('push', data)" style="margin-left: 8px"><UserFilled /></el-icon> | |||||
<el-icon size="16" @click.stop="remove(node, data)" style="margin-left: 8px"><Delete /></el-icon> | |||||
</span> | |||||
</span> | |||||
</template> | |||||
</el-tree> | |||||
</div> | |||||
</div> | |||||
<div class="table-box"> | |||||
<ProTable ref="proTable" title="视频列表" :columns="columns" :request-api="monitorLIVEApi.page"> | |||||
<!-- 表格 header 按钮 --> | |||||
<template #tableHeader="scope"> | |||||
<s-button v-auth="monitorLiveButtonCode.add" suffix="摄像头" @click="onOpen(FormOptEnum.ADD)" /> | |||||
<s-button | |||||
type="danger" | |||||
plain | |||||
suffix="摄像头" | |||||
:opt="FormOptEnum.DELETE" | |||||
:disabled="!scope.isSelected" | |||||
@click="onDelete(scope.selectedListIds, '删除所选数据')" | |||||
/> | |||||
<el-button plain @click="omMove(FormOptEnum.ADD)" type="success">移动至分组</el-button> | |||||
</template> | |||||
<!-- 表格 菜单类型 按钮 --> | |||||
<!-- <template #menuType="scope"> | |||||
<el-space wrap> | |||||
<el-tag v-if="scope.row.menuType === MenuTypeDictEnum.MENU" type="success">{{ | |||||
dictStore.dictTranslation(SysDictEnum.MENU_TYPE, MenuTypeDictEnum.MENU) | |||||
}}</el-tag> | |||||
<el-tag v-else-if="scope.row.menuType === MenuTypeDictEnum.LINK" type="warning">{{ | |||||
dictStore.dictTranslation(SysDictEnum.MENU_TYPE, MenuTypeDictEnum.LINK) | |||||
}}</el-tag> | |||||
<el-tag v-else type="info">{{ dictStore.dictTranslation(SysDictEnum.MENU_TYPE, scope.row.menuType) }}</el-tag> | |||||
<el-tag v-if="scope.row.isHome === true" type="danger">首页</el-tag> | |||||
</el-space> | |||||
</template> --> | |||||
<!-- 操作 --> | |||||
<template #operation="scope"> | |||||
<s-button link :opt="FormOptEnum.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> | |||||
</template> | |||||
</ProTable> | |||||
<!-- 添加分组弹框 --> | |||||
<el-dialog v-model="groupVisible" :title="groupTitle" width="600px" :before-close="closeGroup"> | |||||
<el-form :model="groupForm" :rules="groupRules" ref="groupFormRef" label-width="80px"> | |||||
<el-form-item label="分组名称" prop="name"> | |||||
<el-input v-model="groupForm.name" placeholder="请输入分组名称"></el-input> | |||||
</el-form-item> | |||||
</el-form> | |||||
<!-- 表格 菜单类型 按钮 --> | |||||
<template #menuType="scope"> | |||||
<el-space wrap> | |||||
<el-tag v-if="scope.row.menuType === MenuTypeDictEnum.MENU" type="success">{{ | |||||
dictStore.dictTranslation(SysDictEnum.MENU_TYPE, MenuTypeDictEnum.MENU) | |||||
}}</el-tag> | |||||
<el-tag v-else-if="scope.row.menuType === MenuTypeDictEnum.LINK" type="warning">{{ | |||||
dictStore.dictTranslation(SysDictEnum.MENU_TYPE, MenuTypeDictEnum.LINK) | |||||
}}</el-tag> | |||||
<el-tag v-else type="info">{{ dictStore.dictTranslation(SysDictEnum.MENU_TYPE, scope.row.menuType) }}</el-tag> | |||||
<el-tag v-if="scope.row.isHome === true" type="danger">首页</el-tag> | |||||
</el-space> | |||||
</template> | |||||
<!-- 操作 --> | |||||
<template #operation="scope"> | |||||
<s-button link :opt="FormOptEnum.VIEW" @click="onDetail(scope.row)"> 查看 </s-button> | |||||
<!-- <s-button link :opt="FormOptEnum.EDIT" @click="onOpen(FormOptEnum.EDIT, scope.row)">处理</s-button> | |||||
<s-button link :opt="FormOptEnum.DELETE" @click="onDelete([scope.row.id], `确定删除该预警吗?`)" /> --> | |||||
</template> | |||||
</ProTable> | |||||
<el-dialog v-model="visible" :title="detailData.title" width="830px" :before-close="handleClose"> | |||||
<div> | |||||
<div class="dialogHeader"> | |||||
<div></div> | |||||
<div class="dialogBtn" @click="refreshUrl"> | |||||
<el-icon color="#409efc" :size="20"> | |||||
<Refresh /> | |||||
</el-icon> | |||||
<div>刷新视频</div> | |||||
<template #footer> | |||||
<div class="dialog-footer"> | |||||
<el-button type="primary" @click="onSubmit">提交</el-button> | |||||
<el-button @click="closeGroup">取消</el-button> | |||||
</div> | </div> | ||||
</template> | |||||
</el-dialog> | |||||
<!-- 新增/编辑表单 --> | |||||
<Form ref="formRef" /> | |||||
<!-- 人员选择 --> | |||||
<userForm ref="userFormRef" /> | |||||
<!-- 移动至分组 --> | |||||
<moveForm ref="moveFormRef" /> | |||||
<!-- 视频详情 --> | |||||
<el-dialog v-model="visible" :title="detailData.title" width="830px" :before-close="closeGroup"> | |||||
<div> | |||||
<div class="dialogHeader"> | |||||
<div></div> | |||||
<div class="dialogBtn" @click="refreshUrl"> | |||||
<el-icon color="#409efc" :size="20"> | |||||
<Refresh /> | |||||
</el-icon> | |||||
<div>刷新视频</div> | |||||
</div> | |||||
</div> | |||||
<div v-if="visible || showVideo" class="prism-player" id="player-con"></div> | |||||
<!-- <VideoPlay :videoUrl="detailData.videoUrl" :videoType="detailData.videoType" /> --> | |||||
<!-- <video style="width: 100%; height: 500px" id="video" controls muted="false"></video> --> | |||||
<!-- <iframe src="/static/artcvideo.html" width="100%" height="600px" ref="iframeDom"></iframe> --> | |||||
</div> | </div> | ||||
<div v-if="visible || showVideo" class="prism-player" id="player-con"></div> | |||||
<!-- <VideoPlay :videoUrl="detailData.videoUrl" :videoType="detailData.videoType" /> --> | |||||
<!-- <video style="width: 100%; height: 500px" id="video" controls muted="false"></video> --> | |||||
<!-- <iframe src="/static/artcvideo.html" width="100%" height="600px" ref="iframeDom"></iframe> --> | |||||
</div> | |||||
<template #footer> | |||||
<div class="dialog-footer"> | |||||
<el-button @click="handleClose">关闭</el-button> | |||||
</div> | |||||
</template> | |||||
</el-dialog> | |||||
<template #footer> | |||||
<div class="dialog-footer"> | |||||
<el-button @click="handleClose">关闭</el-button> | |||||
</div> | |||||
</template> | |||||
</el-dialog> | |||||
</div> | |||||
</div> | </div> | ||||
</template> | </template> | ||||
<script setup lang="tsx" name="sysSpa"> | <script setup lang="tsx" name="sysSpa"> | ||||
import VideoPlay from "@/components/VideoPlay/videoplay.vue"; | import VideoPlay from "@/components/VideoPlay/videoplay.vue"; | ||||
import { ElMessage } from "element-plus"; | |||||
import { monitorLIVEApi } from "@/api"; | |||||
import { ElMessage,ElMessageBox } from "element-plus"; | |||||
import type Node from 'element-plus/es/components/tree/src/model/node' | |||||
import { monitorLIVEApi, monitorLiveButtonCode } from "@/api"; | |||||
import { ZJRQ } from "@/api/interface"; | import { ZJRQ } from "@/api/interface"; | ||||
import { useHandleData } from "@/hooks/useHandleData"; | import { useHandleData } from "@/hooks/useHandleData"; | ||||
import { ColumnProps, ProTableInstance } from "@/components/ProTable/interface"; | import { ColumnProps, ProTableInstance } from "@/components/ProTable/interface"; | ||||
import { useDictStore } from "@/stores/modules"; | import { useDictStore } from "@/stores/modules"; | ||||
import Form from "./components/form.vue"; | |||||
import userForm from "./components/userForm.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' | ||||
const groupVisible = ref(false); //是否显示表单 | |||||
const groupTitle = ref('新增分组'); | |||||
const groupForm = reactive({ | |||||
name: '' | |||||
}); | |||||
const groupRules = ref({ | |||||
name: [{ required: true, message: '请输入分组名称', trigger: 'blur' }] | |||||
}); | |||||
const groupFormRef = ref(null); | |||||
const closeGroup = () => { | |||||
groupVisible.value = false; | |||||
groupFormRef.value.resetFields(); | |||||
groupForm.name = '' | |||||
} | |||||
const onSubmit = () => { | |||||
groupFormRef.value.validate((valid:any) => { | |||||
if (valid) { | |||||
closeGroup() | |||||
ElMessage.success('提交成功'); | |||||
} else { | |||||
return false; | |||||
} | |||||
}); | |||||
}; | |||||
// 摄像头分组 | |||||
interface Tree { | |||||
id: any | |||||
label: string | |||||
children?: Tree[] | |||||
} | |||||
let id = 1000 | |||||
const handleNodeClick = (data: Tree) => { | |||||
console.log(data) | |||||
} | |||||
const treeData = ref<Tree[]>([ | |||||
{ | |||||
id: '', | |||||
label: '全部', | |||||
}, | |||||
{ | |||||
id: '-1', | |||||
label: '无分组', | |||||
}, | |||||
{ | |||||
id: 1, | |||||
label: '走廊', | |||||
}, | |||||
{ | |||||
id: 2, | |||||
label: '大厅', | |||||
}, | |||||
{ | |||||
id: 3, | |||||
label: '厨房', | |||||
}, | |||||
]) | |||||
// 新增分组 | |||||
const append = (type:string,data: Tree) => { | |||||
console.log(type,data) | |||||
groupVisible.value = true; | |||||
if(type == 'edit') { | |||||
groupForm.name = treeData.value.find(item => item.id ==data.id).label; | |||||
} | |||||
// const newChild = { id: id++, label: 'testtest', children: [] } | |||||
// if (!data.children) { | |||||
// data.children = [] | |||||
// } | |||||
// data.children.push(newChild) | |||||
// treeData.value = [...treeData.value] | |||||
} | |||||
// 删除分组 | |||||
const remove = (node: Node, data: Tree) => { | |||||
const parent = node.parent | |||||
const children: Tree[] = parent.data.children || parent.data | |||||
const index = children.findIndex((d) => d.id === data.id) | |||||
children.splice(index, 1) | |||||
treeData.value = [...treeData.value] | |||||
} | |||||
// 设置分组推送人 | |||||
// async function pushPerson(type:string,data: Tree) { | |||||
// } | |||||
const visible = ref(false); //是否显示表单 | const visible = ref(false); //是否显示表单 | ||||
// 获取 ProTable 元素,调用其获取刷新数据方法(还能获取到当前查询参数,方便导出携带参数) | // 获取 ProTable 元素,调用其获取刷新数据方法(还能获取到当前查询参数,方便导出携带参数) | ||||
@@ -72,7 +242,7 @@ | |||||
// 表格配置项 | // 表格配置项 | ||||
const columns: ColumnProps<ZJRQ.WarnInfo>[] = [ | const columns: ColumnProps<ZJRQ.WarnInfo>[] = [ | ||||
// { type: "selection", fixed: "left", width: 80 }, | |||||
{ type: "selection", fixed: "left", width: 80 }, | |||||
// { prop: "searchKey", label: "关键字", search: { el: "input" }, isShow: false }, | // { prop: "searchKey", label: "关键字", search: { el: "input" }, isShow: false }, | ||||
// { | // { | ||||
// prop: "poiId", | // prop: "poiId", | ||||
@@ -107,29 +277,57 @@ | |||||
prop: "resWidth", | prop: "resWidth", | ||||
label: "分辨率", | label: "分辨率", | ||||
render: (row) => { | render: (row) => { | ||||
console.log(row,88) | |||||
return row.row.resWidth + '*' + row.row.resHeight; | return row.row.resWidth + '*' + row.row.resHeight; | ||||
} | } | ||||
}, | }, | ||||
{ prop: "operation", label: "操作", width: 250, fixed: "right" } | { prop: "operation", label: "操作", width: 250, fixed: "right" } | ||||
]; | ]; | ||||
/** | /** | ||||
* 删除 | * 删除 | ||||
* @param ids id数组 | * @param ids id数组 | ||||
*/ | */ | ||||
async function onDelete(ids: string[], msg: string) { | async function onDelete(ids: string[], msg: string) { | ||||
return | |||||
// 二次确认 => 请求api => 刷新表格 | // 二次确认 => 请求api => 刷新表格 | ||||
await useHandleData(monitorLIVEApi.delete, { ids }, msg); | await useHandleData(monitorLIVEApi.delete, { ids }, msg); | ||||
RefreshTable(); | RefreshTable(); | ||||
} | } | ||||
const moveFormRef = ref<InstanceType<typeof Form> | null>(null); | |||||
function omMove(opt: FormOptEnum, record: {} | SysOrg.SysOrgInfo = {}) { | |||||
moveFormRef.value?.omMove({ opt: opt, record: record, successful: RefreshTable }); | |||||
} | |||||
/** | /** | ||||
* 刷新表格 | * 刷新表格 | ||||
*/ | */ | ||||
function RefreshTable() { | function RefreshTable() { | ||||
proTable.value?.refresh(); | proTable.value?.refresh(); | ||||
} | } | ||||
// 表单引用 | |||||
const formRef = ref<InstanceType<typeof Form> | null>(null); | |||||
/** | |||||
* 打开表单 | |||||
* @param opt 操作类型 | |||||
* @param record 记录 | |||||
*/ | |||||
function onOpen(opt: FormOptEnum, record: {} | SysOrg.SysOrgInfo = {}) { | |||||
formRef.value?.onOpen({ opt: opt, record: record, successful: RefreshTable }); | |||||
} | |||||
// 人员选择 | |||||
// 表单引用 | |||||
const userFormRef = ref<InstanceType<typeof Form> | null>(null); | |||||
/** | |||||
* 打开表单 | |||||
* @param opt 操作类型 | |||||
* @param record 记录 | |||||
*/ | |||||
function pushPerson(opt: FormOptEnum, record: {} | SysOrg.SysOrgInfo = {}) { | |||||
userFormRef.value?.onOpen({ opt: opt, record: record, successful: RefreshTable }); | |||||
} | |||||
// 详情数据 | // 详情数据 | ||||
// let detailData: globalThis.Ref<{}> | // let detailData: globalThis.Ref<{}> | ||||
let detailData = reactive({ | let detailData = reactive({ | ||||
@@ -174,16 +372,6 @@ | |||||
// detailData.videoUrl = data.pullStreamUrls[2].url; | // detailData.videoUrl = data.pullStreamUrls[2].url; | ||||
detailData.streamId = data.streamId; | detailData.streamId = data.streamId; | ||||
detailData.videoToken = data.videoToken; | detailData.videoToken = data.videoToken; | ||||
// let timer = setInterval(() => { | |||||
// num+=1 | |||||
// if(num > 2) { | |||||
// } else { | |||||
// getvideo1() | |||||
// } | |||||
// },200) | |||||
// getvideo1() | // getvideo1() | ||||
getvideo2() | getvideo2() | ||||
} | } | ||||
@@ -195,7 +383,6 @@ | |||||
// let url = detailData.videoUrl.replace('http://rts-pull-live.deepeleph.com', '/Files') | // let url = detailData.videoUrl.replace('http://rts-pull-live.deepeleph.com', '/Files') | ||||
// console.log(url,888) | // console.log(url,888) | ||||
let pullStreamUrl = detailData.videoUrl; | let pullStreamUrl = detailData.videoUrl; | ||||
console.log(pullStreamUrl,888) | |||||
const mediaEle = document.querySelector('video'); | const mediaEle = document.querySelector('video'); | ||||
aliRts.on("onError", (err) => { | aliRts.on("onError", (err) => { | ||||
console.log(`errorCode: ${err.errorCode}`); | console.log(`errorCode: ${err.errorCode}`); | ||||
@@ -275,11 +462,16 @@ | |||||
detailData.videoUrl = '' | detailData.videoUrl = '' | ||||
detailData.videoType = '' | detailData.videoType = '' | ||||
stopUrl(); | stopUrl(); | ||||
player.value.dispose(); | |||||
if(player.value) { | |||||
player.value.dispose(); | |||||
} | |||||
}; | }; | ||||
function stopUrl() { | function stopUrl() { | ||||
detailData.videoUrl = '' | detailData.videoUrl = '' | ||||
player.value.dispose(); | |||||
if(player.value) { | |||||
player.value.dispose(); | |||||
} | |||||
let params = { | let params = { | ||||
sensorId: detailData.sensorId, | sensorId: detailData.sensorId, | ||||
streamId: detailData.streamId, | streamId: detailData.streamId, | ||||
@@ -291,31 +483,15 @@ | |||||
if (code == 200) { | if (code == 200) { | ||||
// ElMessage.success(msg); | // ElMessage.success(msg); | ||||
} | } | ||||
}); | }); | ||||
}) | }) | ||||
} | } | ||||
</script> | </script> | ||||
<style lang="scss" scoped> | <style lang="scss" scoped> | ||||
@import url("https://g.alicdn.com/apsara-media-box/imp-web-player/2.16.3/skins/default/aliplayer-min.css"); | @import url("https://g.alicdn.com/apsara-media-box/imp-web-player/2.16.3/skins/default/aliplayer-min.css"); | ||||
.detailpic { | |||||
width: 800px; | |||||
object-fit: cover; | |||||
} | |||||
.linebox { | |||||
margin-top: 20px; | |||||
} | |||||
/* 自定义样式 */ | |||||
.vjs-custom-skin .vjs-play-control { | |||||
/* 播放按钮的样式 */ | |||||
} | |||||
@import "./index.scss"; | |||||
.dialogHeader { | .dialogHeader { | ||||
display: flex; | display: flex; | ||||
justify-content: space-between; | justify-content: space-between; | ||||
@@ -0,0 +1,192 @@ | |||||
<!-- | |||||
* @Description: 人员表单 | |||||
* @Author: syy | |||||
* @Date: 2023-12-15 15:45:50 | |||||
--> | |||||
<template> | |||||
<div class="userManageForm"> | |||||
<div> | |||||
<el-row :gutter="16"> | |||||
<el-col :span="12"> | |||||
<s-form-item label="人员姓名" prop="name"> | |||||
<s-input v-model="userInfo.name"></s-input> | |||||
</s-form-item> | |||||
</el-col> | |||||
<el-col :span="12"> | |||||
<s-form-item label="所属班级" prop="personSetId"> | |||||
<s-select v-model="userInfo.personSetId" :options="treeData" label="personSetName" value="personSetId"></s-select> | |||||
</s-form-item> | |||||
</el-col> | |||||
</el-row> | |||||
<el-row :gutter="16"> | |||||
<el-col :span="24"> | |||||
<s-form-item label="上传人脸" prop="faces"> | |||||
<el-upload | |||||
v-model:file-list="fileList" | |||||
action="/api/business/personApi/uploadFile" | |||||
list-type="picture-card" | |||||
:on-success="handleAvatarSuccess" | |||||
:on-error="handleAvatarError" | |||||
:on-preview="handlePictureCardPreview" | |||||
:on-remove="handleRemove" | |||||
accept=".jpg, .jpeg, .png" | |||||
:headers="{ | |||||
Authorization: `${TokenEnum.TOKEN_PREFIX} ${accessToken}` | |||||
}" | |||||
> | |||||
<el-icon><Plus /></el-icon> | |||||
</el-upload> | |||||
<el-dialog v-model="dialogVisible" title="查看图片"> | |||||
<img w-full :src="dialogImageUrl" alt="Preview Image" style="width: 100%" /> | |||||
</el-dialog> | |||||
</s-form-item> | |||||
</el-col> | |||||
</el-row> | |||||
<el-row :gutter="16"> | |||||
<el-col :span="12"> | |||||
<s-form-item label="性别" prop="gender"> | |||||
<s-radio-group v-model="userInfo.gender" :options="genderOptions" /> | |||||
</s-form-item> | |||||
</el-col> | |||||
<el-col :span="12"> | |||||
<s-form-item label="年龄" prop="age"> | |||||
<s-input v-model="userInfo.age"></s-input> | |||||
</s-form-item> | |||||
</el-col> | |||||
</el-row> | |||||
<el-row :gutter="16"> | |||||
<el-col :span="12"> | |||||
<s-form-item label="手机号" prop="phone"> | |||||
<s-input v-model="userInfo.phone"></s-input> | |||||
</s-form-item> | |||||
</el-col> | |||||
<el-col :span="12"> | |||||
<s-form-item label="扩展字段" prop="extData"> | |||||
<s-input v-model="userInfo.extData"></s-input> | |||||
</s-form-item> | |||||
</el-col> | |||||
</el-row> | |||||
</div> | |||||
</div> | |||||
</template> | |||||
<script setup lang="ts"> | |||||
import { SysUserPersonnel, userManagePersonnelApi, userManageClassManageApi } from "@/api"; | |||||
import { Plus } from "@element-plus/icons-vue"; | |||||
import { useUserStore } from "@/stores/modules"; | |||||
import type { UploadProps, UploadUserFile } from "element-plus"; | |||||
import { ElMessage } from "element-plus"; | |||||
import { TokenEnum } from "@/enums"; | |||||
// props | |||||
interface FormProps { | |||||
modelValue: Partial<SysUserPersonnel.SysUserPerInfo>; | |||||
} | |||||
const emit = defineEmits(["update:modelValue"]); //定义emit | |||||
const props = defineProps<FormProps>(); //定义props | |||||
// 人员信息 | |||||
const userInfo = computed({ | |||||
get: () => props.modelValue, | |||||
set: val => emit("update:modelValue", val) | |||||
}); | |||||
/* */ | |||||
const userStore = useUserStore(); | |||||
const { accessToken } = userStore; | |||||
const fileList = ref([]); | |||||
const faces = ref<SysUserPersonnel.SysUserAvatar[]>([]); | |||||
const dialogImageUrl = ref(""); | |||||
const dialogVisible = ref(false); | |||||
const treeData = ref<{ [key: string]: any }[]>([]); | |||||
const handleRemove: UploadProps["onRemove"] = uploadFile => { | |||||
const index = faces.value.findIndex(item => item.uid === uploadFile.uid); | |||||
if (index > -1) { | |||||
faces.value.splice(index, 1); | |||||
} | |||||
userInfo.value.faces = faces.value; | |||||
if (uploadFile.personId) { | |||||
userManagePersonnelApi.deleteFace({ personId: uploadFile.personId, faceIds: [uploadFile.uid] }).then(res => {}); | |||||
} | |||||
}; | |||||
const handlePictureCardPreview: UploadProps["onPreview"] = uploadFile => { | |||||
dialogImageUrl.value = uploadFile.url!; | |||||
dialogVisible.value = true; | |||||
}; | |||||
const handleAvatarSuccess: UploadProps["onSuccess"] = (response, uploadFile) => { | |||||
if (response.code === 200) { | |||||
faces.value.push({ faceUrl: response.data, uid: uploadFile.uid }); | |||||
userInfo.value.faces = faces.value; | |||||
ElMessage.success(response.msg); | |||||
} else { | |||||
ElMessage.error(response.msg); | |||||
fileList.value = fileList.value.splice(0, fileList.value.length - 1); | |||||
} | |||||
}; | |||||
const handleAvatarError: UploadProps["onError"] = (error, uploadFile, uploadFiles) => { | |||||
console.log(error, uploadFile, uploadFiles, "err"); | |||||
}; | |||||
// 通用状态选项 | |||||
const genderOptions = ref([ | |||||
{ | |||||
label: "未知", | |||||
value: "GENDER_UNKNOWN" | |||||
}, | |||||
{ | |||||
label: "男", | |||||
value: "GENDER_MALE" | |||||
}, | |||||
{ | |||||
label: "女", | |||||
value: "GENDER_FEMALE" | |||||
} | |||||
]); | |||||
const getRequestData = async () => { | |||||
const { data } = await userManageClassManageApi.page(); | |||||
treeData.value = data; | |||||
console.log(treeData.value, "treeData"); | |||||
}; | |||||
onMounted(() => { | |||||
// 初始化 | |||||
userInfo.value.gender = userInfo.value.gender ? userInfo.value.gender : genderOptions.value[0].value; | |||||
getRequestData(); | |||||
if (userInfo.value.personId) { | |||||
if (userInfo.value.faces?.length > 0) { | |||||
fileList.value = [ | |||||
...JSON.parse(JSON.stringify(userInfo.value.faces)).map(item => { | |||||
return { | |||||
url: item.faceUrl, | |||||
uid: item.faceId, | |||||
personId: userInfo.value.personId | |||||
}; | |||||
}) | |||||
]; | |||||
faces.value = [ | |||||
...JSON.parse(JSON.stringify(userInfo.value.faces)).map(item => { | |||||
return { | |||||
faceUrl: item.faceUrl, | |||||
uid: item.faceId, | |||||
personId: userInfo.value.personId | |||||
}; | |||||
}) | |||||
]; | |||||
} | |||||
} | |||||
}); | |||||
</script> | |||||
<style lang="scss" scoped> | |||||
:deep(.el-input__wrapper) { | |||||
width: 100% !important; | |||||
} | |||||
:deep(.el-date-editor.el-input) { | |||||
width: 92% !important; | |||||
} | |||||
:deep(.el-upload-list--picture-card .el-upload-list__item) { | |||||
width: 100px !important; | |||||
height: 100px !important; | |||||
} | |||||
:deep(.el-upload--picture-card) { | |||||
width: 100px !important; | |||||
height: 100px !important; | |||||
} | |||||
</style> |
@@ -0,0 +1,120 @@ | |||||
<!-- | |||||
* @Description: 表单 | |||||
* @Author: syy | |||||
* @Date: 2023-12-15 15:45:59 | |||||
--> | |||||
<template> | |||||
<div> | |||||
<form-container v-model="visible" :title="`${sysUserProps.opt}人员`" form-size="800px" @close="onClose"> | |||||
<el-form | |||||
ref="sysUserFormRef" | |||||
:rules="rules" | |||||
:disabled="sysUserProps.disabled" | |||||
:model="sysUserProps.record" | |||||
:hide-required-asterisk="sysUserProps.disabled" | |||||
label-width="auto" | |||||
label-suffix=" :" | |||||
> | |||||
<el-tabs v-model="activeName"> | |||||
<Basic v-model="sysUserProps.record"></Basic> | |||||
</el-tabs> | |||||
</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 { SysUserPersonnel, userManagePersonnelApi } from "@/api"; | |||||
import { FormOptEnum, SysDictEnum } from "@/enums"; | |||||
import { required } from "@/utils/formRules"; | |||||
import { FormInstance } from "element-plus"; | |||||
import { useDictStore } from "@/stores/modules"; | |||||
import Basic from "./form_basic.vue"; | |||||
const visible = ref(false); //是否显示表单 | |||||
const activeName = ref("basic"); | |||||
// 表单参数 | |||||
const sysUserProps = reactive<FormProps.Base<SysUserPersonnel.SysUserPerInfo>>({ | |||||
opt: FormOptEnum.ADD, | |||||
record: {}, | |||||
disabled: false | |||||
}); | |||||
// 表单验证规则 | |||||
const rules = reactive({ | |||||
// personId: [required("请输入人员ID")], | |||||
name: [required("请输入姓名")], | |||||
gender: [required("请选择性别")], | |||||
faces: [required("请上传人脸图片")], | |||||
phone: [required("请输入手机号")] | |||||
// extData: [required("请输入扩展数据")] | |||||
}); | |||||
/** | |||||
* 打开表单 | |||||
* @param props 表单参数 | |||||
*/ | |||||
function onOpen(props: FormProps.Base<SysUserPersonnel.SysUserPerInfo>) { | |||||
Object.assign(sysUserProps, props); //合并参数 | |||||
if (props.opt == FormOptEnum.ADD) { | |||||
//如果是新增,设置默认值 | |||||
// sysUserProps.record.sortCode = 99; | |||||
} | |||||
visible.value = true; //显示表单 | |||||
if (props.record.personId) { | |||||
//如果传了id,就去请求api获取record | |||||
userManagePersonnelApi.detail({ id: props.record.personId }).then(res => { | |||||
sysUserProps.record = res.data; | |||||
}); | |||||
} | |||||
} | |||||
// 提交数据(新增/编辑) | |||||
const sysUserFormRef = ref<FormInstance>(); | |||||
/** 提交表单 */ | |||||
async function handleSubmit() { | |||||
sysUserFormRef.value?.validate(async valid => { | |||||
if (!valid) return; //表单验证失败 | |||||
//提交表单 | |||||
if (sysUserProps.record.faces.length === 0) { | |||||
return ElMessage.error("请上传人脸图片"); | |||||
} | |||||
if (sysUserProps.record.personId) { | |||||
await userManagePersonnelApi | |||||
.update(sysUserProps.record) | |||||
.then(() => { | |||||
sysUserProps.successful!(); //调用父组件的successful方法 | |||||
}) | |||||
.finally(() => { | |||||
onClose(); | |||||
}); | |||||
} else { | |||||
await userManagePersonnelApi | |||||
.add(sysUserProps.record) | |||||
.then(() => { | |||||
sysUserProps.successful!(); //调用父组件的successful方法 | |||||
}) | |||||
.finally(() => { | |||||
onClose(); | |||||
}); | |||||
} | |||||
}); | |||||
} | |||||
/** 关闭表单*/ | |||||
function onClose() { | |||||
visible.value = false; | |||||
activeName.value = "basic"; | |||||
} | |||||
// 暴露给父组件的方法 | |||||
defineExpose({ | |||||
onOpen | |||||
}); | |||||
</script> | |||||
<style lang="scss" scoped></style> |
@@ -0,0 +1,107 @@ | |||||
<!-- | |||||
* @Description: 表单 | |||||
* @Author: syy | |||||
* @Date: 2023-12-15 15:45:59 | |||||
--> | |||||
<template> | |||||
<div> | |||||
<form-container v-model="visibleClass" :title="`${sysUserProps.opt}班级`" form-size="400px" @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="22"> | |||||
<s-form-item label="班级名称" prop="personSetName"> | |||||
<s-input v-model="sysUserProps.record.personSetName"></s-input> | |||||
</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="SysUserPerformClass"> | |||||
import { ref } from "vue"; | |||||
import { SysUserPersonnel, userManageClassManageApi } from "@/api"; | |||||
import { FormOptEnum } from "@/enums"; | |||||
import { required } from "@/utils/formRules"; | |||||
import { FormInstance } from "element-plus"; | |||||
const visibleClass = ref(false); //是否显示表单 | |||||
// 表单参数 | |||||
const sysUserProps = reactive<FormProps.Base<SysUserPersonnel.ClassPage>>({ | |||||
opt: FormOptEnum.ADD, | |||||
record: {}, | |||||
disabled: false | |||||
}); | |||||
// 表单验证规则 | |||||
const rules = reactive({ | |||||
personSetName: [required("请输入班级名称")] | |||||
}); | |||||
/** | |||||
* 打开表单 | |||||
* @param props 表单参数 | |||||
*/ | |||||
function onOpen(props: FormProps.Base<SysUserPersonnel.ClassPage>) { | |||||
Object.assign(sysUserProps, props); //合并参数 | |||||
visibleClass.value = true; //显示表单 | |||||
sysUserProps.record = props.record; | |||||
} | |||||
// 提交数据(新增/编辑) | |||||
const sysUserFormRef = ref<FormInstance>(); | |||||
/** 提交表单 */ | |||||
async function handleSubmit() { | |||||
sysUserFormRef.value?.validate(async valid => { | |||||
if (!valid) return; //表单验证失败 | |||||
sysUserProps.record.name = sysUserProps.record.personSetName; | |||||
//提交表单 | |||||
if (sysUserProps.record.personSetId) { | |||||
sysUserProps.record.id = sysUserProps.record.personSetId; | |||||
await userManageClassManageApi | |||||
.update(sysUserProps.record) | |||||
.then(() => { | |||||
sysUserProps.successful!(); //调用父组件的successful方法 | |||||
}) | |||||
.finally(() => { | |||||
onClose(); | |||||
}); | |||||
} else { | |||||
await userManageClassManageApi | |||||
.add(sysUserProps.record) | |||||
.then(() => { | |||||
sysUserProps.successful!(); //调用父组件的successful方法 | |||||
}) | |||||
.finally(() => { | |||||
onClose(); | |||||
}); | |||||
} | |||||
}); | |||||
} | |||||
/** 关闭表单*/ | |||||
function onClose() { | |||||
visibleClass.value = false; | |||||
} | |||||
// 暴露给父组件的方法 | |||||
defineExpose({ | |||||
onOpen | |||||
}); | |||||
</script> | |||||
<style lang="scss" scoped></style> |
@@ -0,0 +1,291 @@ | |||||
<!-- | |||||
* @Description: 人员管理 | |||||
* @Author: syy | |||||
* @Date: 2024-7-15 | |||||
--> | |||||
<template> | |||||
<div class="main-box"> | |||||
<TreeFilter | |||||
ref="treeFilter" | |||||
label="personSetName" | |||||
id="personSetId" | |||||
width="300px" | |||||
:show-all="false" | |||||
:request-api="userManageClassManageApi.page" | |||||
@change="changeTreeFilter" | |||||
> | |||||
<template v-slot:header> | |||||
<s-button suffix="班级" @click="addClass(FormOptEnum.ADD)" style="margin-bottom: 15px" /> | |||||
</template> | |||||
<template v-slot:label="{ row }"> | |||||
<span class="custom-tree-node"> | |||||
<span>{{ row.node.label }}</span> | |||||
<span> | |||||
<a @click="addClass(FormOptEnum.EDIT, row.node.data)"> | |||||
<el-icon><Edit /></el-icon> | |||||
</a> | |||||
<a style="margin-left: 8px" @click="addDelete(row.node.data.personSetId, '删除班级')"> | |||||
<el-icon><Delete /></el-icon> | |||||
</a> | |||||
</span> | |||||
</span> | |||||
</template> | |||||
</TreeFilter> | |||||
<div class="table-box"> | |||||
<ProTable ref="proTable" title="人员管理" :columns="columns" rowKey="personId" :request-api="userManagePersonnelApi.page"> | |||||
<!-- 表格 header 按钮 --> | |||||
<template #tableHeader="scope"> | |||||
<s-button v-auth="userPerButtonCode.add" suffix="人员" @click="onOpen(FormOptEnum.ADD, { personSetId: personSetId })" /> | |||||
<s-button | |||||
v-auth="userPerButtonCode.delete" | |||||
type="danger" | |||||
:opt="FormOptEnum.DELETE" | |||||
plain | |||||
suffix="人员" | |||||
:disabled="!scope.isSelected" | |||||
@click="onDelete(scope.selectedListIds, '删除所选人员')" | |||||
/> | |||||
</template> | |||||
<!-- 表格操作栏 --> | |||||
<template #operation="scope"> | |||||
<el-space> | |||||
<s-button v-auth="userPerButtonCode.edit" link :opt="FormOptEnum.EDIT" @click="onOpen(FormOptEnum.EDIT, scope.row)" /> | |||||
<s-button v-auth="userPerButtonCode.delete" link :opt="FormOptEnum.DELETE" @click="onDelete([scope.row.personId], `删除人员`)" /> | |||||
<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.AddFace)" | |||||
><el-upload | |||||
ref="upload" | |||||
class="upload-demo" | |||||
action="/api/business/personApi/uploadFile" | |||||
:show-file-list="false" | |||||
:on-success="handleAvatarSuccess" | |||||
accept=".jpg, .jpeg, .png" | |||||
:headers="{ | |||||
Authorization: `${TokenEnum.TOKEN_PREFIX} ${accessToken}` | |||||
}" | |||||
> | |||||
<template #trigger> | |||||
{{ cmdEnum.AddFace }} | |||||
</template> | |||||
</el-upload> | |||||
</el-dropdown-item> | |||||
<el-dropdown-item :command="command(scope.row, cmdEnum.UnderpantsUnBinding)"> | |||||
{{ cmdEnum.UnderpantsUnBinding }} | |||||
</el-dropdown-item> | |||||
</el-dropdown-menu> | |||||
</template> | |||||
</el-dropdown> | |||||
</el-space> | |||||
</template> | |||||
</ProTable> | |||||
</div> | |||||
<!-- 人员新增/编辑表单 --> | |||||
<Form ref="formRef"></Form> | |||||
<!-- 班级新增/编辑表单 --> | |||||
<FormClass ref="formRefC" /> | |||||
<!-- 预览头像 --> | |||||
<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> | |||||
</div> | |||||
</template> | |||||
<script setup lang="tsx" name="SysUserPersonnel"> | |||||
import { userManagePersonnelApi,userPerButtonCode,SysUserPersonnel,userManageClassManageApi } from "@/api"; | |||||
import { useHandleData } from "@/hooks/useHandleData"; | |||||
import { FormOptEnum } from "@/enums"; | |||||
import Form from "./components/form/index.vue"; | |||||
import FormClass from "./components/formClass/index.vue"; | |||||
import { ArrowDown } from "@element-plus/icons-vue"; | |||||
import { ColumnProps, ProTableInstance } from "@/components/ProTable/interface"; | |||||
import TreeFilter from "@/components/TreeFilter/index.vue"; | |||||
import { useUserStore } from "@/stores/modules"; | |||||
import { TokenEnum } from "@/enums"; | |||||
import type { UploadProps } from "element-plus"; | |||||
// 获取 ProTable 元素,调用其获取刷新数据方法(还能获取到当前查询参数,方便导出携带参数) | |||||
const faceUrl = ref(''); | |||||
const visible = ref(false); //是否显示人员表单 | |||||
const proTable = ref<ProTableInstance>(); | |||||
const treeFilter = ref<InstanceType<typeof TreeFilter> | null>(null); | |||||
const userStore = useUserStore(); | |||||
const { accessToken } = userStore; | |||||
// 表格配置项 | |||||
const columns: ColumnProps<SysUserPersonnel.SysUserPerInfo>[] = [ | |||||
{ type: "selection", fixed: "left", width: 50 }, | |||||
{ | |||||
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: "age", | |||||
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 | |||||
console.log(faceUrl); | |||||
}; | |||||
const handleClose = () => { | |||||
visible.value = false; | |||||
}; | |||||
// 人员表单引用 | |||||
const formRef = ref<InstanceType<typeof Form> | null>(null); | |||||
// 班级表单引用 | |||||
const formRefC = ref<InstanceType<typeof FormClass> | null>(null); | |||||
/** | |||||
* 打开表单 | |||||
* @param opt 操作类型 | |||||
* @param record 记录 | |||||
*/ | |||||
function onOpen(opt: FormOptEnum, record: {} | SysUserPersonnel.SysUserPerInfo = {}) { | |||||
formRef.value?.onOpen({ opt: opt, record: record, successful: RefreshTable }); | |||||
} | |||||
/** | |||||
* 打开班级表单 | |||||
* @param opt 操作类型 | |||||
* @param record 记录 | |||||
*/ | |||||
function addClass(opt: FormOptEnum, record: {} | SysUserPersonnel.ClassPage = {}) { | |||||
formRefC.value?.onOpen({ opt: opt, record: record, successful: RefreshTable }); | |||||
} | |||||
/** | |||||
* 班级删除 | |||||
* @param ids id数组 | |||||
*/ | |||||
async function addDelete(id: string[],msg: string) { | |||||
// 二次确认 => 请求api => 刷新表格 | |||||
await useHandleData(userManageClassManageApi.delete, { id }, msg); | |||||
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(); | |||||
treeFilter.value?.refresh(); //刷新树形筛选器 | |||||
} | |||||
/** 更多下拉菜单命令枚举 */ | |||||
enum cmdEnum { | |||||
AddFace = "添加人脸", | |||||
UnderpantsUnBinding = "底库解绑" | |||||
} | |||||
/** 下拉菜单参数接口 */ | |||||
interface Command { | |||||
row: SysUserPersonnel.SysUserPerInfo; | |||||
command: cmdEnum; | |||||
} | |||||
/**配置command的参数 */ | |||||
function command(row: SysUserPersonnel.SysUserPerInfo, command: cmdEnum): Command { | |||||
return { | |||||
row: row, | |||||
command: command | |||||
}; | |||||
} | |||||
/** | |||||
* 更多下拉菜单点击事件 | |||||
* @param command | |||||
*/ | |||||
const personId = ref<number | string>(); //人员id | |||||
function handleCommand(command: Command) { | |||||
switch (command.command) { | |||||
case cmdEnum.AddFace: | |||||
personId.value = command.row.personId; //获取人员id | |||||
break | |||||
case cmdEnum.UnderpantsUnBinding: | |||||
userManagePersonnelApi.personUnBindDfie({ | |||||
personId:command.row.personId, | |||||
personSetId: command.row.personSets[0].personSetId | |||||
}).then(res=>{ | |||||
if(res.code == 200){ | |||||
ElMessage.success('底库解绑成功'); | |||||
RefreshTable() | |||||
} | |||||
}) | |||||
break; | |||||
} | |||||
} | |||||
const handleAvatarSuccess: UploadProps["onSuccess"] = (response, uploadFile) => { | |||||
if (response.code === 200) { | |||||
userManagePersonnelApi.addFace({ | |||||
personId: personId.value, | |||||
faceUrl: response.data | |||||
}).then(res=>{ | |||||
RefreshTable() | |||||
}) | |||||
} else { | |||||
ElMessage.error(response.msg); | |||||
} | |||||
}; | |||||
/** 部门切换 */ | |||||
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> |
@@ -7,13 +7,13 @@ | |||||
<div class="card content-main"> | <div class="card content-main"> | ||||
<el-row :gutter="20"> | <el-row :gutter="20"> | ||||
<el-col :xs="24" :sm="24" :md="12" :lg="12" :xl="12"> | <el-col :xs="24" :sm="24" :md="12" :lg="12" :xl="12"> | ||||
<div ref="chart1" style="width: 600px; height: 400px"></div> | |||||
<div ref="chart1" style="width: 600px; height: 378px"></div> | |||||
</el-col> | </el-col> | ||||
<el-col :xs="24" :sm="24" :md="12" :lg="12" :xl="12"> | <el-col :xs="24" :sm="24" :md="12" :lg="12" :xl="12"> | ||||
<div ref="chart2" style="width: 600px; height: 400px"></div> | |||||
<div ref="chart2" style="width: 600px; height: 378px"></div> | |||||
</el-col> | </el-col> | ||||
<el-col :span="24"> | <el-col :span="24"> | ||||
<div ref="chart3" style="width: 100%; height: 400px"></div> | |||||
<div ref="chart3" style="width: 100%; height: 378px"></div> | |||||
</el-col> | </el-col> | ||||
</el-row> | </el-row> | ||||
</div> | </div> | ||||
@@ -110,7 +110,28 @@ import { ColumnProps, ProTableInstance } from "@/components/ProTable/interface"; | |||||
import { useDictStore } from "@/stores/modules"; | import { useDictStore } from "@/stores/modules"; | ||||
import { FormOptEnum, SysDictEnum, MenuTypeDictEnum } from "@/enums"; | import { FormOptEnum, SysDictEnum, MenuTypeDictEnum } from "@/enums"; | ||||
const visible = ref(false); //是否显示表单 | const visible = ref(false); //是否显示表单 | ||||
onMounted(() => { | |||||
getWarnTypeList(); | |||||
}); | |||||
let warnOptions = ref([]); | |||||
function getWarnTypeList() { | |||||
setTimeout(async ()=> { | |||||
await warnZJRQApi.warnType({}).then(res => { | |||||
let { code, data } = res; | |||||
if (code == 200) { | |||||
warnOptions.value = data.map(item => { | |||||
return { | |||||
label: item.name, | |||||
value: item.code | |||||
}; | |||||
}) | |||||
} | |||||
}); | |||||
}) | |||||
} | |||||
// 获取 ProTable 元素,调用其获取刷新数据方法(还能获取到当前查询参数,方便导出携带参数) | // 获取 ProTable 元素,调用其获取刷新数据方法(还能获取到当前查询参数,方便导出携带参数) | ||||
const proTable = ref<ProTableInstance>(); | const proTable = ref<ProTableInstance>(); | ||||
const dictStore = useDictStore(); | const dictStore = useDictStore(); | ||||
@@ -118,7 +139,7 @@ const dictStore = useDictStore(); | |||||
// 表格配置项 | // 表格配置项 | ||||
const columns: ColumnProps<ZJRQ.WarnInfo>[] = [ | const columns: ColumnProps<ZJRQ.WarnInfo>[] = [ | ||||
{ type: "selection", fixed: "left", width: 80 }, | { type: "selection", fixed: "left", width: 80 }, | ||||
{ prop: "searchKey", label: "关键字", search: { el: "input" }, isShow: false }, | |||||
// { prop: "searchKey", label: "关键字", search: { el: "input" }, isShow: false }, | |||||
// { prop: "cameraId", label: "所属摄像头", search: { el: "input" }, isShow: false }, | // { prop: "cameraId", label: "所属摄像头", search: { el: "input" }, isShow: false }, | ||||
// { prop: "alarmTypeDesc", label: "告警类型", search: { el: "input" }, isShow: false }, | // { prop: "alarmTypeDesc", label: "告警类型", search: { el: "input" }, isShow: false }, | ||||
{ | { | ||||
@@ -151,21 +172,75 @@ const columns: ColumnProps<ZJRQ.WarnInfo>[] = [ | |||||
} | } | ||||
}, | }, | ||||
{ | { | ||||
prop: "alarmTypeDesc", | |||||
label: "告警类型" | |||||
prop: "alarmType", | |||||
label: "告警类型", | |||||
enum: warnOptions, | |||||
search: { | |||||
el: "tree-select", | |||||
// span: 1 | |||||
} | |||||
}, | }, | ||||
{ | { | ||||
prop: "warnHand", | prop: "warnHand", | ||||
label: "处理状态", | label: "处理状态", | ||||
enum: [ | |||||
{ | |||||
label: "已处理", | |||||
value: 1 | |||||
}, | |||||
{ | |||||
label: "未处理", | |||||
value: 0 | |||||
} | |||||
], | |||||
render: scope => { | render: scope => { | ||||
if (scope.row.warnHand === 1) { | if (scope.row.warnHand === 1) { | ||||
return "已处理"; | return "已处理"; | ||||
} else { | } else { | ||||
return "未处理"; | return "未处理"; | ||||
} | } | ||||
} | |||||
}, | |||||
search: { | |||||
el: "tree-select", | |||||
// span: 1 | |||||
} | |||||
}, | }, | ||||
{ prop: "tick", label: "预警时间" }, | |||||
{ | |||||
prop: "tick", | |||||
label: "预警时间", | |||||
search: { | |||||
// 自定义 search 组件 | |||||
span: 1, | |||||
render: ({ searchParam }) => { | |||||
return ( | |||||
<div class="flex-center"> | |||||
<el-date-picker | |||||
style="150px; flex-shink: 1;" | |||||
v-model={searchParam.StartTick} | |||||
type="datetime" | |||||
placeholder="开始时间" | |||||
format="YYYY-MM-DD HH:mm:ss" | |||||
date-format="YYYY-MM-DD" | |||||
time-format="HH:mm:ss" | |||||
value-format="YYYY-MM-DD HH:mm:ss" | |||||
/> | |||||
<span class="mr10 ml10">-</span> | |||||
<el-date-picker | |||||
style="150px;" | |||||
v-model={searchParam.EndTick} | |||||
type="datetime" | |||||
placeholder="结束时间" | |||||
format="YYYY-MM-DD HH:mm:ss" | |||||
date-format="YYYY-MM-DD" | |||||
time-format="HH:mm:ss" | |||||
value-format="YYYY-MM-DD HH:mm:ss" | |||||
/> | |||||
</div> | |||||
); | |||||
} | |||||
} | |||||
}, | |||||
{ prop: "operation", label: "操作", width: 250, fixed: "right" } | { prop: "operation", label: "操作", width: 250, fixed: "right" } | ||||
]; | ]; | ||||