初始化
This commit is contained in:
363
src/views/system/user/modules/user-operate-dialog.vue
Normal file
363
src/views/system/user/modules/user-operate-dialog.vue
Normal file
@@ -0,0 +1,363 @@
|
||||
<script setup lang="ts">
|
||||
import { computed, nextTick, ref, watch } from 'vue';
|
||||
import { userGenderOptions } from '@/constants/business';
|
||||
import {
|
||||
fetchAssignUserRoles,
|
||||
fetchCreateUser,
|
||||
fetchGetUser,
|
||||
fetchGetUserRoleIds,
|
||||
fetchUpdateUser
|
||||
} from '@/service/api';
|
||||
import { useForm, useFormRules } from '@/hooks/common/form';
|
||||
import { translateOptions } from '@/utils/common';
|
||||
import BusinessFormDialog from '@/components/custom/business-form-dialog.vue';
|
||||
import BusinessFormSection from '@/components/custom/business-form-section.vue';
|
||||
import { $t } from '@/locales';
|
||||
|
||||
defineOptions({ name: 'UserOperateDialog' });
|
||||
|
||||
interface Props {
|
||||
operateType: UI.TableOperateType;
|
||||
userId?: number | null;
|
||||
currentDeptId?: number | null;
|
||||
deptTree: Api.SystemManage.Dept[];
|
||||
postOptions: Api.SystemManage.PostSimple[];
|
||||
roleOptions: Api.SystemManage.RoleSimple[];
|
||||
}
|
||||
|
||||
const props = defineProps<Props>();
|
||||
|
||||
interface Emits {
|
||||
(e: 'submitted', userId?: number): void;
|
||||
}
|
||||
|
||||
const emit = defineEmits<Emits>();
|
||||
|
||||
const visible = defineModel<boolean>('visible', {
|
||||
default: false
|
||||
});
|
||||
|
||||
const { formRef, validate } = useForm();
|
||||
const { createRequiredRule, patternRules } = useFormRules();
|
||||
|
||||
const loading = ref(false);
|
||||
const submitting = ref(false);
|
||||
|
||||
const title = computed(() => {
|
||||
const titles: Record<UI.TableOperateType, string> = {
|
||||
add: $t('page.system.user.addUser'),
|
||||
edit: $t('page.system.user.editUser')
|
||||
};
|
||||
|
||||
return titles[props.operateType];
|
||||
});
|
||||
|
||||
const isEdit = computed(() => props.operateType === 'edit');
|
||||
|
||||
type Model = Api.SystemManage.SaveUserParams & {
|
||||
roleIds: number[];
|
||||
};
|
||||
|
||||
const model = ref<Model>(createDefaultModel());
|
||||
|
||||
const genderOptions = computed(() =>
|
||||
translateOptions(userGenderOptions).map(item => ({
|
||||
...item,
|
||||
value: Number(item.value) as Api.SystemManage.UserGender
|
||||
}))
|
||||
);
|
||||
|
||||
const deptTreeProps = {
|
||||
value: 'id',
|
||||
label: 'name',
|
||||
children: 'children'
|
||||
} as const;
|
||||
|
||||
function createDefaultModel(): Model {
|
||||
return {
|
||||
username: '',
|
||||
nickname: '',
|
||||
remark: '',
|
||||
deptId: props.currentDeptId ?? 0,
|
||||
positionId: null,
|
||||
email: '',
|
||||
mobile: '',
|
||||
sex: 1,
|
||||
avatar: '',
|
||||
password: '',
|
||||
roleIds: []
|
||||
};
|
||||
}
|
||||
|
||||
function getNullableText(value?: string | null) {
|
||||
return value?.trim() || null;
|
||||
}
|
||||
|
||||
const rules = computed(() => {
|
||||
const passwordRules = isEdit.value
|
||||
? []
|
||||
: [createRequiredRule($t('page.system.user.form.password')), patternRules.pwd];
|
||||
|
||||
return {
|
||||
username: [createRequiredRule($t('page.system.user.form.userName')), patternRules.userName],
|
||||
deptId: [createRequiredRule($t('page.system.user.form.deptName'))],
|
||||
positionId: [createRequiredRule($t('page.system.user.form.positionName'))],
|
||||
mobile: getNullableText(model.value.mobile) ? [patternRules.phone] : [],
|
||||
email: getNullableText(model.value.email) ? [patternRules.email] : [],
|
||||
password: passwordRules
|
||||
} satisfies Record<string, App.Global.FormRule[]>;
|
||||
});
|
||||
|
||||
async function handleInitModel() {
|
||||
model.value = createDefaultModel();
|
||||
|
||||
if (!isEdit.value || !props.userId) {
|
||||
return;
|
||||
}
|
||||
|
||||
loading.value = true;
|
||||
|
||||
const [userResult, roleResult] = await Promise.all([fetchGetUser(props.userId), fetchGetUserRoleIds(props.userId)]);
|
||||
|
||||
loading.value = false;
|
||||
|
||||
if (userResult.error) {
|
||||
return;
|
||||
}
|
||||
|
||||
const user = userResult.data;
|
||||
|
||||
model.value = {
|
||||
username: user.username,
|
||||
nickname: user.nickname ?? '',
|
||||
remark: user.remark ?? '',
|
||||
deptId: user.deptId,
|
||||
positionId: user.positionId ?? null,
|
||||
email: user.email ?? '',
|
||||
mobile: user.mobile ?? '',
|
||||
sex: user.sex ?? 0,
|
||||
avatar: user.avatar ?? '',
|
||||
password: '',
|
||||
roleIds: roleResult.error ? [] : roleResult.data
|
||||
};
|
||||
}
|
||||
|
||||
function closeDialog() {
|
||||
visible.value = false;
|
||||
}
|
||||
|
||||
async function handleSubmit() {
|
||||
await validate();
|
||||
|
||||
const payload: Api.SystemManage.SaveUserParams = {
|
||||
username: model.value.username.trim(),
|
||||
nickname: getNullableText(model.value.nickname),
|
||||
remark: getNullableText(model.value.remark),
|
||||
deptId: model.value.deptId,
|
||||
positionId: model.value.positionId,
|
||||
email: getNullableText(model.value.email),
|
||||
mobile: getNullableText(model.value.mobile),
|
||||
sex: model.value.sex,
|
||||
avatar: getNullableText(model.value.avatar)
|
||||
};
|
||||
|
||||
if (!isEdit.value) {
|
||||
payload.password = String(model.value.password ?? '').trim();
|
||||
}
|
||||
|
||||
submitting.value = true;
|
||||
|
||||
let userId = props.userId ?? undefined;
|
||||
|
||||
if (isEdit.value && props.userId) {
|
||||
const result = await fetchUpdateUser({ id: props.userId, ...payload });
|
||||
|
||||
if (result.error) {
|
||||
submitting.value = false;
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
const result = await fetchCreateUser(payload);
|
||||
|
||||
if (result.error) {
|
||||
submitting.value = false;
|
||||
return;
|
||||
}
|
||||
|
||||
userId = result.data;
|
||||
}
|
||||
|
||||
if (userId !== undefined) {
|
||||
const roleResult = await fetchAssignUserRoles({
|
||||
userId,
|
||||
roleIds: model.value.roleIds
|
||||
});
|
||||
|
||||
if (roleResult.error) {
|
||||
submitting.value = false;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
submitting.value = false;
|
||||
|
||||
window.$message?.success(isEdit.value ? $t('common.updateSuccess') : $t('common.addSuccess'));
|
||||
closeDialog();
|
||||
emit('submitted', userId);
|
||||
}
|
||||
|
||||
watch(visible, async value => {
|
||||
if (!value) {
|
||||
return;
|
||||
}
|
||||
|
||||
await handleInitModel();
|
||||
await nextTick();
|
||||
formRef.value?.clearValidate();
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<BusinessFormDialog
|
||||
v-model="visible"
|
||||
:title="title"
|
||||
preset="lg"
|
||||
:loading="loading"
|
||||
:confirm-loading="submitting"
|
||||
max-body-height="70vh"
|
||||
@confirm="handleSubmit"
|
||||
>
|
||||
<ElForm ref="formRef" :model="model" :rules="rules" label-position="top" autocomplete="off">
|
||||
<input class="business-form-autofill-guard" type="text" name="fake-username" autocomplete="username" />
|
||||
<input class="business-form-autofill-guard" type="password" name="fake-password" autocomplete="new-password" />
|
||||
|
||||
<BusinessFormSection :title="$t('page.system.user.sections.basicInfo')">
|
||||
<ElRow :gutter="16">
|
||||
<ElCol :span="12">
|
||||
<ElFormItem :label="$t('page.system.user.userName')" prop="username">
|
||||
<ElInput
|
||||
v-model="model.username"
|
||||
name="system-user-username"
|
||||
autocomplete="off"
|
||||
:placeholder="$t('page.system.user.form.userName')"
|
||||
/>
|
||||
</ElFormItem>
|
||||
</ElCol>
|
||||
<ElCol :span="12">
|
||||
<ElFormItem :label="$t('page.system.user.nickName')" prop="nickname">
|
||||
<ElInput
|
||||
v-model="model.nickname"
|
||||
name="system-user-nickname"
|
||||
autocomplete="off"
|
||||
:placeholder="$t('page.system.user.form.nickName')"
|
||||
/>
|
||||
</ElFormItem>
|
||||
</ElCol>
|
||||
<ElCol v-if="!isEdit" :span="12">
|
||||
<ElFormItem :label="$t('page.system.user.password')" prop="password">
|
||||
<ElInput
|
||||
v-model="model.password"
|
||||
name="system-user-password"
|
||||
show-password
|
||||
autocomplete="new-password"
|
||||
:placeholder="$t('page.system.user.form.password')"
|
||||
/>
|
||||
</ElFormItem>
|
||||
</ElCol>
|
||||
<ElCol :span="12">
|
||||
<ElFormItem :label="$t('page.system.user.userGender')" prop="sex">
|
||||
<ElSelect v-model="model.sex" :placeholder="$t('page.system.user.form.userGender')">
|
||||
<ElOption v-for="{ label, value } in genderOptions" :key="value" :label="label" :value="value" />
|
||||
</ElSelect>
|
||||
</ElFormItem>
|
||||
</ElCol>
|
||||
<ElCol :span="12">
|
||||
<ElFormItem :label="$t('page.system.user.userPhone')" prop="mobile">
|
||||
<ElInput
|
||||
v-model="model.mobile"
|
||||
name="system-user-mobile"
|
||||
autocomplete="off"
|
||||
:placeholder="$t('page.system.user.form.userPhone')"
|
||||
/>
|
||||
</ElFormItem>
|
||||
</ElCol>
|
||||
<ElCol :span="12">
|
||||
<ElFormItem :label="$t('page.system.user.userEmail')" prop="email">
|
||||
<ElInput
|
||||
v-model="model.email"
|
||||
name="system-user-email"
|
||||
autocomplete="off"
|
||||
:placeholder="$t('page.system.user.form.userEmail')"
|
||||
/>
|
||||
</ElFormItem>
|
||||
</ElCol>
|
||||
<ElCol :span="24">
|
||||
<ElFormItem :label="$t('page.system.user.remark')" prop="remark">
|
||||
<ElInput
|
||||
v-model="model.remark"
|
||||
type="textarea"
|
||||
:rows="3"
|
||||
:placeholder="$t('page.system.user.form.remark')"
|
||||
/>
|
||||
</ElFormItem>
|
||||
</ElCol>
|
||||
</ElRow>
|
||||
</BusinessFormSection>
|
||||
|
||||
<BusinessFormSection :title="$t('page.system.user.sections.organizationInfo')">
|
||||
<ElRow :gutter="16">
|
||||
<ElCol :span="12">
|
||||
<ElFormItem :label="$t('page.system.user.deptName')" prop="deptId">
|
||||
<ElTreeSelect
|
||||
v-model="model.deptId"
|
||||
check-strictly
|
||||
clearable
|
||||
default-expand-all
|
||||
:data="deptTree"
|
||||
:props="deptTreeProps"
|
||||
:render-after-expand="false"
|
||||
:placeholder="$t('page.system.user.form.deptName')"
|
||||
/>
|
||||
</ElFormItem>
|
||||
</ElCol>
|
||||
<ElCol :span="12">
|
||||
<ElFormItem :label="$t('page.system.user.positionName')" prop="positionId">
|
||||
<ElSelect v-model="model.positionId" clearable :placeholder="$t('page.system.user.form.positionName')">
|
||||
<ElOption v-for="item in postOptions" :key="item.id" :label="item.name" :value="item.id" />
|
||||
</ElSelect>
|
||||
</ElFormItem>
|
||||
</ElCol>
|
||||
<ElCol :span="12">
|
||||
<ElFormItem :label="$t('page.system.user.userRole')" prop="roleIds">
|
||||
<ElSelect
|
||||
v-model="model.roleIds"
|
||||
multiple
|
||||
collapse-tags
|
||||
collapse-tags-tooltip
|
||||
:placeholder="$t('page.system.user.form.userRole')"
|
||||
>
|
||||
<ElOption v-for="item in roleOptions" :key="item.id" :label="item.name" :value="item.id" />
|
||||
</ElSelect>
|
||||
</ElFormItem>
|
||||
</ElCol>
|
||||
</ElRow>
|
||||
</BusinessFormSection>
|
||||
</ElForm>
|
||||
</BusinessFormDialog>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.business-form-autofill-guard {
|
||||
position: absolute;
|
||||
width: 1px;
|
||||
height: 1px;
|
||||
padding: 0;
|
||||
margin: -1px;
|
||||
overflow: hidden;
|
||||
clip: rect(0, 0, 0, 0);
|
||||
white-space: nowrap;
|
||||
border: 0;
|
||||
opacity: 0;
|
||||
pointer-events: none;
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user