@@ -82,7 +82,7 @@ function getOrgTree() { | |||||
function changeOrg(value: number | string) { | function changeOrg(value: number | string) { | ||||
valueOrg.value = value; //更新当前选中的组织名称 | valueOrg.value = value; //更新当前选中的组织名称 | ||||
emit("update:orgValue", value); //更新父组件数据 | emit("update:orgValue", value); //更新父组件数据 | ||||
emit("change", treeRef.value.getCurrentNode().path); //触发change事件 | |||||
emit("change", treeRef.value.getCurrentNode().path, treeRef.value.getCurrentNode()); //触发change事件 | |||||
} | } | ||||
</script> | </script> | ||||
@@ -40,9 +40,9 @@ export const staticRouter: RouteRecordRaw[] = [ | |||||
children: [ | children: [ | ||||
{ | { | ||||
meta: { | meta: { | ||||
title: "任务人员列表" | |||||
title: "学生点名详情" | |||||
}, | }, | ||||
name: "任务人员列表", | |||||
name: "学生点名详情", | |||||
path: "/roolcall/detail", | path: "/roolcall/detail", | ||||
component: () => import("@/views/attendance/roolcall/detail.vue") | component: () => import("@/views/attendance/roolcall/detail.vue") | ||||
} | } | ||||
@@ -19,12 +19,16 @@ | |||||
<el-row :gutter="16"> | <el-row :gutter="16"> | ||||
<el-col :span="12"> | <el-col :span="12"> | ||||
<s-form-item label="摄像头分组" prop="cameraGroudId"> | <s-form-item label="摄像头分组" prop="cameraGroudId"> | ||||
<org-selector v-model:org-value="sysUserProps.record.cameraGroudId" :org-tree-api="monitorLIVEApi.groupList" :show-all="false" | |||||
<org-selector | |||||
@change="handleChange" | |||||
v-model:org-value="sysUserProps.record.cameraGroudId" | |||||
:org-tree-api="monitorLIVEApi.groupList" | |||||
:show-all="false" | |||||
/></s-form-item> | /></s-form-item> | ||||
</el-col> | </el-col> | ||||
<el-col :span="12"> | <el-col :span="12"> | ||||
<s-form-item label="摄像头" prop="cameraId"> | <s-form-item label="摄像头" prop="cameraId"> | ||||
<s-input v-model="sysUserProps.record.cameraId"></s-input> | |||||
<s-select v-model="sysUserProps.record.cameraId" :options="CameraList" label="sensorName" value="sensorId"></s-select> | |||||
</s-form-item> | </s-form-item> | ||||
</el-col> | </el-col> | ||||
</el-row> | </el-row> | ||||
@@ -63,28 +67,23 @@ | |||||
</template> | </template> | ||||
<script setup lang="ts" name="SysUserPersonnelForm"> | <script setup lang="ts" name="SysUserPersonnelForm"> | ||||
import { SysUserPersonnel, userManagePersonnelApi, monitorLIVEApi } from "@/api"; | |||||
import { SysDictEnum } from "@/enums"; | |||||
import { attendanceRoolcallApi, userManagePersonnelApi, monitorLIVEApi } from "@/api"; | |||||
import { required } from "@/utils/formRules"; | import { required } from "@/utils/formRules"; | ||||
import { FormInstance } from "element-plus"; | import { FormInstance } from "element-plus"; | ||||
import { useDictStore } from "@/stores/modules"; | |||||
const visible = ref(false); //是否显示表单 | const visible = ref(false); //是否显示表单 | ||||
const formatTooltip = (val: number) => { | |||||
return val / 80; | |||||
}; | |||||
/** 表单操作类型枚举 */ | |||||
enum FormOptEnums { | |||||
/** 发起 */ | |||||
INITIATE = "发起" | |||||
} | |||||
// 表单参数 | // 表单参数 | ||||
const sysUserProps = reactive<FormProps.Base<SysUserPersonnel.SysUserPerInfo>>({ | |||||
const sysUserProps = reactive<FormProps.Base<any>>({ | |||||
opt: FormOptEnums.INITIATE, | opt: FormOptEnums.INITIATE, | ||||
record: {}, | record: {}, | ||||
treeAllData: [], | treeAllData: [], | ||||
disabled: false | disabled: false | ||||
}); | }); | ||||
const CameraList = ref([]); | |||||
/** 表单操作类型枚举 */ | |||||
enum FormOptEnums { | |||||
/** 发起 */ | |||||
INITIATE = "发起" | |||||
} | |||||
const CameraList = ref<any>([]); | |||||
// 表单验证规则 | // 表单验证规则 | ||||
const rules = reactive({ | const rules = reactive({ | ||||
@@ -99,7 +98,7 @@ const rules = reactive({ | |||||
* 打开表单 | * 打开表单 | ||||
* @param props 表单参数 | * @param props 表单参数 | ||||
*/ | */ | ||||
function onOpen(props: FormProps.Base<SysUserPersonnel.SysUserPerInfo>) { | |||||
function onOpen(props: FormProps.Base<any>) { | |||||
Object.assign(sysUserProps, props); //合并参数 | Object.assign(sysUserProps, props); //合并参数 | ||||
if (props.opt == FormOptEnums.INITIATE) { | if (props.opt == FormOptEnums.INITIATE) { | ||||
//如果是新增,设置默认值 | //如果是新增,设置默认值 | ||||
@@ -108,28 +107,15 @@ function onOpen(props: FormProps.Base<SysUserPersonnel.SysUserPerInfo>) { | |||||
visible.value = true; //显示表单 | visible.value = true; //显示表单 | ||||
if (props.record.personId) { | if (props.record.personId) { | ||||
//如果传了id,就去请求api获取record | //如果传了id,就去请求api获取record | ||||
userManagePersonnelApi.detail({ id: props.record.personId }).then(res => { | |||||
userManagePersonnelApi.detail({ id: props.record.personId }).then((res: any) => { | |||||
sysUserProps.record = res.data; | sysUserProps.record = res.data; | ||||
}); | }); | ||||
} | } | ||||
} | } | ||||
watch( | |||||
sysUserProps.record.cameraGroudId, | |||||
(newVal, oldVal) => { | |||||
console.log(newVal, ".........."); | |||||
}, | |||||
{ | |||||
deep: true, | |||||
immediate: true | |||||
} | |||||
); | |||||
const handleChange = (val: any) => { | |||||
console.log(val); | |||||
// monitorLIVEApi.list({ groupId: val }).then(res => { | |||||
// CameraList.value = res.data; | |||||
// }); | |||||
const handleChange = async (val: any, data: any) => { | |||||
let res = await monitorLIVEApi.list({ pageNum: 1, pageSize: 1000, groupId: data.id }); | |||||
CameraList.value = res.data.list; | |||||
}; | }; | ||||
// 提交数据(新增/编辑) | // 提交数据(新增/编辑) | ||||
const sysUserFormRef = ref<FormInstance>(); | const sysUserFormRef = ref<FormInstance>(); | ||||
@@ -138,11 +124,8 @@ async function handleSubmit() { | |||||
sysUserFormRef.value?.validate(async valid => { | sysUserFormRef.value?.validate(async valid => { | ||||
if (!valid) return; //表单验证失败 | if (!valid) return; //表单验证失败 | ||||
//提交表单 | //提交表单 | ||||
if (sysUserProps.record.faces.length === 0) { | |||||
return ElMessage.error("请上传人脸图片"); | |||||
} | |||||
if (sysUserProps.record.personId) { | if (sysUserProps.record.personId) { | ||||
await userManagePersonnelApi | |||||
await attendanceRoolcallApi | |||||
.update(sysUserProps.record) | .update(sysUserProps.record) | ||||
.then(() => { | .then(() => { | ||||
sysUserProps.successful!(); //调用父组件的successful方法 | sysUserProps.successful!(); //调用父组件的successful方法 | ||||
@@ -151,7 +134,7 @@ async function handleSubmit() { | |||||
onClose(); | onClose(); | ||||
}); | }); | ||||
} else { | } else { | ||||
await userManagePersonnelApi | |||||
await attendanceRoolcallApi | |||||
.add(sysUserProps.record) | .add(sysUserProps.record) | ||||
.then(() => { | .then(() => { | ||||
sysUserProps.successful!(); //调用父组件的successful方法 | sysUserProps.successful!(); //调用父组件的successful方法 | ||||
@@ -1,87 +1,129 @@ | |||||
<template> | <template> | ||||
<div class="roolcallDetail"> | <div class="roolcallDetail"> | ||||
<el-row> | |||||
<el-col :xl="4" :lg="4" :md="6" :sm="12" v-for="(item, index) in listData" :key="index" | |||||
><div class="grid-content"> | |||||
<div class="imgBox"> | |||||
<img | |||||
src="http://deepvision.oss-cn-zhangjiakou.aliyuncs.com/dfield-cruising/online/person-set/quanjiang/DEMO00001/8746a847ecd64c1696b37f4cdf617a18/5dc35e4c7af84b3fb5aab70156574873.jpg?Expires=1721376415&OSSAccessKeyId=STS.NUSm6539EVcLhtZCZEHnhRF8t&Signature=2Kmz3s%2FXjUBLfMfXi0GcuV998WY%3D&security-token=CAIS0wN1q6Ft5B2yfSjIr5bmJoyB3uZk4aGnalLrp1oQROFEvYOTljz2IHFMf3huCeodsv8%2BlGxS5%2FgelrpqVpZDR03Na8RHwrly1lv5O9KY42JpORrg0s%2FLI3OaLjKm9hi7AYygPgK0GJqEb1TDiVUto9%2FTfimjWFqIKICAjYUdAP0cQgi%2Fa0gwZrJRPRAwh8IGEnHTOP2xUHvtmXGCNFd0nQB%2BhGhjk7TdpPeR8R3Dllb35%2FYIroDqWPieYtJrIY10XqWBvqx%2FfbGT1zVLuVoYtvV6gaFc5zbcv9abRFVf4hiCP6%2Ff6MBuNw5%2Fae94efZNp%2BOukuZj6K6B1db7xhtVI%2BBOUiPZA4mr2IzdBeqvNNcwc7m8F1no9YjXbsGs9EEGGStLaVgVI4F8dyAhWEd9FWjgR%2FX5qAyQUGCKULOY1aw6651xwmjz8MCCT1r1GOTBindGasVnMxh5Z0JMjDK9aNkKfgFUbVJ8BrGTCIh%2FYx0bsq7yowDIEyp71TRMo%2Bbu%2FDBhIifKpO4VN7AxMup1DPwu2wNCxATp3htf%2FAxd8uAx9DyyfH1x3TObqd7jjqzaKs3NYdtswV4BUlvK5CGWEjhzQEO8mJtNIDT39awuolxWrfsIeBqAAVOd5Y2r6RQD6ZRZFrkepn9XGhIi2MZGgFU5h4wAMv9fpXFA%2FgTSJhbBoKXkAOvkYLObuS4FAaKYBll7eEMnCpOf%2BVGjABIbd%2BhpQaD8MIuUBVw1SOyjTVaLxMbb7guH7nLPyeZMcRqmZw3WH0leI4eeyeTPTT0DfJMgIezHEGctIAA%3D" | |||||
alt="" | |||||
/> | |||||
</div> | |||||
<div class="info"> | |||||
<div class="desc"> | |||||
<span class="label">姓名:</span> | |||||
{{ item.name }} | |||||
</div> | |||||
<div class="desc"> | |||||
<span class="label">所属分组:</span> | |||||
{{ item.group }} | |||||
</div> | |||||
</div> | |||||
<div class="btn"> | |||||
<el-button type="text" :icon="Edit">编辑</el-button> | |||||
<el-button type="danger" text :icon="Delete">删除</el-button> | |||||
</div> | |||||
</div></el-col | |||||
<div class="header"> | |||||
<el-row> | |||||
<el-col :span="18"> | |||||
<el-row> | |||||
<el-col :span="6"><el-text class="mx-1" type="primary" size="large">应到:8人</el-text></el-col> | |||||
<el-col :span="6"><el-text class="mx-1" type="success" size="large">实到:4</el-text> </el-col> | |||||
<el-col :span="6"> <el-text class="mx-1" type="warning" size="large">趴桌子:2</el-text></el-col> | |||||
<el-col :span="6"> | |||||
<el-text class="mx-1" type="info" size="large">未识别:{{ UnrecognizedD.length }}</el-text></el-col | |||||
> | |||||
</el-row> | |||||
</el-col> | |||||
</el-row> | |||||
</div> | |||||
<el-row :gutter="20"> | |||||
<el-col :span="18" | |||||
><el-row class="rowbg"> | |||||
<el-col :xl="4" :lg="4" :md="6" :sm="8" :xs="12" v-for="(item, index) in listData" :key="index" | |||||
><div class="grid-content"> | |||||
<div class="imgBox" :class="{ active: item.status === 1 ? true : false }"> | |||||
<img :src="item.faces[0].faceUrl" alt="" /> | |||||
</div> | |||||
<div class="info"> | |||||
<div class="desc"> | |||||
<span class="label">姓名:</span> | |||||
{{ item.name }} | |||||
</div> | |||||
<div class="desc"> | |||||
<span class="label">所属分组:</span> | |||||
{{ item.personSets[0].personSetName }} | |||||
</div> | |||||
</div> | |||||
</div></el-col | |||||
> | |||||
</el-row></el-col | |||||
> | > | ||||
<el-col :span="6"> | |||||
<div class="unrecognized"> | |||||
<div class="title">未识别人员</div> | |||||
<div class="imgBox" v-for="(item, index) in UnrecognizedD" :key="index"> | |||||
<img :src="item.faceUrl" alt="" /> | |||||
</div> | |||||
</div> | |||||
</el-col> | |||||
</el-row> | </el-row> | ||||
</div> | </div> | ||||
</template> | </template> | ||||
<script setup lang="ts" name="SysUserPersonnel"> | <script setup lang="ts" name="SysUserPersonnel"> | ||||
import { Delete, Edit } from "@element-plus/icons-vue"; | |||||
const listData = ref([ | |||||
{ | |||||
name: "zhangsan ", | |||||
group: "所属fenzu ", | |||||
status: "正常", | |||||
phone: "1234567890", | |||||
email: "1234567890@qq.com" | |||||
}, | |||||
{ | |||||
name: "zhangsan ", | |||||
group: "所属fenzu ", | |||||
status: "正常", | |||||
phone: "1234567890", | |||||
email: "1234567890@qq.com" | |||||
}, | |||||
{ | |||||
name: "zhangsan ", | |||||
group: "所属fenzu ", | |||||
status: "正常", | |||||
phone: "1234567890", | |||||
email: "1234567890@qq.com" | |||||
}, | |||||
{ | |||||
name: "zhangsan ", | |||||
group: "所属fenzu ", | |||||
status: "正常", | |||||
phone: "1234567890", | |||||
email: "1234567890@qq.com" | |||||
}, | |||||
{ | |||||
name: "zhangsan ", | |||||
group: "所属fenzu ", | |||||
status: "正常", | |||||
phone: "1234567890", | |||||
email: "1234567890@qq.com" | |||||
}, | |||||
{ | |||||
name: "zhangsan ", | |||||
group: "所属fenzu ", | |||||
status: "正常", | |||||
phone: "1234567890", | |||||
email: "1234567890@qq.com" | |||||
} | |||||
]); | |||||
import { userManagePersonnelApi, attendanceRoolcallApi } from "@/api"; | |||||
const route = useRoute(); | |||||
const listData = ref<any>([]); //人员列表 | |||||
const HighlightData = ref<any>([]); //点名人员列表 | |||||
const UnrecognizedD = ref<any>([]); //未识别数据 | |||||
const getList = () => { | |||||
userManagePersonnelApi | |||||
.page({ | |||||
pageNum: 1, | |||||
pageSize: 1000, | |||||
personSetId: route.query.personSetId | |||||
}) | |||||
.then((res: any) => { | |||||
listData.value = res.data.list; | |||||
Highlight(); | |||||
}); | |||||
}; | |||||
const Highlight = () => { | |||||
attendanceRoolcallApi | |||||
.page({ | |||||
pageNum: 1, | |||||
pageSize: 1000, | |||||
taskId: route.query.taskId | |||||
}) | |||||
.then((res: any) => { | |||||
HighlightData.value = res.data.list; | |||||
listData.value | |||||
.map((item: any) => { | |||||
item.status = 0; | |||||
return item; | |||||
}) | |||||
.forEach((item: any) => { | |||||
HighlightData.value.forEach((item1: any) => { | |||||
if (item.personId === item1.personId) { | |||||
item.status = 1; | |||||
} | |||||
}); | |||||
}); | |||||
// 未识别人员摘取 | |||||
UnrecognizedD.value = []; | |||||
JSON.parse(JSON.stringify(HighlightData.value)).map((item: any) => { | |||||
if (!item.personId) { | |||||
UnrecognizedD.value.push(item); | |||||
} | |||||
}); | |||||
console.log(UnrecognizedD.value); | |||||
}); | |||||
}; | |||||
onMounted(() => { | |||||
getList(); | |||||
console.log(route.query); | |||||
}); | |||||
</script> | </script> | ||||
<style lang="scss" scoped> | <style lang="scss" scoped> | ||||
.roolcallDetail { | .roolcallDetail { | ||||
.el-row { | .el-row { | ||||
width: 100%; | width: 100%; | ||||
} | |||||
.header { | |||||
box-sizing: border-box; | |||||
display: flex; | |||||
align-items: center; | |||||
justify-content: space-between; | |||||
width: 100%; | |||||
height: 80px; | |||||
padding: 0 20px; | |||||
background: #ffffff; | |||||
.el-col { | |||||
text-align: center; | |||||
} | |||||
} | |||||
.rowbg { | |||||
width: 100%; | |||||
.el-col { | .el-col { | ||||
box-sizing: border-box; | box-sizing: border-box; | ||||
height: 310px; | |||||
height: 190px; | |||||
margin-bottom: 20px; | margin-bottom: 20px; | ||||
.grid-content { | .grid-content { | ||||
box-sizing: border-box; | box-sizing: border-box; | ||||
@@ -94,8 +136,13 @@ const listData = ref([ | |||||
align-items: center; | align-items: center; | ||||
justify-content: center; | justify-content: center; | ||||
width: 100%; | width: 100%; | ||||
height: 150px; | |||||
height: 100px; | |||||
background: #f2f2f2; | background: #f2f2f2; | ||||
opacity: 0.5; | |||||
&.active { | |||||
background: #79bbff45; | |||||
opacity: 1; | |||||
} | |||||
img { | img { | ||||
max-height: 100%; | max-height: 100%; | ||||
object-fit: cover; | object-fit: cover; | ||||
@@ -111,7 +158,7 @@ const listData = ref([ | |||||
} | } | ||||
.desc { | .desc { | ||||
max-width: 100%; | max-width: 100%; | ||||
margin-top: 15px; | |||||
margin-top: 10px; | |||||
overflow: hidden; | overflow: hidden; | ||||
font-size: 14px; | font-size: 14px; | ||||
color: #41465f; | color: #41465f; | ||||
@@ -131,5 +178,14 @@ const listData = ref([ | |||||
} | } | ||||
} | } | ||||
} | } | ||||
.unrecognized { | |||||
.title { | |||||
font-size: 18px; | |||||
font-weight: bold; | |||||
line-height: 50px; | |||||
color: #41465f; | |||||
text-align: center; | |||||
} | |||||
} | |||||
} | } | ||||
</style> | </style> |
@@ -22,8 +22,7 @@ | |||||
</template> | </template> | ||||
</TreeFilter> | </TreeFilter> | ||||
<div class="table-box"> | <div class="table-box"> | ||||
<!-- :request-api="attendanceRoolcallApi.page" --> | |||||
<ProTable ref="proTable" title="任务列表" :columns="columns" rowKey="personId" :data="tableData"> | |||||
<ProTable ref="proTable" title="任务列表" :columns="columns" rowKey="id" :request-api="attendanceRoolcallApi.getTaskPageList"> | |||||
<!-- 表格 header 按钮 --> | <!-- 表格 header 按钮 --> | ||||
<template #tableHeader="scope"> | <template #tableHeader="scope"> | ||||
<s-button :opt="FormOptEnums.INITIATE" @click="onOpen(FormOptEnums.INITIATE, { personSetId: personSetId }, treeFilter.treeAllData)" /> | <s-button :opt="FormOptEnums.INITIATE" @click="onOpen(FormOptEnums.INITIATE, { personSetId: personSetId }, treeFilter.treeAllData)" /> | ||||
@@ -54,7 +53,6 @@ import { attendanceRoolcallApi,userManagePersonnelApi,userManageClassManageApi} | |||||
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 { 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"; | ||||
import { useRouter } from "vue-router"; | import { useRouter } from "vue-router"; | ||||
@@ -73,20 +71,7 @@ enum FormOptEnums { | |||||
// 获取 ProTable 元素,调用其获取刷新数据方法(还能获取到当前查询参数,方便导出携带参数) | // 获取 ProTable 元素,调用其获取刷新数据方法(还能获取到当前查询参数,方便导出携带参数) | ||||
const visible = ref(false); //是否显示人员表单 | const visible = ref(false); //是否显示人员表单 | ||||
const proTable = ref<ProTableInstance>(); | const proTable = ref<ProTableInstance>(); | ||||
const treeFilter = ref<InstanceType<typeof TreeFilter> | null>(null); | |||||
const tableData = ref([ | |||||
{ | |||||
cameraName: "摄像头1", | |||||
continueTime: "20", | |||||
similarity: "0.7", | |||||
}, | |||||
{ | |||||
cameraName: "摄像头2", | |||||
continueTime: "30", | |||||
similarity: "0.45", | |||||
} | |||||
]) | |||||
const treeFilter = ref<any>(); | |||||
// 表格配置项 | // 表格配置项 | ||||
const columns: ColumnProps[] = [ | const columns: ColumnProps[] = [ | ||||
{ type: "selection", fixed: "left", width: 50 }, | { type: "selection", fixed: "left", width: 50 }, | ||||
@@ -104,12 +89,14 @@ const columns: ColumnProps[] = [ | |||||
}, | }, | ||||
{ prop: "operation", label: "操作", width: 250, fixed: "right" } | { prop: "operation", label: "操作", width: 250, fixed: "right" } | ||||
]; | ]; | ||||
const handleClose = () => { | |||||
visible.value = false; | |||||
}; | |||||
const onView = (row: any) => { | const onView = (row: any) => { | ||||
router.push('/roolcall/detail'); | |||||
router.push( { | |||||
path:'/roolcall/detail', | |||||
query: { | |||||
taskId: row.taskId, | |||||
personSetId:row.personSetId | |||||
} | |||||
}); | |||||
}; | }; | ||||
// 发起任务表单引用 | // 发起任务表单引用 | ||||
const formRef = ref<InstanceType<typeof Form> | null>(null); | const formRef = ref<InstanceType<typeof Form> | null>(null); | ||||
@@ -119,7 +106,7 @@ const formRef = ref<InstanceType<typeof Form> | null>(null); | |||||
* @param opt 操作类型 | * @param opt 操作类型 | ||||
* @param record 记录 | * @param record 记录 | ||||
*/ | */ | ||||
function onOpen(opt: FormOptEnum, record: {},treeAllData:any) { | |||||
function onOpen(opt: FormOptEnums, record: {},treeAllData:any) { | |||||
formRef.value?.onOpen({ opt: opt, record: record,treeAllData:treeAllData, successful: RefreshTable }); | formRef.value?.onOpen({ opt: opt, record: record,treeAllData:treeAllData, successful: RefreshTable }); | ||||
} | } | ||||