feat(hrm): 调岗申请表单新增「调岗人」选择,选中后自动带出原部门/原岗位

- 表单新增「调岗人」下拉(可按姓名搜索),替代原先硬编码取第一个员工的临时逻辑
- 选择员工后自动填充原部门/原岗位(含ID与名称),只读展示
- 提交改为传 userId,修正与后端字段不一致导致调岗人为空的问题
- 列表/详情列改为 userName,标题统一为「调岗人 / 原部门 / 原岗位」
已修改5个文件
108 ■■■■■ 文件已修改
src/api/hrm/employee/index.ts 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/hrm/transfer/index.ts 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/hrm/transfer/data.ts 24 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/hrm/transfer/detail/approve/index.vue 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/hrm/transfer/modules/form.vue 67 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/hrm/employee/index.ts
@@ -91,8 +91,13 @@
    id: number;
    employeeNo: string;
    name: string;
    /** 部门ID */
    deptId?: number;
    deptName?: string;
    /** 岗位ID列表 */
    postIds?: number[];
    postName?: string;
    employeeStatus?: number;
  }
  /** 员工导入结果 */
src/api/hrm/transfer/index.ts
@@ -7,8 +7,10 @@
  /** 调岗申请 */
  export interface Transfer {
    id?: number;
    employeeId?: number;
    employeeName?: string;
    /** 调岗人(员工ID) */
    userId?: number;
    /** 调岗人姓名 */
    userName?: string;
    currentDeptId?: number;
    currentDeptName?: string;
    currentPostId?: number;
src/views/hrm/transfer/data.ts
@@ -7,6 +7,7 @@
import { getDeptList } from '#/api/system/dept';
import { getSimplePostList } from '#/api/system/post';
import { getEmployeeSimpleList } from '#/api/hrm/employee';
import { handleTree } from '#/packages/utils/src';
/** 表单类型 */
@@ -40,12 +41,29 @@
      },
    },
    {
      fieldName: 'userId',
      label: '调岗人',
      component: 'ApiSelect',
      componentProps: {
        api: getEmployeeSimpleList,
        labelField: 'name',
        valueField: 'id',
        showSearch: true,
        filterOption: (input: string, option: any) =>
          `${option?.label ?? ''}`.toLowerCase().includes(input.toLowerCase()),
        allowClear: true,
        placeholder: '请选择要调岗的员工(选择后自动带出原部门/原岗位)',
      },
      rules: 'selectRequired',
      formItemClass: 'col-span-2',
    },
    {
      fieldName: 'currentDeptName',
      label: '原部门',
      component: 'Input',
      componentProps: {
        disabled: true,
        placeholder: '自动获取',
        placeholder: '选择调岗人后自动带出',
      },
    },
    {
@@ -54,7 +72,7 @@
      component: 'Input',
      componentProps: {
        disabled: true,
        placeholder: '自动获取',
        placeholder: '选择调岗人后自动带出',
      },
    },
    {
@@ -175,7 +193,7 @@
export function useGridColumns(): VxeTableGridOptions<HrmTransferApi.Transfer>['columns'] {
  return [
    { field: 'id', title: '申请编号', width: 80 },
    { field: 'employeeName', title: '申请人', minWidth: 100 },
    { field: 'userName', title: '调岗人', minWidth: 100 },
    { field: 'currentDeptName', title: '原部门', minWidth: 120 },
    { field: 'currentPostName', title: '原岗位', minWidth: 120 },
    { field: 'targetDeptName', title: '目标部门', minWidth: 120 },
src/views/hrm/transfer/detail/approve/index.vue
@@ -30,9 +30,9 @@
  bordered: true,
  column: 2,
  schema: [
    { label: '员工姓名', field: 'employeeName', render: textRender },
    { label: '当前部门', field: 'currentDeptName', render: textRender },
    { label: '当前职位', field: 'currentPostName', render: textRender },
    { label: '调岗人', field: 'userName', render: textRender },
    { label: '原部门', field: 'currentDeptName', render: textRender },
    { label: '原岗位', field: 'currentPostName', render: textRender },
    { label: '目标部门', field: 'targetDeptName', render: textRender },
    { label: '目标职位', field: 'targetPostName', render: textRender },
    {
src/views/hrm/transfer/modules/form.vue
@@ -17,7 +17,8 @@
const emit = defineEmits(['success']);
const formType = ref<FormType>('create');
const currentEmployeeId = ref<number>();
/** 员工精简列表缓存(选人时用于带出原部门 / 原岗位) */
let employeeCache: any[] = [];
const isDetail = computed(() => formType.value === 'detail');
const getTitle = computed(() => {
@@ -26,6 +27,34 @@
  }
  return formType.value === 'update' ? '修改调岗申请' : '新增调岗申请';
});
/**
 * 根据选中的员工,自动带出原部门 / 原岗位(含 ID,便于后端落库)
 */
async function fillCurrentPosition(employeeId?: number) {
  if (!employeeId) {
    await formApi.setValues({
      currentDeptId: undefined,
      currentDeptName: undefined,
      currentPostId: undefined,
      currentPostName: undefined,
    });
    return;
  }
  if (employeeCache.length === 0) {
    employeeCache = (await getEmployeeSimpleList()) || [];
  }
  const emp = employeeCache.find((item) => item.id === employeeId);
  if (!emp) {
    return;
  }
  await formApi.setValues({
    currentDeptId: emp.deptId,
    currentDeptName: emp.deptName,
    currentPostId: emp.postIds?.[0],
    currentPostName: emp.postName,
  });
}
const [Form, formApi] = useVbenForm({
  commonConfig: {
@@ -39,6 +68,12 @@
  layout: 'horizontal',
  schema: [],
  showDefaultActions: false,
  // 选择「调岗人」后,自动带出其当前部门 / 岗位
  async handleValuesChange(values: any, changedFields: string[]) {
    if (changedFields?.includes('userId')) {
      await fillCurrentPosition(values?.userId);
    }
  },
});
const [Modal, modalApi] = useVbenModal({
@@ -53,7 +88,6 @@
    }
    modalApi.lock();
    const data = (await formApi.getValues()) as HrmTransferApi.Transfer;
    data.employeeId = currentEmployeeId.value;
    try {
      if (data.id) {
        await updateTransfer(data);
@@ -71,30 +105,31 @@
    if (!isOpen) {
      return;
    }
    employeeCache = [];
    const data = modalApi.getData<{ formType: FormType; id?: number }>();
    formType.value = data.formType;
    formApi.setState({ schema: useFormSchema(data.formType) });
    formApi.setDisabled(data.formType === 'detail');
    modalApi.setState({ showConfirmButton: data.formType !== 'detail' });
    if (!data?.id) {
      // 新增时,自动获取当前登录员工的部门和岗位信息
      const employees = await getEmployeeSimpleList();
      // TODO: 这里应该根据登录用户获取对应的员工信息,暂时取第一个员工作为示例
      const currentEmployee = employees[0];
      if (currentEmployee) {
        currentEmployeeId.value = currentEmployee.id;
        await formApi.setValues({
          currentDeptName: currentEmployee.deptName,
          currentPostName: currentEmployee.postName,
        });
      }
      // 新增:清空表单,由用户选择调岗人
      await formApi.setValues({
        userId: undefined,
        currentDeptId: undefined,
        currentDeptName: undefined,
        currentPostId: undefined,
        currentPostName: undefined,
      });
      return;
    }
    modalApi.lock();
    try {
      const transfer = await getTransfer(data.id);
      currentEmployeeId.value = transfer.employeeId;
      await formApi.setValues(transfer);
      // 历史数据可能没有原部门/岗位,按调岗人补齐
      if (transfer.userId && !transfer.currentDeptId) {
        await fillCurrentPosition(transfer.userId);
      }
      if (transfer.attachmentList?.length) {
        await formApi.setFieldValue('blobIds', transfer.attachmentList.map(item => ({
          uid: String(item.id),
@@ -112,7 +147,7 @@
</script>
<template>
  <Modal :title="getTitle" class="w-[600px]">
  <Modal :title="getTitle" class="w-[700px]">
    <Form class="mx-4" />
  </Modal>
</template>
</template>