1、表单以及表单对应类型更改

This commit is contained in:
汪圳
2025-12-05 14:06:04 +08:00
parent 39733a0107
commit 14c3197dca

View File

@@ -172,65 +172,219 @@
:size="drawerSize"
@close="handleCloseDialog"
>
<el-form ref="userFormRef" :model="formData" :rules="rules" label-width="80px">
<el-form-item label="用户名" prop="username">
<el-form ref="userFormRef" :model="formData" :rules="rules" label-width="120px">
<el-form-item label="名" prop="username">
<el-input
v-model="formData.username"
:readonly="!!formData.id"
placeholder="请输入用户名"
placeholder="请输入名"
/>
</el-form-item>
<el-form-item label="用户昵称" prop="nickname">
<el-input v-model="formData.nickname" placeholder="请输入用户昵称" />
<el-form-item label="民族" prop="nationality">
<el-input
v-model="formData.nationality"
:readonly="!!formData.nationality"
placeholder="请输入民族"
/>
</el-form-item>
<el-form-item label="身份证号码" prop="idCard">
<el-input
v-model="formData.idCard"
:readonly="!!formData.idCard"
placeholder="请输入身份证号码"
maxlength="18"
/>
</el-form-item>
<el-form-item label="手机号" prop="mobile">
<el-input
v-model="formData.mobile"
:readonly="!!formData.mobile"
placeholder="请输入手机号"
maxlength="11"
/>
</el-form-item>
<el-form-item label="所属部门" prop="deptId">
<el-tree-select
<el-select
v-model="formData.deptId"
placeholder="请选择所属部门"
:data="deptOptions"
filterable
check-strictly
:render-after-expand="false"
/>
</el-form-item>
<el-form-item label="性别" prop="gender">
<Dict v-model="formData.gender" code="gender" />
</el-form-item>
<el-form-item label="角色" prop="roleIds">
<el-select v-model="formData.roleIds" multiple placeholder="请选择">
<el-option
v-for="item in roleOptions"
:key="item.value"
:label="item.label"
:value="item.value"
/>
:readonly="!!formData.deptId"
>
<el-option key="行政部" label="行政部" value="行政部" />
<el-option key="财务部" label="财务部" value="财务部" />
<el-option key="执业律师" label="执业律师" value="执业律师" />
<el-option key="实习律师" label="实习律师" value="实习律师" />
</el-select>
</el-form-item>
<el-form-item label="手机号码" prop="mobile">
<el-input v-model="formData.mobile" placeholder="请输入手机号码" maxlength="11" />
<el-form-item label="岗位" prop="roleIds">
<el-select
v-model="formData.roleIds"
placeholder="请选择所属部门"
:readonly="!!formData.roleIds"
>
<el-option key="助理" label="助理" value="助理" />
<el-option key="独立律师" label="独立律师" value="独立律师" />
<el-option key="一级主办律师" label="一级主办律师" value="一级主办律师" />
<el-option key="中级主办律师" label="中级主办律师" value="中级主办律师" />
<el-option key="高级主办律师" label="高级主办律师" value="高级主办律师" />
<el-option key="合伙人" label="合伙人" value="合伙人" />
<el-option key="已离职" label="已离职" value="已离职" />
</el-select>
</el-form-item>
<el-form-item label="邮箱" prop="email">
<el-input v-model="formData.email" placeholder="请输入邮箱" maxlength="50" />
<el-form-item label="所属团队" prop="teamIds">
<el-select
v-model="formData.teamIds"
placeholder="请选择所属团队"
:readonly="!!formData.teamIds"
>
<el-option key="团队一" label="团队一" value="团队一" />
<el-option key="团队二" label="团队二" value="团队二" />
<el-option key="团队三" label="团队三" value="团队三" />
</el-select>
</el-form-item>
<el-form-item label="状态" prop="status">
<el-switch
v-model="formData.status"
inline-prompt
active-text="正常"
inactive-text="禁用"
:active-value="1"
:inactive-value="0"
<el-form-item label="入职时间" prop="hiredDate">
<el-date-picker
v-model="formData.hiredDate"
type="date"
value-format="YYYY-MM-DD"
placeholder="请选择入职时间"
/>
</el-form-item>
<el-form-item label="转正时间" prop="promotionDate">
<el-date-picker
v-model="formData.promotionDate"
type="date"
value-format="YYYY-MM-DD"
placeholder="请选择转正时间"
/>
</el-form-item>
<el-form-item label="执业证时间" prop="licenseDate">
<el-date-picker
v-model="formData.licenseDate"
type="date"
value-format="YYYY-MM"
placeholder="请选择执业证时间"
/>
</el-form-item>
<el-form-item label="离职时间" prop="resignationDate">
<el-date-picker
v-model="formData.resignationDate"
type="date"
value-format="YYYY-MM-DD"
placeholder="请选择离职时间"
/>
</el-form-item>
<el-form-item label="学业简历" prop="educationResume">
<!-- 学业简历表格样式布局 -->
<div class="education-resume-table">
<!-- 表头 -->
<div class="education-resume-header">
<div class="table-col date-col">日期区间</div>
<div class="table-col school-col">毕业院校</div>
<div class="table-col major-col">专业</div>
<div class="table-col degree-col">学历</div>
<div class="table-col action-col">操作</div>
</div>
<!-- 表体 -->
<div
v-for="(item, index) in formData.educationResume"
:key="index"
class="education-resume-row"
>
<div class="table-col date-col">
<el-date-picker
v-model="item.education"
type="datetimerange"
start-placeholder="开始时间"
end-placeholder="结业时间"
format="YYYY-MM-DD"
value-format="YYYY-MM-DD"
/>
</div>
<div class="table-col school-col">
<el-input v-model="item.institute" placeholder="请输入毕业院校" />
</div>
<div class="table-col major-col">
<el-input v-model="item.major" placeholder="请输入专业" />
</div>
<div class="table-col degree-col">
<el-select v-model="item.educationLevel" placeholder="请选择学历">
<el-option key="高中" label="高中" value="高中" />
<el-option key="大专" label="大专" value="大专" />
<el-option key="本科" label="本科" value="本科" />
<el-option key="硕士" label="硕士" value="硕士" />
<el-option key="博士" label="博士" value="博士" />
</el-select>
</div>
<div class="table-col action-col">
<el-button type="danger" @click="handleDelete(index)">删除</el-button>
</div>
</div>
</div>
<!-- 添加按钮 -->
<div class="education-resume-actions">
<el-button type="primary" @click="handleAddEducationResume">添加教育经历</el-button>
</div>
</el-form-item>
<el-form-item label="学历证书" prop="educationLevel">
<el-upload
class="avatar-uploader"
action="#"
:show-file-list="false"
:on-success="(res, file: File) => handleFileUploadSuccess(res, file, 'educationLevel')"
:before-upload="handleBeforeUpload"
>
<div v-if="formData.educationLevel" class="upload-preview">
<el-link :href="formData.educationLevel" target="_blank" type="primary">
查看学历证书
</el-link>
<el-button type="danger" size="small" @click.stop="removeFile('educationLevel')">
删除
</el-button>
</div>
<el-button v-else size="small" type="primary">点击上传</el-button>
</el-upload>
</el-form-item>
<el-form-item label="劳动合同" prop="contractResume">
<el-upload
class="avatar-uploader"
action="#"
:show-file-list="false"
:on-success="(res, file: File) => handleFileUploadSuccess(res, file, 'contractResume')"
:before-upload="handleBeforeUpload"
>
<div v-if="formData.contractResume" class="upload-preview">
<el-link :href="formData.contractResume" target="_blank" type="primary">
查看劳动合同
</el-link>
<el-button type="danger" size="small" @click.stop="removeFile('contractResume')">
删除
</el-button>
</div>
<el-button v-else size="small" type="primary">点击上传</el-button>
</el-upload>
</el-form-item>
<el-form-item label="入职申请表" prop="hiredResume">
<el-upload
class="avatar-uploader"
action="#"
:show-file-list="false"
:on-success="
(res: any, file: File) => handleFileUploadSuccess(res, file, 'hiredResume')
"
:before-upload="handleBeforeUpload"
>
<div v-if="formData.hiredResume" class="upload-preview">
<el-link :href="formData.hiredResume" target="_blank" type="primary">
查看入职申请表
</el-link>
<el-button type="danger" size="small" @click.stop="removeFile('hiredResume')">
删除
</el-button>
</div>
<el-button v-else size="small" type="primary">点击上传</el-button>
</el-upload>
</el-form-item>
</el-form>
<template #footer>
<div class="dialog-footer">
<el-button type="primary" @click="handleSubmit">确 定</el-button>
@@ -258,6 +412,7 @@ import type { UserForm, UserPageQuery, UserPageVO } from "@/api/system/user-api"
import UserAPI from "@/api/system/user-api";
import DeptAPI from "@/api/system/dept-api";
import RoleAPI from "@/api/system/role-api";
import fileApi from "@/api/file-api";
// ==================== 5. Store ====================
import { useAppStore } from "@/store/modules/app-store";
@@ -308,7 +463,17 @@ const dialog = reactive({
// 表单数据
const formData = reactive<UserForm>({
status: 1,
educationResume: [
{
education: [],
// 毕业院校
institute: "",
// 专业
major: "",
// 学历
educationLevel: "",
},
],
});
// 下拉选项数据
@@ -370,6 +535,13 @@ const rules = reactive({
trigger: "blur",
},
],
educationResume: [
{
required: true,
message: "请输入教育经历",
trigger: "blur",
},
],
});
// ==================== 数据加载 ====================
@@ -485,7 +657,6 @@ function handleCloseDialog(): void {
// 重置表单数据
formData.id = undefined;
formData.status = 1;
}
/**
@@ -564,6 +735,43 @@ function handleDelete(id?: string): void {
});
}
// ==================== 上传文件 ====================
/**
* 上传前的校验
* @param file 上传的文件对象
*/
function handleBeforeUpload(file: File): boolean {
// 可以在这里添加文件类型和大小的校验
const isLt10M = file.size / 1024 / 1024 < 10;
if (!isLt10M) {
ElMessage.error("上传文件大小不能超过 10MB!");
return false;
}
return true;
}
/**
* 处理文件上传成功后的回调
* @param res 上传响应数据
* @param file 上传的文件对象
* @param field 表单字段名
*/
function handleFileUploadSuccess(res: any, file: File, field: string): void {
formData[field] = res.data.url;
userFormRef.value.clearValidate(field);
ElMessage.success("文件上传成功");
}
/**
* 删除已上传的文件
* @param field 表单字段名
*/
function removeFile(field: string): void {
formData[field] = undefined;
ElMessage.success("文件已删除");
}
// ==================== 导入导出 ====================
/**
@@ -607,51 +815,6 @@ async function handleExport(): Promise<void> {
}
}
// ==================== AI 助手相关 ====================
useAiAction({
actionHandlers: {
/**
* AI 修改用户昵称
* 使用配置对象方式:自动处理确认、执行、反馈
*/
updateUserNickname: {
needConfirm: true,
callBackendApi: true, // 自动调用后端 API
confirmMessage: (args: any) =>
`AI 助手将执行以下操作:<br/>
<strong>修改用户:</strong> ${args.username}<br/>
<strong>新昵称:</strong> ${args.nickname}<br/><br/>
确认执行吗?`,
successMessage: (args: any) => `已将用户 ${args.username} 的昵称修改为 ${args.nickname}`,
execute: async () => {
// callBackendApi=true 时execute 可以为空
// Composable 会自动调用后端 API
},
},
/**
* AI 查询用户
* 使用配置对象方式:查询操作不需要确认
*/
queryUser: {
needConfirm: false, // 查询操作无需确认
successMessage: (args: any) => `已搜索:${args.keywords}`,
execute: async (args: any) => {
queryParams.keywords = args.keywords;
await handleQuery();
},
},
},
onRefresh: fetchUserList,
onAutoSearch: (keywords: string) => {
queryParams.keywords = keywords;
setTimeout(() => {
handleQuery();
ElMessage.success(`AI 助手已为您自动搜索:${keywords}`);
}, 300);
},
});
// ==================== 生命周期 ====================
/**
@@ -664,3 +827,70 @@ onMounted(() => {
handleQuery();
});
</script>
<!-- 学业简历表格样式 -->
<style scoped>
.education-resume-table {
border: 1px solid #dcdfe6;
border-radius: 4px;
overflow: hidden;
}
.education-resume-header {
display: flex;
background-color: #f5f7fa;
border-bottom: 1px solid #dcdfe6;
font-weight: bold;
padding: 8px 12px;
}
.education-resume-row {
display: flex;
border-bottom: 1px solid #ebeef5;
padding: 12px;
align-items: center;
}
.education-resume-row:last-child {
border-bottom: none;
}
.table-col {
display: flex;
align-items: center;
}
.date-col {
width: 25%;
}
.school-col {
width: 25%;
}
.major-col {
width: 20%;
}
.degree-col {
width: 20%;
}
.action-col {
width: 10%;
justify-content: center;
}
.education-resume-actions {
margin-top: 12px;
display: flex;
justify-content: flex-start;
}
/* 表单元素样式调整 */
.education-resume-row .el-input,
.education-resume-row .el-select,
.education-resume-row .el-date-editor {
width: 100%;
}
</style>