feat(user-management-relation): 创建带人关系页面、编写各组件代码,完善诸多细节

This commit is contained in:
dk
2026-04-10 16:30:42 +08:00
parent b6a50563bc
commit 9b6f5955c3
8 changed files with 1038 additions and 2 deletions

View File

@@ -0,0 +1,316 @@
<script setup lang="ts">
/**
* 用户带人关系操作对话框
*
* 功能说明:
* - 新增用户带人关系
* - 编辑用户带人关系
* - 表单验证和提交
*
* 表单字段:
* - 管理者用户:必填,下拉选择,默认当前登录用户
* - 被管理用户:必填,下拉选择,默认空
* - 生效开始时间:可选
* - 生效结束时间:可选
* - 备注:可选
*
* 用户列表通过 props 传入,由父组件统一管理
*/
import { computed, nextTick, ref, watch } from 'vue';
import {
fetchCreateUserManagementRelation,
fetchGetUserManagementRelation,
fetchUpdateUserManagementRelation
} from '@/service/api';
import { useAuthStore } from '@/store/modules/auth';
import { useForm, useFormRules } from '@/hooks/common/form';
import BusinessFormDialog from '@/components/custom/business-form-dialog.vue';
defineOptions({ name: 'RelationOperateDialog' });
/**
* 组件 Props 定义
*/
interface Props {
/** 操作类型:新增或编辑 */
operateType: UI.TableOperateType;
/** 编辑时的行数据 */
rowData?: Api.SystemManage.UserManagementRelation | null;
/** 用户列表,由父组件统一提供 */
userList: Api.SystemManage.UserSimple[];
}
const props = defineProps<Props>();
/**
* 组件 Emits 定义
*
* 使用 Vue 3.5 标准语法
*/
const emit = defineEmits<{
/** 提交事件:返回提交后的关系 ID */
submitted: [relationId: number];
}>();
/**
* 对话框可见性,支持 v-model 双向绑定
*/
const visible = defineModel<boolean>('visible', {
default: false
});
// 表单相关
const { formRef, validate } = useForm();
const { createRequiredRule } = useFormRules();
// 获取当前登录用户信息
const authStore = useAuthStore();
// 加载和提交状态
const detailLoading = ref(false);
const submitting = ref(false);
// 计算属性:是否为编辑模式
const isEdit = computed(() => props.operateType === 'edit');
/**
* 计算对话框标题
*/
const title = computed(() => {
const titleMap: Record<UI.TableOperateType, string> = {
add: '新增用户带人关系',
edit: '编辑用户带人关系'
};
return titleMap[props.operateType];
});
/**
* 表单模型类型
*/
type Model = Api.SystemManage.UserManagementRelationSaveReqVO;
/**
* 表单模型
*/
const model = ref(createDefaultModel());
/**
* 创建默认表单模型
*
* @returns 默认模型对象
*/
function createDefaultModel(): Model {
return {
managerUserId: null,
subordinateUserId: null,
effectiveFrom: null,
effectiveUntil: null,
remark: null
};
}
/**
* 表单验证规则
*/
const rules = {
managerUserId: createRequiredRule('请选择管理者用户'),
subordinateUserId: createRequiredRule('请选择被管理用户')
} satisfies Record<string, App.Global.FormRule>;
/**
* 关闭对话框
*/
function closeModal() {
visible.value = false;
}
/**
* 初始化表单模型
*
* 编辑模式下加载详情数据,新增模式下设置默认值
*/
async function initModel() {
model.value = createDefaultModel();
if (!isEdit.value) {
// 新增模式:设置管理者用户
// 优先使用 rowData 中传入的管理者用户 ID如从树形节点新增
// 否则使用当前登录用户
let managerUserIdToSet: number | undefined;
if (props.rowData && props.rowData.managerUserId) {
// 从树形节点点击新增,管理者为当前节点用户
managerUserIdToSet = props.rowData.managerUserId;
} else if (authStore.userInfo.userId) {
// 头部新增,管理者为当前登录用户
const currentUserId = Number(authStore.userInfo.userId);
const currentUserName = authStore.userInfo.userName;
// 先尝试通过 ID 匹配
let currentUser = props.userList.find(user => Number(user.id) === currentUserId);
// 如果 ID 匹配失败,尝试通过用户名匹配
if (!currentUser && currentUserName) {
currentUser = props.userList.find(user => user.nickname === currentUserName);
}
if (currentUser) {
managerUserIdToSet = currentUser.id;
}
}
if (managerUserIdToSet) {
model.value.managerUserId = managerUserIdToSet;
}
await nextTick();
formRef.value?.clearValidate();
return;
}
// 编辑模式:加载详情数据
if (!props.rowData) {
await nextTick();
formRef.value?.clearValidate();
return;
}
detailLoading.value = true;
try {
const { error, data } = await fetchGetUserManagementRelation(props.rowData.id);
if (data !== null && !error) {
model.value = {
id: data.id,
managerUserId: data.managerUserId,
subordinateUserId: data.subordinateUserId,
effectiveFrom: data.effectiveFrom ? new Date(data.effectiveFrom).getTime() : null,
effectiveUntil: data.effectiveUntil ? new Date(data.effectiveUntil).getTime() : null,
remark: data.remark ?? null
};
}
} finally {
detailLoading.value = false;
}
await nextTick();
formRef.value?.clearValidate();
}
/**
* 处理表单提交
*
* 验证通过后调用创建或更新接口
*/
async function handleSubmit() {
await validate();
submitting.value = true;
try {
const submitData: Api.SystemManage.UserManagementRelationSaveReqVO = {
...model.value
};
const request =
isEdit.value && props.rowData
? await fetchUpdateUserManagementRelation({ id: props.rowData.id, ...submitData })
: await fetchCreateUserManagementRelation(submitData);
const { error, data } = request;
if (error) {
return;
}
const relationId = isEdit.value && props.rowData ? props.rowData.id : Number(data);
window.$message?.success(isEdit.value ? '修改成功' : '新增成功');
closeModal();
emit('submitted', relationId);
} finally {
submitting.value = false;
}
}
/**
* 监听对话框可见性
*
* 打开时初始化表单
*/
watch(visible, value => {
if (value) {
initModel();
}
});
</script>
<template>
<BusinessFormDialog
v-model="visible"
:title="title"
preset="md"
:loading="detailLoading"
:confirm-loading="submitting"
:scrollbar="false"
@confirm="handleSubmit"
>
<ElForm ref="formRef" :model="model" :rules="rules" label-position="top">
<ElRow :gutter="16">
<ElCol :span="12">
<ElFormItem label="管理者用户" prop="managerUserId">
<ElSelect v-model="model.managerUserId" class="w-full" placeholder="请选择管理者用户" filterable>
<ElOption v-for="user in props.userList" :key="user.id" :label="user.nickname" :value="user.id" />
</ElSelect>
</ElFormItem>
</ElCol>
<ElCol :span="12">
<ElFormItem label="被管理用户" prop="subordinateUserId">
<ElSelect
v-model="model.subordinateUserId"
class="w-full"
placeholder="请选择被管理用户"
filterable
:disabled="isEdit"
>
<ElOption v-for="user in props.userList" :key="user.id" :label="user.nickname" :value="user.id" />
</ElSelect>
</ElFormItem>
</ElCol>
<ElCol :span="12">
<ElFormItem label="生效开始时间" prop="effectiveFrom">
<ElDatePicker
v-model="model.effectiveFrom"
class="w-full"
type="datetime"
placeholder="请选择生效开始时间"
value-format="x"
/>
</ElFormItem>
</ElCol>
<ElCol :span="12">
<ElFormItem label="生效结束时间" prop="effectiveUntil">
<ElDatePicker
v-model="model.effectiveUntil"
class="w-full"
type="datetime"
placeholder="请选择生效结束时间"
value-format="x"
/>
</ElFormItem>
</ElCol>
<ElCol :span="24">
<ElFormItem label="备注" prop="remark">
<ElInput v-model="model.remark" type="textarea" :rows="4" placeholder="请输入备注" />
</ElFormItem>
</ElCol>
</ElRow>
</ElForm>
</BusinessFormDialog>
</template>
<style scoped></style>