@@ -24,6 +24,8 @@ export namespace SysUserPersonnel { | |||||
/** 底库信息 */ | /** 底库信息 */ | ||||
export interface ClassPage { | export interface ClassPage { | ||||
personSetId?: string | undefined; | |||||
personSetName?: string | undefined; | |||||
id?: string | undefined; | id?: string | undefined; | ||||
name?: string | undefined; | name?: string | undefined; | ||||
} | } | ||||
@@ -31,9 +33,14 @@ export namespace SysUserPersonnel { | |||||
export interface SysUserAvatar { | export interface SysUserAvatar { | ||||
/** 人脸 */ | /** 人脸 */ | ||||
personId?: string | undefined; | personId?: string | undefined; | ||||
faceId: string; | |||||
faceId?: string | number; | |||||
faceUrl: string; | faceUrl: string; | ||||
tag: string; | |||||
uid?: string | number; | |||||
} | |||||
// 人脸删除 | |||||
export interface SysUserFace { | |||||
personId: string | undefined; | |||||
faceIds: Array<string | number>; | |||||
} | } | ||||
/** 用户信息 */ | /** 用户信息 */ | ||||
@@ -13,7 +13,7 @@ | |||||
* @see https://gitee.com/dotnetmoyu/SimpleAdmin | * @see https://gitee.com/dotnetmoyu/SimpleAdmin | ||||
*/ | */ | ||||
import { moduleRequest } from "@/api/request"; | import { moduleRequest } from "@/api/request"; | ||||
import { ResPage, ReqPersonId, SysUserPersonnel } from "@/api/interface"; | |||||
import { ReqId, ResPage, ReqPersonId, SysUserPersonnel } from "@/api/interface"; | |||||
const http = moduleRequest("/business/personApi/"); | const http = moduleRequest("/business/personApi/"); | ||||
/** | /** | ||||
@@ -27,18 +27,18 @@ const userManagePersonnelApi = { | |||||
return http.post("pageQuery", params); | return http.post("pageQuery", params); | ||||
}, | }, | ||||
/** 获取单页详情 */ | /** 获取单页详情 */ | ||||
detail(params: ReqPersonId) { | |||||
detail(params: ReqId) { | |||||
return http.get("getPersionById", params); | return http.get("getPersionById", params); | ||||
}, | }, | ||||
/** 删除机构 */ | |||||
delete(params: ReqPersonId) { | |||||
return http.post("deletePersonD", params); | |||||
/** 删除人员 */ | |||||
delete(params: ReqId) { | |||||
return http.delete("deletePersonD", params); | |||||
}, | }, | ||||
/** 新增机构 */ | |||||
/** 新增人员 */ | |||||
add(params: SysUserPersonnel.SysUserPerInfo) { | add(params: SysUserPersonnel.SysUserPerInfo) { | ||||
return http.post("createPersonA", params); | return http.post("createPersonA", params); | ||||
}, | }, | ||||
/** 修改机构 */ | |||||
/** 修改人员 */ | |||||
update(params: SysUserPersonnel.SysUserPerInfo) { | update(params: SysUserPersonnel.SysUserPerInfo) { | ||||
return http.put("updatePersionU", params); | return http.put("updatePersionU", params); | ||||
}, | }, | ||||
@@ -47,8 +47,8 @@ const userManagePersonnelApi = { | |||||
return http.post("addFaceA", params); | return http.post("addFaceA", params); | ||||
}, | }, | ||||
/** 删除人脸 */ | /** 删除人脸 */ | ||||
deleteFace(params: SysUserPersonnel.SysUserAvatar) { | |||||
return http.delete("deleteFaceD", params); | |||||
deleteFace(params: SysUserPersonnel.SysUserFace) { | |||||
return http.post("deleteFaceD", params); | |||||
}, | }, | ||||
/**底库绑定 */ | /**底库绑定 */ | ||||
personBindDfie(params: SysUserPersonnel.ClassPage) { | personBindDfie(params: SysUserPersonnel.ClassPage) { | ||||
@@ -4,15 +4,46 @@ | |||||
* @Date: 2023-12-15 15:45:50 | * @Date: 2023-12-15 15:45:50 | ||||
--> | --> | ||||
<template> | <template> | ||||
<div> | |||||
<div class="userManageForm"> | |||||
<div> | <div> | ||||
<el-row :gutter="16"> | <el-row :gutter="16"> | ||||
<el-col :span="24"> | |||||
<el-col :span="12"> | |||||
<s-form-item label="人员姓名" prop="name"> | <s-form-item label="人员姓名" prop="name"> | ||||
<s-input v-model="userInfo.name"></s-input> | <s-input v-model="userInfo.name"></s-input> | ||||
</s-form-item> | </s-form-item> | ||||
</el-col> | </el-col> | ||||
<el-col :span="12"> | |||||
<s-form-item label="所属班级" prop="personSetId"> | |||||
<s-select v-model="userInfo.personSetId" :options="treeData" label="personSetName" value="personSetId"></s-select> | |||||
<!-- <s-input v-model="userInfo.personSets[0].personSetName" disabled></s-input> --> | |||||
</s-form-item> | |||||
</el-col> | |||||
</el-row> | |||||
<el-row :gutter="16"> | |||||
<el-col :span="24"> | |||||
<s-form-item label="上传人脸" prop="faces"> | |||||
<el-upload | |||||
v-model:file-list="fileList" | |||||
action="/api/business/personApi/uploadFile" | |||||
list-type="picture-card" | |||||
:on-success="handleAvatarSuccess" | |||||
:on-error="handleAvatarError" | |||||
:on-preview="handlePictureCardPreview" | |||||
:on-remove="handleRemove" | |||||
accept=".jpg, .jpeg, .png" | |||||
:headers="{ | |||||
Authorization: `${TokenEnum.TOKEN_PREFIX} ${accessToken}` | |||||
}" | |||||
> | |||||
<el-icon><Plus /></el-icon> | |||||
</el-upload> | |||||
<el-dialog v-model="dialogVisible" title="查看图片"> | |||||
<img w-full :src="dialogImageUrl" alt="Preview Image" style="width: 100%" /> | |||||
</el-dialog> | |||||
</s-form-item> | |||||
</el-col> | |||||
</el-row> | </el-row> | ||||
<el-row :gutter="16"> | <el-row :gutter="16"> | ||||
<el-col :span="12"> | <el-col :span="12"> | ||||
<s-form-item label="性别" prop="gender"> | <s-form-item label="性别" prop="gender"> | ||||
@@ -42,10 +73,12 @@ | |||||
</template> | </template> | ||||
<script setup lang="ts"> | <script setup lang="ts"> | ||||
import { SysUserPersonnel } from "@/api"; | |||||
import { useDictStore } from "@/stores/modules"; | |||||
const dictStore = useDictStore(); //字典仓库 | |||||
import { SysUserPersonnel, userManagePersonnelApi, userManageClassManageApi } from "@/api"; | |||||
import { Plus } from "@element-plus/icons-vue"; | |||||
import { useUserStore } from "@/stores/modules"; | |||||
import type { UploadProps, UploadUserFile } from "element-plus"; | |||||
import { ElMessage } from "element-plus"; | |||||
import { TokenEnum } from "@/enums"; | |||||
// props | // props | ||||
interface FormProps { | interface FormProps { | ||||
modelValue: Partial<SysUserPersonnel.SysUserPerInfo>; | modelValue: Partial<SysUserPersonnel.SysUserPerInfo>; | ||||
@@ -57,25 +90,88 @@ const userInfo = computed({ | |||||
get: () => props.modelValue, | get: () => props.modelValue, | ||||
set: val => emit("update:modelValue", val) | set: val => emit("update:modelValue", val) | ||||
}); | }); | ||||
/* */ | |||||
const userStore = useUserStore(); | |||||
const { accessToken } = userStore; | |||||
const fileList = ref([]); | |||||
const faces = ref<SysUserPersonnel.SysUserAvatar[]>([]); | |||||
const dialogImageUrl = ref(""); | |||||
const dialogVisible = ref(false); | |||||
const treeData = ref<{ [key: string]: any }[]>([]); | |||||
const handleRemove: UploadProps["onRemove"] = uploadFile => { | |||||
const index = faces.value.findIndex(item => item.uid === uploadFile.uid); | |||||
if (index > -1) { | |||||
faces.value.splice(index, 1); | |||||
} | |||||
userInfo.value.faces = faces.value; | |||||
if (uploadFile.personId) { | |||||
userManagePersonnelApi.deleteFace({ personId: uploadFile.personId, faceIds: [uploadFile.uid] }).then(res => {}); | |||||
} | |||||
}; | |||||
const handlePictureCardPreview: UploadProps["onPreview"] = uploadFile => { | |||||
dialogImageUrl.value = uploadFile.url!; | |||||
dialogVisible.value = true; | |||||
}; | |||||
const handleAvatarSuccess: UploadProps["onSuccess"] = (response, uploadFile) => { | |||||
if (response.code === 200) { | |||||
faces.value.push({ faceUrl: response.data, uid: uploadFile.uid }); | |||||
userInfo.value.faces = faces.value; | |||||
ElMessage.success(response.msg); | |||||
} else { | |||||
ElMessage.error(response.msg); | |||||
fileList.value = fileList.value.splice(0, fileList.value.length - 1); | |||||
} | |||||
}; | |||||
const handleAvatarError: UploadProps["onError"] = (error, uploadFile, uploadFiles) => { | |||||
console.log(error, uploadFile, uploadFiles, "err"); | |||||
}; | |||||
// 通用状态选项 | // 通用状态选项 | ||||
const genderOptions = ref([ | const genderOptions = ref([ | ||||
{ | { | ||||
label: "未知", | label: "未知", | ||||
value: "0" | |||||
value: "GENDER_UNKNOWN" | |||||
}, | }, | ||||
{ | { | ||||
label: "男", | label: "男", | ||||
value: "1" | |||||
value: "GENDER_MALE" | |||||
}, | }, | ||||
{ | { | ||||
label: "女", | label: "女", | ||||
value: "2" | |||||
value: "GENDER_FEMALE" | |||||
} | } | ||||
]); | ]); | ||||
const getRequestData = async () => { | |||||
const { data } = await userManageClassManageApi.page(); | |||||
treeData.value = data; | |||||
console.log(treeData.value, "treeData"); | |||||
}; | |||||
onMounted(() => { | onMounted(() => { | ||||
// 初始化 | // 初始化 | ||||
userInfo.value.gender = userInfo.value.gender ? userInfo.value.gender : genderOptions.value[0].value; | userInfo.value.gender = userInfo.value.gender ? userInfo.value.gender : genderOptions.value[0].value; | ||||
getRequestData(); | |||||
if (userInfo.value.personId) { | |||||
if (userInfo.value.faces?.length > 0) { | |||||
fileList.value = [ | |||||
...JSON.parse(JSON.stringify(userInfo.value.faces)).map(item => { | |||||
return { | |||||
url: item.faceUrl, | |||||
uid: item.faceId, | |||||
personId: userInfo.value.personId | |||||
}; | |||||
}) | |||||
]; | |||||
faces.value = [ | |||||
...JSON.parse(JSON.stringify(userInfo.value.faces)).map(item => { | |||||
return { | |||||
faceUrl: item.faceUrl, | |||||
uid: item.faceId, | |||||
personId: userInfo.value.personId | |||||
}; | |||||
}) | |||||
]; | |||||
} | |||||
} | |||||
}); | }); | ||||
</script> | </script> | ||||
@@ -86,4 +182,12 @@ onMounted(() => { | |||||
:deep(.el-date-editor.el-input) { | :deep(.el-date-editor.el-input) { | ||||
width: 92% !important; | width: 92% !important; | ||||
} | } | ||||
:deep(.el-upload-list--picture-card .el-upload-list__item) { | |||||
width: 100px !important; | |||||
height: 100px !important; | |||||
} | |||||
:deep(.el-upload--picture-card) { | |||||
width: 100px !important; | |||||
height: 100px !important; | |||||
} | |||||
</style> | </style> |
@@ -49,7 +49,7 @@ const rules = reactive({ | |||||
// personId: [required("请输入人员ID")], | // personId: [required("请输入人员ID")], | ||||
name: [required("请输入姓名")], | name: [required("请输入姓名")], | ||||
gender: [required("请选择性别")], | gender: [required("请选择性别")], | ||||
// age: [required("请输入年龄")] | |||||
faces: [required("请上传人脸图片")], | |||||
phone: [required("请输入手机号")] | phone: [required("请输入手机号")] | ||||
// extData: [required("请输入扩展数据")] | // extData: [required("请输入扩展数据")] | ||||
}); | }); | ||||
@@ -67,7 +67,7 @@ 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({ personId: props.record.personId }).then(res => { | |||||
userManagePersonnelApi.detail({ id: props.record.personId }).then(res => { | |||||
sysUserProps.record = res.data; | sysUserProps.record = res.data; | ||||
}); | }); | ||||
} | } | ||||
@@ -80,8 +80,9 @@ async function handleSubmit() { | |||||
sysUserFormRef.value?.validate(async valid => { | sysUserFormRef.value?.validate(async valid => { | ||||
if (!valid) return; //表单验证失败 | if (!valid) return; //表单验证失败 | ||||
//提交表单 | //提交表单 | ||||
console.log(sysUserProps); | |||||
debugger; | |||||
if (sysUserProps.record.faces.length === 0) { | |||||
return ElMessage.error("请上传人脸图片"); | |||||
} | |||||
if (sysUserProps.record.personId) { | if (sysUserProps.record.personId) { | ||||
await userManagePersonnelApi | await userManagePersonnelApi | ||||
.update(sysUserProps.record) | .update(sysUserProps.record) | ||||
@@ -15,7 +15,7 @@ | |||||
label-width="auto" | label-width="auto" | ||||
label-suffix=" :" | label-suffix=" :" | ||||
> | > | ||||
<div style="margin-top: 30px"> | |||||
<div> | |||||
<el-row :gutter="16"> | <el-row :gutter="16"> | ||||
<el-col :span="22"> | <el-col :span="22"> | ||||
<s-form-item label="班级名称" prop="personSetName"> | <s-form-item label="班级名称" prop="personSetName"> | ||||
@@ -41,7 +41,6 @@ import { required } from "@/utils/formRules"; | |||||
import { FormInstance } from "element-plus"; | import { FormInstance } from "element-plus"; | ||||
const visibleClass = ref(false); //是否显示表单 | const visibleClass = ref(false); //是否显示表单 | ||||
// 表单参数 | // 表单参数 | ||||
const sysUserProps = reactive<FormProps.Base<SysUserPersonnel.ClassPage>>({ | const sysUserProps = reactive<FormProps.Base<SysUserPersonnel.ClassPage>>({ | ||||
opt: FormOptEnum.ADD, | opt: FormOptEnum.ADD, | ||||
@@ -35,7 +35,7 @@ | |||||
</template> | </template> | ||||
</TreeFilter> | </TreeFilter> | ||||
<div class="table-box"> | <div class="table-box"> | ||||
<ProTable ref="proTable" title="人员管理" :columns="columns" :request-api="userManagePersonnelApi.page"> | |||||
<ProTable ref="proTable" title="人员管理" :columns="columns" rowKey="personId" :request-api="userManagePersonnelApi.page"> | |||||
<!-- 表格 header 按钮 --> | <!-- 表格 header 按钮 --> | ||||
<template #tableHeader="scope"> | <template #tableHeader="scope"> | ||||
<s-button v-auth="userPerButtonCode.add" suffix="人员" @click="onOpen(FormOptEnum.ADD)" /> | <s-button v-auth="userPerButtonCode.add" suffix="人员" @click="onOpen(FormOptEnum.ADD)" /> | ||||
@@ -53,17 +53,12 @@ | |||||
<template #operation="scope"> | <template #operation="scope"> | ||||
<el-space> | <el-space> | ||||
<s-button v-auth="userPerButtonCode.edit" link :opt="FormOptEnum.EDIT" @click="onOpen(FormOptEnum.EDIT, scope.row)" /> | <s-button v-auth="userPerButtonCode.edit" link :opt="FormOptEnum.EDIT" @click="onOpen(FormOptEnum.EDIT, scope.row)" /> | ||||
<s-button | |||||
v-auth="userPerButtonCode.delete" | |||||
link | |||||
:opt="FormOptEnum.DELETE" | |||||
@click="onDelete([scope.row.id], `删除【${scope.row.account}】人员`)" | |||||
/> | |||||
<s-button v-auth="userPerButtonCode.delete" link :opt="FormOptEnum.DELETE" @click="onDelete([scope.row.personId], `删除人员`)" /> | |||||
<el-dropdown @command="handleCommand"> | <el-dropdown @command="handleCommand"> | ||||
<el-link type="primary" :underline="false" :icon="ArrowDown"> 更多 </el-link> | <el-link type="primary" :underline="false" :icon="ArrowDown"> 更多 </el-link> | ||||
<template #dropdown> | <template #dropdown> | ||||
<el-dropdown-menu> | <el-dropdown-menu> | ||||
<el-dropdown-item :command="command(scope.row, cmdEnum.DeleteFace)">{{ cmdEnum.DeleteFace }}</el-dropdown-item> | |||||
<el-dropdown-item :command="command(scope.row, cmdEnum.AddFace)">{{ cmdEnum.AddFace }}</el-dropdown-item> | |||||
<el-dropdown-item :command="command(scope.row, cmdEnum.UnderpantsUnBinding)">{{ cmdEnum.UnderpantsUnBinding }}</el-dropdown-item> | <el-dropdown-item :command="command(scope.row, cmdEnum.UnderpantsUnBinding)">{{ cmdEnum.UnderpantsUnBinding }}</el-dropdown-item> | ||||
</el-dropdown-menu> | </el-dropdown-menu> | ||||
</template> | </template> | ||||
@@ -73,7 +68,7 @@ | |||||
</ProTable> | </ProTable> | ||||
</div> | </div> | ||||
<!-- 人员新增/编辑表单 --> | <!-- 人员新增/编辑表单 --> | ||||
<Form ref="formRef" /> | |||||
<Form ref="formRef"></Form> | |||||
<!-- 班级新增/编辑表单 --> | <!-- 班级新增/编辑表单 --> | ||||
<FormClass ref="formRefC" /> | <FormClass ref="formRefC" /> | ||||
<!-- 预览头像 --> | <!-- 预览头像 --> | ||||
@@ -105,9 +100,10 @@ const proTable = ref<ProTableInstance>(); | |||||
const treeFilter = ref<InstanceType<typeof TreeFilter> | null>(null); | const treeFilter = ref<InstanceType<typeof TreeFilter> | null>(null); | ||||
// 表格配置项 | // 表格配置项 | ||||
const columns: ColumnProps<SysUserPersonnel.SysUserPerInfo>[] = [ | const columns: ColumnProps<SysUserPersonnel.SysUserPerInfo>[] = [ | ||||
{ type: "selection", fixed: "left", width: 50 }, | |||||
{ | { | ||||
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:50px;height:50px' alt=''/> | ||||
@@ -127,7 +123,7 @@ const columns: ColumnProps<SysUserPersonnel.SysUserPerInfo>[] = [ | |||||
label: "年龄" | label: "年龄" | ||||
}, | }, | ||||
{ | { | ||||
prop: "name", | |||||
prop: "personSets", | |||||
label: "所属班级", | label: "所属班级", | ||||
render: scope => { | render: scope => { | ||||
return scope.row.personSets.length > 0 ? scope.row.personSets[0].name : '' | return scope.row.personSets.length > 0 ? scope.row.personSets[0].name : '' | ||||
@@ -182,8 +178,15 @@ function onOpen(opt: FormOptEnum, record: {} | SysUserPersonnel.SysUserPerInfo = | |||||
* @param ids id数组 | * @param ids id数组 | ||||
*/ | */ | ||||
async function onDelete(ids: string[], msg: string) { | async function onDelete(ids: string[], msg: string) { | ||||
if(ids.length === 0){ | |||||
ElMessage({ | |||||
message: '请选择要删除的人员', | |||||
type: 'warning' | |||||
}); | |||||
return | |||||
} | |||||
// 二次确认 => 请求api => 刷新表格 | // 二次确认 => 请求api => 刷新表格 | ||||
await useHandleData(userManagePersonnelApi.delete, { ids }, msg); | |||||
await useHandleData(userManagePersonnelApi.delete, {id: ids.join(",") }, msg); | |||||
RefreshTable(); //刷新表格 | RefreshTable(); //刷新表格 | ||||
} | } | ||||
@@ -196,7 +199,7 @@ const RefreshTable = () => { | |||||
/** 更多下拉菜单命令枚举 */ | /** 更多下拉菜单命令枚举 */ | ||||
enum cmdEnum { | enum cmdEnum { | ||||
DeleteFace = "删除人脸", | |||||
AddFace = "添加人脸", | |||||
UnderpantsUnBinding = "底库解绑" | UnderpantsUnBinding = "底库解绑" | ||||
} | } | ||||
/** 下拉菜单参数接口 */ | /** 下拉菜单参数接口 */ | ||||
@@ -218,7 +221,7 @@ function command(row: SysUserPersonnel.SysUserPerInfo, command: cmdEnum): Comman | |||||
*/ | */ | ||||
function handleCommand(command: Command) { | function handleCommand(command: Command) { | ||||
switch (command.command) { | switch (command.command) { | ||||
case cmdEnum.DeleteFace: | |||||
case cmdEnum.AddFace: | |||||
break | break | ||||
case cmdEnum.UnderpantsUnBinding: | case cmdEnum.UnderpantsUnBinding: | ||||
break; | break; | ||||