@@ -51,6 +51,13 @@ export interface ReqId { | |||
/** id */ | |||
id: number | string; | |||
} | |||
/** ReqClothId请求参数 */ | |||
export interface ReqClothId { | |||
/** ReqClothId */ | |||
clothSetId: number | string; | |||
} | |||
/** id请求参数 */ | |||
export interface ReqPersonId { | |||
/** id */ | |||
@@ -0,0 +1,39 @@ | |||
/** | |||
* @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.任何基于本软件而产生的一切法律纠纷和责任,均于我司无关 | |||
*/ | |||
/** | |||
* @Description: 服装底库管理接口 | |||
* @Author: syy | |||
* @Date: 2023-12-15 15:34:54 | |||
*/ | |||
export namespace SysUserCloth { | |||
// 服装底库树 | |||
export interface Page { | |||
clothSetId?: number | string; | |||
clothSetName?: number | string; | |||
} | |||
export interface list { | |||
clothUrl: string; | |||
clothId: number | string; | |||
clothSetId: string; | |||
} | |||
/** 用户信息 */ | |||
export interface SysUserClothInfo { | |||
clothSetId: number | string; | |||
clothSetName: number | string; | |||
/** 列表 */ | |||
clothes?: Array<list>; | |||
} | |||
} |
@@ -13,3 +13,4 @@ | |||
* @see https://gitee.com/dotnetmoyu/SimpleAdmin | |||
*/ | |||
export * from "./personnel"; | |||
export * from "./clothing"; |
@@ -26,9 +26,11 @@ export namespace SysUserPersonnel { | |||
export interface ClassPage { | |||
personSetId?: string | number | undefined; | |||
personSetName?: string | undefined; | |||
id?: string | undefined; | |||
name?: string | undefined; | |||
personId?: string | undefined | number; | |||
id?: string | number | undefined; | |||
name?: string | number | undefined; | |||
userId?: string | number | undefined; | |||
personId?: string | number | undefined; | |||
userName?: string | number | undefined; | |||
} | |||
/** 人脸信息 */ | |||
export interface SysUserAvatar { | |||
@@ -59,9 +61,9 @@ export namespace SysUserPersonnel { | |||
/** 扩展字段 */ | |||
extData?: string; | |||
/** 人脸 */ | |||
faces: Array<SysUserAvatar>; | |||
faces: any; | |||
/** 分组 */ | |||
personSets: Array<ClassPage>; | |||
personSets: any; | |||
personSetId?: number | string; | |||
} | |||
} |
@@ -23,8 +23,8 @@ const http = moduleRequest("/business/dfieldApi/"); | |||
*/ | |||
const userManageClassManageApi = { | |||
/** 查询底库列表 */ | |||
page(params: SysUserPersonnel.ClassPage) { | |||
return http.get("queryAll", params); | |||
page() { | |||
return http.get("queryAll"); | |||
}, | |||
/** 删除底库 */ | |||
delete(params: ReqId) { | |||
@@ -0,0 +1,68 @@ | |||
/** | |||
* @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"; | |||
import { ReqId, SysUserCloth, ReqClothId } from "@/api/interface"; | |||
const http = moduleRequest("/business/clothApi/"); | |||
/** | |||
* @Description: 单页管理 | |||
* @Author: SYY | |||
* @Date: 2023-12-15 15:34:54 | |||
*/ | |||
const userManageClothApi = { | |||
/** 查询服装底库列表 */ | |||
getList(params: SysUserCloth.Page) { | |||
return http.get("getList", params); | |||
}, | |||
/** 查询服装底库详情 */ | |||
page(params: ReqClothId) { | |||
return http.get("getInfo", params); | |||
}, | |||
/** 删除服装底库 */ | |||
deleteClothDataBaseD(params: ReqClothId) { | |||
return http.delete("deleteClothDataBaseD", params); | |||
}, | |||
/** 新增服装底库 */ | |||
addClothDataBaseA(params: SysUserCloth.Page) { | |||
return http.post("addClothDataBaseA", params); | |||
}, | |||
/** 更新服装底库 */ | |||
update(params: SysUserCloth.Page) { | |||
return http.put("updateClothU", params); | |||
}, | |||
/** 服装图片上传 */ | |||
uploadFile(params: any) { | |||
return http.post("uploadFile", params); | |||
}, | |||
/** 新增服装 */ | |||
add(params: any) { | |||
return http.post("addClothA", params); | |||
}, | |||
/** 删除服装 */ | |||
delete(params: SysUserCloth.list) { | |||
return http.post("deleteClothD", params); | |||
} | |||
}; | |||
const userClothButtonCode = { | |||
/** 新增人员 */ | |||
add: "userManageClothAdd", | |||
/** 删除人员 */ | |||
edit: "userManageClothEdit", | |||
/** 删除人员 */ | |||
delete: "userManageClothDelete" | |||
}; | |||
export { userManageClothApi, userClothButtonCode }; |
@@ -14,3 +14,6 @@ | |||
*/ | |||
export * from "./personnel"; | |||
export * from "./classManage"; | |||
export * from "./clothing"; | |||
export * from "./teacher"; | |||
export * from "./keyPersonnel"; |
@@ -0,0 +1,63 @@ | |||
/** | |||
* @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"; | |||
import { ReqId, SysUserPersonnel } from "@/api/interface"; | |||
const http = moduleRequest("/business/keyPersonnel/"); | |||
/** | |||
* @Description: 单页管理 | |||
* @Author: SYY | |||
* @Date: 2024-7-19 15:34:54 | |||
*/ | |||
const userManageKeyPersonApi = { | |||
/** 获取单页分页 */ | |||
page(params: SysUserPersonnel.Page) { | |||
return http.post("pageQuery", params); | |||
}, | |||
/** 获取单页详情 */ | |||
detail(params: ReqId) { | |||
return http.get("getPersionById", params); | |||
}, | |||
/** 删除人员 */ | |||
delete(params: ReqId) { | |||
return http.delete("deletePersonD", params); | |||
}, | |||
/** 新增人员 */ | |||
add(params: any) { | |||
return http.post("createPersonA", params); | |||
}, | |||
/** 修改人员 */ | |||
update(params: any) { | |||
return http.put("updatePersionU", params); | |||
}, | |||
/** 添加人脸 */ | |||
addFace(params: SysUserPersonnel.SysUserAvatar) { | |||
return http.post("addFaceA", params); | |||
}, | |||
/** 删除人脸 */ | |||
deleteFace(params: SysUserPersonnel.SysUserFace) { | |||
return http.post("deleteFaceD", params); | |||
} | |||
}; | |||
const userKeyPerButtonCode = { | |||
/** 新增人员 */ | |||
add: "userManageKeyPersonAdd", | |||
/** 删除人员 */ | |||
edit: "userManageKeyPersonEdit", | |||
/** 删除人员 */ | |||
delete: "userManageKeyPersonDelete" | |||
}; | |||
export { userManageKeyPersonApi, userKeyPerButtonCode }; |
@@ -0,0 +1,54 @@ | |||
/** | |||
* @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("/business/classTeacher/"); | |||
/** | |||
* @Description: 单页管理 | |||
* @Author: SYY | |||
* @Date: 2023-12-15 15:34:54 | |||
*/ | |||
const userManageTeacherApi = { | |||
/** 查询班主任列表 */ | |||
page() { | |||
return http.get("getNoPageList"); | |||
}, | |||
/** 获取单页详情 */ | |||
detail(params: any) { | |||
return http.get("getInfo", params); | |||
}, | |||
/** 删除班主任 */ | |||
delete(params: any) { | |||
return http.delete("delete", params); | |||
}, | |||
/** 创建班主任 */ | |||
add(params: any) { | |||
return http.post("add", params); | |||
}, | |||
/** 更新班主任 */ | |||
update(params: any) { | |||
return http.put("update", params); | |||
} | |||
}; | |||
const userTeacherButtonCode = { | |||
/** 新增人员 */ | |||
add: "userManageClassManageAdd", | |||
/** 删除人员 */ | |||
edit: "userManageClassManageEdit", | |||
/** 删除人员 */ | |||
delete: "userManageClassManageDelete" | |||
}; | |||
export { userManageTeacherApi, userTeacherButtonCode }; |
@@ -56,6 +56,7 @@ interface TreeFilterProps { | |||
topName?: string; // 顶级分类名称 ==> 非必传,默认为 “全部” | |||
showAll?: boolean; // 是否显示全部选项 ==> 非必传,默认为 true | |||
width: string; | |||
isData?: boolean; | |||
} | |||
const props = withDefaults(defineProps<TreeFilterProps>(), { | |||
id: "id", | |||
@@ -65,7 +66,8 @@ const props = withDefaults(defineProps<TreeFilterProps>(), { | |||
defaultExpandLevel: 1, | |||
checkStrictly: false, | |||
topName: "全部", | |||
showAll: true | |||
showAll: true, | |||
isData: false | |||
}); | |||
const defaultProps = { | |||
@@ -156,13 +158,17 @@ const refresh = async () => { | |||
treeRef.value?.setCheckedKeys([]); | |||
treeRef.value?.setCurrentKey(""); | |||
setSelected(); | |||
await getRequestData(); | |||
if (!props.isData) { | |||
await getRequestData(); | |||
} | |||
}; | |||
const getRequestData = async () => { | |||
const { data } = await props.requestApi!(); | |||
treeData.value = data; | |||
setTreeAllData(data); | |||
if (!props.isData) { | |||
const { data } = await props.requestApi!(); | |||
treeData.value = data; | |||
setTreeAllData(data); | |||
} | |||
}; | |||
/** 获取默认展开层级 */ | |||
@@ -27,6 +27,8 @@ declare namespace FormProps { | |||
disabled?: boolean; | |||
/** 行内表单模式 */ | |||
inline?: boolean; | |||
// 树数据 | |||
treeAllData?: Array<any>; | |||
/** 表单布局 */ | |||
successful?: () => void; | |||
} | |||
@@ -0,0 +1,156 @@ | |||
<!-- | |||
* @Description: 表单 | |||
* @Author: syy | |||
* @Date: 2023-12-15 15:45:59 | |||
--> | |||
<template> | |||
<div> | |||
<form-container v-model="visible" :title="`${sysUserProps.opt}服装`" form-size="500px" @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="24"> | |||
<s-form-item label="所属服装库" prop="clothSetId"> | |||
<s-select | |||
v-model="sysUserProps.record.clothSetId" | |||
:options="sysUserProps.treeAllData" | |||
label="clothSetName" | |||
value="clothSetId" | |||
></s-select> | |||
</s-form-item> | |||
</el-col> | |||
</el-row> | |||
<el-row :gutter="16"> | |||
<el-col :span="24"> | |||
<s-form-item label="上传服装" prop="faces"> | |||
<el-upload | |||
class="avatar-uploader" | |||
action="/api/business/clothApi/uploadFile" | |||
:show-file-list="false" | |||
:on-success="handleAvatarSuccess" | |||
accept=".jpg, .jpeg, .png" | |||
:headers="{ | |||
Authorization: `${TokenEnum.TOKEN_PREFIX} ${accessToken}` | |||
}" | |||
> | |||
<img v-if="sysUserProps.record.clothUrl" :src="sysUserProps.record.clothUrl" class="avatar" /> | |||
<el-icon v-else class="avatar-uploader-icon"><Plus /></el-icon> | |||
</el-upload> | |||
</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="SysUserClothForm"> | |||
import { SysUserCloth, userManageClothApi } from "@/api"; | |||
import { FormOptEnum } from "@/enums"; | |||
import { required } from "@/utils/formRules"; | |||
import { FormInstance } from "element-plus"; | |||
import { useUserStore } from "@/stores/modules"; | |||
import type { UploadProps } from "element-plus"; | |||
import { TokenEnum } from "@/enums"; | |||
const visible = ref(false); //是否显示表单 | |||
const activeName = ref("basic"); | |||
const userStore = useUserStore(); | |||
const { accessToken } = userStore; | |||
// 表单参数 | |||
const sysUserProps = reactive<FormProps.Base<SysUserCloth.list>>({ | |||
opt: FormOptEnum.ADD, | |||
record: {}, | |||
treeAllData: [], | |||
disabled: false | |||
}); | |||
// 表单验证规则 | |||
const rules = reactive({ | |||
clothSetId: [required("请选择所属服装库")], | |||
clothUrl: [required("请上传服装")] | |||
}); | |||
const handleAvatarSuccess: UploadProps["onSuccess"] = (response: any) => { | |||
if (response.code === 200) { | |||
sysUserProps.record.clothUrl = response.data; | |||
} | |||
}; | |||
/** | |||
* 打开表单 | |||
* @param props 表单参数 | |||
*/ | |||
function onOpen(props: FormProps.Base<SysUserCloth.list>) { | |||
Object.assign(sysUserProps, props); //合并参数 | |||
visible.value = true; //显示表单 | |||
sysUserProps.record = props.record; | |||
} | |||
// 提交数据(新增/编辑) | |||
const sysUserFormRef = ref<FormInstance>(); | |||
/** 提交表单 */ | |||
async function handleSubmit() { | |||
sysUserFormRef.value?.validate(async valid => { | |||
if (!valid) return; //表单验证失败 | |||
await userManageClothApi | |||
.add(sysUserProps.record) | |||
.then(() => { | |||
sysUserProps.successful!(); //调用父组件的successful方法 | |||
}) | |||
.finally(() => { | |||
onClose(); | |||
}); | |||
}); | |||
} | |||
/** 关闭表单*/ | |||
function onClose() { | |||
visible.value = false; | |||
activeName.value = "basic"; | |||
} | |||
// 暴露给父组件的方法 | |||
defineExpose({ | |||
onOpen | |||
}); | |||
</script> | |||
<style lang="scss" scoped> | |||
.avatar-uploader .avatar { | |||
display: block; | |||
width: 178px; | |||
height: 178px; | |||
} | |||
</style> | |||
<style> | |||
.avatar-uploader .el-upload { | |||
position: relative; | |||
overflow: hidden; | |||
cursor: pointer; | |||
border: 1px dashed var(--el-border-color); | |||
border-radius: 6px; | |||
transition: var(--el-transition-duration-fast); | |||
} | |||
.avatar-uploader .el-upload:hover { | |||
border-color: var(--el-color-primary); | |||
} | |||
.el-icon.avatar-uploader-icon { | |||
width: 178px; | |||
height: 178px; | |||
font-size: 28px; | |||
color: #8c939d; | |||
text-align: center; | |||
} | |||
</style> |
@@ -0,0 +1,105 @@ | |||
<!-- | |||
* @Description: 表单 | |||
* @Author: syy | |||
* @Date: 2023-12-18 15:45:59 | |||
--> | |||
<template> | |||
<div> | |||
<form-container v-model="visibleClass" :title="`${sysUserProps.opt}服装库`" form-size="400px" @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="22"> | |||
<s-form-item label="服装库名称" prop="clothSetName"> | |||
<s-input v-model="sysUserProps.record.clothSetName"></s-input> | |||
</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="SysUserClothDk"> | |||
import { ref } from "vue"; | |||
import { userManageClothApi, SysUserCloth } from "@/api"; | |||
import { FormOptEnum } from "@/enums"; | |||
import { required } from "@/utils/formRules"; | |||
import { FormInstance } from "element-plus"; | |||
const visibleClass = ref(false); //是否显示表单 | |||
// 表单参数 | |||
const sysUserProps = reactive<FormProps.Base<SysUserCloth.Page>>({ | |||
opt: FormOptEnum.ADD, | |||
record: {}, | |||
disabled: false | |||
}); | |||
// 表单验证规则 | |||
const rules = reactive({ | |||
clothSetName: [required("请输入服装库名称")] | |||
}); | |||
/** | |||
* 打开表单 | |||
* @param props 表单参数 | |||
*/ | |||
function onOpen(props: FormProps.Base<SysUserCloth.Page>) { | |||
Object.assign(sysUserProps, props); //合并参数 | |||
visibleClass.value = true; //显示表单 | |||
sysUserProps.record = props.record; | |||
} | |||
// 提交数据(新增/编辑) | |||
const sysUserFormRef = ref<FormInstance>(); | |||
/** 提交表单 */ | |||
async function handleSubmit() { | |||
sysUserFormRef.value?.validate(async valid => { | |||
if (!valid) return; //表单验证失败 | |||
//提交表单 | |||
if (sysUserProps.record.clothSetId) { | |||
await userManageClothApi | |||
.update(sysUserProps.record) | |||
.then(() => { | |||
sysUserProps.successful!(); //调用父组件的successful方法 | |||
}) | |||
.finally(() => { | |||
onClose(); | |||
}); | |||
} else { | |||
await userManageClothApi | |||
.addClothDataBaseA(sysUserProps.record) | |||
.then(() => { | |||
sysUserProps.successful!(); //调用父组件的successful方法 | |||
}) | |||
.finally(() => { | |||
onClose(); | |||
}); | |||
} | |||
}); | |||
} | |||
/** 关闭表单*/ | |||
function onClose() { | |||
visibleClass.value = false; | |||
} | |||
// 暴露给父组件的方法 | |||
defineExpose({ | |||
onOpen | |||
}); | |||
</script> | |||
<style lang="scss" scoped></style> |
@@ -0,0 +1,195 @@ | |||
<!-- | |||
* @Description: 服装库管理 | |||
* @Author: syy | |||
* @Date: 2024-7-18 | |||
--> | |||
<template> | |||
<div class="main-box"> | |||
<TreeFilter | |||
ref="treeFilter" | |||
label="clothSetName" | |||
id="clothSetId" | |||
width="300px" | |||
:show-all="true" | |||
:request-api="userManageClothApi.getList" | |||
@change="changeTreeFilter" | |||
> | |||
<template v-slot:header> | |||
<s-button suffix="服装库" @click="addClass(FormOptEnum.ADD)" style="margin-bottom: 15px" /> | |||
</template> | |||
<template v-slot:label="{ row }"> | |||
<span class="custom-tree-node"> | |||
<span>{{ row.node.label }}</span> | |||
<span v-if="row.node.label != '全部'"> | |||
<a @click.stop="addClass(FormOptEnum.EDIT, row.node.data)"> | |||
<el-icon><Edit /></el-icon> | |||
</a> | |||
<a style="margin-left: 8px" @click.stop="addDelete(row.node.data.clothSetId, '删除服装库')"> | |||
<el-icon><Delete /></el-icon> | |||
</a> | |||
</span> | |||
</span> | |||
</template> | |||
</TreeFilter> | |||
<div class="table-box"> | |||
<ProTable ref="proTable" title="服装库管理" :columns="columns" rowKey="clothId" :data="tableData.clothes"> | |||
<!-- 表格 header 按钮 --> | |||
<template #tableHeader="scope"> | |||
<s-button suffix="服装" @click="onOpen(FormOptEnum.ADD, { clothSetId: clothSetId }, 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.DELETE" @click="onDelete([scope.row.clothId], `删除服装`)" /> | |||
</el-space> | |||
</template> | |||
</ProTable> | |||
</div> | |||
<!-- 人员新增/编辑表单 --> | |||
<Form ref="formRef"></Form> | |||
<!-- 班级新增/编辑表单 --> | |||
<Form1 ref="formRefC" /> | |||
<!-- 预览头像 --> | |||
<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%" class="detailpic" :src="faceUrl" alt="" /> | |||
</div> | |||
<template #footer> | |||
<div class="dialog-footer"> | |||
<el-button @click="visible = false">关闭</el-button> | |||
</div> | |||
</template> | |||
</el-dialog> | |||
</div> | |||
</template> | |||
<script setup lang="tsx" name="SysUserClothing"> | |||
import { userManageClothApi,userClothButtonCode,SysUserCloth } from "@/api"; | |||
import { useHandleData } from "@/hooks/useHandleData"; | |||
import { FormOptEnum } from "@/enums"; | |||
import Form from "./components/form/index.vue"; | |||
import Form1 from "./components/form1/index.vue"; | |||
import { ColumnProps, ProTableInstance } from "@/components/ProTable/interface"; | |||
import TreeFilter from "@/components/TreeFilter/index.vue"; | |||
import { useUserStore } from "@/stores/modules"; | |||
// 获取 ProTable 元素,调用其获取刷新数据方法(还能获取到当前查询参数,方便导出携带参数) | |||
const faceUrl = ref(''); | |||
const visible = ref(false); //是否显示人员表单 | |||
const proTable = ref<ProTableInstance>(); | |||
const treeFilter = ref<any>({}); | |||
const userStore = useUserStore(); | |||
const { accessToken } = userStore; | |||
const tableData = ref<any>([]) | |||
// 表格配置项 | |||
const columns: ColumnProps<SysUserCloth.list>[] = [ | |||
{ type: "selection", fixed: "left", width: 50 }, | |||
{ | |||
prop: "clothUrl", | |||
label: "服装图", | |||
render: scope => { | |||
return ( | |||
<img src={scope.row.clothUrl} onClick={() => viewHeadImage(scope)} style='width:50px;height:50px' alt=''/> | |||
); | |||
} | |||
}, | |||
{ prop: "operation", label: "操作", width: 250, fixed: "right" } | |||
]; | |||
const viewHeadImage = (scope: any) => { | |||
faceUrl.value = scope.row.clothUrl; | |||
visible.value = true | |||
}; | |||
const handleClose = () => { | |||
visible.value = false; | |||
}; | |||
// 人员表单引用 | |||
const formRef = ref<InstanceType<typeof Form> | null>(null); | |||
// 班级表单引用 | |||
const formRefC = ref<InstanceType<typeof Form1> | 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 opt 操作类型 | |||
* @param record 记录 | |||
*/ | |||
function addClass(opt: FormOptEnum, record: {} | SysUserCloth.list = {}) { | |||
formRefC.value?.onOpen({ opt: opt, record: JSON.parse(JSON.stringify(record)), successful: RefreshTree }); | |||
} | |||
/** | |||
* 服装库删除 | |||
* @param ids id数组 | |||
*/ | |||
async function addDelete(clothSetId: string[],msg: string) { | |||
// 二次确认 => 请求api => 刷新表格 | |||
await useHandleData(userManageClothApi.deleteClothDataBaseD, { clothSetId }, msg); | |||
RefreshTree(); //刷新表格 | |||
} | |||
/** | |||
* 服装删除 | |||
* @param ids id数组 | |||
*/ | |||
async function onDelete(ids: string[], msg: string) { | |||
// 二次确认 => 请求api => 刷新表格 | |||
await useHandleData(userManageClothApi.delete, {clothId: ids.join(","), clothSetId:tableData.value.clothSetId}, msg); | |||
RefreshTable(); //刷新表格 | |||
} | |||
// 刷新表格 | |||
const RefreshTable = () => { | |||
getList(clothSetId.value) | |||
} | |||
// 刷新表格+树 | |||
const RefreshTree = () => { | |||
getList(clothSetId.value) | |||
treeFilter.value?.refresh(); //刷新树形筛选器 | |||
} | |||
/** 服装库切换切换 */ | |||
const clothSetId = ref<number | string>() | |||
function changeTreeFilter(val: number | string) { | |||
clothSetId.value = val | |||
proTable.value!.pageable.pageNum = 1; | |||
getList(val) | |||
} | |||
// 获取列表 | |||
const getList = (clothSetId:any)=>{ | |||
if(!clothSetId) return false | |||
userManageClothApi.page({clothSetId:clothSetId}).then((resp:any)=>{ | |||
if(resp.code == 200){ | |||
tableData.value = resp.data | |||
} | |||
}) | |||
} | |||
</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,181 @@ | |||
<!-- | |||
* @Description: 人员表单 | |||
* @Author: syy | |||
* @Date: 2023-12-15 15:45:50 | |||
--> | |||
<template> | |||
<div class="userManageForm"> | |||
<div> | |||
<el-row :gutter="16"> | |||
<el-col :span="24"> | |||
<s-form-item label="人员姓名" prop="name"> | |||
<s-input v-model="userInfo.name"></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"> | |||
<s-radio-group v-model="userInfo.gender" :options="genderOptions" /> | |||
</s-form-item> | |||
</el-col> | |||
<el-col :span="12"> | |||
<s-form-item label="年龄" prop="age"> | |||
<s-input v-model="userInfo.age"></s-input> | |||
</s-form-item> | |||
</el-col> | |||
</el-row> | |||
<el-row :gutter="16"> | |||
<el-col :span="12"> | |||
<s-form-item label="手机号" prop="phone"> | |||
<s-input v-model="userInfo.phone"></s-input> | |||
</s-form-item> | |||
</el-col> | |||
<el-col :span="12"> | |||
<s-form-item label="扩展字段" prop="extData"> | |||
<s-input v-model="userInfo.extData"></s-input> | |||
</s-form-item> | |||
</el-col> | |||
</el-row> | |||
</div> | |||
</div> | |||
</template> | |||
<script setup lang="ts"> | |||
import { SysUserPersonnel, userManageKeyPersonApi } from "@/api"; | |||
import { Plus } from "@element-plus/icons-vue"; | |||
import { useUserStore } from "@/stores/modules"; | |||
import type { UploadProps } from "element-plus"; | |||
import { ElMessage } from "element-plus"; | |||
import { TokenEnum } from "@/enums"; | |||
// props | |||
interface FormProps { | |||
modelValue: Partial<SysUserPersonnel.SysUserPerInfo>; | |||
} | |||
const emit = defineEmits(["update:modelValue"]); //定义emit | |||
const props = defineProps<FormProps>(); //定义props | |||
// 人员信息 | |||
const userInfo = computed({ | |||
get: () => props.modelValue, | |||
set: val => emit("update:modelValue", val) | |||
}); | |||
/* */ | |||
const userStore = useUserStore(); | |||
const { accessToken } = userStore; | |||
const fileList = ref<any>([]); | |||
const faces = ref<SysUserPersonnel.SysUserAvatar[]>([]); | |||
const dialogImageUrl = ref(""); | |||
const dialogVisible = ref(false); | |||
const handleRemove: UploadProps["onRemove"] = (uploadFile: any) => { | |||
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) { | |||
userManageKeyPersonApi.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: "GENDER_UNKNOWN" | |||
}, | |||
{ | |||
label: "男", | |||
value: "GENDER_MALE" | |||
}, | |||
{ | |||
label: "女", | |||
value: "GENDER_FEMALE" | |||
} | |||
]); | |||
onMounted(() => { | |||
// 初始化 | |||
userInfo.value.gender = userInfo.value.gender ? userInfo.value.gender : genderOptions.value[0].value; | |||
if (userInfo.value.personId) { | |||
if (userInfo.value.faces?.length > 0) { | |||
fileList.value = [ | |||
...JSON.parse(JSON.stringify(userInfo.value.faces)).map((item: any) => { | |||
return { | |||
url: item.faceUrl, | |||
uid: item.faceId, | |||
personId: userInfo.value.personId | |||
}; | |||
}) | |||
]; | |||
faces.value = [ | |||
...JSON.parse(JSON.stringify(userInfo.value.faces)).map((item: any) => { | |||
return { | |||
faceUrl: item.faceUrl, | |||
uid: item.faceId, | |||
personId: userInfo.value.personId | |||
}; | |||
}) | |||
]; | |||
} | |||
} | |||
}); | |||
</script> | |||
<style lang="scss" scoped> | |||
:deep(.el-input__wrapper) { | |||
width: 100% !important; | |||
} | |||
: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> |
@@ -0,0 +1,117 @@ | |||
<!-- | |||
* @Description: 表单 | |||
* @Author: syy | |||
* @Date: 2023-12-15 15:45:59 | |||
--> | |||
<template> | |||
<div> | |||
<form-container v-model="visible" :title="`${sysUserProps.opt}人员`" form-size="800px" @close="onClose"> | |||
<el-form | |||
ref="sysUserFormRef" | |||
:rules="rules" | |||
:disabled="sysUserProps.disabled" | |||
:model="sysUserProps.record" | |||
:hide-required-asterisk="sysUserProps.disabled" | |||
label-width="auto" | |||
label-suffix=" :" | |||
> | |||
<el-tabs v-model="activeName"> | |||
<Basic v-model="sysUserProps.record"></Basic> | |||
</el-tabs> | |||
</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="SysUserKeyPersonnelForm"> | |||
import { SysUserPersonnel, userManageKeyPersonApi } from "@/api"; | |||
import { FormOptEnum } from "@/enums"; | |||
import { required } from "@/utils/formRules"; | |||
import { FormInstance } from "element-plus"; | |||
import Basic from "./form_basic.vue"; | |||
const visible = ref(false); //是否显示表单 | |||
const activeName = ref("basic"); | |||
// 表单参数 | |||
const sysUserProps = reactive<FormProps.Base<SysUserPersonnel.SysUserPerInfo>>({ | |||
opt: FormOptEnum.ADD, | |||
record: {}, | |||
disabled: false | |||
}); | |||
// 表单验证规则 | |||
const rules = reactive({ | |||
name: [required("请输入姓名")], | |||
gender: [required("请选择性别")], | |||
faces: [required("请上传人脸图片")], | |||
phone: [required("请输入手机号")] | |||
}); | |||
/** | |||
* 打开表单 | |||
* @param props 表单参数 | |||
*/ | |||
function onOpen(props: FormProps.Base<SysUserPersonnel.SysUserPerInfo>) { | |||
Object.assign(sysUserProps, props); //合并参数 | |||
if (props.opt == FormOptEnum.ADD) { | |||
//如果是新增,设置默认值 | |||
// sysUserProps.record.sortCode = 99; | |||
} | |||
visible.value = true; //显示表单 | |||
if (props.record.personId) { | |||
//如果传了id,就去请求api获取record | |||
userManageKeyPersonApi.detail({ id: props.record.personId }).then((res: any) => { | |||
sysUserProps.record = 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 userManageKeyPersonApi | |||
.update(sysUserProps.record) | |||
.then(() => { | |||
sysUserProps.successful!(); //调用父组件的successful方法 | |||
}) | |||
.finally(() => { | |||
onClose(); | |||
}); | |||
} else { | |||
await userManageKeyPersonApi | |||
.add(sysUserProps.record) | |||
.then(() => { | |||
sysUserProps.successful!(); //调用父组件的successful方法 | |||
}) | |||
.finally(() => { | |||
onClose(); | |||
}); | |||
} | |||
}); | |||
} | |||
/** 关闭表单*/ | |||
function onClose() { | |||
visible.value = false; | |||
activeName.value = "basic"; | |||
} | |||
// 暴露给父组件的方法 | |||
defineExpose({ | |||
onOpen | |||
}); | |||
</script> | |||
<style lang="scss" scoped></style> |
@@ -0,0 +1,220 @@ | |||
<!-- | |||
* @Description: 人员管理 | |||
* @Author: syy | |||
* @Date: 2024-7-15 | |||
--> | |||
<template> | |||
<div class="main-box"> | |||
<div class="table-box"> | |||
<ProTable ref="proTable" title="人员管理" :columns="columns" rowKey="personId" :request-api="userManageKeyPersonApi.page"> | |||
<!-- 表格 header 按钮 --> | |||
<template #tableHeader="scope"> | |||
<s-button suffix="人员" @click="onOpen(FormOptEnum.ADD)" /> | |||
<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.EDIT" @click="onOpen(FormOptEnum.EDIT, scope.row)" /> | |||
<s-button 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.AddFace)" | |||
><el-upload | |||
ref="upload" | |||
class="upload-demo" | |||
action="/api/business/personApi/uploadFile" | |||
:show-file-list="false" | |||
:on-success="handleAvatarSuccess" | |||
accept=".jpg, .jpeg, .png" | |||
:headers="{ | |||
Authorization: `${TokenEnum.TOKEN_PREFIX} ${accessToken}` | |||
}" | |||
> | |||
<template #trigger> | |||
{{ cmdEnum.AddFace }} | |||
</template> | |||
</el-upload> | |||
</el-dropdown-item> | |||
</el-dropdown-menu> | |||
</template> | |||
</el-dropdown> | |||
</el-space> | |||
</template> | |||
</ProTable> | |||
</div> | |||
<!-- 人员新增/编辑表单 --> | |||
<Form ref="formRef"></Form> | |||
<!-- 预览头像 --> | |||
<el-dialog v-model="visible" title="查看头像" width="830px" :before-close="handleClose"> | |||
<div style="display: flex; align-items: center; justify-content: center"> | |||
<img class="detailpic" :src="faceUrl" alt="" style="max-width: 100%" /> | |||
</div> | |||
</el-dialog> | |||
</div> | |||
</template> | |||
<script setup lang="tsx" name="SysUserKeyPersonnel"> | |||
import { userManageKeyPersonApi,SysUserPersonnel } from "@/api"; | |||
import { useHandleData } from "@/hooks/useHandleData"; | |||
import { FormOptEnum } from "@/enums"; | |||
import Form from "./components/form/index.vue"; | |||
import { ArrowDown } from "@element-plus/icons-vue"; | |||
import { ColumnProps, ProTableInstance } from "@/components/ProTable/interface"; | |||
import { ElMessage } from "element-plus"; | |||
import { useUserStore } from "@/stores/modules"; | |||
import { TokenEnum } from "@/enums"; | |||
import type { UploadProps } from "element-plus"; | |||
// 获取 ProTable 元素,调用其获取刷新数据方法(还能获取到当前查询参数,方便导出携带参数) | |||
const faceUrl = ref(''); | |||
const visible = ref(false); //是否显示人员表单 | |||
const proTable = ref<ProTableInstance>(); | |||
const userStore = useUserStore(); | |||
const { accessToken } = userStore; | |||
// 表格配置项 | |||
const columns: ColumnProps<SysUserPersonnel.SysUserPerInfo>[] = [ | |||
{ type: "selection", fixed: "left", width: 50 }, | |||
{ | |||
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: "age", | |||
label: "年龄" | |||
}, | |||
{ | |||
prop: "personSets", | |||
label: "所属班级", | |||
render: scope => { | |||
return scope.row.personSets.length > 0 ? scope.row.personSets[0].personSetName : '' | |||
} | |||
}, | |||
{ 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 handleClose = () => { | |||
visible.value = false; | |||
}; | |||
// 人员表单引用 | |||
const formRef = ref<InstanceType<typeof Form> | null>(null); | |||
/** | |||
* 打开表单 | |||
* @param opt 操作类型 | |||
* @param record 记录 | |||
*/ | |||
function onOpen(opt: FormOptEnum, record: {} | SysUserPersonnel.SysUserPerInfo = {}) { | |||
formRef.value?.onOpen({ opt: opt, record: record, successful: RefreshTable }); | |||
} | |||
/** | |||
* 人员删除 | |||
* @param ids id数组 | |||
*/ | |||
async function onDelete(ids: string[], msg: string) { | |||
if(ids.length === 0){ | |||
ElMessage({ | |||
message: '请选择要删除的人员', | |||
type: 'warning' | |||
}); | |||
return | |||
} | |||
// 二次确认 => 请求api => 刷新表格 | |||
await useHandleData(userManageKeyPersonApi.delete, {id: ids.join(",") }, msg); | |||
RefreshTable(); //刷新表格 | |||
} | |||
// 刷新表格 | |||
const RefreshTable = () => { | |||
proTable.value?.refresh(); | |||
} | |||
/** 更多下拉菜单命令枚举 */ | |||
enum cmdEnum { | |||
AddFace = "添加人脸", | |||
} | |||
/** 下拉菜单参数接口 */ | |||
interface Command { | |||
row: SysUserPersonnel.SysUserPerInfo; | |||
command: cmdEnum; | |||
} | |||
/**配置command的参数 */ | |||
function command(row: SysUserPersonnel.SysUserPerInfo, command: cmdEnum): Command { | |||
return { | |||
row: row, | |||
command: command | |||
}; | |||
} | |||
/** | |||
* 列表更多下拉菜单点击事件 | |||
* @param command | |||
*/ | |||
const personId = ref<number | string>(); //人员id | |||
function handleCommand(command: Command) { | |||
switch (command.command) { | |||
case cmdEnum.AddFace: | |||
personId.value = command.row.personId; //获取人员id | |||
break | |||
} | |||
} | |||
const handleAvatarSuccess: UploadProps["onSuccess"] = (response) => { | |||
if (response.code === 200) { | |||
userManageKeyPersonApi.addFace({ | |||
personId: personId.value, | |||
faceUrl: response.data | |||
}).then(res=>{ | |||
RefreshTable() | |||
}) | |||
} else { | |||
ElMessage.error(response.msg); | |||
} | |||
}; | |||
</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> |
@@ -75,7 +75,7 @@ | |||
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 type { UploadProps } from "element-plus"; | |||
import { ElMessage } from "element-plus"; | |||
import { TokenEnum } from "@/enums"; | |||
// props | |||
@@ -92,12 +92,12 @@ const userInfo = computed({ | |||
/* */ | |||
const userStore = useUserStore(); | |||
const { accessToken } = userStore; | |||
const fileList = ref([]); | |||
const fileList = ref<any>([]); | |||
const faces = ref<SysUserPersonnel.SysUserAvatar[]>([]); | |||
const dialogImageUrl = ref(""); | |||
const dialogVisible = ref(false); | |||
const treeData = ref<{ [key: string]: any }[]>([]); | |||
const handleRemove: UploadProps["onRemove"] = uploadFile => { | |||
const treeData = ref<any>([]); | |||
const handleRemove: UploadProps["onRemove"] = (uploadFile: any) => { | |||
const index = faces.value.findIndex(item => item.uid === uploadFile.uid); | |||
if (index > -1) { | |||
faces.value.splice(index, 1); | |||
@@ -143,7 +143,6 @@ const genderOptions = ref([ | |||
const getRequestData = async () => { | |||
const { data } = await userManageClassManageApi.page(); | |||
treeData.value = data; | |||
console.log(treeData.value, "treeData"); | |||
}; | |||
onMounted(() => { | |||
// 初始化 | |||
@@ -152,7 +151,7 @@ onMounted(() => { | |||
if (userInfo.value.personId) { | |||
if (userInfo.value.faces?.length > 0) { | |||
fileList.value = [ | |||
...JSON.parse(JSON.stringify(userInfo.value.faces)).map(item => { | |||
...JSON.parse(JSON.stringify(userInfo.value.faces)).map((item: any) => { | |||
return { | |||
url: item.faceUrl, | |||
uid: item.faceId, | |||
@@ -161,7 +160,7 @@ onMounted(() => { | |||
}) | |||
]; | |||
faces.value = [ | |||
...JSON.parse(JSON.stringify(userInfo.value.faces)).map(item => { | |||
...JSON.parse(JSON.stringify(userInfo.value.faces)).map((item: any) => { | |||
return { | |||
faceUrl: item.faceUrl, | |||
uid: item.faceId, | |||
@@ -0,0 +1,116 @@ | |||
<!-- | |||
* @Description: 表单 | |||
* @Author: syy | |||
* @Date: 2023-12-15 15:45:59 | |||
--> | |||
<template> | |||
<div> | |||
<form-container v-model="visibleClass" :title="`${sysUserProps.opt}`" form-size="400px" @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="22"> | |||
<s-form-item label="班主任" prop="userId"> | |||
<s-select v-model="sysUserProps.record.userId" :options="teacherData" label="name" value="userId"></s-select> | |||
</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="SysUserPerformClass"> | |||
import { ref } from "vue"; | |||
import { SysUserPersonnel, userManageTeacherApi } from "@/api"; | |||
import { required } from "@/utils/formRules"; | |||
import { FormInstance } from "element-plus"; | |||
const teacherData = ref<any>([]); | |||
const visibleClass = ref(false); //是否显示表单 | |||
// 表单参数 | |||
enum FormOptEnum { | |||
/** 新增 */ | |||
AddTeacher = "绑定班主任", | |||
/** 编辑 */ | |||
UpdateTeacher = "修改班主任" | |||
} | |||
const sysUserProps = reactive<FormProps.Base<SysUserPersonnel.ClassPage>>({ | |||
opt: FormOptEnum.AddTeacher, | |||
record: {}, | |||
disabled: false | |||
}); | |||
// 表单验证规则 | |||
const rules = reactive({ | |||
userId: [required("请选择班主任名称")] | |||
}); | |||
/** | |||
* 打开表单 | |||
* @param props 表单参数 | |||
*/ | |||
function onOpen(props: FormProps.Base<SysUserPersonnel.ClassPage>) { | |||
getRequestData(); | |||
Object.assign(sysUserProps, props); //合并参数 | |||
visibleClass.value = true; //显示表单 | |||
sysUserProps.record = props.record; | |||
} | |||
const getRequestData = async () => { | |||
const { data } = await userManageTeacherApi.page(); | |||
teacherData.value = data; | |||
}; | |||
// 提交数据(新增/编辑) | |||
const sysUserFormRef = ref<FormInstance>(); | |||
/** 提交表单 */ | |||
async function handleSubmit() { | |||
sysUserFormRef.value?.validate(async valid => { | |||
if (!valid) return; //表单验证失败 | |||
console.log(sysUserProps); | |||
//提交表单 | |||
if (sysUserProps.opt === FormOptEnum.UpdateTeacher) { | |||
await userManageTeacherApi | |||
.update(sysUserProps.record) | |||
.then(() => { | |||
sysUserProps.successful!(); //调用父组件的successful方法 | |||
}) | |||
.finally(() => { | |||
onClose(); | |||
}); | |||
} else { | |||
await userManageTeacherApi | |||
.add(sysUserProps.record) | |||
.then(() => { | |||
sysUserProps.successful!(); //调用父组件的successful方法 | |||
}) | |||
.finally(() => { | |||
onClose(); | |||
}); | |||
} | |||
}); | |||
} | |||
/** 关闭表单*/ | |||
function onClose() { | |||
visibleClass.value = false; | |||
} | |||
// 暴露给父组件的方法 | |||
defineExpose({ | |||
onOpen | |||
}); | |||
</script> | |||
<style lang="scss" scoped></style> |
@@ -10,7 +10,7 @@ | |||
label="personSetName" | |||
id="personSetId" | |||
width="300px" | |||
:show-all="false" | |||
:show-all="true" | |||
:request-api="userManageClassManageApi.page" | |||
@change="changeTreeFilter" | |||
> | |||
@@ -20,13 +20,31 @@ | |||
<template v-slot:label="{ row }"> | |||
<span class="custom-tree-node"> | |||
<span>{{ row.node.label }}</span> | |||
<span> | |||
<a @click="addClass(FormOptEnum.EDIT, row.node.data)"> | |||
<span v-if="row.node.label != '全部'"> | |||
<a @click.stop="addClass(FormOptEnum.EDIT, row.node.data)"> | |||
<el-icon><Edit /></el-icon> | |||
</a> | |||
<a style="margin-left: 8px" @click="addDelete(row.node.data.personSetId, '删除班级')"> | |||
<a style="margin-left: 8px" @click.stop="addDelete(row.node.data.personSetId, '删除班级')"> | |||
<el-icon><Delete /></el-icon> | |||
</a> | |||
<a style="margin-left: 8px" @click.stop> | |||
<el-dropdown @command="handleCommandTree"> | |||
<el-link :underline="false" :icon="More"> </el-link> | |||
<template #dropdown> | |||
<el-dropdown-menu> | |||
<el-dropdown-item v-if="!row.node.data.userId" :command="commander(row.node.data, cmdEnumTree.AddTeacher)"> | |||
{{ cmdEnumTree.AddTeacher }} | |||
</el-dropdown-item> | |||
<el-dropdown-item v-if="row.node.data.userId" :command="commander(row.node.data, cmdEnumTree.UpdateTeacher)"> | |||
{{ cmdEnumTree.UpdateTeacher }} | |||
</el-dropdown-item> | |||
<el-dropdown-item v-if="row.node.data.userId" :command="commander(row.node.data, cmdEnumTree.DeleteTeacher)"> | |||
{{ cmdEnumTree.DeleteTeacher }} | |||
</el-dropdown-item> | |||
</el-dropdown-menu> | |||
</template> | |||
</el-dropdown> | |||
</a> | |||
</span> | |||
</span> | |||
</template> | |||
@@ -86,6 +104,8 @@ | |||
<Form ref="formRef"></Form> | |||
<!-- 班级新增/编辑表单 --> | |||
<FormClass ref="formRefC" /> | |||
<!-- 班主任绑定/修改 --> | |||
<FormTeacher ref="formRefT" /> | |||
<!-- 预览头像 --> | |||
<el-dialog v-model="visible" title="查看头像" width="830px" :before-close="handleClose"> | |||
<div style="display: flex; align-items: center; justify-content: center"> | |||
@@ -95,12 +115,13 @@ | |||
</div> | |||
</template> | |||
<script setup lang="tsx" name="SysUserPersonnel"> | |||
import { userManagePersonnelApi,userPerButtonCode,SysUserPersonnel,userManageClassManageApi } from "@/api"; | |||
import { userManagePersonnelApi,userPerButtonCode,SysUserPersonnel,userManageClassManageApi,userManageTeacherApi } from "@/api"; | |||
import { useHandleData } from "@/hooks/useHandleData"; | |||
import { FormOptEnum } from "@/enums"; | |||
import Form from "./components/form/index.vue"; | |||
import FormClass from "./components/formClass/index.vue"; | |||
import { ArrowDown } from "@element-plus/icons-vue"; | |||
import FormTeacher from "./components/formTeacher/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 { useUserStore } from "@/stores/modules"; | |||
@@ -134,8 +155,8 @@ const columns: ColumnProps<SysUserPersonnel.SysUserPerInfo>[] = [ | |||
label: "人员ID" | |||
}, | |||
{ | |||
prop: "age", | |||
label: "年龄" | |||
prop: "phone", | |||
label: "手机号" | |||
}, | |||
{ | |||
prop: "personSets", | |||
@@ -158,8 +179,11 @@ const handleClose = () => { | |||
// 人员表单引用 | |||
const formRef = ref<InstanceType<typeof Form> | null>(null); | |||
// 班级表单引用 | |||
// 班级表单引用 | |||
const formRefC = ref<InstanceType<typeof FormClass> | null>(null); | |||
// 班级表单引用 | |||
const formRefT = ref<InstanceType<typeof FormTeacher> | null>(null); | |||
/** | |||
* 打开表单 | |||
* @param opt 操作类型 | |||
@@ -176,7 +200,7 @@ function onOpen(opt: FormOptEnum, record: {} | SysUserPersonnel.SysUserPerInfo = | |||
*/ | |||
function addClass(opt: FormOptEnum, record: {} | SysUserPersonnel.ClassPage = {}) { | |||
formRefC.value?.onOpen({ opt: opt, record: record, successful: RefreshTable }); | |||
formRefC.value?.onOpen({ opt: opt, record: JSON.parse(JSON.stringify(record)), successful: RefreshTable }); | |||
} | |||
/** | |||
* 班级删除 | |||
@@ -231,11 +255,11 @@ function command(row: SysUserPersonnel.SysUserPerInfo, command: cmdEnum): Comman | |||
}; | |||
} | |||
/** | |||
* 更多下拉菜单点击事件 | |||
* 列表更多下拉菜单点击事件 | |||
* @param command | |||
*/ | |||
const personId = ref<number | string>(); //人员id | |||
function handleCommand(command: Command) { | |||
const personId = ref<number | string>(); //人员id | |||
function handleCommand(command: Command) { | |||
switch (command.command) { | |||
case cmdEnum.AddFace: | |||
personId.value = command.row.personId; //获取人员id | |||
@@ -245,15 +269,57 @@ function command(row: SysUserPersonnel.SysUserPerInfo, command: cmdEnum): Comman | |||
personId:command.row.personId, | |||
personSetId: command.row.personSets[0].personSetId | |||
}).then(res=>{ | |||
if(res.code == 200){ | |||
ElMessage.success('底库解绑成功'); | |||
RefreshTable() | |||
} | |||
}) | |||
break; | |||
} | |||
} | |||
const handleAvatarSuccess: UploadProps["onSuccess"] = (response, uploadFile) => { | |||
/** 更多下拉菜单命令枚举 */ | |||
enum cmdEnumTree { | |||
AddTeacher = "绑定班主任", | |||
UpdateTeacher = "修改班主任", | |||
DeleteTeacher = "解绑班主任", | |||
} | |||
/** 树下拉菜单参数接口 */ | |||
interface CommandTree { | |||
row: SysUserPersonnel.ClassPage; | |||
commander: cmdEnumTree; | |||
} | |||
/**配置command的参数 */ | |||
function commander(row: SysUserPersonnel.ClassPage, commander: cmdEnumTree): CommandTree { | |||
return { | |||
row: row, | |||
commander: commander, | |||
}; | |||
} | |||
/** | |||
* 树更多下拉菜单点击事件 | |||
* @param commandtree | |||
*/ | |||
async function handleCommandTree(commander: CommandTree) { | |||
switch (commander.commander) { | |||
case cmdEnumTree.AddTeacher: | |||
formRefT.value?.onOpen({ opt: commander.commander, record: commander.row, successful: RefreshTable }); | |||
break | |||
case cmdEnumTree.UpdateTeacher: | |||
formRefT.value?.onOpen({ opt: commander.commander, record: commander.row, successful: RefreshTable }); | |||
break; | |||
case cmdEnumTree.DeleteTeacher: | |||
// 二次确认 => 请求api => 刷新表格 | |||
await useHandleData(userManageTeacherApi.delete, {id: commander.row.id}, '解绑教师'); | |||
RefreshTable(); //刷新表格 | |||
break; | |||
} | |||
} | |||
const handleAvatarSuccess: UploadProps["onSuccess"] = (response) => { | |||
if (response.code === 200) { | |||
userManagePersonnelApi.addFace({ | |||
personId: personId.value, | |||