@@ -13,31 +13,37 @@ | |||
* @see https://gitee.com/dotnetmoyu/SimpleAdmin | |||
*/ | |||
import { moduleRequest } from "@/api/request"; | |||
import { ReqId, SysUserPersonnel } from "@/api/interface"; | |||
const http = moduleRequest("/business/dfieldApi/"); | |||
const http = moduleRequest("/business/classRoomCallApi/"); | |||
/** | |||
* @Description: 单页管理 | |||
* @Description: 教师点名 | |||
* @Author: SYY | |||
* @Date: 2023-12-15 15:34:54 | |||
*/ | |||
const attendanceRoolcall = { | |||
/** 查询底库列表 */ | |||
page(params: SysUserPersonnel.ClassPage) { | |||
return http.get("page", params); | |||
const attendanceRoolcallApi = { | |||
// 获取列表 | |||
page(params: any) { | |||
return http.get("getPageList", params); | |||
}, | |||
/** 查询点名任务列表 */ | |||
getTaskPageList(params: any) { | |||
return http.get("getTaskPageList", params); | |||
}, | |||
/** 删除点名任务(删除关联点名数据) */ | |||
delete(params: any) { | |||
return http.delete("delete", params); | |||
}, | |||
/** 删除底库 */ | |||
delete(params: ReqId) { | |||
return http.delete("deleteDfieldD", params); | |||
/** 删除点名任务(只可删除待处理的任务) */ | |||
remove(params: any) { | |||
return http.delete("remove", params); | |||
}, | |||
/** 创建底库 */ | |||
add(params: SysUserPersonnel.ClassPage) { | |||
return http.post("createDfieldA", params); | |||
/** 点名任务下发 */ | |||
add(params: any) { | |||
return http.post("taskSubmit", params); | |||
}, | |||
/** 更新底库 */ | |||
update(params: SysUserPersonnel.ClassPage) { | |||
return http.put("updateDfieldU", params); | |||
/** 修改点名任务 */ | |||
update(params: any) { | |||
return http.post("update", params); | |||
} | |||
}; | |||
export { attendanceRoolcall }; | |||
export { attendanceRoolcallApi }; |
@@ -37,7 +37,16 @@ export const staticRouter: RouteRecordRaw[] = [ | |||
component: () => import("@/layouts/index.vue"), | |||
// component: () => import("@/layouts/indexAsync.vue"), | |||
redirect: HOME_URL, | |||
children: [] | |||
children: [ | |||
{ | |||
meta: { | |||
title: "任务人员列表" | |||
}, | |||
name: "任务人员列表", | |||
path: "/roolcall/detail", | |||
component: () => import("@/views/attendance/roolcall/detail.vue") | |||
} | |||
] | |||
} | |||
]; | |||
@@ -0,0 +1,177 @@ | |||
<!-- | |||
* @Description: 表单 | |||
* @Author: syy | |||
* @Date: 2023-12-15 15:45:59 | |||
--> | |||
<template> | |||
<div> | |||
<form-container v-model="visible" :title="`${sysUserProps.opt}点名`" form-size="900px" @close="onClose"> | |||
<el-form | |||
ref="sysUserFormRef" | |||
:rules="rules" | |||
:disabled="sysUserProps.disabled" | |||
:model="sysUserProps.record" | |||
:hide-required-asterisk="sysUserProps.disabled" | |||
label-width="auto" | |||
label-suffix=" :" | |||
> | |||
<div> | |||
<el-row :gutter="16"> | |||
<el-col :span="12"> | |||
<s-form-item label="摄像头分组" prop="cameraGroudId"> | |||
<org-selector v-model:org-value="sysUserProps.record.cameraGroudId" :org-tree-api="monitorLIVEApi.groupList" :show-all="false" | |||
/></s-form-item> | |||
</el-col> | |||
<el-col :span="12"> | |||
<s-form-item label="摄像头" prop="cameraId"> | |||
<s-input v-model="sysUserProps.record.cameraId"></s-input> | |||
</s-form-item> | |||
</el-col> | |||
</el-row> | |||
<el-row :gutter="16"> | |||
<el-col :span="12"> | |||
<s-form-item label="所属班级" prop="personSetId"> | |||
<s-select | |||
v-model="sysUserProps.record.personSetId" | |||
:options="sysUserProps.treeAllData" | |||
label="personSetName" | |||
value="personSetId" | |||
></s-select> | |||
</s-form-item> | |||
</el-col> | |||
<el-col :span="12"> | |||
<s-form-item label="持续时间" prop="continueTime"> | |||
<el-slider v-model="sysUserProps.record.continueTime" /> | |||
</s-form-item> | |||
</el-col> | |||
</el-row> | |||
<el-row :gutter="16"> | |||
<el-col :span="12"> | |||
<s-form-item label="相似度" prop="similarity"> | |||
<el-slider v-model="sysUserProps.record.similarity" :min="0.3" :max="0.8" :step="0.01" /> | |||
</s-form-item> | |||
</el-col> | |||
</el-row> | |||
</div> | |||
</el-form> | |||
<template #footer> | |||
<el-button @click="onClose"> 取消 </el-button> | |||
<el-button v-show="!sysUserProps.disabled" type="primary" @click="handleSubmit"> 确定 </el-button> | |||
</template> | |||
</form-container> | |||
</div> | |||
</template> | |||
<script setup lang="ts" name="SysUserPersonnelForm"> | |||
import { SysUserPersonnel, userManagePersonnelApi, monitorLIVEApi } from "@/api"; | |||
import { SysDictEnum } from "@/enums"; | |||
import { required } from "@/utils/formRules"; | |||
import { FormInstance } from "element-plus"; | |||
import { useDictStore } from "@/stores/modules"; | |||
const visible = ref(false); //是否显示表单 | |||
const formatTooltip = (val: number) => { | |||
return val / 80; | |||
}; | |||
// 表单参数 | |||
const sysUserProps = reactive<FormProps.Base<SysUserPersonnel.SysUserPerInfo>>({ | |||
opt: FormOptEnums.INITIATE, | |||
record: {}, | |||
treeAllData: [], | |||
disabled: false | |||
}); | |||
const CameraList = ref([]); | |||
/** 表单操作类型枚举 */ | |||
enum FormOptEnums { | |||
/** 发起 */ | |||
INITIATE = "发起" | |||
} | |||
// 表单验证规则 | |||
const rules = reactive({ | |||
cameraGroudId: [required("请选择摄像头分组")], | |||
similarity: [required("请选择相似度")], | |||
cameraId: [required("请选择摄像头")], | |||
continueTime: [required("请选择持续时间")], | |||
personSetId: [required("请选择所属班级")] | |||
}); | |||
/** | |||
* 打开表单 | |||
* @param props 表单参数 | |||
*/ | |||
function onOpen(props: FormProps.Base<SysUserPersonnel.SysUserPerInfo>) { | |||
Object.assign(sysUserProps, props); //合并参数 | |||
if (props.opt == FormOptEnums.INITIATE) { | |||
//如果是新增,设置默认值 | |||
// sysUserProps.record.sortCode = 99; | |||
} | |||
visible.value = true; //显示表单 | |||
if (props.record.personId) { | |||
//如果传了id,就去请求api获取record | |||
userManagePersonnelApi.detail({ id: props.record.personId }).then(res => { | |||
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 sysUserFormRef = ref<FormInstance>(); | |||
/** 提交表单 */ | |||
async function handleSubmit() { | |||
sysUserFormRef.value?.validate(async valid => { | |||
if (!valid) return; //表单验证失败 | |||
//提交表单 | |||
if (sysUserProps.record.faces.length === 0) { | |||
return ElMessage.error("请上传人脸图片"); | |||
} | |||
if (sysUserProps.record.personId) { | |||
await userManagePersonnelApi | |||
.update(sysUserProps.record) | |||
.then(() => { | |||
sysUserProps.successful!(); //调用父组件的successful方法 | |||
}) | |||
.finally(() => { | |||
onClose(); | |||
}); | |||
} else { | |||
await userManagePersonnelApi | |||
.add(sysUserProps.record) | |||
.then(() => { | |||
sysUserProps.successful!(); //调用父组件的successful方法 | |||
}) | |||
.finally(() => { | |||
onClose(); | |||
}); | |||
} | |||
}); | |||
} | |||
/** 关闭表单*/ | |||
function onClose() { | |||
visible.value = false; | |||
} | |||
// 暴露给父组件的方法 | |||
defineExpose({ | |||
onOpen | |||
}); | |||
</script> | |||
<style lang="scss" scoped></style> |
@@ -1,33 +0,0 @@ | |||
<!-- | |||
* @Description: 人脸识别失败表格 | |||
* @Author: yxq | |||
* @Date: 2023-12-15 15:45:59 | |||
--> | |||
<template> | |||
<div> | |||
<ProTable ref="proTable" title="教师点名" :columns="columns" :data="data" :request-api="userManageClassManageApi.page"> | |||
<!-- 表格操作栏 --> | |||
<template #operation="scope"> | |||
<el-space> | |||
<s-button link prefix="人工" :opt="FormOptEnum.EDIT" suffix="确认" @click="onOpen(FormOptEnum.VIEW, scope.row)" /> | |||
</el-space> | |||
</template> | |||
</ProTable> | |||
</div> | |||
</template> | |||
<script setup lang="ts"> | |||
/** 关闭表单*/ | |||
function onClose() { | |||
visible.value = false; | |||
activeName.value = "basic"; | |||
} | |||
// 暴露给父组件的方法 | |||
defineExpose({ | |||
onOpen | |||
}); | |||
</script> | |||
<style lang="scss" scoped></style> | |||
@@ -0,0 +1,135 @@ | |||
<template> | |||
<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 | |||
> | |||
</el-row> | |||
</div> | |||
</template> | |||
<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" | |||
} | |||
]); | |||
</script> | |||
<style lang="scss" scoped> | |||
.roolcallDetail { | |||
.el-row { | |||
width: 100%; | |||
.el-col { | |||
box-sizing: border-box; | |||
height: 310px; | |||
margin-bottom: 20px; | |||
.grid-content { | |||
box-sizing: border-box; | |||
height: 100%; | |||
padding: 15px; | |||
margin: 10px; | |||
background: #ffffff; | |||
.imgBox { | |||
display: flex; | |||
align-items: center; | |||
justify-content: center; | |||
width: 100%; | |||
height: 150px; | |||
background: #f2f2f2; | |||
img { | |||
max-height: 100%; | |||
object-fit: cover; | |||
} | |||
} | |||
.info { | |||
height: 80px; | |||
.label { | |||
margin-right: 8px; | |||
font-size: 14px; | |||
color: #41465f; | |||
opacity: 0.6; | |||
} | |||
.desc { | |||
max-width: 100%; | |||
margin-top: 15px; | |||
overflow: hidden; | |||
font-size: 14px; | |||
color: #41465f; | |||
text-overflow: ellipsis; | |||
white-space: nowrap; | |||
} | |||
} | |||
.btn { | |||
display: flex; | |||
align-items: center; | |||
justify-content: space-between; | |||
height: 40px; | |||
font-size: 14px; | |||
color: #41465f; | |||
border-top: 1px solid #f3f3f3; | |||
} | |||
} | |||
} | |||
} | |||
} | |||
</style> |
@@ -1,70 +1,172 @@ | |||
<!-- | |||
* @Description: 教师点名 | |||
* @Author: yxq | |||
* @Date: 2024-7-16 | |||
* @Author: syy | |||
* @Date: 2024-7-15 | |||
--> | |||
<template> | |||
<div class="table-box"> | |||
<ProTable ref="proTable" title="教师点名" :columns="columns" :data="data" :request-api="userManageClassManageApi.page"> | |||
<!-- 表格操作栏 --> | |||
<template #operation="scope"> | |||
<el-space> | |||
<s-button link prefix="人工" :opt="FormOptEnum.EDIT" suffix="确认" @click="onOpen(FormOptEnum.VIEW, scope.row)" /> | |||
</el-space> | |||
<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> | |||
</ProTable> | |||
</TreeFilter> | |||
<div class="table-box"> | |||
<!-- :request-api="attendanceRoolcallApi.page" --> | |||
<ProTable ref="proTable" title="任务列表" :columns="columns" rowKey="personId" :data="tableData"> | |||
<!-- 表格 header 按钮 --> | |||
<template #tableHeader="scope"> | |||
<s-button :opt="FormOptEnums.INITIATE" @click="onOpen(FormOptEnums.INITIATE, { personSetId: personSetId }, treeFilter.treeAllData)" /> | |||
<s-button | |||
type="danger" | |||
:opt="FormOptEnum.DELETE" | |||
plain | |||
suffix="点名任务" | |||
:disabled="!scope.isSelected" | |||
@click="onDelete(scope.selectedListIds, '删除点名任务')" | |||
/> | |||
</template> | |||
<!-- 表格操作栏 --> | |||
<template #operation="scope"> | |||
<el-space> | |||
<s-button link :opt="FormOptEnum.VIEW" @click="onView(scope.row)" /> | |||
<s-button link :opt="FormOptEnum.DELETE" @click="onDelete([scope.row.personId], `删除点名任务`)" /> | |||
</el-space> | |||
</template> | |||
</ProTable> | |||
</div> | |||
<!-- 发起新增/编辑表单 --> | |||
<Form ref="formRef"></Form> | |||
</div> | |||
</template> | |||
<script setup lang="ts"> | |||
import { userManageClassManageApi } from "@/api"; | |||
import { ColumnProps, ProTableInstance } from "@/components/ProTable/interface"; | |||
<script setup lang="tsx" name="SysUserPersonnel"> | |||
import { attendanceRoolcallApi,userManagePersonnelApi,userManageClassManageApi} from "@/api"; | |||
import { useHandleData } from "@/hooks/useHandleData"; | |||
import { FormOptEnum } from "@/enums"; | |||
const data = ref([ | |||
import Form from "./components/form/index.vue"; | |||
import { ArrowDown,More } from "@element-plus/icons-vue"; | |||
import { ColumnProps, ProTableInstance } from "@/components/ProTable/interface"; | |||
import TreeFilter from "@/components/TreeFilter/index.vue"; | |||
import { useRouter } from "vue-router"; | |||
const router = useRouter(); | |||
/** 表单操作类型枚举 */ | |||
enum FormOptEnums { | |||
/** 发起 */ | |||
INITIATE = "发起", | |||
/* 查看点名任务 */ | |||
VIEWTASK = "查看", | |||
/* 修改点名记录 */ | |||
EDITTASK = "修改点名记录" | |||
} | |||
// 获取 ProTable 元素,调用其获取刷新数据方法(还能获取到当前查询参数,方便导出携带参数) | |||
const visible = ref(false); //是否显示人员表单 | |||
const proTable = ref<ProTableInstance>(); | |||
const treeFilter = ref<InstanceType<typeof TreeFilter> | null>(null); | |||
const tableData = ref([ | |||
{ | |||
classname: "XXXXX班级", | |||
classId: "544165", | |||
studentNum: "43", | |||
guiqinNum: "38", | |||
noFaceNum: "5" | |||
cameraName: "摄像头1", | |||
continueTime: "20", | |||
similarity: "0.7", | |||
}, | |||
{ | |||
classname: "XX班级", | |||
classId: "555333", | |||
studentNum: "42", | |||
guiqinNum: "37", | |||
noFaceNum: "4" | |||
cameraName: "摄像头2", | |||
continueTime: "30", | |||
similarity: "0.45", | |||
} | |||
]); | |||
// 获取 ProTable 元素,调用其获取刷新数据方法(还能获取到当前查询参数,方便导出携带参数) | |||
const proTable = ref<ProTableInstance>(); | |||
]) | |||
// 表格配置项 | |||
const columns: ColumnProps[] = [ | |||
{ type: "selection", fixed: "left", width: 50 }, | |||
{ | |||
prop: "classname", | |||
label: "班级名称" | |||
}, | |||
{ | |||
prop: "classId", | |||
label: "班级ID" | |||
prop: "cameraName", | |||
label: "摄像头名称" | |||
}, | |||
{ | |||
prop: "studentNum", | |||
label: "学生人数" | |||
prop: "continueTime", | |||
label: "持续时间" | |||
}, | |||
{ | |||
prop: "guiqinNum", | |||
label: "归寝人数" | |||
}, | |||
{ | |||
prop: "noFaceNum", | |||
label: "人脸无法识别人数" | |||
prop: "similarity", | |||
label: "相似度" | |||
}, | |||
{ prop: "operation", label: "操作", width: 250, fixed: "right" } | |||
]; | |||
const handleClose = () => { | |||
visible.value = false; | |||
}; | |||
const onView = (row: any) => { | |||
router.push('/roolcall/detail'); | |||
}; | |||
// 发起任务表单引用 | |||
const formRef = ref<InstanceType<typeof Form> | null>(null); | |||
/** | |||
* 打开表单 | |||
* @param opt 操作类型 | |||
* @param record 记录 | |||
*/ | |||
function onOpen(opt: FormOptEnum, record: {},treeAllData:any) { | |||
formRef.value?.onOpen({ opt: opt, record: record,treeAllData:treeAllData, successful: RefreshTable }); | |||
} | |||
/** | |||
* 任务删除 | |||
* @param ids id数组 | |||
*/ | |||
async function onDelete(ids: string[], msg: string) { | |||
if(ids.length === 0){ | |||
ElMessage({ | |||
message: '请选择要删除的人员', | |||
type: 'warning' | |||
}); | |||
return | |||
} | |||
// 二次确认 => 请求api => 刷新表格 | |||
await useHandleData(userManagePersonnelApi.delete, {id: ids.join(",") }, msg); | |||
RefreshTable(); //刷新表格 | |||
} | |||
// 刷新表格 | |||
const RefreshTable = () => { | |||
proTable.value?.refresh(); | |||
} | |||
/** 班级切换 */ | |||
const personSetId = ref<number | string>() | |||
function changeTreeFilter(val: number | string) { | |||
personSetId.value = val | |||
proTable.value!.pageable.pageNum = 1; | |||
proTable.value!.searchParam.personSetId = val; | |||
proTable.value!.search(); | |||
} | |||
</script> | |||
<style scoped lang="scss"> | |||
.table-box { | |||
width: 100%; | |||
height: 100%; | |||
} | |||
.custom-tree-node { | |||
display: flex; | |||
flex: 1; | |||
align-items: center; | |||
justify-content: space-between; | |||
padding-right: 8px; | |||
font-size: 14px; | |||
} | |||
</style> |
@@ -30,7 +30,7 @@ | |||
</el-row> | |||
<el-row :gutter="16"> | |||
<el-col :span="24"> | |||
<s-form-item label="上传服装" prop="faces"> | |||
<s-form-item label="上传服装" prop="clothUrl"> | |||
<el-upload | |||
class="avatar-uploader" | |||
action="/api/business/clothApi/uploadFile" | |||