| | |
| | | remark?: string; |
| | | createTime?: string; |
| | | } |
| | | |
| | | /** 审批流程 */ |
| | | export interface ApproveProcess { |
| | | key: string; |
| | | name: string; |
| | | } |
| | | } |
| | | |
| | | /** 查询离职申请分页列表 */ |
| | |
| | | } |
| | | |
| | | /** 提交离职申请(发起审批) */ |
| | | export function submitResignation(id: number) { |
| | | return requestClient.post(`/hrm/resignation/submit?id=${id}`); |
| | | export function submitResignation(id: number, processDefinitionKey: string) { |
| | | return requestClient.post('/hrm/resignation/submit', null, { |
| | | params: { id, processDefinitionKey }, |
| | | }); |
| | | } |
| | | |
| | | /** 撤销离职申请 */ |
| | |
| | | |
| | | /** 获取可用流程定义列表 */ |
| | | export function getResignationApproveProcessDefinitionList() { |
| | | return requestClient.get<any[]>('/hrm/resignation/approve-process-definition-list'); |
| | | return requestClient.get<HrmResignationApi.ApproveProcess[]>( |
| | | '/hrm/resignation/approve-process-definition-list', |
| | | ); |
| | | } |
| | |
| | | /** 调岗申请 */ |
| | | export interface Transfer { |
| | | id?: number; |
| | | employeeId?: number; |
| | | employeeName?: string; |
| | | userId?: number; |
| | | userName?: string; |
| | | currentDeptId?: number; |
| | | currentDeptName?: string; |
| | | currentPostId?: number; |
| | |
| | | processInstanceId?: string; |
| | | remark?: string; |
| | | createTime?: string; |
| | | } |
| | | |
| | | /** 审批流程 */ |
| | | export interface ApproveProcess { |
| | | key: string; |
| | | name: string; |
| | | } |
| | | } |
| | | |
| | |
| | | } |
| | | |
| | | /** 提交调岗申请(发起审批) */ |
| | | export function submitTransfer(id: number) { |
| | | return requestClient.post(`/hrm/transfer/submit?id=${id}`); |
| | | export function submitTransfer(id: number, processDefinitionKey: string) { |
| | | return requestClient.post('/hrm/transfer/submit', null, { |
| | | params: { id, processDefinitionKey }, |
| | | }); |
| | | } |
| | | |
| | | /** 撤销调岗申请 */ |
| | |
| | | |
| | | /** 获取可用流程定义列表 */ |
| | | export function getTransferApproveProcessDefinitionList() { |
| | | return requestClient.get<any[]>('/hrm/transfer/approve-process-definition-list'); |
| | | return requestClient.get<HrmTransferApi.ApproveProcess[]>( |
| | | '/hrm/transfer/approve-process-definition-list', |
| | | ); |
| | | } |
| | |
| | | import type { VxeTableGridOptions } from '#/adapter/vxe-table'; |
| | | import type { HrmResignationApi } from '#/api/hrm/resignation'; |
| | | |
| | | import { ref } from 'vue'; |
| | | |
| | | import { Page, useVbenModal } from '#/packages/effects/common-ui/src'; |
| | | |
| | | import { message } from 'ant-design-vue'; |
| | | import { message, Modal, Select } from 'ant-design-vue'; |
| | | |
| | | import { ACTION_ICON, TableAction, useVbenVxeGrid } from '#/adapter/vxe-table'; |
| | | import { |
| | | cancelResignation, |
| | | deleteResignation, |
| | | getResignationApproveProcessDefinitionList, |
| | | getResignationPage, |
| | | submitResignation, |
| | | updateHandoverStatus, |
| | |
| | | } |
| | | } |
| | | |
| | | /** 提交离职申请 */ |
| | | const submitModalVisible = ref(false); |
| | | const currentRow = ref<HrmResignationApi.Resignation>(); |
| | | const processList = ref<HrmResignationApi.ApproveProcess[]>([]); |
| | | const selectedProcessKey = ref<string>(); |
| | | const submitLoading = ref(false); |
| | | |
| | | /** 提交离职申请(先选择审批流程) */ |
| | | async function handleSubmit(row: HrmResignationApi.Resignation) { |
| | | await submitResignation(row.id!); |
| | | message.success('提交成功'); |
| | | handleRefresh(); |
| | | processList.value = await getResignationApproveProcessDefinitionList(); |
| | | currentRow.value = row; |
| | | selectedProcessKey.value = undefined; |
| | | submitModalVisible.value = true; |
| | | } |
| | | |
| | | async function confirmSubmit() { |
| | | if (!selectedProcessKey.value) { |
| | | message.warning('请选择离职审批流程'); |
| | | return; |
| | | } |
| | | submitLoading.value = true; |
| | | try { |
| | | await submitResignation(currentRow.value!.id!, selectedProcessKey.value); |
| | | message.success('提交成功'); |
| | | submitModalVisible.value = false; |
| | | handleRefresh(); |
| | | } finally { |
| | | submitLoading.value = false; |
| | | } |
| | | } |
| | | |
| | | /** 撤销离职申请 */ |
| | |
| | | /> |
| | | </template> |
| | | </Grid> |
| | | <Modal |
| | | v-model:open="submitModalVisible" |
| | | title="提交至协同办公" |
| | | width="420px" |
| | | :confirm-loading="submitLoading" |
| | | @ok="confirmSubmit" |
| | | > |
| | | <Select |
| | | v-model:value="selectedProcessKey" |
| | | class="w-full" |
| | | placeholder="请选择离职审批流程" |
| | | :options="processList.map((item) => ({ label: item.name, value: item.key }))" |
| | | /> |
| | | </Modal> |
| | | </Page> |
| | | </template> |
| | |
| | | " |
| | | class="py-20" |
| | | /> |
| | | <table v-else class="schedule-table w-full text-sm"> |
| | | <table v-else class="schedule-table text-sm"> |
| | | <!-- 勾选列 40px、员工列 160px 固定;日期列按视图模式定宽 --> |
| | | <colgroup> |
| | | <col style="width: 40px" /> |
| | | <col style="width: 160px" /> |
| | | <!-- 周视图:日期列均分剩余宽度(保证班次名完整显示);月视图:固定 52px 横向滚动 --> |
| | | <col |
| | | v-for="vd in viewDays" |
| | | :key="vd.date" |
| | | :style="viewMode === 'month' ? 'width: 52px' : undefined" |
| | | /> |
| | | </colgroup> |
| | | <thead> |
| | | <tr> |
| | | <th class="schedule-check-col bg-gray-100"> |
| | |
| | | min-width: max-content; |
| | | border-collapse: separate; |
| | | border-spacing: 0; |
| | | table-layout: fixed; |
| | | |
| | | th, |
| | | td { |
| | |
| | | } |
| | | |
| | | .schedule-date-col { |
| | | width: 52px; |
| | | min-width: 52px; |
| | | } |
| | | |
| | |
| | | |
| | | .schedule-name-col { |
| | | left: 40px; |
| | | min-width: 180px; |
| | | width: 160px; |
| | | min-width: 160px; |
| | | padding: 0 12px; |
| | | line-height: 1.3; |
| | | } |
| | |
| | | padding: 1px 6px; |
| | | overflow: hidden; |
| | | color: #fff; |
| | | font-size: 11px; |
| | | font-size: 12px; |
| | | text-overflow: ellipsis; |
| | | white-space: nowrap; |
| | | border-radius: 3px; |
| | |
| | | import type { VbenFormSchema } from '#/adapter/form'; |
| | | import type { VxeTableGridOptions } from '#/adapter/vxe-table'; |
| | | import type { HrmTransferApi } from '#/api/hrm/transfer'; |
| | | import type { SystemUserApi } from '#/api/system/user'; |
| | | |
| | | import { markRaw } from 'vue'; |
| | | |
| | | import { DICT_TYPE } from '#/packages/constants/src'; |
| | | import { getDictOptions } from '#/packages/effects/hooks/src'; |
| | |
| | | import { getDeptList } from '#/api/system/dept'; |
| | | import { getSimplePostList } from '#/api/system/post'; |
| | | import { handleTree } from '#/packages/utils/src'; |
| | | import { UserSelect } from '#/views/system/user/components'; |
| | | |
| | | /** 表单类型 */ |
| | | export type FormType = 'create' | 'detail' | 'update'; |
| | | |
| | | /** 新增/修改调岗申请的表单 */ |
| | | export function useFormSchema(formType: FormType): VbenFormSchema[] { |
| | | export function useFormSchema( |
| | | formType: FormType, |
| | | onUserChange?: (user?: SystemUserApi.User) => void, |
| | | ): VbenFormSchema[] { |
| | | return [ |
| | | { |
| | | fieldName: 'id', |
| | |
| | | triggerFields: [''], |
| | | show: () => false, |
| | | }, |
| | | }, |
| | | { |
| | | fieldName: 'userId', |
| | | label: '调岗人员', |
| | | component: markRaw(UserSelect), |
| | | componentProps: { |
| | | placeholder: '请选择调岗人员', |
| | | onChange: onUserChange, |
| | | }, |
| | | rules: 'selectRequired', |
| | | }, |
| | | { |
| | | fieldName: 'currentDeptId', |
| | |
| | | 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 }, |
| | |
| | | bordered: true, |
| | | column: 2, |
| | | schema: [ |
| | | { label: '员工姓名', field: 'employeeName', render: textRender }, |
| | | { label: '调岗人员', field: 'userName', render: textRender }, |
| | | { label: '当前部门', field: 'currentDeptName', render: textRender }, |
| | | { label: '当前职位', field: 'currentPostName', render: textRender }, |
| | | { label: '目标部门', field: 'targetDeptName', render: textRender }, |
| | |
| | | import type { VxeTableGridOptions } from '#/adapter/vxe-table'; |
| | | import type { HrmTransferApi } from '#/api/hrm/transfer'; |
| | | |
| | | import { ref } from 'vue'; |
| | | |
| | | import { Page, useVbenModal } from '#/packages/effects/common-ui/src'; |
| | | |
| | | import { message } from 'ant-design-vue'; |
| | | import { message, Modal, Select } from 'ant-design-vue'; |
| | | |
| | | import { ACTION_ICON, TableAction, useVbenVxeGrid } from '#/adapter/vxe-table'; |
| | | import { |
| | | cancelTransfer, |
| | | deleteTransfer, |
| | | getTransferApproveProcessDefinitionList, |
| | | getTransferPage, |
| | | submitTransfer, |
| | | } from '#/api/hrm/transfer'; |
| | |
| | | } |
| | | } |
| | | |
| | | /** 提交调岗申请 */ |
| | | const submitModalVisible = ref(false); |
| | | const currentRow = ref<HrmTransferApi.Transfer>(); |
| | | const processList = ref<HrmTransferApi.ApproveProcess[]>([]); |
| | | const selectedProcessKey = ref<string>(); |
| | | const submitLoading = ref(false); |
| | | |
| | | /** 提交调岗申请(先选择审批流程) */ |
| | | async function handleSubmit(row: HrmTransferApi.Transfer) { |
| | | await submitTransfer(row.id!); |
| | | message.success('提交成功'); |
| | | handleRefresh(); |
| | | processList.value = await getTransferApproveProcessDefinitionList(); |
| | | currentRow.value = row; |
| | | selectedProcessKey.value = undefined; |
| | | submitModalVisible.value = true; |
| | | } |
| | | |
| | | async function confirmSubmit() { |
| | | if (!selectedProcessKey.value) { |
| | | message.warning('请选择调岗审批流程'); |
| | | return; |
| | | } |
| | | submitLoading.value = true; |
| | | try { |
| | | await submitTransfer(currentRow.value!.id!, selectedProcessKey.value); |
| | | message.success('提交成功'); |
| | | submitModalVisible.value = false; |
| | | handleRefresh(); |
| | | } finally { |
| | | submitLoading.value = false; |
| | | } |
| | | } |
| | | |
| | | /** 撤销调岗申请 */ |
| | |
| | | /> |
| | | </template> |
| | | </Grid> |
| | | <Modal |
| | | v-model:open="submitModalVisible" |
| | | title="提交至协同办公" |
| | | width="420px" |
| | | :confirm-loading="submitLoading" |
| | | @ok="confirmSubmit" |
| | | > |
| | | <Select |
| | | v-model:value="selectedProcessKey" |
| | | class="w-full" |
| | | placeholder="请选择调岗审批流程" |
| | | :options="processList.map((item) => ({ label: item.name, value: item.key }))" |
| | | /> |
| | | </Modal> |
| | | </Page> |
| | | </template> |
| | |
| | | <script lang="ts" setup> |
| | | import type { FormType } from '../data'; |
| | | import type { HrmTransferApi } from '#/api/hrm/transfer'; |
| | | import type { SystemPostApi } from '#/api/system/post'; |
| | | import type { SystemUserApi } from '#/api/system/user'; |
| | | |
| | | import { computed, ref } from 'vue'; |
| | | |
| | | import { useUserStore } from '@vben/stores'; |
| | | |
| | | import { useVbenModal } from '#/packages/effects/common-ui/src'; |
| | | |
| | |
| | | |
| | | import { useVbenForm } from '#/adapter/form'; |
| | | import { createTransfer, getTransfer, updateTransfer } from '#/api/hrm/transfer'; |
| | | import { getEmployeeSimpleList } from '#/api/hrm/employee'; |
| | | import { getSimplePostList } from '#/api/system/post'; |
| | | import { getUser } from '#/api/system/user'; |
| | | import { $t } from '#/locales'; |
| | | |
| | | import { useFormSchema } from '../data'; |
| | | |
| | | const emit = defineEmits(['success']); |
| | | const formType = ref<FormType>('create'); |
| | | const currentEmployeeId = ref<number>(); |
| | | const userStore = useUserStore(); |
| | | |
| | | const isDetail = computed(() => formType.value === 'detail'); |
| | | const getTitle = computed(() => { |
| | |
| | | showDefaultActions: false, |
| | | }); |
| | | |
| | | /** 岗位列表缓存(用于把岗位 ID 回显成名称) */ |
| | | const postList = ref<SystemPostApi.Post[]>([]); |
| | | |
| | | /** 根据岗位编号取岗位名称 */ |
| | | async function getPostName(postId?: number) { |
| | | if (!postId) { |
| | | return undefined; |
| | | } |
| | | if (postList.value.length === 0) { |
| | | postList.value = await getSimplePostList(); |
| | | } |
| | | return postList.value.find((item) => item.id === postId)?.name; |
| | | } |
| | | |
| | | /** 选择调岗人员后,自动带出其原部门、原岗位 */ |
| | | async function fillCurrentByUser(user?: SystemUserApi.User) { |
| | | if (!user?.id) { |
| | | await formApi.setValues({ |
| | | currentDeptId: undefined, |
| | | currentDeptName: undefined, |
| | | currentPostId: undefined, |
| | | currentPostName: undefined, |
| | | }); |
| | | return; |
| | | } |
| | | // 选择组件带回的数据可能缺少部门名称 / 岗位,按编号再查一次用户详情 |
| | | const detail = !user.deptName || !user.postIds?.length |
| | | ? await getUser(user.id) |
| | | : user; |
| | | const postId = detail.postIds?.[0] ? Number(detail.postIds[0]) : undefined; |
| | | await formApi.setValues({ |
| | | currentDeptId: detail.deptId, |
| | | currentDeptName: detail.deptName, |
| | | currentPostId: postId, |
| | | currentPostName: await getPostName(postId), |
| | | }); |
| | | } |
| | | |
| | | const [Modal, modalApi] = useVbenModal({ |
| | | async onConfirm() { |
| | | if (isDetail.value) { |
| | |
| | | } |
| | | modalApi.lock(); |
| | | const data = (await formApi.getValues()) as HrmTransferApi.Transfer; |
| | | data.employeeId = currentEmployeeId.value; |
| | | try { |
| | | if (data.id) { |
| | | await updateTransfer(data); |
| | |
| | | } |
| | | const data = modalApi.getData<{ formType: FormType; id?: number }>(); |
| | | formType.value = data.formType; |
| | | formApi.setState({ schema: useFormSchema(data.formType) }); |
| | | formApi.setState({ schema: useFormSchema(data.formType, fillCurrentByUser) }); |
| | | 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, |
| | | }); |
| | | // 新增时默认带出当前登录人,并回填其原部门 / 原岗位 |
| | | const loginUserId = userStore.userInfo?.id; |
| | | if (loginUserId) { |
| | | formApi.setFieldValue('userId', loginUserId); |
| | | await fillCurrentByUser(await getUser(loginUserId)); |
| | | } |
| | | return; |
| | | } |
| | | modalApi.lock(); |
| | | try { |
| | | const transfer = await getTransfer(data.id); |
| | | currentEmployeeId.value = transfer.employeeId; |
| | | await formApi.setValues(transfer); |
| | | if (transfer.attachmentList?.length) { |
| | | await formApi.setFieldValue('blobIds', transfer.attachmentList.map(item => ({ |
| | |
| | | </script> |
| | | |
| | | <template> |
| | | <Modal :title="getTitle" class="w-[600px]"> |
| | | <Modal :title="getTitle" class="w-[850px]"> |
| | | <Form class="mx-4" /> |
| | | </Modal> |
| | | </template> |
| | | </template> |
| | |
| | | > |
| | | <Row :gutter="12"> |
| | | <Col :span="5"> |
| | | <DeptTreeSelect ref="deptTreeRef" @select="handleDeptNodeClick" /> |
| | | <!-- 部门树高度与右侧用户列表保持一致,超出部分内部滚动,避免撑高弹窗 --> |
| | | <div class="h-[520px] overflow-y-auto pr-1"> |
| | | <DeptTreeSelect ref="deptTreeRef" @select="handleDeptNodeClick" /> |
| | | </div> |
| | | </Col> |
| | | <Col :span="19"> |
| | | <Grid table-title="用户列表" /> |