| | |
| | | <template> |
| | | <ElDialog |
| | | v-model="dialogVisible" |
| | | :title="dialogType === 'add' ? '添加用户' : '编辑用户'" |
| | | width="30%" |
| | | :title="dialogTitle" |
| | | :model-value="visible" |
| | | @update:model-value="handleCancel" |
| | | width="960px" |
| | | align-center |
| | | class="user-dialog" |
| | | @closed="handleClosed" |
| | | > |
| | | <ElForm ref="formRef" :model="formData" :rules="rules" label-width="80px"> |
| | | <ElFormItem label="用户名" prop="username"> |
| | | <ElInput v-model="formData.username" placeholder="请输入用户名" /> |
| | | </ElFormItem> |
| | | <ElFormItem label="手机号" prop="phone"> |
| | | <ElInput v-model="formData.phone" placeholder="请输入手机号" /> |
| | | </ElFormItem> |
| | | <ElFormItem label="性别" prop="gender"> |
| | | <ElSelect v-model="formData.gender"> |
| | | <ElOption label="男" value="男" /> |
| | | <ElOption label="女" value="女" /> |
| | | </ElSelect> |
| | | </ElFormItem> |
| | | <ElFormItem label="角色" prop="role"> |
| | | <ElSelect v-model="formData.role" multiple> |
| | | <ElOption |
| | | v-for="role in roleList" |
| | | :key="role.roleCode" |
| | | :value="role.roleCode" |
| | | :label="role.roleName" |
| | | /> |
| | | </ElSelect> |
| | | </ElFormItem> |
| | | </ElForm> |
| | | <ArtForm |
| | | ref="formRef" |
| | | v-model="form" |
| | | :items="formItems" |
| | | :rules="rules" |
| | | :span="12" |
| | | :gutter="20" |
| | | label-width="110px" |
| | | :show-reset="false" |
| | | :show-submit="false" |
| | | /> |
| | | |
| | | <template #footer> |
| | | <div class="dialog-footer"> |
| | | <ElButton @click="dialogVisible = false">取消</ElButton> |
| | | <ElButton type="primary" @click="handleSubmit">提交</ElButton> |
| | | </div> |
| | | <span class="dialog-footer"> |
| | | <ElButton @click="handleCancel">取消</ElButton> |
| | | <ElButton type="primary" @click="handleSubmit">确定</ElButton> |
| | | </span> |
| | | </template> |
| | | </ElDialog> |
| | | </template> |
| | | |
| | | <script setup> |
| | | import { ROLE_LIST_DATA } from '@/mock/temp/formData' |
| | | import ArtForm from '@/components/core/forms/art-form/index.vue' |
| | | import { buildUserDialogModel, createUserFormState } from '../userPage.helpers' |
| | | |
| | | const props = defineProps({ |
| | | visible: { required: true }, |
| | | type: { required: true }, |
| | | userData: { required: false } |
| | | visible: { required: false, default: false }, |
| | | type: { required: false, default: 'add' }, |
| | | userData: { required: false, default: () => ({}) }, |
| | | roleOptions: { required: false, default: () => [] }, |
| | | deptTreeOptions: { required: false, default: () => [] } |
| | | }) |
| | | |
| | | const emit = defineEmits(['update:visible', 'submit']) |
| | | const roleList = ref(ROLE_LIST_DATA) |
| | | const dialogVisible = computed({ |
| | | get: () => props.visible, |
| | | set: (value) => emit('update:visible', value) |
| | | }) |
| | | const dialogType = computed(() => props.type) |
| | | const formRef = ref() |
| | | const formData = reactive({ |
| | | username: '', |
| | | phone: '', |
| | | gender: '男', |
| | | role: [] |
| | | }) |
| | | const rules = { |
| | | username: [ |
| | | { required: true, message: '请输入用户名', trigger: 'blur' }, |
| | | { min: 2, max: 20, message: '长度在 2 到 20 个字符', trigger: 'blur' } |
| | | ], |
| | | phone: [ |
| | | { required: true, message: '请输入手机号', trigger: 'blur' }, |
| | | { pattern: /^1[3-9]\d{9}$/, message: '请输入正确的手机号格式', trigger: 'blur' } |
| | | ], |
| | | gender: [{ required: true, message: '请选择性别', trigger: 'blur' }], |
| | | role: [{ required: true, message: '请选择角色', trigger: 'blur' }] |
| | | const form = reactive(createUserFormState()) |
| | | |
| | | const isEdit = computed(() => props.type === 'edit') |
| | | const dialogTitle = computed(() => (isEdit.value ? '编辑用户' : '新增用户')) |
| | | |
| | | const validatePassword = (_rule, value, callback) => { |
| | | if (!isEdit.value && !value) { |
| | | callback(new Error('请输入密码')) |
| | | return |
| | | } |
| | | if (value && String(value).length < 6) { |
| | | callback(new Error('密码长度至少 6 位')) |
| | | return |
| | | } |
| | | callback() |
| | | } |
| | | const initFormData = () => { |
| | | const isEdit = props.type === 'edit' && props.userData |
| | | const row = props.userData |
| | | Object.assign(formData, { |
| | | username: isEdit && row ? row.userName || '' : '', |
| | | phone: isEdit && row ? row.userPhone || '' : '', |
| | | gender: isEdit && row ? row.userGender || '男' : '男', |
| | | role: isEdit && row ? (Array.isArray(row.userRoles) ? row.userRoles : []) : [] |
| | | }) |
| | | |
| | | const validateConfirmPassword = (_rule, value, callback) => { |
| | | if (!form.password && !value && isEdit.value) { |
| | | callback() |
| | | return |
| | | } |
| | | if (!value) { |
| | | callback(new Error('请再次输入密码')) |
| | | return |
| | | } |
| | | if (value !== form.password) { |
| | | callback(new Error('两次输入的密码不一致')) |
| | | return |
| | | } |
| | | callback() |
| | | } |
| | | |
| | | const rules = computed(() => ({ |
| | | username: [{ required: true, message: '请输入用户名', trigger: 'blur' }], |
| | | nickname: [{ required: true, message: '请输入昵称', trigger: 'blur' }], |
| | | roleIds: [{ type: 'array', required: true, message: '请选择角色', trigger: 'change' }], |
| | | password: [{ validator: validatePassword, trigger: 'blur' }], |
| | | confirmPassword: [{ validator: validateConfirmPassword, trigger: 'blur' }] |
| | | })) |
| | | |
| | | const formItems = computed(() => [ |
| | | { |
| | | label: '用户名', |
| | | key: 'username', |
| | | type: 'input', |
| | | props: { |
| | | placeholder: '请输入用户名', |
| | | clearable: true |
| | | } |
| | | }, |
| | | { |
| | | label: '昵称', |
| | | key: 'nickname', |
| | | type: 'input', |
| | | props: { |
| | | placeholder: '请输入昵称', |
| | | clearable: true |
| | | } |
| | | }, |
| | | { |
| | | label: '部门', |
| | | key: 'deptId', |
| | | type: 'treeselect', |
| | | props: { |
| | | data: props.deptTreeOptions, |
| | | props: { |
| | | label: 'label', |
| | | value: 'value', |
| | | children: 'children' |
| | | }, |
| | | placeholder: '请选择部门', |
| | | clearable: true, |
| | | checkStrictly: true |
| | | } |
| | | }, |
| | | { |
| | | label: '角色', |
| | | key: 'roleIds', |
| | | type: 'select', |
| | | props: { |
| | | placeholder: '请选择角色', |
| | | clearable: true, |
| | | multiple: true, |
| | | collapseTags: true, |
| | | filterable: true, |
| | | options: props.roleOptions |
| | | } |
| | | }, |
| | | { |
| | | label: '密码', |
| | | key: 'password', |
| | | type: 'input', |
| | | props: { |
| | | type: 'password', |
| | | showPassword: true, |
| | | placeholder: isEdit.value ? '不修改则留空' : '请输入密码', |
| | | clearable: true |
| | | } |
| | | }, |
| | | { |
| | | label: '确认密码', |
| | | key: 'confirmPassword', |
| | | type: 'input', |
| | | props: { |
| | | type: 'password', |
| | | showPassword: true, |
| | | placeholder: '请再次输入密码', |
| | | clearable: true |
| | | } |
| | | }, |
| | | { |
| | | label: '性别', |
| | | key: 'sex', |
| | | type: 'select', |
| | | props: { |
| | | placeholder: '请选择性别', |
| | | clearable: true, |
| | | options: [ |
| | | { label: '未知', value: 0 }, |
| | | { label: '男', value: 1 }, |
| | | { label: '女', value: 2 } |
| | | ] |
| | | } |
| | | }, |
| | | { |
| | | label: '工号', |
| | | key: 'code', |
| | | type: 'input', |
| | | props: { |
| | | placeholder: '请输入工号', |
| | | clearable: true |
| | | } |
| | | }, |
| | | { |
| | | label: '手机号', |
| | | key: 'phone', |
| | | type: 'input', |
| | | props: { |
| | | placeholder: '请输入手机号', |
| | | clearable: true |
| | | } |
| | | }, |
| | | { |
| | | label: '邮箱', |
| | | key: 'email', |
| | | type: 'input', |
| | | props: { |
| | | placeholder: '请输入邮箱', |
| | | clearable: true |
| | | } |
| | | }, |
| | | { |
| | | label: '真实姓名', |
| | | key: 'realName', |
| | | type: 'input', |
| | | props: { |
| | | placeholder: '请输入真实姓名', |
| | | clearable: true |
| | | } |
| | | }, |
| | | { |
| | | label: '身份证号', |
| | | key: 'idCard', |
| | | type: 'input', |
| | | props: { |
| | | placeholder: '请输入身份证号', |
| | | clearable: true |
| | | } |
| | | }, |
| | | { |
| | | label: '状态', |
| | | key: 'status', |
| | | type: 'select', |
| | | props: { |
| | | placeholder: '请选择状态', |
| | | clearable: true, |
| | | options: [ |
| | | { label: '正常', value: 1 }, |
| | | { label: '禁用', value: 0 } |
| | | ] |
| | | } |
| | | }, |
| | | { |
| | | label: '备注', |
| | | key: 'memo', |
| | | type: 'input', |
| | | props: { |
| | | type: 'textarea', |
| | | rows: 3, |
| | | placeholder: '请输入备注', |
| | | clearable: true |
| | | }, |
| | | span: 24 |
| | | } |
| | | ]) |
| | | |
| | | const resetForm = () => { |
| | | Object.assign(form, createUserFormState()) |
| | | formRef.value?.clearValidate?.() |
| | | } |
| | | |
| | | const loadFormData = () => { |
| | | Object.assign(form, buildUserDialogModel(props.userData)) |
| | | } |
| | | |
| | | const handleSubmit = async () => { |
| | | if (!formRef.value) return |
| | | try { |
| | | await formRef.value.validate() |
| | | emit('submit', { ...form }) |
| | | } catch { |
| | | return |
| | | } |
| | | } |
| | | |
| | | const handleCancel = () => { |
| | | emit('update:visible', false) |
| | | } |
| | | |
| | | const handleClosed = () => { |
| | | resetForm() |
| | | } |
| | | |
| | | watch( |
| | | () => [props.visible, props.type, props.userData], |
| | | ([visible]) => { |
| | | () => props.visible, |
| | | (visible) => { |
| | | if (visible) { |
| | | initFormData() |
| | | loadFormData() |
| | | nextTick(() => { |
| | | formRef.value?.clearValidate() |
| | | formRef.value?.clearValidate?.() |
| | | }) |
| | | } |
| | | }, |
| | | { immediate: true } |
| | | ) |
| | | const handleSubmit = async () => { |
| | | if (!formRef.value) return |
| | | await formRef.value.validate((valid) => { |
| | | if (valid) { |
| | | ElMessage.success(dialogType.value === 'add' ? '添加成功' : '更新成功') |
| | | dialogVisible.value = false |
| | | emit('submit') |
| | | |
| | | watch( |
| | | () => props.userData, |
| | | () => { |
| | | if (props.visible) { |
| | | loadFormData() |
| | | } |
| | | }) |
| | | } |
| | | }, |
| | | { deep: true } |
| | | ) |
| | | |
| | | watch( |
| | | () => props.type, |
| | | () => { |
| | | if (props.visible) { |
| | | loadFormData() |
| | | } |
| | | } |
| | | ) |
| | | </script> |