<template>
|
<el-dialog
|
v-model="visible"
|
:title="isEdit ? '编辑员工' : '新增员工'"
|
width="600px"
|
:before-close="handleClose"
|
>
|
<el-form
|
ref="formRef"
|
:model="form"
|
:rules="rules"
|
label-width="100px"
|
label-position="left"
|
>
|
<el-form-item label="员工姓名" prop="name">
|
<el-input
|
v-model="form.name"
|
placeholder="请输入员工姓名"
|
maxlength="50"
|
show-word-limit
|
/>
|
</el-form-item>
|
|
<el-form-item label="联系电话" prop="phone">
|
<el-input
|
v-model="form.phone"
|
placeholder="请输入11位手机号码"
|
maxlength="11"
|
/>
|
</el-form-item>
|
|
<el-form-item label="登录密码" prop="password" v-if="!isEdit">
|
<el-input
|
v-model="form.password"
|
type="password"
|
placeholder="请输入登录密码(6-20位)"
|
maxlength="20"
|
show-password
|
/>
|
</el-form-item>
|
|
<el-form-item label="密码" prop="password" v-if="isEdit">
|
<div style="display: flex; align-items: center; gap: 10px;">
|
<el-input
|
v-model="form.password"
|
type="password"
|
:placeholder="isPasswordModified ? '请输入新密码(6-20位,包含字母和数字)' : '点击重置密码按钮来修改密码'"
|
maxlength="20"
|
show-password
|
:disabled="!isPasswordModified"
|
@focus="handlePasswordFocus"
|
@input="handlePasswordInput"
|
style="flex: 1;"
|
/>
|
<el-button
|
type="primary"
|
size="small"
|
@click="handleResetPassword"
|
>
|
重置密码
|
</el-button>
|
</div>
|
</el-form-item>
|
|
<el-form-item label="员工角色" prop="roleId">
|
<el-select
|
v-model="form.roleId"
|
placeholder="请选择员工角色"
|
style="width: 100%"
|
:loading="rolesLoading"
|
>
|
<el-option
|
v-for="role in roles"
|
:key="role.id"
|
:label="role.name"
|
:value="role.code"
|
/>
|
</el-select>
|
</el-form-item>
|
|
<el-form-item label="员工描述" prop="description">
|
<el-input
|
v-model="form.description"
|
type="textarea"
|
:rows="4"
|
placeholder="请输入员工描述信息(可选)"
|
maxlength="500"
|
show-word-limit
|
/>
|
</el-form-item>
|
</el-form>
|
|
<template #footer>
|
<div class="dialog-footer">
|
<el-button @click="handleClose">取消</el-button>
|
<el-button type="primary" @click="handleSubmit" :loading="submitting">
|
{{ isEdit ? '更新' : '创建' }}
|
</el-button>
|
</div>
|
</template>
|
</el-dialog>
|
</template>
|
|
<script setup lang="ts">
|
import { reactive, ref, computed, watch, onMounted } from 'vue'
|
import { ElMessage, type FormInstance, type FormRules } from 'element-plus'
|
import { employeeApi, type Employee, type EmployeeInput } from '@/api/employee'
|
import { roleApi, type Role } from '@/api/role'
|
|
interface Props {
|
visible: boolean
|
employee?: Employee | null
|
}
|
|
interface Emits {
|
(e: 'update:visible', value: boolean): void
|
(e: 'success'): void
|
}
|
|
const props = withDefaults(defineProps<Props>(), {
|
employee: null
|
})
|
|
const emit = defineEmits<Emits>()
|
|
const formRef = ref<FormInstance>()
|
const submitting = ref(false)
|
const roles = ref<Role[]>([])
|
const rolesLoading = ref(false)
|
|
// 跟踪密码是否被修改
|
const isPasswordModified = ref(false)
|
|
// 计算是否为编辑模式
|
const isEdit = computed(() => !!props.employee?.id)
|
|
// 获取角色列表
|
const fetchRoles = async () => {
|
try {
|
rolesLoading.value = true
|
roles.value = await roleApi.getActiveRoles()
|
} catch (error: any) {
|
ElMessage.error(error.message || '获取角色列表失败')
|
console.error('获取角色列表失败:', error)
|
} finally {
|
rolesLoading.value = false
|
}
|
}
|
|
// 组件挂载时获取角色列表
|
onMounted(() => {
|
fetchRoles()
|
})
|
|
// 表单数据
|
const form = reactive<EmployeeInput>({
|
id: undefined,
|
name: '',
|
phone: '',
|
password: '',
|
roleId: '',
|
description: ''
|
})
|
|
// 表单验证规则
|
const rules: FormRules = {
|
name: [
|
{ required: true, message: '请输入员工姓名', trigger: 'blur' },
|
{ min: 2, max: 50, message: '姓名长度应在2-50个字符之间', trigger: 'blur' }
|
],
|
phone: [
|
{ required: true, message: '请输入联系电话', trigger: 'blur' },
|
{ pattern: /^1[3-9]\d{9}$/, message: '请输入正确的11位手机号码', trigger: 'blur' }
|
],
|
password: [
|
{
|
validator: (rule, value, callback) => {
|
// 编辑模式下,如果是占位符密码且未修改,则跳过验证
|
if (isEdit.value && value === '••••••••' && !isPasswordModified.value) {
|
callback()
|
return
|
}
|
|
if (!value || value.trim() === '') {
|
callback(new Error('请输入登录密码'))
|
} else if (!/^(?=.*[A-Za-z])(?=.*\d)[A-Za-z\d@$!%*?&]{6,}$/.test(value)) {
|
callback(new Error('密码至少6个字符,必须包含字母和数字'))
|
} else {
|
callback()
|
}
|
},
|
trigger: 'blur'
|
}
|
],
|
roleId: [
|
{ required: true, message: '请选择员工角色', trigger: 'change' }
|
]
|
}
|
|
// 监听 visible 变化
|
const visible = computed({
|
get: () => props.visible,
|
set: (value) => emit('update:visible', value)
|
})
|
|
// 重置表单
|
const resetForm = () => {
|
form.id = undefined
|
form.name = ''
|
form.phone = ''
|
form.password = ''
|
form.roleId = ''
|
form.description = ''
|
isPasswordModified.value = false
|
formRef.value?.clearValidate()
|
}
|
|
// 监听员工数据变化,初始化表单
|
watch(() => props.employee, (employee) => {
|
if (employee) {
|
// 编辑模式,填充表单数据
|
form.id = employee.id
|
form.name = employee.name
|
form.phone = employee.phone
|
form.password = '••••••••' // 编辑时显示占位符密码
|
isPasswordModified.value = false // 重置密码修改状态
|
form.roleId = employee.roleId
|
form.description = employee.description || ''
|
} else {
|
// 新增模式,重置表单
|
resetForm()
|
}
|
}, { immediate: true })
|
|
// 关闭对话框
|
const handleClose = () => {
|
visible.value = false
|
resetForm()
|
}
|
|
// 处理密码字段焦点事件
|
const handlePasswordFocus = () => {
|
if (isEdit.value && form.password === '••••••••') {
|
form.password = ''
|
}
|
}
|
|
// 处理密码输入事件
|
const handlePasswordInput = (value: string) => {
|
if (isEdit.value) {
|
isPasswordModified.value = value !== '' && value !== '••••••••'
|
}
|
}
|
|
// 处理重置密码
|
const handleResetPassword = () => {
|
form.password = ''
|
isPasswordModified.value = true
|
ElMessage.success('密码已清空,请输入新密码')
|
}
|
|
// 提交表单
|
const handleSubmit = async () => {
|
if (!formRef.value) return
|
|
try {
|
const valid = await formRef.value.validate()
|
if (!valid) return
|
|
submitting.value = true
|
|
// 准备提交数据
|
const submitData: EmployeeInput = {
|
id: form.id,
|
name: form.name.trim(),
|
phone: form.phone.trim(),
|
roleId: form.roleId,
|
description: form.description?.trim() || undefined
|
}
|
|
// 只有在新建或密码被修改时才包含密码字段
|
if (!isEdit.value || isPasswordModified.value) {
|
submitData.password = form.password
|
}
|
|
await employeeApi.saveEmployee(submitData)
|
|
ElMessage.success(isEdit.value ? '员工信息更新成功' : '员工创建成功')
|
emit('success')
|
handleClose()
|
} catch (error: any) {
|
ElMessage.error(error.message || '操作失败')
|
} finally {
|
submitting.value = false
|
}
|
}
|
</script>
|
|
<style lang="scss" scoped>
|
.dialog-footer {
|
display: flex;
|
justify-content: flex-end;
|
gap: 12px;
|
}
|
|
:deep(.el-form-item__label) {
|
font-weight: 500;
|
}
|
|
:deep(.el-textarea__inner) {
|
resize: vertical;
|
}
|
</style>
|