@@ -23,5 +23,5 @@ VITE_HTTP_PROXY = true | |||||
# 开发环境跨域代理,支持配置多个 | # 开发环境跨域代理,支持配置多个 | ||||
# VITE_PROXY = [["/api","http://192.168.10.186:5566","/Files"]] | # VITE_PROXY = [["/api","http://192.168.10.186:5566","/Files"]] | ||||
VITE_PROXY = [["/api","http://192.168.10.186:8003"],["/Files","artc://rts-pull-live.deepeleph.com"]] | |||||
VITE_PROXY = [["/api","http://192.168.10.186:8003"],["/Files","http://192.168.10.186:8003/Files"]] | |||||
@@ -2,6 +2,7 @@ | |||||
"name": "simple-admin", | "name": "simple-admin", | ||||
"private": true, | "private": true, | ||||
"version": "1.0.0", | "version": "1.0.0", | ||||
"node-version": "18.12.0 - 20.9.0", | |||||
"type": "module", | "type": "module", | ||||
"description": "SimpleAdmin是ElementUI最好看的开源通用业务型后台管理系统", | "description": "SimpleAdmin是ElementUI最好看的开源通用业务型后台管理系统", | ||||
"author": { | "author": { | ||||
@@ -26,6 +26,8 @@ export namespace SysDormitory { | |||||
name?: string | undefined; | name?: string | undefined; | ||||
gender?: boolean | undefined; | gender?: boolean | undefined; | ||||
createTime?: string | undefined; | createTime?: string | undefined; | ||||
insCameraId?: string | number | undefined; | |||||
outCameraId?: string | number | undefined; | |||||
} | } | ||||
// 寝室列表传参 | // 寝室列表传参 | ||||
export interface Page extends ReqPage { | export interface Page extends ReqPage { | ||||
@@ -41,5 +41,7 @@ export namespace ZJRQ { | |||||
rects: string; | rects: string; | ||||
/** 扩展字段 */ | /** 扩展字段 */ | ||||
extend: string; | extend: string; | ||||
// 处理意见 | |||||
remark: string; | |||||
} | } | ||||
} | } |
@@ -1,5 +1,5 @@ | |||||
/** | /** | ||||
* @description 学生归寝 | |||||
* @description 考勤事件管理 | |||||
* @license Apache License Version 2.0 | * @license Apache License Version 2.0 | ||||
* @Copyright (c) 2022-Now 少林寺驻北固山办事处大神父王喇嘛 | * @Copyright (c) 2022-Now 少林寺驻北固山办事处大神父王喇嘛 | ||||
* @remarks | * @remarks | ||||
@@ -13,31 +13,30 @@ | |||||
* @see https://gitee.com/dotnetmoyu/SimpleAdmin | * @see https://gitee.com/dotnetmoyu/SimpleAdmin | ||||
*/ | */ | ||||
import { moduleRequest } from "@/api/request"; | import { moduleRequest } from "@/api/request"; | ||||
import { ReqId, SysUserPersonnel } from "@/api/interface"; | |||||
const http = moduleRequest("/business/dfieldApi/"); | |||||
const http = moduleRequest("/business/attendanceApi/"); | |||||
/** | /** | ||||
* @Description: 单页管理 | * @Description: 单页管理 | ||||
* @Author: SYY | |||||
* @Author: yxq | |||||
* @Date: 2023-12-15 15:34:54 | * @Date: 2023-12-15 15:34:54 | ||||
*/ | */ | ||||
const attendanceStudentsReturn = { | |||||
/** 查询底库列表 */ | |||||
page(params: SysUserPersonnel.ClassPage) { | |||||
return http.get("test", params); | |||||
const attendanceApi = { | |||||
/** 查询考勤记录列表 */ | |||||
page(params: any) { | |||||
return http.get("getPageList", params); | |||||
}, | }, | ||||
/** 删除底库 */ | |||||
delete(params: ReqId) { | |||||
return http.delete("test", params); | |||||
/** 查询所有列表 */ | |||||
list(params: any) { | |||||
return http.get("getNoPageList", params); | |||||
}, | }, | ||||
/** 创建底库 */ | |||||
add(params: SysUserPersonnel.ClassPage) { | |||||
return http.post("test", params); | |||||
/** 添加考勤记录 */ | |||||
add(params: any) { | |||||
return http.post("add", params); | |||||
}, | |||||
/** 根据楼栋查询出入记录 */ | |||||
pageByBuild(params: any) { | |||||
return http.get("getPageListByBuild", params); | |||||
}, | }, | ||||
/** 更新底库 */ | |||||
update(params: SysUserPersonnel.ClassPage) { | |||||
return http.put("test", params); | |||||
} | |||||
}; | }; | ||||
export { attendanceStudentsReturn }; | |||||
export { attendanceApi }; |
@@ -15,5 +15,4 @@ | |||||
export * from "./behaviorTrace"; | export * from "./behaviorTrace"; | ||||
export * from "./passenger"; | export * from "./passenger"; | ||||
export * from "./roolcall"; | export * from "./roolcall"; | ||||
export * from "./studentsReturn"; | |||||
export * from "./attendanceApi"; |
@@ -20,4 +20,5 @@ export * from "./monitor"; | |||||
export * from "./sysconfig"; | export * from "./sysconfig"; | ||||
export * from "./statistion"; | export * from "./statistion"; | ||||
export * from "./usermanage"; | export * from "./usermanage"; | ||||
export * from "./attendance"; | |||||
export * from "./attendance"; | |||||
export * from "./violation"; |
@@ -13,11 +13,11 @@ | |||||
* @see https://gitee.com/dotnetmoyu/SimpleAdmin | * @see https://gitee.com/dotnetmoyu/SimpleAdmin | ||||
*/ | */ | ||||
import { moduleRequest } from "@/api/request"; | import { moduleRequest } from "@/api/request"; | ||||
import { ReqId, ResPage, ZJRQ,setWarn } from "@/api/interface"; | |||||
import { ReqId, ResPage, ZJRQ, setWarn } from "@/api/interface"; | |||||
const http = moduleRequest("/business/warn/"); | const http = moduleRequest("/business/warn/"); | ||||
const http1 = moduleRequest("/violation/analysis/"); | |||||
const abilityApi = { | const abilityApi = { | ||||
/** 获取告警分组 */ | /** 获取告警分组 */ | ||||
warnGroup(params: ReqId) { | warnGroup(params: ReqId) { | ||||
return http.get("getWarnGroup", params); | return http.get("getWarnGroup", params); | ||||
@@ -26,6 +26,12 @@ const abilityApi = { | |||||
setWarnGroup(params: setWarn) { | setWarnGroup(params: setWarn) { | ||||
return http.post("setWarnGroupDevice", params); | return http.post("setWarnGroupDevice", params); | ||||
}, | }, | ||||
/* 预警分析报告导出 */ | |||||
reportExport(params: any) { | |||||
return http1.download("reportExport", params, { | |||||
showHeader: true | |||||
}); | |||||
} | |||||
}; | }; | ||||
export { abilityApi }; | export { abilityApi }; |
@@ -53,7 +53,7 @@ const userManageDormitoryApi = { | |||||
}, | }, | ||||
/** 删除寝室 */ | /** 删除寝室 */ | ||||
delete(params: ReqId) { | delete(params: ReqId) { | ||||
return httpChamber.delete("delete", params); | |||||
return httpChamber.post("delete", params); | |||||
}, | }, | ||||
/**寝室分配人员*/ | /**寝室分配人员*/ | ||||
setAssignPerson(params: SysDormitory.ChamberPersonnel) { | setAssignPerson(params: SysDormitory.ChamberPersonnel) { | ||||
@@ -68,7 +68,7 @@ const userManageDormitoryApi = { | |||||
return httpChamber.get("getReturnInfo", params); | return httpChamber.get("getReturnInfo", params); | ||||
}, | }, | ||||
/** 获取详情(带寝室人员) */ | /** 获取详情(带寝室人员) */ | ||||
detail(params: ReqId) { | |||||
detail(params: any) { | |||||
return httpChamber.get("getInfo", params); | return httpChamber.get("getInfo", params); | ||||
}, | }, | ||||
/** 设置归寝时间 */ | /** 设置归寝时间 */ | ||||
@@ -76,8 +76,8 @@ const userManageDormitoryApi = { | |||||
return httpChamber.post("setReturnTime", params); | return httpChamber.post("setReturnTime", params); | ||||
}, | }, | ||||
/** 获取归寝时间 */ | /** 获取归寝时间 */ | ||||
getReturnTime(params: ReqId) { | |||||
return httpChamber.get("getReturnTime", params); | |||||
getReturnTime() { | |||||
return httpChamber.get("getReturnTime"); | |||||
} | } | ||||
}; | }; | ||||
@@ -27,7 +27,7 @@ const userManagePersonnelApi = { | |||||
return http.post("pageQuery", params); | return http.post("pageQuery", params); | ||||
}, | }, | ||||
/** 获取单页详情 */ | /** 获取单页详情 */ | ||||
detail(params: ReqId) { | |||||
detail(params: any) { | |||||
return http.get("getPersionById", params); | return http.get("getPersionById", params); | ||||
}, | }, | ||||
/** 删除人员 */ | /** 删除人员 */ | ||||
@@ -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 "./portraitSummary"; |
@@ -0,0 +1,45 @@ | |||||
/** | |||||
* @description 学校画像接口 | |||||
* @license Apache License Version 2.0 | |||||
* @Copyright (c) 2022-Now 少林寺驻北固山办事处大神父王喇嘛 | |||||
* @remarks | |||||
* SimpleAdmin 基于 Apache License Version 2.0 协议发布,可用于商业项目,但必须遵守以下补充条款: | |||||
* 1.请不要删除和修改根目录下的LICENSE文件。 | |||||
* 2.请不要删除和修改SimpleAdmin源码头部的版权声明。 | |||||
* 3.分发源码时候,请注明软件出处 https://gitee.com/dotnetmoyu/SimpleAdmin | |||||
* 4.基于本软件的作品,只能使用 SimpleAdmin 作为后台服务,除外情况不可商用且不允许二次分发或开源。 | |||||
* 5.请不得将本软件应用于危害国家安全、荣誉和利益的行为,不能以任何形式用于非法为目的的行为不要删除和修改作者声明。 | |||||
* 6.任何基于本软件而产生的一切法律纠纷和责任,均于我司无关 | |||||
* @see https://gitee.com/dotnetmoyu/SimpleAdmin | |||||
*/ | |||||
import { moduleRequest } from "@/api/request"; | |||||
const http = moduleRequest("/violation/portraitSummary/"); | |||||
/** | |||||
* @Description: 学校画像 | |||||
* @Author: SYY | |||||
* @Date: 2024-7-30 15:34:54 | |||||
*/ | |||||
const portraitSummaryApi = { | |||||
/** 获取学生性别 */ | |||||
getStudentSex() { | |||||
return http.get("getStudentSex"); | |||||
}, | |||||
/** 获取学生年龄 */ | |||||
getStudentAge() { | |||||
return http.get("getStudentAge"); | |||||
}, | |||||
/** 获取地理位置 */ | |||||
getAddress() { | |||||
return http.get("getAddress"); | |||||
}, | |||||
/** 获取属性标签 */ | |||||
getStudentAttr() { | |||||
return http.get("getStudentAttr"); | |||||
}, | |||||
/** 获取学生属性标签 */ | |||||
getStudentDetail(params: any) { | |||||
return http.get("getStudentDetail", params); | |||||
} | |||||
}; | |||||
export { portraitSummaryApi }; |
@@ -42,6 +42,10 @@ const warnZJRQApi = { | |||||
warnType(params: ReqId) { | warnType(params: ReqId) { | ||||
return http.get("getAlarmType", params); | return http.get("getAlarmType", params); | ||||
}, | }, | ||||
/** 处理告警 */ | |||||
handWarn(params: ReqId) { | |||||
return http.post("handWarn", params); | |||||
} | |||||
}; | }; | ||||
export { warnZJRQApi }; | export { warnZJRQApi }; |
@@ -22,6 +22,7 @@ import { checkStatus } from "../helper/checkStatus"; | |||||
import { useUserStore } from "@/stores/modules"; | import { useUserStore } from "@/stores/modules"; | ||||
import { AxiosCanceler } from "../helper/axiosCancel"; | import { AxiosCanceler } from "../helper/axiosCancel"; | ||||
import router from "@/routers"; | import router from "@/routers"; | ||||
import { i } from "vite/dist/node/types.d-jgA8ss1A"; | |||||
// 自定义 AxiosRequestConfig 接口,增加 noLoading 属性 | // 自定义 AxiosRequestConfig 接口,增加 noLoading 属性 | ||||
export interface CustomAxiosRequestConfig extends InternalAxiosRequestConfig { | export interface CustomAxiosRequestConfig extends InternalAxiosRequestConfig { | ||||
@@ -111,7 +112,7 @@ export default class RequestHttp { | |||||
(response: AxiosResponse) => { | (response: AxiosResponse) => { | ||||
// 检查并存储授权信息 | // 检查并存储授权信息 | ||||
this.checkAndStoreAuthentication(response); | this.checkAndStoreAuthentication(response); | ||||
const { data, config } = response; | |||||
const { data, config }: any = response; | |||||
const userStore = useUserStore(); | const userStore = useUserStore(); | ||||
axiosCanceler.removePending(config); | axiosCanceler.removePending(config); | ||||
tryHideFullScreenLoading(); | tryHideFullScreenLoading(); | ||||
@@ -140,7 +141,11 @@ export default class RequestHttp { | |||||
}); | }); | ||||
} | } | ||||
// 成功请求(在页面上除非特殊情况,否则不用处理失败逻辑) | // 成功请求(在页面上除非特殊情况,否则不用处理失败逻辑) | ||||
return data; | |||||
if (config.showHeader) { | |||||
return response; //平时用在打印、导出、下载的时候使用 | |||||
} else { | |||||
return data; | |||||
} | |||||
}, | }, | ||||
async (error: AxiosError) => { | async (error: AxiosError) => { | ||||
const { response } = error; | const { response } = error; | ||||
@@ -4,7 +4,7 @@ | |||||
* @Date: 2023-12-15 15:38:32 | * @Date: 2023-12-15 15:38:32 | ||||
!--> | !--> | ||||
<template> | <template> | ||||
<el-select :placeholder="placeholder" class="w-full" v-bind="$attrs" clearable> | |||||
<el-select :placeholder="placeholder" :filterable="filterable" class="w-full" v-bind="$attrs" clearable> | |||||
<el-option v-for="(item, index) in options" :key="index" :label="item[props.label]" :value="item[props.value]" /> | <el-option v-for="(item, index) in options" :key="index" :label="item[props.label]" :value="item[props.value]" /> | ||||
</el-select> | </el-select> | ||||
</template> | </template> | ||||
@@ -20,7 +20,8 @@ const props = withDefaults(defineProps<SSelectProps>(), { | |||||
options: [] as any, | options: [] as any, | ||||
value: "value", | value: "value", | ||||
label: "label", | label: "label", | ||||
button: false | |||||
button: false, | |||||
filterable: false //是否可搜索 | |||||
}); | }); | ||||
const placeholder = computed(() => { | const placeholder = computed(() => { | ||||
@@ -21,4 +21,5 @@ export interface SSelectProps { | |||||
label?: string; | label?: string; | ||||
/** 选项值 */ | /** 选项值 */ | ||||
value?: string; | value?: string; | ||||
filterable?: boolean; | |||||
} | } |
@@ -20,7 +20,15 @@ | |||||
</div> | </div> | ||||
</div> | </div> | ||||
<!-- 表格主体 --> | <!-- 表格主体 --> | ||||
<el-table ref="tableRef" v-bind="$attrs" :data="processTableData" :border="border" :row-key="rowKey" @selection-change="selectionChange"> | |||||
<el-table | |||||
ref="tableRef" | |||||
v-bind="$attrs" | |||||
:data="processTableData" | |||||
:border="border" | |||||
:max-height="maxHeight" | |||||
:row-key="rowKey" | |||||
@selection-change="selectionChange" | |||||
> | |||||
<!-- 默认插槽 --> | <!-- 默认插槽 --> | ||||
<slot /> | <slot /> | ||||
<template v-for="item in tableColumns" :key="item"> | <template v-for="item in tableColumns" :key="item"> | ||||
@@ -113,6 +121,7 @@ export interface ProTableProps { | |||||
rowKey?: string; // 行数据的 Key,用来优化 Table 的渲染,当表格数据多选时,所指定的 id ==> 非必传(默认为 id) | rowKey?: string; // 行数据的 Key,用来优化 Table 的渲染,当表格数据多选时,所指定的 id ==> 非必传(默认为 id) | ||||
searchCol?: number | Record<BreakPoint, number>; // 表格搜索项 每列占比配置 ==> 非必传 { xs: 1, sm: 2, md: 2, lg: 3, xl: 4 } | searchCol?: number | Record<BreakPoint, number>; // 表格搜索项 每列占比配置 ==> 非必传 { xs: 1, sm: 2, md: 2, lg: 3, xl: 4 } | ||||
pagerCount?: number; // 分页组件显示最大页码按钮数 ==> 非必传(默认为7) | pagerCount?: number; // 分页组件显示最大页码按钮数 ==> 非必传(默认为7) | ||||
maxHeight?: number | string; | |||||
} | } | ||||
// 接受父组件参数,配置默认值 | // 接受父组件参数,配置默认值 | ||||
@@ -52,7 +52,7 @@ | |||||
</el-tabs> | </el-tabs> | ||||
</el-col> | </el-col> | ||||
<el-col :span="10"> | <el-col :span="10"> | ||||
<ProTable ref="userTable" :columns="columns" :tool-button="false" :init-param="initParam" :request-api="userSelectorApi"> | |||||
<ProTable ref="userTable" :columns="columns" maxHeight="480" :tool-button="false" :init-param="initParam" :request-api="userSelectorApi"> | |||||
<!-- 表格 header 按钮 --> | <!-- 表格 header 按钮 --> | ||||
<template #tableHeader="scope"> | <template #tableHeader="scope"> | ||||
<el-button type="primary" @click="addRecords(userTable!.tableData)">添加当前</el-button> | <el-button type="primary" @click="addRecords(userTable!.tableData)">添加当前</el-button> | ||||
@@ -65,7 +65,15 @@ | |||||
</ProTable> | </ProTable> | ||||
</el-col> | </el-col> | ||||
<el-col :span="10"> | <el-col :span="10"> | ||||
<ProTable ref="chooseTable" :columns="columns" :tool-button="true" :data="chooseDataTmp" @search="searchRecords" @reset="resetRecords"> | |||||
<ProTable | |||||
ref="chooseTable" | |||||
:columns="columns" | |||||
maxHeight="480" | |||||
:tool-button="true" | |||||
:data="chooseDataTmp" | |||||
@search="searchRecords" | |||||
@reset="resetRecords" | |||||
> | |||||
<!-- 表格 header 按钮 --> | <!-- 表格 header 按钮 --> | ||||
<template #tableHeader="scope"> | <template #tableHeader="scope"> | ||||
<el-button type="danger" @click="delRecords(chooseTable!.tableData)">删除当前</el-button> | <el-button type="danger" @click="delRecords(chooseTable!.tableData)">删除当前</el-button> | ||||
@@ -84,12 +92,18 @@ | |||||
</el-row> | </el-row> | ||||
</div> | </div> | ||||
<template #footer> | <template #footer> | ||||
<div class="mt-20px"> | |||||
<div> | |||||
<el-button @click="onClose"> 取消 </el-button> | <el-button @click="onClose"> 取消 </el-button> | ||||
<el-button type="primary" @click="handleOk"> 确定 </el-button> | <el-button type="primary" @click="handleOk"> 确定 </el-button> | ||||
</div> | </div> | ||||
</template> | </template> | ||||
</form-container> | </form-container> | ||||
<!-- 预览头像 --> | |||||
<el-dialog v-model="imgVisible" title="查看头像" width="830px" :before-close="handleClose"> | |||||
<div style="display: flex; align-items: center; justify-content: center"> | |||||
<img style="max-width: 100%; max-height: 600px" class="detailpic" :src="faceUrl" alt="" /> | |||||
</div> | |||||
</el-dialog> | |||||
</template> | </template> | ||||
<script setup lang="tsx" name="UserSelector"> | <script setup lang="tsx" name="UserSelector"> | ||||
@@ -104,7 +118,16 @@ const emit = defineEmits({ successful: null }); // 自定义事件 | |||||
// console.log(tab, event); | // console.log(tab, event); | ||||
// }; | // }; | ||||
const visible = ref(false); //是否显示 | const visible = ref(false); //是否显示 | ||||
const imgVisible = ref(false); //是否显示寝室表单 | |||||
const faceUrl = ref(''); | |||||
const viewHeadImage = (scope: any) => { | |||||
faceUrl.value = scope.row.faces[0].faceUrl; | |||||
imgVisible.value = true | |||||
console.log(faceUrl); | |||||
}; | |||||
const handleClose = () => { | |||||
imgVisible.value = false; | |||||
}; | |||||
// 定义组件props | // 定义组件props | ||||
const props = withDefaults(defineProps<UserSelectProps>(), { | const props = withDefaults(defineProps<UserSelectProps>(), { | ||||
multiple: false, | multiple: false, | ||||
@@ -112,7 +135,7 @@ const props = withDefaults(defineProps<UserSelectProps>(), { | |||||
}); | }); | ||||
// 根据是否业务显示不同名称 | // 根据是否业务显示不同名称 | ||||
const userName = props.biz ? "人员" : "用户"; | |||||
const userName = props.biz ? "用户" : "人员"; | |||||
const positionName = props.biz ? "职位" : "岗位"; | const positionName = props.biz ? "职位" : "岗位"; | ||||
const orgName = props.biz ? "机构" : "班级"; | const orgName = props.biz ? "机构" : "班级"; | ||||
@@ -126,13 +149,12 @@ const chooseTable = ref<ProTableInstance>(); | |||||
const columns: ColumnProps<SysUser.SysUserInfo>[] = [ | const columns: ColumnProps<SysUser.SysUserInfo>[] = [ | ||||
{ type: "selection", fixed: "left", width: 50 }, | { type: "selection", fixed: "left", width: 50 }, | ||||
{ prop: "operation", label: "操作", width: 80, fixed: "left" }, | { prop: "operation", label: "操作", width: 80, fixed: "left" }, | ||||
{ prop: "personSetName", label: "班级" }, | |||||
{ | { | ||||
prop: "faceUrl", | prop: "faceUrl", | ||||
label: "人脸", | label: "人脸", | ||||
render: scope => { | render: scope => { | ||||
return ( | return ( | ||||
<img src={scope.row.faces.length > 0 ? scope.row.faces[0].faceUrl : ''} onClick={() => viewHeadImage(scope)} style='width:50px;height:50px;' alt=''/> | |||||
<img src={scope.row.faces.length > 0 ? scope.row.faces[0].faceUrl : ''} onClick={() => viewHeadImage(scope)} style='width:30px;height:30px;' alt=''/> | |||||
); | ); | ||||
} | } | ||||
}, | }, | ||||
@@ -143,7 +165,10 @@ const columns: ColumnProps<SysUser.SysUserInfo>[] = [ | |||||
return row.row.name; | return row.row.name; | ||||
}, | }, | ||||
search: { el: "input", span: 2 } | search: { el: "input", span: 2 } | ||||
} | |||||
}, | |||||
{ prop: "personSetName", label: "班级" }, | |||||
{ prop: "dormitoryName", label: "寝室" }, | |||||
]; | ]; | ||||
/** 显示选择器 */ | /** 显示选择器 */ | ||||
@@ -162,6 +187,10 @@ function onClose() { | |||||
/** 提交数据 */ | /** 提交数据 */ | ||||
function handleOk() { | function handleOk() { | ||||
if (chooseData.value.length == 0) { | |||||
ElMessage.warning("请选择" + userName); | |||||
return; | |||||
} | |||||
visible.value = false; | visible.value = false; | ||||
console.log(chooseData.value,'提交得数据') | console.log(chooseData.value,'提交得数据') | ||||
emit("successful", chooseData.value); | emit("successful", chooseData.value); | ||||
@@ -86,8 +86,8 @@ const setSelected = () => { | |||||
}; | }; | ||||
onBeforeMount(async () => { | onBeforeMount(async () => { | ||||
setSelected(); | |||||
await getRequestData(); | await getRequestData(); | ||||
setSelected(); | |||||
}); | }); | ||||
// 使用 nextTick 防止打包后赋值不生效,开发环境是正常的 | // 使用 nextTick 防止打包后赋值不生效,开发环境是正常的 | ||||
@@ -40,7 +40,8 @@ import hljsCommon from "highlight.js/lib/common"; | |||||
import hljsVuePlugin from "@highlightjs/vue-plugin"; | import hljsVuePlugin from "@highlightjs/vue-plugin"; | ||||
//解决谷歌浏览器 Added non-passive event listener to a scroll-blocking 'touchstart' event. Consider markin... | //解决谷歌浏览器 Added non-passive event listener to a scroll-blocking 'touchstart' event. Consider markin... | ||||
import "default-passive-events"; | |||||
// import "default-passive-events"; | |||||
import "@/utils/browser_patch"; | |||||
// import "vue3-video-play/dist/style.css"; // 引入css | // import "vue3-video-play/dist/style.css"; // 引入css | ||||
const app = createApp(App); | const app = createApp(App); | ||||
@@ -43,8 +43,16 @@ export const staticRouter: RouteRecordRaw[] = [ | |||||
title: "学生点名详情" | title: "学生点名详情" | ||||
}, | }, | ||||
name: "学生点名详情", | name: "学生点名详情", | ||||
path: "/roolcall/detail", | |||||
path: "/attendance/roolcall/detail", | |||||
component: () => import("@/views/attendance/roolcall/detail.vue") | component: () => import("@/views/attendance/roolcall/detail.vue") | ||||
}, | |||||
{ | |||||
meta: { | |||||
title: "学生画像详情" | |||||
}, | |||||
name: "学生画像详情", | |||||
path: "/violation/portrait/detail", | |||||
component: () => import("@/views/violation/portrait/detail.vue") | |||||
} | } | ||||
] | ] | ||||
} | } | ||||
@@ -0,0 +1,14 @@ | |||||
//去除谷歌浏览器的scroll、wheel等事件警告 | |||||
(function () { | |||||
if (typeof EventTarget !== "undefined") { | |||||
let func = EventTarget.prototype.addEventListener; | |||||
EventTarget.prototype.addEventListener = function (type, fn, capture) { | |||||
this.func = func; | |||||
if (typeof capture !== "boolean") { | |||||
capture = capture || {}; | |||||
capture.passive = false; | |||||
} | |||||
this.func(type, fn, capture); | |||||
}; | |||||
} | |||||
})(); |
@@ -6,7 +6,15 @@ | |||||
<template> | <template> | ||||
<div> | <div> | ||||
<form-container v-model="visible" :title="`分片详情`" form-size="800px" @close="onClose"> | <form-container v-model="visible" :title="`分片详情`" form-size="800px" @close="onClose"> | ||||
<ProTable ref="proTable" title="分片详情" height="500px" :data="tableData" :columns="columns"></ProTable> | |||||
<ProTable | |||||
:toolButton="false" | |||||
:pagination="false" | |||||
ref="proTable" | |||||
title="分片详情" | |||||
height="500px" | |||||
:data="tableData" | |||||
:columns="columns" | |||||
></ProTable> | |||||
<template #footer> | <template #footer> | ||||
<el-button @click="onClose"> 关闭 </el-button> | <el-button @click="onClose"> 关闭 </el-button> | ||||
</template> | </template> | ||||
@@ -67,7 +67,7 @@ const splitOptions = ref([ | |||||
]); | ]); | ||||
// 摄像头 | // 摄像头 | ||||
let cameraldsOptions = ref([]); | let cameraldsOptions = ref([]); | ||||
monitorLIVEApi.list({ pageSize: 1000, pageNum: 1 }).then(res => { | |||||
monitorLIVEApi.list({ pageSize: 1000, pageNum: 1 }).then((res: any) => { | |||||
if (res.code == 200) { | if (res.code == 200) { | ||||
cameraldsOptions.value = res.data.list.map(e => { | cameraldsOptions.value = res.data.list.map(e => { | ||||
return { | return { | ||||
@@ -88,7 +88,7 @@ function onOpen(opt: FormOptEnum, record: {} | AttendancePassenger.PassengerInfo | |||||
const RefreshTable = () => { | const RefreshTable = () => { | ||||
proTable.value?.refresh(); | proTable.value?.refresh(); | ||||
}; | }; | ||||
const haseExtJson = row => { | |||||
const haseExtJson = (row: any) => { | |||||
let extJson = JSON.parse(row.extJson); | let extJson = JSON.parse(row.extJson); | ||||
return extJson.length == 0; | return extJson.length == 0; | ||||
}; | }; | ||||
@@ -91,7 +91,7 @@ const columns: ColumnProps[] = [ | |||||
]; | ]; | ||||
const onView = (row: any) => { | const onView = (row: any) => { | ||||
router.push( { | router.push( { | ||||
path:'/roolcall/detail', | |||||
path:'/attendance/roolcall/detail', | |||||
query: { | query: { | ||||
taskId: row.taskId, | taskId: row.taskId, | ||||
personSetId:row.personSetId | personSetId:row.personSetId | ||||
@@ -1,21 +1,30 @@ | |||||
<!-- | <!-- | ||||
* @Description: 人脸识别失败表格 | |||||
* @Description: 未归寝 | |||||
* @Author: yxq | * @Author: yxq | ||||
* @Date: 2023-12-15 15:45:59 | * @Date: 2023-12-15 15:45:59 | ||||
--> | --> | ||||
<template> | <template> | ||||
<div> | <div> | ||||
<form-container v-model="visible" row-key="id" :title="`${propsInfo.record.qinshibianhao}归寝确认`" form-size="800px" @close="onClose"> | |||||
<ProTable ref="noFaceTableRef" title="归寝确认" height="500px" :data="tableData" :columns="columns"> | |||||
<form-container v-model="visible" row-key="id" :title="`寝室${propsInfo.record.name}归寝确认`" form-size="800px" @close="onClose"> | |||||
<ProTable | |||||
ref="noReturnTableRef" | |||||
:request-auto="false" | |||||
title="归寝确认" | |||||
height="500px" | |||||
:pagination="false" | |||||
:columns="columns" | |||||
:request-api="userManageDormitoryApi.returnDetail" | |||||
:data-callback="dataCallback" | |||||
> | |||||
<!-- 表格 header 按钮 --> | <!-- 表格 header 按钮 --> | ||||
<template #tableHeader="scope"> | <template #tableHeader="scope"> | ||||
<s-button | <s-button | ||||
type="primary" | type="primary" | ||||
:disabled="!scope.isSelected" | :disabled="!scope.isSelected" | ||||
icon="check" | icon="check" | ||||
prefix="人工" | |||||
suffix="确认" | |||||
@click="personConfirm(scope.selectedListIds, '确认已归寝')" | |||||
prefix="确认" | |||||
suffix="归寝" | |||||
@click="personConfirm(scope.selectedList, '确认已归寝')" | |||||
/> | /> | ||||
</template> | </template> | ||||
</ProTable> | </ProTable> | ||||
@@ -26,118 +35,39 @@ | |||||
<!-- 预览头像 --> | <!-- 预览头像 --> | ||||
<el-dialog v-model="imgVisible" title="查看头像" width="830px"> | <el-dialog v-model="imgVisible" title="查看头像" width="830px"> | ||||
<div style="display: flex; align-items: center; justify-content: center"> | <div style="display: flex; align-items: center; justify-content: center"> | ||||
<img class="detailpic" :src="faceUrl" alt="" /> | |||||
<img class="detailpic" :src="'/api/' + faceUrl" alt="" /> | |||||
</div> | </div> | ||||
</el-dialog> | </el-dialog> | ||||
</div> | </div> | ||||
</template> | </template> | ||||
<script setup lang="tsx" name="attendanceStudentsReturn"> | <script setup lang="tsx" name="attendanceStudentsReturn"> | ||||
import { AttendanceStudentsReturn, attendanceStudentsReturn } from "@/api"; | |||||
import { ColumnProps, noFaceTableInstance } from "@/components/noFaceTableRef/interface"; | |||||
import { userManageDormitoryApi,attendanceApi } from "@/api"; | |||||
import { ColumnProps,ProTableInstance } from "@/components/ProTable/interface"; | |||||
import { FormOptEnum } from "@/enums"; | import { FormOptEnum } from "@/enums"; | ||||
import { useHandleData } from "@/hooks"; | import { useHandleData } from "@/hooks"; | ||||
import { formatDate } from "@/utils"; | |||||
const visible = ref(false); //是否显示 | const visible = ref(false); //是否显示 | ||||
// 弹框参数 | // 弹框参数 | ||||
const propsInfo = reactive<FormProps.Base<AttendanceStudentsReturn.PassengerInfo>>({ | |||||
const propsInfo = reactive<FormProps.Base<{}>>({ | |||||
opt: FormOptEnum.VIEW, //操作类型 | opt: FormOptEnum.VIEW, //操作类型 | ||||
record: {}, //弹框数据 | record: {}, //弹框数据 | ||||
disabled: false | disabled: false | ||||
}); | }); | ||||
/** | |||||
* 打开弹框 | |||||
* @param props 弹框参数 | |||||
*/ | |||||
function onOpen(props: FormProps.Base<AttendanceStudentsReturn.PassengerInfo>) { | |||||
Object.assign(propsInfo, props); //合并参数 | |||||
visible.value = true; //显示弹框 | |||||
if (props.record.id) { | |||||
//如果传了id,就去请求api获取record | |||||
attendanceStudentsReturn.detail({ id: props.record.id }).then(res => { | |||||
propsInfo.record = res.data; | |||||
}); | |||||
} | |||||
} | |||||
const tableData = ref([ | |||||
{ | |||||
id:'1', | |||||
studentname: "张三", | |||||
faces: [ | |||||
{ | |||||
faceUrl: | |||||
"http://deepvision.oss-cn-zhangjiakou.aliyuncs.com/dfield-cruising/online/person-set/quanjiang/DEMO00001/8746a847ecd64c1696b37f4cdf617a18/5dc35e4c7af84b3fb5aab70156574873.jpg?Expires=1721375257&OSSAccessKeyId=STS.NTfeBHwzU7kivsSS2EypREace&Signature=c1aTbDc1hNISq%2BV05o0slEfoCTI%3D&security-token=CAIS0wN1q6Ft5B2yfSjIr5fTLvj8mqV0gKmCdFXitzIQdf9%2BqqTIhzz2IHFMf3huCeodsv8%2BlGxS5%2FgelrpqVpZDR03Na8RHwrly1lv5O9KY4x49TRng0s%2FLI3OaLjKm9hi7AYygPgK0GJqEb1TDiVUto9%2FTfimjWFqIKICAjYUdAP0cQgi%2Fa0gwZrJRPRAwh8IGEnHTOP2xUHvtmXGCNFd0nQB%2BhGhjk7TdpPeR8R3Dllb35%2FYIroDqWPieYtJrIY10XqWBvqx%2FfbGT1zVLuVoYtvV6gaFc5zbcv9abRFVf4hiCP6%2Ff6MBuNw5%2Fae94efZNp%2BOukuZj6K6B1db7xhtVI%2BBOUiPZA4mr2IzdBeqvNNcwc7m8F1no9YjXbsGs9EEGGStLaVgVI4F8dyAhWEd9FWjgR%2FX5qAyQUGCKULOY1aw6651xwmjz8MCCT1r1GOTBindGasVnMxh5Z0JMjDK9aNkKfgFUbVJ8BrGTCIh%2FYx0bsq7yowDIEyp71TRMo%2Bbu%2FDBhIifKpO4VN7AxMup1DPwu2wNCxORK3yyybb5sa3aTR6942p%2F%2FF5VxFNPqOx1rmCMf4znuW4yrvNkAVvNcuIqdR8aLhaLIEbHzoKxuEKRnrfsIeBqAAUB%2FCKIuI1UaCj4LYX8DyIYOI8tUKFsMguPHpPENaK9Lcz5ZhB%2BrX6BcQfNWOLhDx7KyRE28vtEs2uolAhLTRaZsZFjbAZE5Ngt09%2FbSXdD%2FR%2BOlGMpQdp752x5lOlvPsJp1skuFLbramyqY4oj4tVwv1OLWpcsEc3AEosPalpAuIAA%3D" | |||||
}, | |||||
], | |||||
louceng:'3', | |||||
qinshi:'301', | |||||
}, | |||||
{ | |||||
id:'2', | |||||
studentname: "李四", | |||||
faces: [ | |||||
{ | |||||
faceUrl: | |||||
"http://deepvision.oss-cn-zhangjiakou.aliyuncs.com/dfield-cruising/online/person-set/quanjiang/DEMO00001/8746a847ecd64c1696b37f4cdf617a18/5dc35e4c7af84b3fb5aab70156574873.jpg?Expires=1721375257&OSSAccessKeyId=STS.NTfeBHwzU7kivsSS2EypREace&Signature=c1aTbDc1hNISq%2BV05o0slEfoCTI%3D&security-token=CAIS0wN1q6Ft5B2yfSjIr5fTLvj8mqV0gKmCdFXitzIQdf9%2BqqTIhzz2IHFMf3huCeodsv8%2BlGxS5%2FgelrpqVpZDR03Na8RHwrly1lv5O9KY4x49TRng0s%2FLI3OaLjKm9hi7AYygPgK0GJqEb1TDiVUto9%2FTfimjWFqIKICAjYUdAP0cQgi%2Fa0gwZrJRPRAwh8IGEnHTOP2xUHvtmXGCNFd0nQB%2BhGhjk7TdpPeR8R3Dllb35%2FYIroDqWPieYtJrIY10XqWBvqx%2FfbGT1zVLuVoYtvV6gaFc5zbcv9abRFVf4hiCP6%2Ff6MBuNw5%2Fae94efZNp%2BOukuZj6K6B1db7xhtVI%2BBOUiPZA4mr2IzdBeqvNNcwc7m8F1no9YjXbsGs9EEGGStLaVgVI4F8dyAhWEd9FWjgR%2FX5qAyQUGCKULOY1aw6651xwmjz8MCCT1r1GOTBindGasVnMxh5Z0JMjDK9aNkKfgFUbVJ8BrGTCIh%2FYx0bsq7yowDIEyp71TRMo%2Bbu%2FDBhIifKpO4VN7AxMup1DPwu2wNCxORK3yyybb5sa3aTR6942p%2F%2FF5VxFNPqOx1rmCMf4znuW4yrvNkAVvNcuIqdR8aLhaLIEbHzoKxuEKRnrfsIeBqAAUB%2FCKIuI1UaCj4LYX8DyIYOI8tUKFsMguPHpPENaK9Lcz5ZhB%2BrX6BcQfNWOLhDx7KyRE28vtEs2uolAhLTRaZsZFjbAZE5Ngt09%2FbSXdD%2FR%2BOlGMpQdp752x5lOlvPsJp1skuFLbramyqY4oj4tVwv1OLWpcsEc3AEosPalpAuIAA%3D" | |||||
}, | |||||
], | |||||
louceng:'3', | |||||
qinshi:'302', | |||||
}, | |||||
{ | |||||
id:'3', | |||||
studentname: "张三", | |||||
faces: [ | |||||
{ | |||||
faceUrl: | |||||
"http://deepvision.oss-cn-zhangjiakou.aliyuncs.com/dfield-cruising/online/person-set/quanjiang/DEMO00001/8746a847ecd64c1696b37f4cdf617a18/5dc35e4c7af84b3fb5aab70156574873.jpg?Expires=1721375257&OSSAccessKeyId=STS.NTfeBHwzU7kivsSS2EypREace&Signature=c1aTbDc1hNISq%2BV05o0slEfoCTI%3D&security-token=CAIS0wN1q6Ft5B2yfSjIr5fTLvj8mqV0gKmCdFXitzIQdf9%2BqqTIhzz2IHFMf3huCeodsv8%2BlGxS5%2FgelrpqVpZDR03Na8RHwrly1lv5O9KY4x49TRng0s%2FLI3OaLjKm9hi7AYygPgK0GJqEb1TDiVUto9%2FTfimjWFqIKICAjYUdAP0cQgi%2Fa0gwZrJRPRAwh8IGEnHTOP2xUHvtmXGCNFd0nQB%2BhGhjk7TdpPeR8R3Dllb35%2FYIroDqWPieYtJrIY10XqWBvqx%2FfbGT1zVLuVoYtvV6gaFc5zbcv9abRFVf4hiCP6%2Ff6MBuNw5%2Fae94efZNp%2BOukuZj6K6B1db7xhtVI%2BBOUiPZA4mr2IzdBeqvNNcwc7m8F1no9YjXbsGs9EEGGStLaVgVI4F8dyAhWEd9FWjgR%2FX5qAyQUGCKULOY1aw6651xwmjz8MCCT1r1GOTBindGasVnMxh5Z0JMjDK9aNkKfgFUbVJ8BrGTCIh%2FYx0bsq7yowDIEyp71TRMo%2Bbu%2FDBhIifKpO4VN7AxMup1DPwu2wNCxORK3yyybb5sa3aTR6942p%2F%2FF5VxFNPqOx1rmCMf4znuW4yrvNkAVvNcuIqdR8aLhaLIEbHzoKxuEKRnrfsIeBqAAUB%2FCKIuI1UaCj4LYX8DyIYOI8tUKFsMguPHpPENaK9Lcz5ZhB%2BrX6BcQfNWOLhDx7KyRE28vtEs2uolAhLTRaZsZFjbAZE5Ngt09%2FbSXdD%2FR%2BOlGMpQdp752x5lOlvPsJp1skuFLbramyqY4oj4tVwv1OLWpcsEc3AEosPalpAuIAA%3D" | |||||
}, | |||||
], | |||||
louceng:'4', | |||||
qinshi:'401', | |||||
}, | |||||
{ | |||||
id:'4', | |||||
studentname: "李四", | |||||
faces: [ | |||||
{ | |||||
faceUrl: | |||||
"http://deepvision.oss-cn-zhangjiakou.aliyuncs.com/dfield-cruising/online/person-set/quanjiang/DEMO00001/8746a847ecd64c1696b37f4cdf617a18/5dc35e4c7af84b3fb5aab70156574873.jpg?Expires=1721375257&OSSAccessKeyId=STS.NTfeBHwzU7kivsSS2EypREace&Signature=c1aTbDc1hNISq%2BV05o0slEfoCTI%3D&security-token=CAIS0wN1q6Ft5B2yfSjIr5fTLvj8mqV0gKmCdFXitzIQdf9%2BqqTIhzz2IHFMf3huCeodsv8%2BlGxS5%2FgelrpqVpZDR03Na8RHwrly1lv5O9KY4x49TRng0s%2FLI3OaLjKm9hi7AYygPgK0GJqEb1TDiVUto9%2FTfimjWFqIKICAjYUdAP0cQgi%2Fa0gwZrJRPRAwh8IGEnHTOP2xUHvtmXGCNFd0nQB%2BhGhjk7TdpPeR8R3Dllb35%2FYIroDqWPieYtJrIY10XqWBvqx%2FfbGT1zVLuVoYtvV6gaFc5zbcv9abRFVf4hiCP6%2Ff6MBuNw5%2Fae94efZNp%2BOukuZj6K6B1db7xhtVI%2BBOUiPZA4mr2IzdBeqvNNcwc7m8F1no9YjXbsGs9EEGGStLaVgVI4F8dyAhWEd9FWjgR%2FX5qAyQUGCKULOY1aw6651xwmjz8MCCT1r1GOTBindGasVnMxh5Z0JMjDK9aNkKfgFUbVJ8BrGTCIh%2FYx0bsq7yowDIEyp71TRMo%2Bbu%2FDBhIifKpO4VN7AxMup1DPwu2wNCxORK3yyybb5sa3aTR6942p%2F%2FF5VxFNPqOx1rmCMf4znuW4yrvNkAVvNcuIqdR8aLhaLIEbHzoKxuEKRnrfsIeBqAAUB%2FCKIuI1UaCj4LYX8DyIYOI8tUKFsMguPHpPENaK9Lcz5ZhB%2BrX6BcQfNWOLhDx7KyRE28vtEs2uolAhLTRaZsZFjbAZE5Ngt09%2FbSXdD%2FR%2BOlGMpQdp752x5lOlvPsJp1skuFLbramyqY4oj4tVwv1OLWpcsEc3AEosPalpAuIAA%3D" | |||||
}, | |||||
], | |||||
louceng:'3', | |||||
qinshi:'301', | |||||
}, | |||||
{ | |||||
id:'5', | |||||
studentname: "张三", | |||||
faces: [ | |||||
{ | |||||
faceUrl: | |||||
"http://deepvision.oss-cn-zhangjiakou.aliyuncs.com/dfield-cruising/online/person-set/quanjiang/DEMO00001/8746a847ecd64c1696b37f4cdf617a18/5dc35e4c7af84b3fb5aab70156574873.jpg?Expires=1721375257&OSSAccessKeyId=STS.NTfeBHwzU7kivsSS2EypREace&Signature=c1aTbDc1hNISq%2BV05o0slEfoCTI%3D&security-token=CAIS0wN1q6Ft5B2yfSjIr5fTLvj8mqV0gKmCdFXitzIQdf9%2BqqTIhzz2IHFMf3huCeodsv8%2BlGxS5%2FgelrpqVpZDR03Na8RHwrly1lv5O9KY4x49TRng0s%2FLI3OaLjKm9hi7AYygPgK0GJqEb1TDiVUto9%2FTfimjWFqIKICAjYUdAP0cQgi%2Fa0gwZrJRPRAwh8IGEnHTOP2xUHvtmXGCNFd0nQB%2BhGhjk7TdpPeR8R3Dllb35%2FYIroDqWPieYtJrIY10XqWBvqx%2FfbGT1zVLuVoYtvV6gaFc5zbcv9abRFVf4hiCP6%2Ff6MBuNw5%2Fae94efZNp%2BOukuZj6K6B1db7xhtVI%2BBOUiPZA4mr2IzdBeqvNNcwc7m8F1no9YjXbsGs9EEGGStLaVgVI4F8dyAhWEd9FWjgR%2FX5qAyQUGCKULOY1aw6651xwmjz8MCCT1r1GOTBindGasVnMxh5Z0JMjDK9aNkKfgFUbVJ8BrGTCIh%2FYx0bsq7yowDIEyp71TRMo%2Bbu%2FDBhIifKpO4VN7AxMup1DPwu2wNCxORK3yyybb5sa3aTR6942p%2F%2FF5VxFNPqOx1rmCMf4znuW4yrvNkAVvNcuIqdR8aLhaLIEbHzoKxuEKRnrfsIeBqAAUB%2FCKIuI1UaCj4LYX8DyIYOI8tUKFsMguPHpPENaK9Lcz5ZhB%2BrX6BcQfNWOLhDx7KyRE28vtEs2uolAhLTRaZsZFjbAZE5Ngt09%2FbSXdD%2FR%2BOlGMpQdp752x5lOlvPsJp1skuFLbramyqY4oj4tVwv1OLWpcsEc3AEosPalpAuIAA%3D" | |||||
}, | |||||
], | |||||
louceng:'5', | |||||
qinshi:'502', | |||||
} | |||||
]); | |||||
// 获取 noFaceTableRef 元素,调用其获取刷新数据方法(还能获取到当前查询参数,方便导出携带参数) | |||||
const noFaceTableRef = ref<noFaceTableInstance>(); | |||||
// 获取 noReturnTableRef 元素,调用其获取刷新数据方法(还能获取到当前查询参数,方便导出携带参数) | |||||
const noReturnTableRef = ref<ProTableInstance>(); | |||||
// 表格配置项 | // 表格配置项 | ||||
const columns: ColumnProps[] = [ | const columns: ColumnProps[] = [ | ||||
{ type: "selection" }, | { type: "selection" }, | ||||
{ | { | ||||
prop: "louceng", | |||||
label: "楼层" | |||||
}, | |||||
{ | |||||
prop: "qinshi", | |||||
label: "寝室编号" | |||||
prop: "name", | |||||
label: "学生姓名" | |||||
}, | }, | ||||
{ | { | ||||
prop: "studentname", | |||||
label: "学生姓名" | |||||
prop: "personSetName", | |||||
label: "班级" | |||||
}, | }, | ||||
{ | { | ||||
prop: "faces", | prop: "faces", | ||||
@@ -145,7 +75,7 @@ const columns: ColumnProps[] = [ | |||||
render: scope => { | render: scope => { | ||||
return ( | return ( | ||||
<img | <img | ||||
src={scope.row.faces.length > 0 ? scope.row.faces[0].faceUrl : ""} | |||||
src={scope.row.faces.length > 0 ? '/api/'+scope.row.faces[0].faceUrl : ""} | |||||
onClick={() => viewHeadImage(scope)} | onClick={() => viewHeadImage(scope)} | ||||
style="width:50px;height:50px;cursor:pointer" | style="width:50px;height:50px;cursor:pointer" | ||||
alt="" | alt="" | ||||
@@ -154,6 +84,25 @@ const columns: ColumnProps[] = [ | |||||
} | } | ||||
} | } | ||||
]; | ]; | ||||
/** | |||||
* 打开弹框 | |||||
* @param props 弹框参数 | |||||
*/ | |||||
function onOpen(props: FormProps.Base<{}>) { | |||||
Object.assign(propsInfo, props); //合并参数 | |||||
visible.value = true; //显示弹框 | |||||
nextTick(()=>{ | |||||
noReturnTableRef.value!.searchParam.id = props.record.id; | |||||
noReturnTableRef.value!.searchParam.returnTime = props.record.ReturnTime; | |||||
noReturnTableRef.value.search() | |||||
}) | |||||
} | |||||
const dataCallback = (res:any)=>{ | |||||
if(!res.attendanceDtos)return res.personInfos | |||||
return res.personInfos.filter(e=>{ | |||||
return !res.attendanceDtos.find(e1=>e1.personId == e.personId) | |||||
}) | |||||
} | |||||
// 图片预览 | // 图片预览 | ||||
const imgVisible = ref(false); | const imgVisible = ref(false); | ||||
const faceUrl = ref(''); | const faceUrl = ref(''); | ||||
@@ -162,8 +111,15 @@ const viewHeadImage = (scope: any) => { | |||||
imgVisible.value = true | imgVisible.value = true | ||||
}; | }; | ||||
/** 人工确认 */ | /** 人工确认 */ | ||||
async function personConfirm(ids: string[], msg: string) { | |||||
await useHandleData(attendanceStudentsReturn.delete, {id: ids.toString() }, msg); | |||||
async function personConfirm(list:any, msg: string) { | |||||
list = list.map(e=>{ | |||||
return { | |||||
personSetId:e.personSetId, | |||||
personId:e.personId, | |||||
tick:formatDate(new Date().valueOf()) | |||||
} | |||||
}) | |||||
await useHandleData(attendanceApi.add, list, msg); | |||||
RefreshTable(); //刷新表格 | RefreshTable(); //刷新表格 | ||||
} | } | ||||
/** 关闭表单*/ | /** 关闭表单*/ | ||||
@@ -172,7 +128,7 @@ function onClose() { | |||||
} | } | ||||
// 刷新表格 | // 刷新表格 | ||||
const RefreshTable = () => { | const RefreshTable = () => { | ||||
noFaceTableRef.value?.refresh(); | |||||
noReturnTableRef.value?.refresh(); | |||||
}; | }; | ||||
// 暴露给父组件的方法 | // 暴露给父组件的方法 | ||||
defineExpose({ | defineExpose({ | ||||
@@ -1,72 +1,138 @@ | |||||
<!-- | <!-- | ||||
* @Description: 教师点名 | |||||
* @Description: 学生归寝 | |||||
* @Author: yxq | * @Author: yxq | ||||
* @Date: 2024-7-16 | |||||
* @Date: 2024-7-24 | |||||
--> | --> | ||||
<template> | <template> | ||||
<div class="table-box"> | |||||
<ProTable ref="proTable" title="教师点名" :columns="columns" :data="data"> | |||||
<!-- 表格操作栏 --> | |||||
<template #operation="scope"> | |||||
<el-space> | |||||
<s-button | |||||
:disabled="!scope.row.noFaceNum" | |||||
link | |||||
prefix="人工" | |||||
:opt="FormOptEnum.EDIT" | |||||
suffix="确认" | |||||
@click="onOpen(FormOptEnum.VIEW, scope.row)" | |||||
/> | |||||
</el-space> | |||||
<div class="main-box"> | |||||
<TreeFilter | |||||
ref="treeFilter" | |||||
label="name" | |||||
id="id" | |||||
width="300px" | |||||
:show-all="false" | |||||
:isData="true" | |||||
:data="treeData" | |||||
:default-value="defaultValue" | |||||
@change="changeTreeFilter" | |||||
> | |||||
<template v-slot:header> | |||||
<h4 style="margin: 0 0 15px; font-size: 18px; font-weight: bold; color: var(--el-color-info-dark-2); letter-spacing: 0.5px">所属楼栋</h4> | |||||
</template> | </template> | ||||
</ProTable> | |||||
<ReturnConfirm ref="ReturnConfirmRef" /> | |||||
<template v-slot:label="{ row }"> | |||||
<span class="custom-tree-node"> | |||||
<span>{{ row.node.label }}</span> | |||||
</span> | |||||
</template> | |||||
</TreeFilter> | |||||
<div class="table-box"> | |||||
<ProTable ref="proTable" title="教师点名" :request-auto="false" :columns="columns" :request-api="userManageDormitoryApi.returnList"> | |||||
<!-- 表格 header 按钮 --> | |||||
<template #tableHeader> | |||||
<div style="display: flex; align-items: center"> | |||||
<el-date-picker | |||||
v-model="ReturnTime" | |||||
:clearable="false" | |||||
value-format="YYYY-MM-DD" | |||||
type="date" | |||||
placeholder="选择查询日期" | |||||
@change="retrunTimeChange" | |||||
> | |||||
</el-date-picker> | |||||
<div style="margin-left: 15px; color: #606266">归寝时间:{{ returnTime }}</div> | |||||
</div> | |||||
</template> | |||||
<!-- 表格操作栏 --> | |||||
<template #operation="scope"> | |||||
<el-space> | |||||
<!-- :disabled="!scope.row.noReturnNum" --> | |||||
<s-button link prefix="归寝" :opt="FormOptEnum.EDIT" suffix="确认" @click="onOpen(FormOptEnum.VIEW, scope.row)" /> | |||||
</el-space> | |||||
</template> | |||||
</ProTable> | |||||
<ReturnConfirm ref="ReturnConfirmRef" /> | |||||
</div> | |||||
</div> | </div> | ||||
</template> | </template> | ||||
<script setup lang="ts"> | <script setup lang="ts"> | ||||
import { attendanceStudentsReturn, AttendanceStudentsReturn } from "@/api"; | |||||
import { userManageDormitoryApi } from "@/api"; | |||||
import { ColumnProps, ProTableInstance } from "@/components/ProTable/interface"; | import { ColumnProps, ProTableInstance } from "@/components/ProTable/interface"; | ||||
import { FormOptEnum } from "@/enums"; | import { FormOptEnum } from "@/enums"; | ||||
import ReturnConfirm from "./components/returnConfirm/index.vue"; | import ReturnConfirm from "./components/returnConfirm/index.vue"; | ||||
const data = ref([ | |||||
{ | |||||
louceng: "3", | |||||
qinshibianhao: "306", | |||||
qinshirenshu: "6", | |||||
guiqinNum: "5", | |||||
noFaceNum: "1" | |||||
}, | |||||
{ | |||||
louceng: "3", | |||||
qinshibianhao: "307", | |||||
qinshirenshu: "8", | |||||
guiqinNum: "6", | |||||
noFaceNum: "2" | |||||
} | |||||
]); | |||||
// 获取 ProTable 元素,调用其获取刷新数据方法(还能获取到当前查询参数,方便导出携带参数) | |||||
const proTable = ref<ProTableInstance>(); | const proTable = ref<ProTableInstance>(); | ||||
/**左侧楼栋**/ | |||||
import TreeFilter from "@/components/TreeFilter/index.vue"; | |||||
import { formatDate } from "@/utils"; | |||||
const treeFilter = ref<InstanceType<typeof TreeFilter> | null>(null); | |||||
//楼栋切换 | |||||
const buildId = ref<number | string>(); | |||||
function changeTreeFilter(val: number | string) { | |||||
console.log(treeFilter.value?.treeData); | |||||
buildId.value = val; | |||||
proTable.value!.pageable.pageNum = 1; | |||||
proTable.value!.searchParam.buildId = val; | |||||
proTable.value!.search(); | |||||
} | |||||
// 初始化数据 | |||||
const treeData = ref([]); | |||||
const defaultValue = ref(""); | |||||
const ReturnTime = ref(""); | |||||
let ReturnTimeDefault = ""; | |||||
const returnTime = ref(); | |||||
onMounted(() => { | |||||
// 设置默认查询日期 | |||||
let date = formatDate(new Date().valueOf()); | |||||
ReturnTime.value = date.substring(0, 10); | |||||
proTable.value!.searchParam.ReturnTime = ReturnTime.value; | |||||
ReturnTimeDefault = ReturnTime.value; | |||||
// 请求楼栋 | |||||
userManageDormitoryApi.list().then(res => { | |||||
if (res.code == 200) { | |||||
if (res.data.length) { | |||||
treeData.value = res.data; | |||||
defaultValue.value = res.data[0].id.toString(); | |||||
buildId.value = defaultValue.value; | |||||
// 请求表格 | |||||
proTable.value!.pageable.pageNum = 1; | |||||
proTable.value!.searchParam.buildId = defaultValue.value; | |||||
proTable.value!.search(); | |||||
} | |||||
} | |||||
}); | |||||
// 归寝时间 | |||||
userManageDormitoryApi.getReturnTime().then(res => { | |||||
if (res.code == 200) { | |||||
returnTime.value = res.data.timeBegin + " ~ " + res.data.timeEnd; | |||||
} | |||||
}); | |||||
}); | |||||
// 查询日期修改 | |||||
const retrunTimeChange = () => { | |||||
proTable.value!.pageable.pageNum = 1; | |||||
proTable.value!.searchParam.ReturnTime = ReturnTime.value || ReturnTimeDefault; | |||||
proTable.value!.search(); | |||||
}; | |||||
// 获取 ProTable 元素,调用其获取刷新数据方法(还能获取到当前查询参数,方便导出携带参数) | |||||
// 表格配置项 | // 表格配置项 | ||||
const columns: ColumnProps[] = [ | const columns: ColumnProps[] = [ | ||||
{ | { | ||||
prop: "louceng", | |||||
label: "楼层" | |||||
}, | |||||
{ | |||||
prop: "qinshibianhao", | |||||
prop: "name", | |||||
label: "寝室编号" | label: "寝室编号" | ||||
}, | }, | ||||
{ | { | ||||
prop: "qinshirenshu", | |||||
prop: "personCount", | |||||
label: "寝室人数" | label: "寝室人数" | ||||
}, | }, | ||||
{ | { | ||||
prop: "guiqinNum", | |||||
prop: "dormitoryCount", | |||||
label: "归寝人数" | label: "归寝人数" | ||||
}, | }, | ||||
{ | { | ||||
prop: "noFaceNum", | |||||
label: "未归寝人数" | |||||
prop: "noDormitoryCount", | |||||
label: "未归寝人数", | |||||
render: scope => { | |||||
return scope.row.personCount - scope.row.dormitoryCount; | |||||
} | |||||
}, | }, | ||||
{ prop: "operation", label: "操作", width: 250, fixed: "right" } | { prop: "operation", label: "操作", width: 250, fixed: "right" } | ||||
]; | ]; | ||||
@@ -76,10 +142,14 @@ const ReturnConfirmRef = ref<InstanceType<typeof ReturnConfirm> | null>(null); | |||||
* @param opt 操作类型 | * @param opt 操作类型 | ||||
* @param record 弹框数据 | * @param record 弹框数据 | ||||
*/ | */ | ||||
function onOpen(opt: FormOptEnum, record: {} | AttendanceStudentsReturn.studentsReturnInfo = {}) { | |||||
function onOpen(opt: FormOptEnum, record = {}) { | |||||
switch (opt) { | switch (opt) { | ||||
case FormOptEnum.VIEW: | case FormOptEnum.VIEW: | ||||
ReturnConfirmRef.value?.onOpen({ opt: opt, record: record, successful: RefreshTable }); | |||||
ReturnConfirmRef.value?.onOpen({ | |||||
opt: opt, | |||||
record: { ...record, ReturnTime: ReturnTime.value || ReturnTimeDefault }, | |||||
successful: RefreshTable | |||||
}); | |||||
break; | break; | ||||
} | } | ||||
} | } | ||||
@@ -158,7 +158,7 @@ function getDataChart() { | |||||
}); | }); | ||||
}); | }); | ||||
} | } | ||||
function getCharts1(data) { | |||||
function getCharts1(data: any) { | |||||
const chart = echarts.init(chart1.value); | const chart = echarts.init(chart1.value); | ||||
const option = { | const option = { | ||||
tooltip: { | tooltip: { | ||||
@@ -208,7 +208,7 @@ function getCharts1(data) { | |||||
chart.resize(); | chart.resize(); | ||||
}); | }); | ||||
} | } | ||||
function getCharts2(data) { | |||||
function getCharts2(data: any) { | |||||
const chartstation = echarts.init(chart2.value); | const chartstation = echarts.init(chart2.value); | ||||
const option = { | const option = { | ||||
tooltip: { | tooltip: { | ||||
@@ -261,22 +261,22 @@ function getCharts2(data) { | |||||
function getWeekData() { | function getWeekData() { | ||||
setTimeout(async () => { | setTimeout(async () => { | ||||
await statistionApi.weekstatistion({}).then(res => { | |||||
await statistionApi.weekstatistion({}).then((res: any) => { | |||||
let { code, data } = res; | let { code, data } = res; | ||||
if (code == 200) { | if (code == 200) { | ||||
// let chartData = data; | // let chartData = data; | ||||
let time = data.dataX; | let time = data.dataX; | ||||
let chartData = data.dataY.map(item => { | |||||
let chartData = data.dataY.map((item: any) => { | |||||
return { | return { | ||||
data: item.data, | data: item.data, | ||||
name: item.name, | name: item.name, | ||||
type: "bar", | type: "bar", | ||||
barWidth: "12px", // 设置柱子粗细 | barWidth: "12px", // 设置柱子粗细 | ||||
itemStyle: { | itemStyle: { | ||||
normal: { | |||||
barBorderRadius: [30, 30, 0, 0] | |||||
} | |||||
// normal: { | |||||
borderRadius: [30, 30, 0, 0] | |||||
// } | |||||
} | } | ||||
}; | }; | ||||
}); | }); | ||||
@@ -285,7 +285,7 @@ function getWeekData() { | |||||
}); | }); | ||||
}); | }); | ||||
} | } | ||||
function getCharts3(time, data) { | |||||
function getCharts3(time: any, data: any) { | |||||
const chartstation3 = echarts.init(chart3.value); | const chartstation3 = echarts.init(chart3.value); | ||||
const option = { | const option = { | ||||
tooltip: { | tooltip: { | ||||
@@ -10,7 +10,7 @@ | |||||
label="clothSetName" | label="clothSetName" | ||||
id="clothSetId" | id="clothSetId" | ||||
width="300px" | width="300px" | ||||
:show-all="true" | |||||
:show-all="false" | |||||
:request-api="userManageClothApi.getList" | :request-api="userManageClothApi.getList" | ||||
@change="changeTreeFilter" | @change="changeTreeFilter" | ||||
> | > | ||||
@@ -27,6 +27,28 @@ | |||||
<s-radio-group v-model="sysDormitoryProps.record.gender" :options="genderOptions" /> | <s-radio-group v-model="sysDormitoryProps.record.gender" :options="genderOptions" /> | ||||
</s-form-item> | </s-form-item> | ||||
</el-col> | </el-col> | ||||
<el-col :span="22"> | |||||
<s-form-item label="进楼摄像头" prop="insCameraId"> | |||||
<s-select | |||||
v-model="sysDormitoryProps.record.insCameraId" | |||||
:filterable="true" | |||||
:options="creamaData" | |||||
label="sensorName" | |||||
value="sensorId" | |||||
></s-select> | |||||
</s-form-item> | |||||
</el-col> | |||||
<el-col :span="22"> | |||||
<s-form-item label="出楼摄像头" prop="outCameraId"> | |||||
<s-select | |||||
v-model="sysDormitoryProps.record.outCameraId" | |||||
:filterable="true" | |||||
:options="creamaData" | |||||
label="sensorName" | |||||
value="sensorId" | |||||
></s-select> | |||||
</s-form-item> | |||||
</el-col> | |||||
</el-row> | </el-row> | ||||
</div> | </div> | ||||
</el-form> | </el-form> | ||||
@@ -40,12 +62,13 @@ | |||||
<script setup lang="ts" name="SysDormitoryformClass"> | <script setup lang="ts" name="SysDormitoryformClass"> | ||||
import { ref } from "vue"; | import { ref } from "vue"; | ||||
import { SysDormitory, userManageDormitoryApi } from "@/api"; | |||||
import { SysDormitory, userManageDormitoryApi, monitorLIVEApi } from "@/api"; | |||||
import { FormOptEnum } from "@/enums"; | import { FormOptEnum } from "@/enums"; | ||||
import { required } from "@/utils/formRules"; | import { required } from "@/utils/formRules"; | ||||
import { FormInstance } from "element-plus"; | import { FormInstance } from "element-plus"; | ||||
const visibleDormitory = ref(false); //是否显示表单 | const visibleDormitory = ref(false); //是否显示表单 | ||||
const creamaData = ref<any>([]); | |||||
const genderOptions = [ | const genderOptions = [ | ||||
{ | { | ||||
label: "男", | label: "男", | ||||
@@ -65,7 +88,9 @@ const sysDormitoryProps = reactive<FormProps.Base<SysDormitory.DormitoryInfo>>({ | |||||
// 表单验证规则 | // 表单验证规则 | ||||
const rules = reactive({ | const rules = reactive({ | ||||
name: [required("请输入宿舍楼名称")], | name: [required("请输入宿舍楼名称")], | ||||
gender: [required("请选择性别")] | |||||
gender: [required("请选择性别")], | |||||
insCameraId: [required("请选择进楼摄像头")], | |||||
outCameraId: [required("请选择出楼摄像头")] | |||||
}); | }); | ||||
/** | /** | ||||
@@ -113,7 +138,14 @@ async function handleSubmit() { | |||||
function onClose() { | function onClose() { | ||||
visibleDormitory.value = false; | visibleDormitory.value = false; | ||||
} | } | ||||
onMounted(() => { | |||||
getCreamaList(); | |||||
}); | |||||
const getCreamaList = () => { | |||||
monitorLIVEApi.list({ pageNum: 1, pageSize: 1000 }).then(res => { | |||||
creamaData.value = res.data.list; | |||||
}); | |||||
}; | |||||
// 暴露给父组件的方法 | // 暴露给父组件的方法 | ||||
defineExpose({ | defineExpose({ | ||||
onOpen | onOpen | ||||
@@ -1,144 +0,0 @@ | |||||
<!-- | |||||
* @Description: 表单 | |||||
* @Author: huguodong | |||||
* @Date: 2023-12-15 15:45:28 | |||||
!--> | |||||
<template> | |||||
<div> | |||||
<form-container v-model="visible" title="人员选择" form-size="600px"> | |||||
<el-form | |||||
ref="userFormRef" | |||||
:rules="rules" | |||||
:disabled="liveUserProps.disabled" | |||||
:model="liveUserProps.record" | |||||
:hide-required-asterisk="liveUserProps.disabled" | |||||
label-width="auto" | |||||
label-suffix=" :" | |||||
> | |||||
<s-form-item label="分配人员" prop="userId"> | |||||
<el-button link type="primary" @click="showSelector">选择</el-button> | |||||
<el-tag v-if="liveUserProps.record.userId" class="ml-3px" type="warning" closable @close="removeDirector">{{ | |||||
liveUserProps.record.userInfo?.name | |||||
}}</el-tag> | |||||
</s-form-item> | |||||
</el-form> | |||||
<template #footer> | |||||
<el-button @click="onClose"> 取消 </el-button> | |||||
<el-button v-show="!liveUserProps.disabled" type="primary" @click="handleSubmit"> 确定 </el-button> | |||||
</template> | |||||
</form-container> | |||||
<user-selector | |||||
multiple | |||||
ref="userSelectorRef" | |||||
:org-tree-api="sysOrgApi.tree" | |||||
:user-selector-api="sysUserApi.selector" | |||||
@successful="handleChooseUser" | |||||
/> | |||||
</div> | |||||
</template> | |||||
<script setup lang="ts"> | |||||
import { SysOrg, SysUser, sysOrgApi, sysPositionApi, sysRoleApi, sysUserApi, monitorLIVEApi } from "@/api"; | |||||
import { FormOptEnum, SysDictEnum } from "@/enums"; | |||||
import { required } from "@/utils/formRules"; | |||||
import { FormInstance } from "element-plus"; | |||||
import { useDictStore } from "@/stores/modules"; | |||||
import { UserSelectorInstance } from "@/components/Selectors/UserSelector/interface"; | |||||
const visible = ref(false); //是否显示表单 | |||||
const dictStore = useDictStore(); //字典仓库 | |||||
// 表单参数 | |||||
const liveUserProps = reactive<FormProps.Base<any>>({ | |||||
opt: FormOptEnum.ADD, | |||||
record: {}, | |||||
disabled: false | |||||
}); | |||||
// 表单验证规则 | |||||
const rules = reactive({ | |||||
userId: [required("请选择人员")] | |||||
}); | |||||
/** | |||||
* 打开表单 | |||||
* @param props 表单参数 | |||||
*/ | |||||
function onOpen(props: FormProps.Base<any>) { | |||||
Object.assign(liveUserProps, props); //合并参数 | |||||
if (props.opt == FormOptEnum.ADD) { | |||||
//如果是新增,设置默认值 | |||||
} | |||||
visible.value = true; //显示表单 | |||||
if (props.record.pushUserId) { | |||||
//如果传了id,就去请求api获取record | |||||
liveUserProps.record.userId = props.record.pushUserId; | |||||
liveUserProps.record.userInfo = props.record.sysUserItem; | |||||
// sysOrgApi.detail({ id: props.record.id }).then(res => { | |||||
// liveUserProps.record.userId = res.data; | |||||
// }); | |||||
} | |||||
} | |||||
// 提交数据(新增/编辑) | |||||
const userFormRef = ref<FormInstance>(); | |||||
/** 提交表单 */ | |||||
async function handleSubmit() { | |||||
userFormRef.value?.validate(async valid => { | |||||
if (!valid) return; //表单验证失败 | |||||
let params: any = { | |||||
warnCode: "", | |||||
userId: "" | |||||
}; | |||||
if (liveUserProps.opt == "预警推送人") { | |||||
params.warnCode = liveUserProps.record.warnCode; | |||||
params.userId = liveUserProps.record.userId; | |||||
//提交表单 | |||||
await monitorLIVEApi | |||||
.setWarningPushPerson(params) | |||||
.then(() => { | |||||
liveUserProps.successful!(); //调用父组件的successful方法 | |||||
}) | |||||
.finally(() => { | |||||
onClose(); | |||||
}); | |||||
} | |||||
}); | |||||
} | |||||
/** 关闭表单*/ | |||||
function onClose() { | |||||
visible.value = false; | |||||
liveUserProps.record.userId = null; | |||||
liveUserProps.record.userInfo = null; | |||||
} | |||||
const userSelectorRef = ref<UserSelectorInstance>(); //用户选择器引用 | |||||
/** 显示用户选择器 */ | |||||
function showSelector() { | |||||
//将liveUserProps.record.userInfo转为 SysUser.SysUserInfo[]类型 | |||||
const userInfo = liveUserProps.record.userInfo ? [liveUserProps.record.userInfo] : []; | |||||
userSelectorRef.value?.showSelector(userInfo); | |||||
} | |||||
/** 选择用户 */ | |||||
function handleChooseUser(data: SysUser.SysUserInfo[]) { | |||||
// 选择用户后,将用户id赋值给liveUserProps.record.userId | |||||
if (data.length > 0) { | |||||
liveUserProps.record.userId = data[0].id; | |||||
liveUserProps.record.userInfo = data[0]; | |||||
} | |||||
} | |||||
/** 移除主管 */ | |||||
function removeDirector() { | |||||
liveUserProps.record.userId = null; | |||||
liveUserProps.record.userInfo = null; | |||||
} | |||||
// 暴露给父组件的方法 | |||||
defineExpose({ | |||||
onOpen | |||||
}); | |||||
</script> | |||||
<style lang="scss" scoped></style> |
@@ -1,7 +1,7 @@ | |||||
<!-- | <!-- | ||||
* @Description: 寝室管理 | * @Description: 寝室管理 | ||||
* @Author: syy | |||||
* @Date: 2024-7-15 | |||||
* @Author: wwp | |||||
* @Date: 2024-7-25 | |||||
--> | --> | ||||
<template> | <template> | ||||
<div class="main-box"> | <div class="main-box"> | ||||
@@ -17,6 +17,7 @@ | |||||
> | > | ||||
<template v-slot:header> | <template v-slot:header> | ||||
<s-button suffix="宿舍楼" @click="addDormitory(FormOptEnum.ADD)" style="margin-bottom: 15px" /> | <s-button suffix="宿舍楼" @click="addDormitory(FormOptEnum.ADD)" style="margin-bottom: 15px" /> | ||||
<el-button @click="settingTime" style="margin-bottom: 15px">归寝时间设置</el-button> | |||||
</template> | </template> | ||||
<template v-slot:label="{ row }"> | <template v-slot:label="{ row }"> | ||||
<span class="custom-tree-node"> | <span class="custom-tree-node"> | ||||
@@ -65,38 +66,68 @@ | |||||
</el-space> | </el-space> | ||||
</template> | </template> | ||||
</ProTable> | </ProTable> | ||||
<ClassUserselector | |||||
ref="userSelectorRef" | |||||
:org-tree-api="userManageClassManageApi.page" | |||||
:user-selector-api="userManagePersonnelApi.page" | |||||
multiple | |||||
@successful="handleChooseUser" | |||||
> | |||||
</ClassUserselector> | |||||
</div> | </div> | ||||
<!-- 寝室新增/编辑表单 --> | <!-- 寝室新增/编辑表单 --> | ||||
<Form ref="formRef"></Form> | <Form ref="formRef"></Form> | ||||
<!-- 宿舍楼新增/编辑表单 --> | <!-- 宿舍楼新增/编辑表单 --> | ||||
<FormDormitory ref="formRefD" /> | <FormDormitory ref="formRefD" /> | ||||
<!-- 班主任绑定/修改 --> | |||||
<!-- :user-selector-params="{ orgId: orgId }" --> | |||||
<ClassUserselector | |||||
ref="userSelectorRef" | |||||
:org-tree-api="userManageClassManageApi.page" | |||||
:org-tree-props="{ label: 'name', children: 'children' }" | |||||
:user-selector-api="userManagePersonnelApi.page" | |||||
multiple | |||||
@successful="handleChooseUser" | |||||
> | |||||
</ClassUserselector> | |||||
<!-- <formUser ref="formRefU" /> --> | |||||
<!-- 预览头像 --> | <!-- 预览头像 --> | ||||
<el-dialog v-model="visible" title="查看头像" width="830px" :before-close="handleClose"> | |||||
<div style="display: flex; align-items: center; justify-content: center"> | |||||
<img style="max-width: 100%; max-height: 600px" class="detailpic" :src="faceUrl" alt="" /> | |||||
</div> | |||||
<el-dialog v-model="timeVisible" title="归寝时间设置" :before-close="closeTime"> | |||||
<el-form :model="timeForm" :rules="timeRules" ref="timeFormRef" label-width="100px"> | |||||
<el-row> | |||||
<el-col :span="16"> | |||||
<el-form-item label="功能有效期:" prop="dateArr"> | |||||
<el-date-picker | |||||
v-model="timeForm.dateArr" | |||||
type="daterange" | |||||
format="YYYY-MM-DD" | |||||
value-format="YYYY-MM-DD" | |||||
range-separator="-" | |||||
start-placeholder="开始日期" | |||||
end-placeholder="结束日期" | |||||
:size="size" | |||||
/> | |||||
</el-form-item> | |||||
</el-col> | |||||
<el-col :span="16"> | |||||
<el-form-item label="布防时间:" prop="timeArr"> | |||||
<el-time-picker | |||||
v-model="timeForm.timeArr" | |||||
format="HH:mm:ss" | |||||
value-format="HH:mm:ss" | |||||
is-range | |||||
range-separator="-" | |||||
start-placeholder="开始时间" | |||||
end-placeholder="结束时间" | |||||
/> | |||||
</el-form-item> | |||||
</el-col> | |||||
</el-row> | |||||
</el-form> | |||||
<template #footer> | |||||
<div class="dialog-footer"> | |||||
<el-button type="primary" @click="onTimeSubmit">提交</el-button> | |||||
<el-button @click="closeTime">取消</el-button> | |||||
</div> | |||||
</template> | |||||
</el-dialog> | </el-dialog> | ||||
</div> | </div> | ||||
</template> | </template> | ||||
<script setup lang="tsx" name="SysDormitory"> | <script setup lang="tsx" name="SysDormitory"> | ||||
import { userManageDormitoryApi,dormitoryButtonCode,SysDormitory,sysOrgApi,sysPositionApi,sysUserApi,sysRoleApi,userManagePersonnelApi,userManageClassManageApi } from "@/api"; | |||||
import { userManageDormitoryApi,dormitoryButtonCode,SysDormitory,userManagePersonnelApi,userManageClassManageApi,SysUser } from "@/api"; | |||||
import { useHandleData } from "@/hooks/useHandleData"; | import { useHandleData } from "@/hooks/useHandleData"; | ||||
import { FormOptEnum } from "@/enums"; | import { FormOptEnum } from "@/enums"; | ||||
import Form from "./components/form/index.vue"; | import Form from "./components/form/index.vue"; | ||||
import FormDormitory from "./components/formDormitory/index.vue"; | import FormDormitory from "./components/formDormitory/index.vue"; | ||||
import formUser from "./components/formUser/index.vue"; | |||||
import { ArrowDown,More } from "@element-plus/icons-vue"; | import { ArrowDown,More } from "@element-plus/icons-vue"; | ||||
import { ColumnProps, ProTableInstance } from "@/components/ProTable/interface"; | import { ColumnProps, ProTableInstance } from "@/components/ProTable/interface"; | ||||
import TreeFilter from "@/components/TreeFilter/index.vue"; | import TreeFilter from "@/components/TreeFilter/index.vue"; | ||||
@@ -105,8 +136,7 @@ import { TokenEnum } from "@/enums"; | |||||
import type { UploadProps } from "element-plus"; | import type { UploadProps } from "element-plus"; | ||||
import { UserSelectorInstance } from "@/components/Selectors/UserSelector/interface"; | import { UserSelectorInstance } from "@/components/Selectors/UserSelector/interface"; | ||||
// 获取 ProTable 元素,调用其获取刷新数据方法(还能获取到当前查询参数,方便导出携带参数) | // 获取 ProTable 元素,调用其获取刷新数据方法(还能获取到当前查询参数,方便导出携带参数) | ||||
const faceUrl = ref(''); | |||||
const visible = ref(false); //是否显示寝室表单 | |||||
const proTable = ref<ProTableInstance>(); | const proTable = ref<ProTableInstance>(); | ||||
const treeFilter = ref<InstanceType<typeof TreeFilter> | null>(null); | const treeFilter = ref<InstanceType<typeof TreeFilter> | null>(null); | ||||
const userStore = useUserStore(); | const userStore = useUserStore(); | ||||
@@ -128,32 +158,84 @@ const columns: ColumnProps<SysDormitory.ChamberInfo>[] = [ | |||||
}, | }, | ||||
{ prop: "operation", label: "操作", width: 250, fixed: "right" } | { 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 size = ref<'default' | 'large' | 'small'>('default') | |||||
const timeVisible = ref(false); //是否显示时间设置 | |||||
const timeForm = reactive<any>({ | |||||
dateArr: [], | |||||
timeArr: [], | |||||
}); | |||||
const timeRules = ref({ | |||||
dateArr: [{ required: true, message: "请选择功能有效期", trigger: "change" }], | |||||
timeArr: [{ required: true, message: "请选择布防时间", trigger: "change" }], | |||||
}); | |||||
const timeFormRef = ref<any>(null); | |||||
const settingTime = () => { | |||||
timeVisible.value = true; | |||||
getTimeDetail() | |||||
}; | |||||
const getTimeDetail = () => { | |||||
userManageDormitoryApi.getReturnTime().then((res:any) => { | |||||
let {data} = res | |||||
timeForm.dateArr = [data.funcStart,data.funcEnd] as never[]; | |||||
timeForm.timeArr = [data.timeBegin,data.timeEnd] as never[]; | |||||
}); | |||||
} | |||||
const closeTime = () => { | |||||
timeForm.dateArr = []; | |||||
timeForm.timeArr = []; | |||||
timeVisible.value = false; | |||||
}; | }; | ||||
const handleClose = () => { | |||||
visible.value = false; | |||||
// 提交分组 | |||||
const onTimeSubmit = () => { | |||||
timeFormRef.value.validate((valid: any) => { | |||||
if (valid) { | |||||
let params: any = reactive({ | |||||
funcStart: timeForm.dateArr[0], | |||||
funcEnd: timeForm.dateArr[1], | |||||
timeBegin: timeForm.timeArr[0], | |||||
timeEnd: timeForm.timeArr[1] | |||||
}); | |||||
userManageDormitoryApi.setReturnTime(params).then((res:any) => { | |||||
if (res.code == 200) { | |||||
// getGroupList(); | |||||
ElMessage({ | |||||
message: res.msg, | |||||
type: 'success' | |||||
}); | |||||
closeTime(); | |||||
} | |||||
}); | |||||
} else { | |||||
return false; | |||||
} | |||||
}); | |||||
}; | }; | ||||
// 确定人员 | |||||
function handleChooseUser(data: SysUser.SysUserInfo[]) { | function handleChooseUser(data: SysUser.SysUserInfo[]) { | ||||
console.log(data) | |||||
//组装参数 | //组装参数 | ||||
const grantUser: SysRole.GrantUserReq = { | |||||
const grantUser: SysDormitory.ChamberPersonnel = { | |||||
// id: roleId.value, | // id: roleId.value, | ||||
// grantInfoList: data.map(item => item.id) as number[] | string[], | // grantInfoList: data.map(item => item.id) as number[] | string[], | ||||
dormitoryId: chamberId.value, | dormitoryId: chamberId.value, | ||||
personIds: data.map(item => item.personId) as number[] | string[], | |||||
personIds: data.map((item:any) => item.personId) as number[] | string[], | |||||
}; | }; | ||||
userManageDormitoryApi.setAssignPerson(grantUser); | |||||
userManageDormitoryApi.setAssignPerson(grantUser).then(res => { | |||||
ElMessage({ | |||||
message: res.msg, | |||||
type: 'success' | |||||
}); | |||||
RefreshTable(); | |||||
}) | |||||
} | } | ||||
// 寝室表单引用 | // 寝室表单引用 | ||||
const formRef = ref<InstanceType<typeof Form> | null>(null); | const formRef = ref<InstanceType<typeof Form> | null>(null); | ||||
// 宿舍楼表单引用 | // 宿舍楼表单引用 | ||||
const formRefD = ref<InstanceType<typeof FormDormitory> | null>(null); | const formRefD = ref<InstanceType<typeof FormDormitory> | null>(null); | ||||
// 人员引用 | |||||
const formRefU = ref<InstanceType<typeof formUser> | null>(null); | |||||
/** | /** | ||||
* 打开表单 | * 打开表单 | ||||
@@ -161,13 +243,14 @@ const formRefU = ref<InstanceType<typeof formUser> | null>(null); | |||||
* @param record 记录 | * @param record 记录 | ||||
*/ | */ | ||||
function onOpen(opt: FormOptEnum, record: {} | SysDormitory.ChamberInfo = {}) { | function onOpen(opt: FormOptEnum, record: {} | SysDormitory.ChamberInfo = {}) { | ||||
if(buildId.value) { | |||||
formRef.value?.onOpen({ opt: opt, record: record, successful: RefreshTable }); | |||||
} else { | |||||
if(!buildId.value && opt == '新增') { | |||||
ElMessage({ | ElMessage({ | ||||
message: '请选择宿舍楼', | message: '请选择宿舍楼', | ||||
type: 'warning' | type: 'warning' | ||||
}); | }); | ||||
} else { | |||||
formRef.value?.onOpen({ opt: opt, record: record, successful: RefreshTable }); | |||||
} | } | ||||
} | } | ||||
@@ -204,7 +287,7 @@ function onOpen(opt: FormOptEnum, record: {} | SysDormitory.ChamberInfo = {}) { | |||||
return | return | ||||
} | } | ||||
// 二次确认 => 请求api => 刷新表格 | // 二次确认 => 请求api => 刷新表格 | ||||
await useHandleData(userManageDormitoryApi.delete, {id: ids.join(",") }, msg); | |||||
await useHandleData(userManageDormitoryApi.delete, {ids: ids }, msg); | |||||
RefreshTable(); //刷新表格 | RefreshTable(); //刷新表格 | ||||
} | } | ||||
@@ -248,16 +331,17 @@ const chamberId = ref<number | string>(); //寝室id | |||||
function handleCommand(command: Command) { | function handleCommand(command: Command) { | ||||
switch (command.command) { | switch (command.command) { | ||||
case cmdEnum.AddPerson: | case cmdEnum.AddPerson: | ||||
console.log(111) | |||||
// addPerson(FormOptEnum.add, command.row) | // addPerson(FormOptEnum.add, command.row) | ||||
userSelectorRef.value?.showSelector(); //显示用户选择器 | |||||
userManageDormitoryApi.detail({ id: command.row.id }).then((res:any) => { | |||||
userSelectorRef.value?.showSelector(res.data.personInfos); //显示用户选择器 | |||||
}); | |||||
chamberId.value = command.row.id; //获取寝室id | chamberId.value = command.row.id; //获取寝室id | ||||
break; | break; | ||||
} | } | ||||
} | } | ||||
function addPerson(opt: FormOptEnum, record: {} | SysDormitory.DormitoryInfo = {}) { | |||||
formRefU.value?.onOpen({ opt: opt, record: record, successful: RefreshTable }); | |||||
} | |||||
// function addPerson(opt: FormOptEnum, record: {} | SysDormitory.DormitoryInfo = {}) { | |||||
// formRefU.value?.onOpen({ opt: opt, record: record, successful: RefreshTable }); | |||||
// } | |||||
/** 宿舍楼切换 */ | /** 宿舍楼切换 */ | ||||
const buildId = ref<number | string>() | const buildId = ref<number | string>() | ||||
const buildGender = ref<boolean>() | const buildGender = ref<boolean>() | ||||
@@ -0,0 +1,143 @@ | |||||
<!-- | |||||
* @Description: 学生画像 | |||||
* @Author: syy | |||||
* @Date: 2024-7-24 | |||||
--> | |||||
<template> | |||||
<div class="main-box"> | |||||
<div class="table-box"> | |||||
<ProTable ref="proTable" title="预警分析" :columns="columns" rowKey="id" :pagination="false" :request-api="abilityApi.warnGroup"> | |||||
<!-- 表格 header 按钮 --> | |||||
<template #operation="scope"> | |||||
<s-button icon="Download" link :opt="FormOptEnums.EXPORT" @click="exportFn(scope.row)" /> | |||||
</template> | |||||
</ProTable> | |||||
</div> | |||||
<el-dialog v-model="timeForm.visible" title="选择导出时间范围" :before-close="closeTime" width="600px"> | |||||
<el-form :model="timeForm" :rules="timeRules" ref="timeFormRef" label-width="100px"> | |||||
<el-row> | |||||
<el-col :span="21"> | |||||
<el-form-item label="时间:" prop="dateArr"> | |||||
<el-date-picker | |||||
v-model="timeForm.dateArr" | |||||
type="daterange" | |||||
format="YYYY-MM-DD" | |||||
value-format="YYYY-MM-DD" | |||||
range-separator="-" | |||||
start-placeholder="开始日期" | |||||
end-placeholder="结束日期" | |||||
/> | |||||
</el-form-item> | |||||
</el-col> | |||||
</el-row> | |||||
</el-form> | |||||
<template #footer> | |||||
<div class="dialog-footer"> | |||||
<el-button type="primary" @click="onTimeSubmit">提交</el-button> | |||||
<el-button @click="closeTime">取消</el-button> | |||||
</div> | |||||
</template> | |||||
</el-dialog> | |||||
</div> | |||||
</template> | |||||
<script setup lang="tsx" name="SysUserPersonnel"> | |||||
import { abilityApi} from "@/api"; | |||||
import { ColumnProps, ProTableInstance } from "@/components/ProTable/interface"; | |||||
// 获取 ProTable 元素,调用其获取刷新数据方法(还能获取到当前查询参数,方便导出携带参数) | |||||
const proTable = ref<ProTableInstance>(); | |||||
const timeForm:any= reactive({ | |||||
dateArr:[], | |||||
rowItem:{}, | |||||
visible:false | |||||
}); | |||||
const timeFormRef = ref(); | |||||
const timeRules = ref({ | |||||
dateArr: [ | |||||
{ required: true, message: "请选择导出时间范围", trigger: "change" } | |||||
] | |||||
}); | |||||
/** 表单操作类型枚举 */ | |||||
enum FormOptEnums { | |||||
/** 导出 */ | |||||
EXPORT = "导出", | |||||
} | |||||
// 表格配置项 | |||||
const columns: ColumnProps[] = [{ type: "index", label: "序号", width: 60, fixed: "left" }, | |||||
{ | |||||
prop: "cameraName", | |||||
label: "摄像头", | |||||
render: (scope: any) => { | |||||
return scope.row.cameraName.join(", "); | |||||
} | |||||
}, | |||||
{ | |||||
prop: "name", | |||||
label: "场景" | |||||
}, | |||||
{ | |||||
prop: "state", | |||||
label: "状态", | |||||
render: (scope: any) => { | |||||
return scope.row.state ? <el-tag type="success">启用</el-tag> : <el-tag type="danger">禁用</el-tag>; | |||||
} | |||||
}, | |||||
{ prop: "operation", label: "操作", width: 250, fixed: "right" } | |||||
]; | |||||
/* 导出 */ | |||||
const onTimeSubmit = ()=>{ | |||||
timeFormRef.value.validate((valid: any) => { | |||||
if (valid) { | |||||
abilityApi.reportExport({ | |||||
groupCode:timeForm.rowItem.code, | |||||
startTime: timeForm.dateArr[0], | |||||
endTime: timeForm.dateArr[1], | |||||
}).then((res:any) => { | |||||
console.log(res,"....UTF-8''"); | |||||
const filename:any = ref() | |||||
filename.value = window.decodeURI(res.headers["content-disposition"].split("=")[2]); | |||||
filename.value = filename.value.slice(7,-1) | |||||
let blobUrl = window.URL.createObjectURL(res.data); | |||||
const a = document.createElement('a'); | |||||
a.style.display = 'none'; | |||||
a.setAttribute("target", "_blank"); | |||||
a.download = filename.value | |||||
a.href = blobUrl; | |||||
a.click(); | |||||
a.remove(); | |||||
ElMessage({ | |||||
message: res.msg, | |||||
type: 'success' | |||||
}); | |||||
closeTime(); | |||||
}); | |||||
} else { | |||||
return false; | |||||
} | |||||
}); | |||||
}; | |||||
const closeTime = () =>{ | |||||
timeForm.visible = false | |||||
} | |||||
const exportFn = (row: any) => { | |||||
timeForm.rowItem = JSON.parse(JSON.stringify(row)); | |||||
timeForm.visible = true | |||||
}; | |||||
</script> | |||||
<style scoped lang="scss"> | |||||
.table-box { | |||||
width: 100%; | |||||
height: 100%; | |||||
} | |||||
.custom-tree-node { | |||||
display: flex; | |||||
flex: 1; | |||||
align-items: center; | |||||
justify-content: space-between; | |||||
padding-right: 8px; | |||||
font-size: 14px; | |||||
} | |||||
</style> |
@@ -0,0 +1,254 @@ | |||||
<template> | |||||
<div class="roolcallDetail"> | |||||
<div class="header"> | |||||
<div class="left"> | |||||
<el-image | |||||
style="width: 100px; height: 100px" | |||||
src="https://fuss10.elemecdn.com/a/3f/3302e58f9a181d2509f3dc0fa68b0jpeg.jpeg" | |||||
:zoom-rate="1.2" | |||||
:max-scale="7" | |||||
:min-scale="0.2" | |||||
:preview-src-list="['https://fuss10.elemecdn.com/a/3f/3302e58f9a181d2509f3dc0fa68b0jpeg.jpeg']" | |||||
:initial-index="4" | |||||
fit="cover" | |||||
/> | |||||
</div> | |||||
<div class="right"> | |||||
<el-row> | |||||
<el-col :span="6"> | |||||
<span>人员编号:{{ formData.personId }}</span></el-col | |||||
> | |||||
<el-col :span="6" | |||||
><span>姓名:{{ formData.name }}</span></el-col | |||||
> | |||||
<el-col :span="6" | |||||
><span>性别:{{ genderOptions[formData.gender] }}</span></el-col | |||||
> | |||||
<el-col :span="6" | |||||
><span>年龄:{{ formData.age }}</span></el-col | |||||
> | |||||
<el-col :span="6" | |||||
><span>联系方式:{{ formData.phone }}</span> | |||||
</el-col> | |||||
<el-col :span="6"><span>班级:演示一班</span> </el-col> | |||||
</el-row> | |||||
</div> | |||||
</div> | |||||
<div class="content"> | |||||
<div ref="chartEl" style="width: 100%; height: 100%"></div> | |||||
</div> | |||||
</div> | |||||
</template> | |||||
<script setup lang="ts" name="ViolationPortraitDetail"> | |||||
import { userManagePersonnelApi, portraitSummaryApi } from "@/api"; | |||||
const route = useRoute(); | |||||
const formData = ref<any>({}); //班级人员列表 | |||||
import * as echarts from "echarts"; | |||||
const chartEl = ref(null); | |||||
const genderOptions = ref<any>({ | |||||
GENDER_UNKNOWN: "未知", | |||||
GENDER_MALE: "男", | |||||
GENDER_FEMALE: "女" | |||||
}); | |||||
const getDetail = () => { | |||||
userManagePersonnelApi.detail({ id: route.query.personId }).then((res: any) => { | |||||
formData.value = res.data; | |||||
}); | |||||
portraitSummaryApi.getStudentDetail({ id: route.query.personId }).then((res: any) => { | |||||
getCharts(res.data.label, res.data.value); | |||||
}); | |||||
}; | |||||
const getCharts = (nameArr: any, valueArr: any) => { | |||||
const chart = echarts.init(chartEl.value); | |||||
const option = { | |||||
title: { | |||||
text: "人员属性标签", | |||||
left: "center", | |||||
top: "5%", | |||||
textStyle: { | |||||
color: "#000", | |||||
fontSize: 25 | |||||
} | |||||
}, | |||||
grid: { | |||||
top: "18%", | |||||
left: "5%", | |||||
right: "5%", | |||||
bottom: "12%" | |||||
}, | |||||
tooltip: { | |||||
trigger: "axis", | |||||
backgroundColor: "#3A4667", | |||||
borderColor: "#3A4667", | |||||
textStyle: { | |||||
color: "#fff" | |||||
}, | |||||
formatter: "{b} : {c}", | |||||
axisPointer: { | |||||
type: "cross", | |||||
crossStyle: { | |||||
color: "#999" | |||||
} | |||||
} | |||||
}, | |||||
legend: { | |||||
icon: "rect", | |||||
top: 10, | |||||
right: 5, | |||||
itemWidth: 10, | |||||
itemHeight: 10, | |||||
textStyle: { | |||||
fontSize: 12, // 字体大小 | |||||
// color: '#B3CFFF', // 字体颜色 | |||||
color: "#FFEB3B" | |||||
} | |||||
}, | |||||
xAxis: { | |||||
type: "category", | |||||
axisPointer: { | |||||
type: "shadow" | |||||
}, | |||||
axisLine: { | |||||
lineStyle: { | |||||
color: "rgba(112, 138, 198, 1)" | |||||
} | |||||
}, | |||||
axisLabel: { | |||||
textStyle: { | |||||
color: "#333", // x轴文本颜色 | |||||
fontSize: 12 | |||||
} | |||||
// rotate:30, | |||||
}, | |||||
axisTick: { | |||||
show: false | |||||
}, | |||||
data: nameArr | |||||
}, | |||||
yAxis: { | |||||
name: "次", | |||||
type: "value", | |||||
splitLine: { | |||||
show: true, | |||||
lineStyle: { | |||||
color: "#333", | |||||
type: "dashed" | |||||
} | |||||
}, | |||||
axisLabel: { | |||||
formatter: "{value}", | |||||
textStyle: { | |||||
color: "#333", // x轴文本颜色 | |||||
fontSize: 12 | |||||
} | |||||
}, | |||||
nameTextStyle: { | |||||
color: "#333", | |||||
fontSize: 12 | |||||
} | |||||
}, | |||||
series: [ | |||||
{ | |||||
type: "bar", | |||||
name: "", | |||||
barWidth: 27, | |||||
emphasis: { | |||||
itemStyle: { | |||||
color: "#7fb7e9" | |||||
}, | |||||
label: { | |||||
textStyle: { | |||||
color: "#7fb7e9" | |||||
} | |||||
} | |||||
}, | |||||
label: { | |||||
show: true, | |||||
position: "top", | |||||
textStyle: { | |||||
color: "rgba(12, 245, 229, 1)", | |||||
padding: [0, 10] | |||||
} | |||||
}, | |||||
itemStyle: { | |||||
normal: { | |||||
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [ | |||||
{ | |||||
offset: 1, | |||||
color: "rgba(12, 245, 229, 1)" | |||||
// opacity: 0.6 | |||||
}, | |||||
{ | |||||
offset: 0, | |||||
color: "rgba(12, 245, 229, 0)" | |||||
// opacity: 1 | |||||
} | |||||
]) | |||||
} | |||||
}, | |||||
data: valueArr | |||||
}, | |||||
{ | |||||
name: "", | |||||
type: "pictorialBar", | |||||
itemStyle: { | |||||
normal: { | |||||
color: "rgba(12, 245, 229, 1)" | |||||
} | |||||
}, | |||||
symbol: "rect", // 图形类型,这里是矩形 | |||||
symbolRotate: 0, | |||||
symbolSize: ["27", "3"], | |||||
symbolPosition: "end", | |||||
data: valueArr, | |||||
z: 3 | |||||
} | |||||
] | |||||
}; | |||||
chart.setOption(option); | |||||
window.addEventListener("resize", function () { | |||||
chart.resize(); | |||||
}); | |||||
}; | |||||
onMounted(() => { | |||||
getDetail(); | |||||
}); | |||||
</script> | |||||
<style lang="scss" scoped> | |||||
.roolcallDetail { | |||||
.header { | |||||
box-sizing: border-box; | |||||
display: flex; | |||||
align-items: center; | |||||
justify-content: space-between; | |||||
width: 100%; | |||||
height: 180px; | |||||
padding: 10px 20px; | |||||
background: #ffffff; | |||||
.left { | |||||
display: flex; | |||||
align-items: center; | |||||
justify-content: flex-end; | |||||
width: 200px; | |||||
height: 100%; | |||||
} | |||||
.right { | |||||
width: calc(100% - 200px); | |||||
.el-row { | |||||
height: 100%; | |||||
.el-col { | |||||
height: 50px; | |||||
line-height: 50px; | |||||
text-align: center; | |||||
} | |||||
} | |||||
} | |||||
} | |||||
.content { | |||||
height: 550px; | |||||
margin-top: 20px; | |||||
background: #ffffff; | |||||
} | |||||
} | |||||
</style> |
@@ -0,0 +1,123 @@ | |||||
<!-- | |||||
* @Description: 学生画像 | |||||
* @Author: syy | |||||
* @Date: 2024-7-24 | |||||
--> | |||||
<template> | |||||
<div class="main-box"> | |||||
<TreeFilter | |||||
ref="treeFilter" | |||||
label="personSetName" | |||||
id="personSetId" | |||||
width="300px" | |||||
title="班级管理" | |||||
:show-all="true" | |||||
:request-api="userManageClassManageApi.page" | |||||
@change="changeTreeFilter" | |||||
> | |||||
<template v-slot:label="{ row }"> | |||||
<span class="custom-tree-node"> | |||||
<span>{{ row.node.label }} {{ row.node.userName ? `(${row.node.userName})` : "" }}</span> | |||||
</span> | |||||
</template> | |||||
</TreeFilter> | |||||
<div class="table-box"> | |||||
<ProTable ref="proTable" title="人员列表" :columns="columns" rowKey="id" :request-api="userManagePersonnelApi.page"> | |||||
<!-- 表格操作栏 --> | |||||
<template #operation="scope"> | |||||
<el-space> | |||||
<s-button link :opt="FormOptEnum.VIEW" @click="onView(scope.row)" /> | |||||
</el-space> | |||||
</template> | |||||
</ProTable> | |||||
</div> | |||||
<!-- 预览头像 --> | |||||
<el-dialog v-model="visible" title="查看头像" width="830px" :before-close="handleClose"> | |||||
<div style="display: flex; align-items: center; justify-content: center"> | |||||
<img style="max-width: 100%; max-height: 600px" class="detailpic" :src="faceUrl" alt="" /> | |||||
</div> | |||||
</el-dialog> | |||||
</div> | |||||
</template> | |||||
<script setup lang="tsx" name="ViolationPortrait"> | |||||
import { userManagePersonnelApi,userManageClassManageApi} from "@/api"; | |||||
import { FormOptEnum } from "@/enums"; | |||||
import { ColumnProps, ProTableInstance } from "@/components/ProTable/interface"; | |||||
import TreeFilter from "@/components/TreeFilter/index.vue"; | |||||
import { useRouter } from "vue-router"; | |||||
const visible = ref(false); //是否显示人员表单 | |||||
const faceUrl = ref(''); | |||||
const router = useRouter(); | |||||
// 获取 ProTable 元素,调用其获取刷新数据方法(还能获取到当前查询参数,方便导出携带参数) | |||||
const proTable = ref<ProTableInstance>(); | |||||
const treeFilter = ref<any>(); | |||||
// 表格配置项 | |||||
const columns: ColumnProps[] = [ | |||||
{ | |||||
prop: "faceUrl", | |||||
label: "人脸", | |||||
render: scope => { | |||||
return ( | |||||
<img src={scope.row.faces.length > 0 ? scope.row.faces[0].faceUrl : ''} onClick={() => viewHeadImage(scope)} style='width:50px;height:50px;' alt=''/> | |||||
); | |||||
} | |||||
}, | |||||
{ | |||||
prop: "name", | |||||
label: "姓名" | |||||
}, | |||||
{ | |||||
prop: "personId", | |||||
label: "人员ID" | |||||
}, | |||||
{ | |||||
prop: "phone", | |||||
label: "手机号" | |||||
}, | |||||
{ | |||||
prop: "personSetName", | |||||
label: "所属班级", | |||||
}, | |||||
{ prop: "operation", label: "操作", width: 250, fixed: "right" } | |||||
]; | |||||
const viewHeadImage = (scope: any) => { | |||||
faceUrl.value = scope.row.faces[0].faceUrl; | |||||
visible.value = true | |||||
}; | |||||
const handleClose = () => { | |||||
visible.value = false; | |||||
}; | |||||
const onView = (row: any) => { | |||||
router.push({ | |||||
path:'/violation/portrait/detail', | |||||
query: { | |||||
personId: row.personId | |||||
} | |||||
}); | |||||
}; | |||||
/** 部门切换 */ | |||||
const personSetId = ref<number | string>() | |||||
function changeTreeFilter(val: number | string) { | |||||
personSetId.value = val | |||||
proTable.value!.pageable.pageNum = 1; | |||||
proTable.value!.searchParam.personSetId = val; | |||||
proTable.value!.search(); | |||||
} | |||||
</script> | |||||
<style scoped lang="scss"> | |||||
.table-box { | |||||
width: 100%; | |||||
height: 100%; | |||||
} | |||||
.custom-tree-node { | |||||
display: flex; | |||||
flex: 1; | |||||
align-items: center; | |||||
justify-content: space-between; | |||||
padding-right: 8px; | |||||
font-size: 14px; | |||||
} | |||||
</style> |
@@ -0,0 +1,539 @@ | |||||
<template> | |||||
<div class="home"> | |||||
<el-row :gutter="20"> | |||||
<el-col :xs="24" :sm="24" :md="12" :lg="12" :xl="12"> | |||||
<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="12"> | |||||
<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="12"> | |||||
<div class="home-bg card"> | |||||
<div class="home-bg-title"> | |||||
<div></div> | |||||
<div>地理位置</div> | |||||
</div> | |||||
<div class="home-bg-content"> | |||||
<div ref="chart5" style="width: 100%; height: 100%"></div> | |||||
</div> | |||||
</div> | |||||
</el-col> | |||||
<el-col :xs="24" :sm="24" :md="12" :lg="12" :xl="12"> | |||||
<div class="home-bg card"> | |||||
<div class="home-bg-title"> | |||||
<div></div> | |||||
<div>标签属性</div> | |||||
</div> | |||||
<div class="home-bg-content handleBox"> | |||||
<div ref="chart4" style="width: 100%; height: 100%"></div> | |||||
</div> | |||||
</div> | |||||
</el-col> | |||||
</el-row> | |||||
</div> | |||||
</template> | |||||
<script setup lang="ts" name="home"> | |||||
import * as echarts from "echarts"; | |||||
import { portraitSummaryApi } from "@/api"; | |||||
const chart1 = ref(null); | |||||
const chart2 = ref(null); | |||||
const chart4 = ref(null); | |||||
const chart5 = ref(null); | |||||
onMounted(() => { | |||||
getDataChart(); | |||||
}); | |||||
const getDataChart = async () => { | |||||
/* 获取学生性别 */ | |||||
let sex: any = await portraitSummaryApi.getStudentSex(); | |||||
getCharts1(sex.data.label, sex.data.value); | |||||
/* 获取学生年龄 */ | |||||
let age: any = await portraitSummaryApi.getStudentAge(); | |||||
getCharts2(age.data.label, age.data.value); | |||||
/* 获取属性标签 */ | |||||
let attr: any = await portraitSummaryApi.getStudentAttr(); | |||||
getCharts4(attr.data.label, attr.data.value); | |||||
/* 获取地理位置 */ | |||||
let address: any = await portraitSummaryApi.getAddress(); | |||||
getCharts5(address.data.label, address.data.value); | |||||
}; | |||||
const handleDate = (label: any, value: any, key: any = "") => { | |||||
let data: any = []; | |||||
label.forEach((item: any, index: number) => { | |||||
data.push({ | |||||
value: value[index], | |||||
name: item + key | |||||
}); | |||||
}); | |||||
return data; | |||||
}; | |||||
/* 性別 */ | |||||
function getCharts1(label: any, value: any) { | |||||
const chart = echarts.init(chart1.value); | |||||
const data = handleDate(label, value); | |||||
const option = { | |||||
tooltip: { | |||||
confine: true | |||||
}, | |||||
legend: { | |||||
show: true, | |||||
right: "0%", | |||||
top: "center", | |||||
orient: "vertical", | |||||
data: label | |||||
}, | |||||
series: [ | |||||
{ | |||||
type: "pie", | |||||
radius: "80%", | |||||
center: ["50%", "50%"], | |||||
roseType: "area", | |||||
label: { | |||||
normal: { | |||||
show: true | |||||
}, | |||||
emphasis: { | |||||
show: true | |||||
} | |||||
}, | |||||
itemStyle: { | |||||
normal: { | |||||
label: { | |||||
show: true, | |||||
// position:'inside', | |||||
formatter: "{b} : {c}人" | |||||
} | |||||
}, | |||||
labelLine: { | |||||
show: true | |||||
} | |||||
}, | |||||
data: data | |||||
} | |||||
] | |||||
}; | |||||
chart.setOption(option); | |||||
window.addEventListener("resize", function () { | |||||
chart.resize(); | |||||
}); | |||||
} | |||||
/* 年齡 */ | |||||
function getCharts2(label: any, value: any) { | |||||
const chartstation = echarts.init(chart2.value); | |||||
const data = handleDate(label, value, "岁"); | |||||
const labelArr: any = []; | |||||
label.map((item: any) => labelArr.push(item + "岁")); | |||||
const option = { | |||||
legend: { | |||||
show: true, | |||||
right: "0%", | |||||
top: "center", | |||||
orient: "vertical", | |||||
data: labelArr | |||||
}, | |||||
tooltip: { | |||||
trigger: "item", | |||||
formatter: "{a} <br/>{b} : {c} ({d}%)" | |||||
}, | |||||
calculable: true, | |||||
series: [ | |||||
{ | |||||
name: "年龄分布", | |||||
type: "pie", | |||||
radius: [50, 140], | |||||
roseType: "area", | |||||
data: data, | |||||
itemStyle: { | |||||
normal: { | |||||
label: { | |||||
show: true, | |||||
// position:'inside', | |||||
formatter: "{b} : {c}人" | |||||
} | |||||
}, | |||||
labelLine: { | |||||
show: true | |||||
} | |||||
} | |||||
} | |||||
] | |||||
}; | |||||
chartstation.setOption(option); | |||||
window.addEventListener("resize", function () { | |||||
chartstation.resize(); | |||||
}); | |||||
} | |||||
/* 兴趣爱好 */ | |||||
function getCharts4(categoryData: any, dataArr: any) { | |||||
const chartstation = echarts.init(chart4.value); | |||||
var spaceLength = 5, | |||||
fixedData = [], | |||||
end = 0, | |||||
max = 300; | |||||
// var categoryData = ys.超市品牌; | |||||
let xhao: any = []; | |||||
for (var i = 0; i < dataArr.length; i++) { | |||||
xhao.push(i + 1); | |||||
} | |||||
var data1 = dataArr.map((item: any) => { | |||||
fixedData.push(spaceLength); | |||||
return item - spaceLength; | |||||
}); | |||||
if (categoryData.length < 5) { | |||||
end = categoryData.length - 1; | |||||
} else { | |||||
end = 5; | |||||
} | |||||
const option = { | |||||
xAxis: [{ show: false }], | |||||
yAxis: [ | |||||
{ | |||||
splitLine: { | |||||
show: false | |||||
}, | |||||
axisLine: { | |||||
//y轴 | |||||
show: false | |||||
}, | |||||
type: "category", | |||||
inverse: true, | |||||
axisTick: { | |||||
show: false | |||||
}, | |||||
data: categoryData, | |||||
axisLabel: { | |||||
align: "left", | |||||
margin: 170, | |||||
formatter: function (value: any, index: any) { | |||||
const num = ref<any>(""); | |||||
var str = ""; | |||||
num.value = xhao[categoryData.indexOf(value)]; | |||||
if (index === 0) { | |||||
str = "{no1|" + "} {num1|" + num.value + "} {title| " + value + "}"; | |||||
} else if (index === 1) { | |||||
str = "{no2|" + "} {num2|" + num.value + "} {title| " + value + "}"; | |||||
} else if (index === 2) { | |||||
str = "{no3|" + "} {num3|" + num.value + "} {title| " + value + "}"; | |||||
} else { | |||||
str = " {num|" + num.value + "} {title| " + value + "}"; | |||||
} | |||||
return str; | |||||
}, | |||||
rich: { | |||||
num: { | |||||
color: "#387ec1", | |||||
backgroundColor: "#112b67", | |||||
width: 10, | |||||
height: 10, | |||||
fontSize: 14, | |||||
padding: [6, 5, 3, 5], | |||||
align: "center", | |||||
shadowColor: "#3374ba", | |||||
borderColor: "#3374ba", | |||||
borderWidth: 1 | |||||
}, | |||||
num1: { | |||||
color: "#51aff8", | |||||
backgroundColor: "#112b67", | |||||
width: 10, | |||||
height: 10, | |||||
fontSize: 14, | |||||
padding: [7, 5, 3, 5], | |||||
align: "center", | |||||
shadowColor: "#4db2ff", | |||||
borderColor: "#4db2ff", | |||||
borderWidth: 1 | |||||
}, | |||||
num2: { | |||||
color: "#51aff8", | |||||
backgroundColor: "#112b67", | |||||
width: 10, | |||||
height: 10, | |||||
fontSize: 14, | |||||
padding: [7, 5, 3, 5], | |||||
align: "center", | |||||
shadowColor: "#4db2ff", | |||||
borderColor: "#4db2ff", | |||||
borderWidth: 1 | |||||
}, | |||||
num3: { | |||||
color: "#51aff8", | |||||
backgroundColor: "#112b67", | |||||
width: 10, | |||||
height: 10, | |||||
fontSize: 14, | |||||
padding: [7, 5, 3, 5], | |||||
align: "center", | |||||
shadowColor: "#4db2ff", | |||||
borderColor: "#4db2ff", | |||||
borderWidth: 1 | |||||
}, | |||||
title: { | |||||
color: "#000" | |||||
} | |||||
} | |||||
} | |||||
} | |||||
], | |||||
dataZoom: [ | |||||
{ | |||||
show: false, | |||||
type: "slider", | |||||
yAxisIndex: 0, | |||||
zoomLock: false, | |||||
width: 8, | |||||
showDetail: false, | |||||
startValue: 0, // 从头开始。 | |||||
endValue: end, // 一次性展示五个。 | |||||
borderWidth: 0, | |||||
borderColor: "transparent", | |||||
backgroundColor: "#343F4B", | |||||
fillerColor: "#4291CE", | |||||
showDataShadow: false, | |||||
brushSelect: false, | |||||
height: "88%", | |||||
handleStyle: { | |||||
color: "#4291CE" | |||||
}, | |||||
handleIcon: "path://M512 512m-320 0a320 320 0 1 0 640 0 320 320 0 1 0-640 0Z" | |||||
} | |||||
], | |||||
grid: { | |||||
right: "14%", | |||||
left: "35%", | |||||
top: "4%", | |||||
bottom: "1%" | |||||
}, | |||||
series: [ | |||||
{ | |||||
name: "", | |||||
type: "bar", | |||||
barWidth: 12, // 柱子宽度 | |||||
itemStyle: { | |||||
normal: { | |||||
color: function (params: any) { | |||||
// var colorList = [ | |||||
// '#7711AF', '#CF77FF', '#AE004F', '#F35872', '#FA7729', | |||||
// '#FFC526', '#F8E71C', '#34ADAE', '#3DDFD2', '#A0FFFF' | |||||
// ]; | |||||
var colorListr = [ | |||||
"#8A64B8", | |||||
"#7575D3", | |||||
"#5F85DD", | |||||
"#6FABE8", | |||||
"#7ED3F4", | |||||
"#8CD8C0", | |||||
"#9CDF8D", | |||||
"#BFED6B", | |||||
"#EAFE4F", | |||||
"#FFFD47", | |||||
"#FFEA55", | |||||
"#FFCF63", | |||||
"#FFA069", | |||||
"#fce38a", | |||||
"#eaffd0", | |||||
"#95e1d3", | |||||
"#e3fdfd", | |||||
"#749f83", | |||||
"#ca8622" | |||||
]; | |||||
return colorListr[params.dataIndex]; | |||||
}, | |||||
shadowBlur: 20, | |||||
shadowColor: "rgba(40, 40, 40, 0.5)" | |||||
} | |||||
}, | |||||
label: { | |||||
formatter: function (parms: any) { | |||||
return parms.value + spaceLength; | |||||
}, | |||||
show: true, | |||||
position: "right", // 位置 | |||||
color: "#1CD8A8", | |||||
fontSize: 14, | |||||
fontWeight: "bold", // 加粗 | |||||
distance: 10 // 距离 | |||||
}, | |||||
data: data1 | |||||
} | |||||
] | |||||
}; | |||||
chartstation.setOption(option); | |||||
window.addEventListener("resize", function () { | |||||
chartstation.resize(); | |||||
}); | |||||
} | |||||
/* 标签、地理位置 */ | |||||
function getCharts5(nameArr: any, valueArr: any) { | |||||
const chartstation5 = echarts.init(chart5.value); | |||||
const option = { | |||||
grid: { | |||||
top: "10%", | |||||
left: "8%", | |||||
right: "5%", | |||||
bottom: "20%" | |||||
}, | |||||
tooltip: { | |||||
trigger: "axis", | |||||
backgroundColor: "#3A4667", | |||||
borderColor: "#3A4667", | |||||
textStyle: { | |||||
color: "#fff" | |||||
}, | |||||
formatter: "{b} : {c}", | |||||
axisPointer: { | |||||
type: "cross", | |||||
crossStyle: { | |||||
color: "#999" | |||||
} | |||||
} | |||||
}, | |||||
legend: { | |||||
icon: "rect", | |||||
top: 10, | |||||
right: 5, | |||||
itemWidth: 10, | |||||
itemHeight: 10, | |||||
textStyle: { | |||||
fontSize: 12, // 字体大小 | |||||
color: "#B3CFFF" // 字体颜色 | |||||
} | |||||
}, | |||||
xAxis: { | |||||
type: "category", | |||||
axisPointer: { | |||||
type: "shadow" | |||||
}, | |||||
axisLine: { | |||||
lineStyle: { | |||||
color: "rgba(112, 138, 198, 1)" | |||||
} | |||||
}, | |||||
axisLabel: { | |||||
textStyle: { | |||||
color: "#333", // x轴文本颜色 | |||||
fontSize: 12 | |||||
} | |||||
// rotate:30, | |||||
}, | |||||
axisTick: { | |||||
show: false | |||||
}, | |||||
data: nameArr | |||||
}, | |||||
yAxis: { | |||||
type: "value", | |||||
splitLine: { | |||||
show: true, | |||||
lineStyle: { | |||||
color: "#162647", | |||||
type: "solid" | |||||
} | |||||
}, | |||||
axisLabel: { | |||||
formatter: "{value}", | |||||
textStyle: { | |||||
color: "#333", // x轴文本颜色 | |||||
fontSize: 12 | |||||
} | |||||
}, | |||||
name: "", | |||||
nameTextStyle: { | |||||
color: "#B3CFFF", | |||||
fontSize: 12 | |||||
} | |||||
}, | |||||
series: [ | |||||
{ | |||||
type: "bar", | |||||
name: "", | |||||
barWidth: 16, | |||||
emphasis: { | |||||
itemStyle: { | |||||
color: "#7fb7e9" | |||||
}, | |||||
label: { | |||||
textStyle: { | |||||
color: "#7fb7e9" | |||||
} | |||||
} | |||||
}, | |||||
label: { | |||||
show: true, | |||||
position: "top", | |||||
textStyle: { | |||||
color: "rgba(147, 157, 223, 1)", | |||||
padding: [0, 10] | |||||
} | |||||
}, | |||||
itemStyle: { | |||||
normal: { | |||||
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [ | |||||
{ | |||||
offset: 1, | |||||
color: "rgba(147, 157, 223, 1)" | |||||
}, | |||||
{ | |||||
offset: 0, | |||||
color: "rgba(147, 157, 223, 0)" | |||||
} | |||||
]) | |||||
} | |||||
}, | |||||
data: valueArr | |||||
}, | |||||
{ | |||||
name: "", | |||||
type: "pictorialBar", | |||||
itemStyle: { | |||||
normal: { | |||||
color: "rgba(147, 157, 223, 1)" | |||||
} | |||||
}, | |||||
symbolRotate: 0, | |||||
symbolSize: ["16", "3"], | |||||
symbolPosition: "end", | |||||
data: valueArr, | |||||
z: 3 | |||||
} | |||||
] | |||||
}; | |||||
chartstation5.setOption(option); | |||||
window.addEventListener("resize", function () { | |||||
chartstation5.resize(); | |||||
}); | |||||
} | |||||
</script> | |||||
<style scoped lang="scss"> | |||||
@import "../../home/index.scss"; | |||||
</style> |
@@ -36,17 +36,17 @@ onMounted(() => { | |||||
}); | }); | ||||
function getDataChart() { | function getDataChart() { | ||||
setTimeout(async () => { | setTimeout(async () => { | ||||
await statistionApi.warnstatistion({}).then(res => { | |||||
await statistionApi.warnstatistion({}).then((res: any) => { | |||||
let { code, data } = res; | let { code, data } = res; | ||||
if (code == 200) { | if (code == 200) { | ||||
let chartData1 = data.alarm.map(item => { | |||||
let chartData1 = data.alarm.map((item: any) => { | |||||
return { | return { | ||||
value: item.count, | value: item.count, | ||||
name: item.name | name: item.name | ||||
}; | }; | ||||
}); | }); | ||||
let chartData2 = data.hand.map(item => { | |||||
let chartData2 = data.hand.map((item: any) => { | |||||
return { | return { | ||||
value: item.count, | value: item.count, | ||||
name: item.name | name: item.name | ||||
@@ -68,7 +68,7 @@ function getDataChart() { | |||||
}); | }); | ||||
}); | }); | ||||
} | } | ||||
function getCharts1(data) { | |||||
function getCharts1(data: any) { | |||||
const chart = echarts.init(chart1.value); | const chart = echarts.init(chart1.value); | ||||
const option = { | const option = { | ||||
title: { | title: { | ||||
@@ -105,7 +105,7 @@ function getCharts1(data) { | |||||
chart.resize(); | chart.resize(); | ||||
}); | }); | ||||
} | } | ||||
function getCharts2(data) { | |||||
function getCharts2(data: any) { | |||||
const chartstation = echarts.init(chart2.value); | const chartstation = echarts.init(chart2.value); | ||||
const option = { | const option = { | ||||
title: { | title: { | ||||
@@ -142,39 +142,23 @@ function getCharts2(data) { | |||||
chartstation.resize(); | chartstation.resize(); | ||||
}); | }); | ||||
} | } | ||||
function flattenArray(arr) { | |||||
const result = []; | |||||
arr.forEach(item => { | |||||
if (Array.isArray(item)) { | |||||
result.push(...flattenArray(item)); | |||||
} else { | |||||
result.push(item); | |||||
} | |||||
}); | |||||
return result; | |||||
} | |||||
function unique(arr) { | |||||
return arr.filter((item, index, arr) => arr.indexOf(item, 0) === index); | |||||
} | |||||
function getWeekData() { | function getWeekData() { | ||||
setTimeout(async () => { | setTimeout(async () => { | ||||
await statistionApi.weekstatistion({}).then(res => { | |||||
await statistionApi.weekstatistion({}).then((res: any) => { | |||||
let { code, data } = res; | let { code, data } = res; | ||||
if (code == 200) { | if (code == 200) { | ||||
// let chartData = data; | // let chartData = data; | ||||
let time = data.dataX; | let time = data.dataX; | ||||
let chartData = data.dataY.map(item => { | |||||
let chartData = data.dataY.map((item: any) => { | |||||
return { | return { | ||||
data: item.data, | data: item.data, | ||||
name: item.name, | name: item.name, | ||||
type: "bar", | type: "bar", | ||||
barWidth: "12px", // 设置柱子粗细 | barWidth: "12px", // 设置柱子粗细 | ||||
itemStyle: { | itemStyle: { | ||||
normal: { | |||||
barBorderRadius: [30, 30, 0, 0] | |||||
} | |||||
borderRadius: [30, 30, 0, 0] | |||||
} | } | ||||
}; | }; | ||||
}); | }); | ||||
@@ -183,7 +167,7 @@ function getWeekData() { | |||||
}); | }); | ||||
}); | }); | ||||
} | } | ||||
function getCharts3(time, data) { | |||||
function getCharts3(time: any, data: any) { | |||||
const chartstation3 = echarts.init(chart3.value); | const chartstation3 = echarts.init(chart3.value); | ||||
const option = { | const option = { | ||||
title: { | title: { | ||||
@@ -228,21 +212,20 @@ function getCharts3(time, data) { | |||||
height: 50px; | height: 50px; | ||||
line-height: 50px; | line-height: 50px; | ||||
} | } | ||||
.collapse-title { | .collapse-title { | ||||
flex: 1 0 90%; | |||||
order: 1; | |||||
display: flex; | display: flex; | ||||
flex: 1 0 90%; | |||||
align-items: center; | align-items: center; | ||||
justify-content: space-between; | justify-content: space-between; | ||||
// padding: 30px 0; | |||||
order: 1; | |||||
// padding: 30px 0; | |||||
.titlemodel { | .titlemodel { | ||||
margin-right: 40px; | |||||
// display: inline-block; | // display: inline-block; | ||||
font-size: 18px; | font-size: 18px; | ||||
margin-right: 40px; | |||||
} | } | ||||
.btns { | .btns { | ||||
margin-left: 40px; | margin-left: 40px; | ||||
} | } | ||||
@@ -250,19 +233,22 @@ function getCharts3(time, data) { | |||||
.collapse-content { | .collapse-content { | ||||
padding: 20px; | padding: 20px; | ||||
.contentinfo { | .contentinfo { | ||||
margin-top: 20px; | |||||
box-sizing: border-box; | |||||
// display: flex; | // display: flex; | ||||
// justify-content: space-between; | // justify-content: space-between; | ||||
// align-items: center; | // align-items: center; | ||||
padding: 20px 20px; | |||||
box-sizing: border-box; | |||||
padding: 20px; | |||||
margin-top: 20px; | |||||
// border-bottom: 1px solid #dcdfe6; | // border-bottom: 1px solid #dcdfe6; | ||||
// background: red; | // background: red; | ||||
border-radius: 10px; | border-radius: 10px; | ||||
// box-shadow: 3px 3px 3px #00000014, 3px -3px 3px #00000014, -3px 3px 3px #00000014, -3px -3px 3px #00000014; | // box-shadow: 3px 3px 3px #00000014, 3px -3px 3px #00000014, -3px 3px 3px #00000014, -3px -3px 3px #00000014; | ||||
// box-shadow: 0 1px 1px hsl(0deg 0% 0% / 0.075), 0 2px 2px hsl(0deg 0% 0% / 0.075), 0 4px 4px hsl(0deg 0% 0% / 0.075), | // box-shadow: 0 1px 1px hsl(0deg 0% 0% / 0.075), 0 2px 2px hsl(0deg 0% 0% / 0.075), 0 4px 4px hsl(0deg 0% 0% / 0.075), | ||||
// 0 8px 8px hsl(0deg 0% 0% / 0.075), 0 16px 16px hsl(0deg 0% 0% / 0.075); | // 0 8px 8px hsl(0deg 0% 0% / 0.075), 0 16px 16px hsl(0deg 0% 0% / 0.075); | ||||
box-shadow: 0px 2px 1px rgba(0, 0, 0, 0.1), 0 0px 8px rgba(0, 0, 0, 0.1), 0 -1px 1px #fff, 0px 0 0px #fff, 0 0 16px #fff; | |||||
box-shadow: 0 2px 1px rgb(0 0 0 / 10%), 0 0 8px rgb(0 0 0 / 10%), 0 -1px 1px #ffffff, 0 0 0 #ffffff, 0 0 16px #ffffff; | |||||
.modellabel { | .modellabel { | ||||
font-size: 16px; | font-size: 16px; | ||||
} | } | ||||
@@ -0,0 +1,101 @@ | |||||
<!-- | |||||
* @Description: 表单 | |||||
* @Author: syy | |||||
* @Date: 2023-12-15 15:45:59 | |||||
--> | |||||
<template> | |||||
<div> | |||||
<form-container v-model="visibleChamber" title="处理" form-size="600px" @close="onClose"> | |||||
<el-form | |||||
ref="SysDormitoryFormRef" | |||||
:rules="rules" | |||||
:disabled="warnHandleProps.disabled" | |||||
:model="warnHandleProps.record" | |||||
:hide-required-asterisk="warnHandleProps.disabled" | |||||
label-width="auto" | |||||
label-suffix=" :" | |||||
> | |||||
<div> | |||||
<el-row :gutter="16"> | |||||
<el-col :span="22"> | |||||
<s-form-item label="处理意见" prop="remark"> | |||||
<el-input v-model="warnHandleProps.record.remark" :autosize="{ minRows: 4 }" type="textarea" placeholder="请输入处理意见" /> | |||||
</s-form-item> | |||||
</el-col> | |||||
</el-row> | |||||
</div> | |||||
</el-form> | |||||
<template #footer> | |||||
<el-button @click="onClose"> 取消 </el-button> | |||||
<el-button v-show="!warnHandleProps.disabled" type="primary" @click="handleSubmit"> 确定 </el-button> | |||||
</template> | |||||
</form-container> | |||||
</div> | |||||
</template> | |||||
<script setup lang="ts" name="warnHandleForm"> | |||||
import { ref } from "vue"; | |||||
import { ZJRQ, warnZJRQApi } from "@/api"; | |||||
import { FormOptEnum } from "@/enums"; | |||||
import { required } from "@/utils/formRules"; | |||||
import { FormInstance } from "element-plus"; | |||||
const visibleChamber = ref(false); //是否显示表单 | |||||
// 表单参数 | |||||
const warnHandleProps = reactive<FormProps.Base<ZJRQ.WarnInfo>>({ | |||||
opt: FormOptEnum.ADD, | |||||
record: {}, | |||||
disabled: false | |||||
}); | |||||
// 表单验证规则 | |||||
const rules = reactive({ | |||||
remark: [required("请输入处理意见")] | |||||
}); | |||||
/** | |||||
* 打开表单 | |||||
* @param props 表单参数 | |||||
*/ | |||||
function onOpen(props: FormProps.Base<ZJRQ.WarnInfo>) { | |||||
Object.assign(warnHandleProps, props); //合并参数 | |||||
visibleChamber.value = true; //显示表单 | |||||
warnHandleProps.record = props.record; | |||||
} | |||||
// 提交数据(新增/编辑) | |||||
const SysDormitoryFormRef = ref<FormInstance>(); | |||||
/** 提交表单 */ | |||||
async function handleSubmit() { | |||||
SysDormitoryFormRef.value?.validate(async valid => { | |||||
if (!valid) return; //表单验证失败 | |||||
let params: any = { | |||||
id: warnHandleProps.record.id, | |||||
remark: warnHandleProps.record.remark | |||||
}; | |||||
await warnZJRQApi | |||||
.handWarn(params) | |||||
.then((res: any) => { | |||||
ElMessage({ | |||||
message: res.msg, | |||||
type: "success" | |||||
}); | |||||
warnHandleProps.successful!(); //调用父组件的successful方法 | |||||
}) | |||||
.finally(() => { | |||||
onClose(); | |||||
}); | |||||
}); | |||||
} | |||||
/** 关闭表单*/ | |||||
function onClose() { | |||||
visibleChamber.value = false; | |||||
} | |||||
// 暴露给父组件的方法 | |||||
defineExpose({ | |||||
onOpen | |||||
}); | |||||
</script> | |||||
<style lang="scss" scoped></style> |
@@ -34,7 +34,7 @@ | |||||
<!-- 操作 --> | <!-- 操作 --> | ||||
<template #operation="scope"> | <template #operation="scope"> | ||||
<s-button link :opt="FormOptEnum.VIEW" @click="onDetail(scope.row)"> 详情 </s-button> | <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 v-if="scope.row.warnHand == 0" link :opt="FormOptEnum.EDIT" @click="toHandle(FormOptEnum.EDIT, scope.row)">处理</s-button> | |||||
<s-button link :opt="FormOptEnum.DELETE" @click="onDelete([scope.row.id], `确定删除该预警吗?`)" /> | <s-button link :opt="FormOptEnum.DELETE" @click="onDelete([scope.row.id], `确定删除该预警吗?`)" /> | ||||
</template> | </template> | ||||
</ProTable> | </ProTable> | ||||
@@ -77,6 +77,16 @@ | |||||
<!-- {{ detailData.videoUrl }} --> | <!-- {{ detailData.videoUrl }} --> | ||||
</div> | </div> | ||||
</el-col> | </el-col> | ||||
<el-col :span="24"> | |||||
<div class="linebox"> | |||||
处理意见: | |||||
<span style="cursor: pointer" v-if="detailData.remark"> | |||||
{{ detailData.remark }} | |||||
</span> | |||||
<span v-else>暂无数据</span> | |||||
<!-- {{ detailData.videoUrl }} --> | |||||
</div> | |||||
</el-col> | |||||
</el-row> | </el-row> | ||||
</div> | </div> | ||||
<template #footer> | <template #footer> | ||||
@@ -111,6 +121,8 @@ | |||||
<img class="detailpic" :src="faceUrl" alt="" /> | <img class="detailpic" :src="faceUrl" alt="" /> | ||||
</div> | </div> | ||||
</el-dialog> | </el-dialog> | ||||
<!-- 处理告警 --> | |||||
<handleForm ref="formRefH" /> | |||||
</div> | </div> | ||||
</template> | </template> | ||||
@@ -120,6 +132,7 @@ import { warnZJRQApi } 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 handleForm from "./components/handleForm.vue"; | |||||
import { useDictStore } from "@/stores/modules"; | import { useDictStore } from "@/stores/modules"; | ||||
import { FormOptEnum, SysDictEnum, MenuTypeDictEnum } from "@/enums"; | import { FormOptEnum, SysDictEnum, MenuTypeDictEnum } from "@/enums"; | ||||
const faceUrl = ref(''); | const faceUrl = ref(''); | ||||
@@ -136,14 +149,18 @@ const visible = ref(false); //是否显示表单 | |||||
onMounted(() => { | onMounted(() => { | ||||
getWarnTypeList(); | getWarnTypeList(); | ||||
}); | }); | ||||
const formRefH = ref<InstanceType<typeof handleForm> | null>(null); | |||||
function toHandle(opt: FormOptEnum, record: {} | ZJRQ.WarnInfo= {}) { | |||||
formRefH.value?.onOpen({ opt: opt, record: JSON.parse(JSON.stringify(record)), successful: RefreshTable }); | |||||
} | |||||
let warnOptions = ref([]); | let warnOptions = ref([]); | ||||
function getWarnTypeList() { | function getWarnTypeList() { | ||||
setTimeout(async ()=> { | setTimeout(async ()=> { | ||||
await warnZJRQApi.warnType({}).then(res => { | |||||
await warnZJRQApi.warnType({}).then((res:any) => { | |||||
let { code, data } = res; | let { code, data } = res; | ||||
if (code == 200) { | if (code == 200) { | ||||
warnOptions.value = data.map(item => { | |||||
warnOptions.value = data.map((item:any) => { | |||||
return { | return { | ||||
label: item.name, | label: item.name, | ||||
value: item.code | value: item.code | ||||
@@ -299,14 +316,14 @@ let detailData = ref({}); | |||||
function onDetail(row: any) { | function onDetail(row: any) { | ||||
visible.value = true; | visible.value = true; | ||||
setTimeout(async ()=> { | setTimeout(async ()=> { | ||||
await warnZJRQApi.detail({ id: row.id }).then(res => { | |||||
let { code, data } = res; | |||||
if (code == 200) { | |||||
detailData.value = data | |||||
} | |||||
}); | |||||
await warnZJRQApi.detail({ id: row.id }).then((res:any) => { | |||||
let { code, data } = res; | |||||
if (code == 200) { | |||||
detailData.value = data | |||||
} | |||||
}); | |||||
}) | }) | ||||
} | } | ||||