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