Commit 535cbc70 authored by 刘斌's avatar 刘斌

feat: 增加培训,面试,人力成本

parent 3dad53ac
import type { BaseModel, PageQuery } from '#/api/baseModel';
import { commonExport } from '#/api/helper';
import { requestClient } from '#/api/request';
export namespace InterviewProfileApi {
export interface InterviewProfile extends BaseModel {
/**
* 员工信息ID
*/
employeeId?: number;
/**
* 招揽岗位
*/
jobPosition?: string;
/**
* 姓名
*/
name?: string;
/**
* 性别
*/
gender?: string;
/**
* 身份证号
*/
idCardNumber?: number;
/**
* 学历
*/
education?: string;
/**
* 院校
*/
school?: string;
/**
* 专业
*/
major?: string;
/**
* 联系方式
*/
phoneNumber?: string;
/**
* 标杆企业
*/
benchmarkEnterprise?: string;
/**
* 面试时间
*/
interviewDate?: string;
/**
* 面试情况
*/
interviewSituation?: string;
/**
* 面试结果
*/
interviewResult?: string;
/**
* 备注
*/
remark?: string;
}
}
/**
* 查询面试档案列表
* @param params
* @returns {*} page
*/
export function apiPage(params: PageQuery) {
return requestClient.get('/employee/interviewProfile/page', { params });
}
/**
* 查询面试档案详细
* @param id
*/
export function apiDetail(id: number) {
return requestClient.get(`/employee/interviewProfile/${id}`);
}
/**
* 新增面试档案
* @param data
*/
export function apiAdd(data: InterviewProfileApi.InterviewProfile) {
return requestClient.post('/employee/interviewProfile', data);
}
/**
* 修改面试档案
* @param data
*/
export function apiUpdate(data: InterviewProfileApi.InterviewProfile) {
return requestClient.put('/employee/interviewProfile', data);
}
/**
* 删除面试档案
* @param id
*/
export function apiDelete(id: Array<number> | number) {
return requestClient.delete(`/employee/interviewProfile/${id}`);
}
/**
* 导出面试档案
* @param params
*/
export function apiExport(params: PageQuery) {
return commonExport('/employee/interviewProfile/export', params);
}
/**
* 下载用户导入模板
* @returns blob
*/
export function downloadImportTemplate() {
return commonExport('/employee/interviewProfile/importTemplate', {});
}
/**
* 从excel导入面试信息
* @param file
* @returns void
*/
export function interviewProfileImportData(file: Blob) {
return requestClient.post<{ errMessage: string; success: boolean }>(
'/employee/interviewProfile/import',
{ file },
{
headers: {
'Content-Type': 'multipart/form-data;charset=UTF-8',
},
isTransformResponse: false,
responseReturn: 'body',
timeout: 300_000,
},
);
}
import type { BaseModel, PageQuery } from '#/api/baseModel';
import { commonExport } from '#/api/helper';
import { requestClient } from '#/api/request';
export namespace LaborCostApi {
export interface LaborCost extends BaseModel {
/**
* 记录时间
*/
recordDate?: string;
/**
* 文件ID
*/
ossId?: number;
/**
* 文件Key
*/
fileKey?: string;
/**
* 备注
*/
remark?: string;
}
}
/**
* 查询人工成本档案列表
* @param params
* @returns {*} page
*/
export function apiPage(params: PageQuery) {
return requestClient.get('/employee/laborCost/page', { params });
}
/**
* 查询人工成本档案详细
* @param id
*/
export function apiDetail(id: number) {
return requestClient.get(`/employee/laborCost/${id}`);
}
/**
* 新增人工成本档案
* @param data
*/
export function apiAdd(data: LaborCostApi.LaborCost) {
return requestClient.post('/employee/laborCost', data);
}
/**
* 修改人工成本档案
* @param data
*/
export function apiUpdate(data: LaborCostApi.LaborCost) {
return requestClient.put('/employee/laborCost', data);
}
/**
* 删除人工成本档案
* @param id
*/
export function apiDelete(id: Array<number> | number) {
return requestClient.delete(`/employee/laborCost/${id}`);
}
/**
* 导出人工成本档案
* @param params
*/
export function apiExport(params: PageQuery) {
return commonExport('/employee/laborCost/export', params);
}
import type { BaseModel, PageQuery } from '#/api/baseModel';
import { commonExport } from '#/api/helper';
import { requestClient } from '#/api/request';
export namespace TrainingApi {
export interface Training extends BaseModel {
/**
* 员工信息ID
*/
employeeId?: number;
/**
* 姓名
*/
name?: string;
/**
* 身份证号
*/
idCardNumber?: string;
/**
* 培训课程
*/
trainingCourse?: string;
/**
* 培训机构
*/
trainingInstitution?: string;
/**
* 培训讲师
*/
trainer?: string;
/**
* 参训时间
*/
trainingTime?: string;
/**
* 服务期
*/
serviceEndDate?: string;
/**
* 服务年限
*/
serviceYears?: string;
/**
* 培训金额
*/
trainingAmount?: number;
/**
* 备注
*/
remark?: string;
}
}
/**
* 查询员工培训档案列表
* @param params
* @returns {*} page
*/
export function apiPage(params: PageQuery) {
return requestClient.get('/employee/training/page', { params });
}
/**
* 查询员工培训档案详细
* @param id
*/
export function apiDetail(id: number) {
return requestClient.get(`/employee/training/${id}`);
}
/**
* 新增员工培训档案
* @param data
*/
export function apiAdd(data: TrainingApi.Training) {
return requestClient.post('/employee/training', data);
}
/**
* 修改员工培训档案
* @param data
*/
export function apiUpdate(data: TrainingApi.Training) {
return requestClient.put('/employee/training', data);
}
/**
* 删除员工培训档案
* @param id
*/
export function apiDelete(id: Array<number> | number) {
return requestClient.delete(`/employee/training/${id}`);
}
/**
* 导出员工培训档案
* @param params
*/
export function apiExport(params: PageQuery) {
return commonExport('/employee/training/export', params);
}
/**
* 下载用户导入模板
* @returns blob
*/
export function downloadImportTemplate() {
return commonExport('/employee/training/importTemplate', {});
}
/**
* 从excel导入培训信息
* @param file
* @returns void
*/
export function trainingImportData(file: Blob) {
return requestClient.post<{ errMessage: string; success: boolean }>(
'/employee/training/import',
{ file },
{
headers: {
'Content-Type': 'multipart/form-data;charset=UTF-8',
},
isTransformResponse: false,
responseReturn: 'body',
timeout: 300_000,
},
);
}
......@@ -85,6 +85,42 @@ const routes: RouteRecordRaw[] = [
componentPath: '#/views/hr/changeLog/list.vue',
},
},
{
path: '/hr/training/list',
name: 'EmployeeTrainingList',
component: () => import('#/views/hr/training/list.vue'),
meta: {
title: '员工培训档案',
icon: 'streamline-plump:contact-phonebook',
keepAlive: true,
permission: ['dashboard'],
componentPath: '#/views/hr/training/list.vue',
},
},
{
path: '/hr/interviewProfile/list',
name: 'InterviewProfileList',
component: () => import('#/views/hr/interviewProfile/list.vue'),
meta: {
title: '面试档案',
icon: 'streamline-plump:contact-phonebook',
keepAlive: true,
permission: ['dashboard'],
componentPath: '#/views/hr/interviewProfile/list.vue',
},
},
{
path: '/hr/laborCost/list',
name: 'EmployeeLaborCostList',
component: () => import('#/views/hr/laborCost/list.vue'),
meta: {
title: '人工成本档案',
icon: 'streamline-plump:contact-phonebook',
keepAlive: true,
permission: ['dashboard'],
componentPath: '#/views/hr/laborCost/list.vue',
},
},
{
path: '/hr/report',
name: 'HrReport',
......
......@@ -163,7 +163,21 @@ export function useColumns(): VxeTableGridOptions<ChangeAnalysisApi.ChangeAnalys
},
{
title: '被动离职',
field: 'passiveResignation',
headerAlign: 'center',
children: [
{
title: '试用期内(6个月)',
field: 'passiveProbationPeriod',
},
{
title: '优化',
field: 'passiveLayoff',
},
],
},
{
title: '退休',
field: 'retirement',
},
{
title: '总离职',
......@@ -185,22 +199,36 @@ export function useColumns(): VxeTableGridOptions<ChangeAnalysisApi.ChangeAnalys
headerAlign: 'center',
children: [
{
title: '试用期内离职率',
title: '试用期内(6个月)',
field: 'probationResignationRate',
},
{
title: '入职3年内离职率',
title: '入职3年内',
field: 'within3YearsResignationRate',
},
{
title: '入职3年以上离职率',
title: '入职3年以上',
field: 'over3YearsResignationRate',
},
],
},
{
title: '被动离职率',
field: 'passiveResignationRate',
headerAlign: 'center',
children: [
{
title: '试用期内(6个月)',
field: 'passiveProbationPeriodRate',
},
{
title: '优化',
field: 'passiveLayoffRate',
},
],
},
{
title: '退休',
field: 'retirementRate',
},
{
title: '总离职率',
......
......@@ -67,20 +67,17 @@ const [Grid, gridApi] = useVbenVxeGrid({
{ row: 0, col: 2, rowspan: 3, colspan: 1 },
{ row: 0, col: 3, rowspan: 3, colspan: 1 },
{ row: 0, col: 4, rowspan: 2, colspan: 2 },
{ row: 2, col: 4, rowspan: 1, colspan: 1 },
{ row: 2, col: 5, rowspan: 1, colspan: 1 },
{ row: 0, col: 6, rowspan: 1, colspan: 5 },
{ row: 0, col: 6, rowspan: 1, colspan: 7 },
{ row: 1, col: 6, rowspan: 1, colspan: 3 },
{ row: 2, col: 6, rowspan: 1, colspan: 1 },
{ row: 2, col: 7, rowspan: 1, colspan: 1 },
{ row: 2, col: 8, rowspan: 1, colspan: 1 },
{ row: 1, col: 9, rowspan: 2, colspan: 1 },
{ row: 1, col: 10, rowspan: 2, colspan: 1 },
{ row: 0, col: 11, rowspan: 3, colspan: 1 },
{ row: 0, col: 12, rowspan: 1, colspan: 5 },
{ row: 1, col: 12, rowspan: 1, colspan: 3 },
{ row: 1, col: 15, rowspan: 2, colspan: 1 },
{ row: 1, col: 16, rowspan: 2, colspan: 1 },
{ row: 1, col: 9, rowspan: 1, colspan: 2 },
{ row: 1, col: 11, rowspan: 2, colspan: 1 },
{ row: 1, col: 12, rowspan: 2, colspan: 1 },
{ row: 0, col: 13, rowspan: 3, colspan: 1 },
{ row: 0, col: 14, rowspan: 1, colspan: 7 },
{ row: 1, col: 14, rowspan: 1, colspan: 3 },
{ row: 1, col: 17, rowspan: 1, colspan: 2 },
{ row: 1, col: 19, rowspan: 2, colspan: 1 },
{ row: 1, col: 20, rowspan: 2, colspan: 1 },
],
rowConfig: {
keyField: 'plate',
......
......@@ -17,6 +17,8 @@ export const HrDictEnum = {
HR_CHANGE_LOG_TYPE: 'hr_change_log_type', // 员工离职类型
HR_RESIGNATION_CATEGORY: 'hr_resignation_category', // 员工离职类别
HR_COST_TYPE: 'hr_cost_type', // 员工成本费用细分
HR_APPLY_TYPE: 'hr_apply_type', // 员工审批类型
HR_INTERVIEW_RESULT: 'hr_interview_result', // 员工审批类型
// SYS_JOB_TYPE: 'sys_job_type', // 定时任务类型
// SYS_JOB_STATUS: 'sys_job_status', // 定时任务状态
// SYS_OSS_ACCESS_POLICY: 'oss_access_policy', // oss权限桶类型
......
......@@ -318,7 +318,7 @@ export function useColumns(): VxeTableGridOptions<EmployeeInfoApi.Employee>['col
},
{
title: '性别',
field: 'gender',
field: 'genderName',
width: 80,
},
{
......
import type { VbenFormSchema } from '#/adapter/form';
import type { OnActionClickFn, VxeTableGridOptions } from '#/adapter/vxe-table';
import type { InterviewProfileApi } from '#/api/hr/interviewProfile';
import { getDictOptions, getTagDicts } from '#/utils/dict';
import { HrDictEnum } from '../dict-enum';
export const querySchema: VbenFormSchema[] = [
// {
// component: 'Input',
// fieldName: 'employeeId',
// label: '员工信息ID',
// },
{
component: 'Input',
fieldName: 'jobPosition',
label: '招揽岗位',
},
{
component: 'Input',
fieldName: 'name',
label: '姓名',
},
// {
// component: 'Input',
// fieldName: 'gender',
// label: '性别',
// },
{
component: 'Input',
fieldName: 'idCardNumber',
label: '身份证号',
},
{
component: 'Input',
fieldName: 'education',
label: '学历',
},
{
component: 'Input',
fieldName: 'school',
label: '院校',
},
{
component: 'Input',
fieldName: 'major',
label: '专业',
},
{
component: 'Input',
fieldName: 'phoneNumber',
label: '联系方式',
},
{
component: 'Input',
fieldName: 'benchmarkEnterprise',
label: '标杆企业',
},
{
component: 'DatePicker',
fieldName: 'interviewDate',
label: '面试时间',
},
{
component: 'Input',
fieldName: 'interviewSituation',
label: '面试情况',
},
{
component: 'Select',
componentProps: {
options: getDictOptions(HrDictEnum.HR_INTERVIEW_RESULT),
},
fieldName: 'interviewResult',
label: '面试结果',
},
];
export function useColumns(
onActionClick: OnActionClickFn<InterviewProfileApi.InterviewProfile>,
): VxeTableGridOptions<InterviewProfileApi.InterviewProfile>['columns'] {
return [
// {
// title: '员工信息ID',
// field: 'employeeId',
// },
{
title: '招揽岗位',
field: 'jobPosition',
},
{
title: '姓名',
field: 'name',
},
{
title: '性别',
field: 'gender',
cellRender: {
name: 'CellTag',
options: [getTagDicts(HrDictEnum.HR_USER_SEX)],
},
},
{
title: '身份证号',
field: 'idCardNumber',
},
{
title: '学历',
field: 'education',
},
{
title: '标杆企业',
field: 'benchmarkEnterprise',
},
{
title: '院校',
field: 'school',
},
{
title: '专业',
field: 'major',
},
{
title: '联系方式',
field: 'phoneNumber',
},
{
title: '面试时间',
field: 'interviewDate',
formatter: 'formatDateTime',
},
{
title: '面试情况',
field: 'interviewSituation',
},
{
title: '面试结果',
field: 'interviewResult',
cellRender: {
name: 'CellTag',
options: [getTagDicts(HrDictEnum.HR_INTERVIEW_RESULT)],
},
},
// {
// title: '备注',
// field: 'remark',
// },
{
align: 'right',
cellRender: {
attrs: {
nameField: 'name',
nameTitle: '姓名',
onClick: onActionClick,
},
name: 'CellOperation',
options: [
{
code: 'edit',
accessCode: ['employee:interviewProfile:edit'],
}, // 默认的编辑按钮
{
code: 'delete',
accessCode: ['employee:interviewProfile:remove'],
}, // 默认的删除按钮
],
},
field: 'action',
fixed: 'right',
headerAlign: 'center',
resizable: false,
showOverflow: false,
title: '操作',
width: 'auto',
},
];
}
<script lang="ts" setup>
import type { VbenFormSchema } from '#/adapter/form';
import type { InterviewProfileApi } from '#/api/hr/interviewProfile';
import { computed, ref } from 'vue';
import { useVbenDrawer } from '@vben/common-ui';
import { getVxePopupContainer } from '@vben/utils';
import { useVbenForm } from '#/adapter/form';
import { apiAdd, apiUpdate } from '#/api/hr/interviewProfile';
import { getDictOptions } from '#/utils/dict';
import { defaultFormValueGetter, useBeforeCloseDiff } from '#/utils/popup';
import { HrDictEnum } from '../dict-enum';
const emit = defineEmits<{
success: [];
}>();
const isUpdate = ref(false);
const formSchema: VbenFormSchema[] = [
{
component: 'Input',
dependencies: {
show: () => false,
triggerFields: [''],
},
fieldName: 'id',
label: 'id',
},
// {
// component: 'Input',
// fieldName: 'employeeId',
// label: '员工信息ID',
// rules: 'required',
// },
{
component: 'Input',
fieldName: 'jobPosition',
label: '招揽岗位',
rules: 'required',
},
{
component: 'Input',
fieldName: 'name',
label: '姓名',
rules: 'required',
},
{
component: 'RadioGroup',
componentProps: {
buttonStyle: 'solid',
optionType: 'button',
options: getDictOptions(HrDictEnum.HR_USER_SEX),
},
defaultValue: '1',
fieldName: 'gender',
label: '性别',
rules: 'required',
},
{
component: 'Input',
fieldName: 'idCardNumber',
label: '身份证号',
rules: 'required',
},
{
component: 'Input',
fieldName: 'education',
label: '学历',
rules: 'required',
},
{
component: 'Input',
fieldName: 'benchmarkEnterprise',
label: '标杆企业',
rules: 'required',
},
{
component: 'Input',
fieldName: 'school',
label: '院校',
rules: 'required',
},
{
component: 'Input',
fieldName: 'major',
label: '专业',
rules: 'required',
},
{
component: 'Input',
fieldName: 'phoneNumber',
label: '联系方式',
rules: 'required',
},
{
component: 'DatePicker',
fieldName: 'interviewDate',
label: '面试时间',
rules: 'required',
},
{
component: 'Input',
fieldName: 'interviewSituation',
label: '面试情况',
rules: 'required',
},
{
component: 'Select',
componentProps: {
getVxePopupContainer,
options: getDictOptions(HrDictEnum.HR_INTERVIEW_RESULT),
},
fieldName: 'interviewResult',
label: '面试结果',
rules: 'selectRequired',
},
{
component: 'Input',
fieldName: 'remark',
label: '备注',
// rules: 'required',
},
];
const [BasicForm, formApi] = useVbenForm({
commonConfig: {
componentProps: {
class: 'w-full',
},
formItemClass: 'col-span-2',
labelWidth: 90,
},
schema: formSchema,
showDefaultActions: false,
wrapperClass: 'grid-cols-2',
});
const { onBeforeClose, markInitialized, resetInitialized } = useBeforeCloseDiff(
{
initializedGetter: defaultFormValueGetter(formApi),
currentGetter: defaultFormValueGetter(formApi),
},
);
const [Drawer, drawerApi] = useVbenDrawer({
onBeforeClose,
onClosed: handleClosed,
onConfirm: onSubmit,
async onOpenChange(isOpen) {
if (!isOpen) {
return null;
}
const data = drawerApi.getData<InterviewProfileApi.InterviewProfile>();
isUpdate.value = !!data?.id;
if (isUpdate.value) {
await formApi.setValues(data);
} else {
formApi.resetForm();
}
await markInitialized();
},
});
async function onSubmit() {
const { valid } = await formApi.validate();
if (valid) {
drawerApi.lock();
const data =
await formApi.getValues<InterviewProfileApi.InterviewProfile>();
try {
await (isUpdate.value ? apiUpdate(data) : apiAdd(data));
resetInitialized();
emit('success');
drawerApi.close();
} finally {
drawerApi.unlock();
}
}
}
async function handleClosed() {
await formApi.resetForm();
resetInitialized();
}
const getDrawerTitle = computed(() =>
isUpdate.value ? '修改面试档案' : '新增面试档案',
);
</script>
<template>
<Drawer class="w-full max-w-[800px]" :title="getDrawerTitle">
<BasicForm class="mx-4" />
</Drawer>
</template>
<script setup lang="ts">
import type { UploadFile } from 'ant-design-vue/es/upload/interface';
import { h, ref } from 'vue';
import { useVbenModal } from '@vben/common-ui';
import { ExcelIcon, InBoxIcon } from '@vben/icons';
import { Button, Modal, Upload } from 'ant-design-vue';
import {
downloadImportTemplate,
interviewProfileImportData,
} from '#/api/hr/interviewProfile';
import { commonDownloadExcel } from '#/utils/file/download';
const emit = defineEmits<{ reload: [] }>();
const UploadDragger = Upload.Dragger;
const [BasicModal, modalApi] = useVbenModal({
onCancel: handleCancel,
onConfirm: handleSubmit,
});
const fileList = ref<UploadFile[]>([]);
// const checked = ref(false);
async function handleSubmit() {
try {
modalApi.modalLoading(true);
if (fileList.value.length !== 1) {
handleCancel();
return;
}
// const data = {
// file: fileList.value[0]!.originFileObj as Blob,
// updateSupport: unref(checked),
// };
const { success, errMessage } = await interviewProfileImportData(
fileList.value[0]!.originFileObj as Blob,
);
let modal = Modal.success;
if (success) {
emit('reload');
} else {
modal = Modal.error;
}
handleCancel();
modal({
content: h('div', {
class: 'max-h-[260px] overflow-y-auto',
innerHTML: errMessage, // 后台已经处理xss问题
}),
title: '提示',
});
} catch (error) {
console.warn(error);
modalApi.close();
} finally {
modalApi.modalLoading(false);
}
}
function handleCancel() {
modalApi.close();
fileList.value = [];
// checked.value = false;
}
</script>
<template>
<BasicModal
:close-on-click-modal="false"
:fullscreen-button="false"
title="面试档案导入"
>
<!-- z-index不设置会遮挡模板下载loading -->
<!-- 手动处理 而不是放入文件就上传 -->
<UploadDragger
v-model:file-list="fileList"
:before-upload="() => false"
:max-count="1"
:show-upload-list="true"
accept="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet, application/vnd.ms-excel"
>
<p class="ant-upload-drag-icon flex items-center justify-center">
<InBoxIcon class="text-primary size-[48px]" />
</p>
<p class="ant-upload-text">点击或者拖拽到此处上传文件</p>
</UploadDragger>
<div class="mt-2 flex flex-col gap-2">
<div class="flex items-center gap-2">
<span>允许导入xlsx, xls文件</span>
<Button
type="link"
@click="
commonDownloadExcel(downloadImportTemplate, '面试档案导入模板')
"
>
<div class="flex items-center gap-[4px]">
<ExcelIcon />
<span>下载模板</span>
</div>
</Button>
</div>
<!-- <div class="flex items-center gap-2">
<span :class="{ 'text-red-500': checked }">
是否更新/覆盖已存在的用户数据
</span>
<Switch v-model:checked="checked" />
</div> -->
</div>
</BasicModal>
</template>
<script lang="ts" setup>
import type { VbenFormProps } from '@vben/common-ui';
import type {
OnActionClickParams,
VxeTableGridOptions,
} from '#/adapter/vxe-table';
import type { InterviewProfileApi } from '#/api/hr/interviewProfile';
import { Page, useVbenDrawer, useVbenModal } from '@vben/common-ui';
import { Plus } from '@vben/icons';
import { ExportOutlined, UploadOutlined } from '@ant-design/icons-vue';
import { Button, message, Space } from 'ant-design-vue';
import { useVbenVxeGrid } from '#/adapter/vxe-table';
import { apiDelete, apiExport, apiPage } from '#/api/hr/interviewProfile';
import { commonDownloadExcel } from '#/utils/file/download';
import { querySchema, useColumns } from './data';
import Form from './form.vue';
import interviewImportModal from './interview-import-modal.vue';
/**
* 导入
*/
const [InterviewImportModal, interviewImportModalApi] = useVbenModal({
connectedComponent: interviewImportModal,
});
function handleImport() {
interviewImportModalApi.open();
}
const formOptions: VbenFormProps = {
commonConfig: {
labelWidth: 80,
componentProps: {
allowClear: true,
},
},
schema: querySchema,
wrapperClass: 'grid-cols-1 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4',
};
const [FormDrawer, formDrawerApi] = useVbenDrawer({
connectedComponent: Form,
});
const [Grid, gridApi] = useVbenVxeGrid({
formOptions,
gridOptions: {
columns: useColumns(onActionClick),
height: 'auto',
keepSource: true,
pagerConfig: {
enabled: true,
},
proxyConfig: {
ajax: {
query: async ({ page }, formValues = {}) => {
return await apiPage({
pageNo: page.currentPage,
pageSize: page.pageSize,
...formValues,
});
},
},
},
rowConfig: {
keyField: 'id',
// 高亮当前行
isCurrent: true,
},
} as VxeTableGridOptions,
});
function onActionClick({
code,
row,
}: OnActionClickParams<InterviewProfileApi.InterviewProfile>) {
switch (code) {
case 'delete': {
onDelete(row);
break;
}
case 'edit': {
onEdit(row);
break;
}
default: {
break;
}
}
}
function onRefresh() {
gridApi.query();
}
function onEdit(row: InterviewProfileApi.InterviewProfile) {
formDrawerApi.setData(row).open();
}
function onCreate() {
formDrawerApi.setData({}).open();
}
function onDelete(row: InterviewProfileApi.InterviewProfile) {
const hideLoading = message.loading({
content: `正在删除${row.name}...`,
duration: 0,
key: 'action_process_msg',
});
apiDelete(row.id || 0)
.then(() => {
message.success({
content: `${row.name}删除成功`,
key: 'action_process_msg',
});
onRefresh();
})
.catch(() => {
hideLoading();
});
}
function handleDownloadExcel() {
commonDownloadExcel(apiExport, '面试档案', gridApi.formApi.form.values);
}
</script>
<template>
<Page auto-content-height>
<FormDrawer @success="onRefresh" />
<Grid table-title="面试档案列表">
<template #toolbar-tools>
<Space>
<Button
type="primary"
ghost
v-access:code="['employee:interviewProfile:export']"
@click.stop="handleDownloadExcel"
>
<template #icon>
<ExportOutlined />
</template>
导出
</Button>
<Button
v-access:code="['employee:interviewProfile:import']"
@click="handleImport"
>
<template #icon>
<UploadOutlined />
</template>
导入
</Button>
<Button
v-access:code="['employee:interviewProfile:add']"
type="primary"
@click="onCreate"
>
<Plus class="size-5" />
新增
</Button>
</Space>
</template>
</Grid>
<InterviewImportModal @reload="onRefresh" />
</Page>
</template>
import type { VbenFormSchema } from '#/adapter/form';
import type { OnActionClickFn, VxeTableGridOptions } from '#/adapter/vxe-table';
import type { LaborCostApi } from '#/api/hr/laborCost';
export const querySchema: VbenFormSchema[] = [
{
component: 'DatePicker',
fieldName: 'recordDate',
label: '记录时间',
},
// {
// component: 'Input',
// fieldName: 'ossId',
// label: '文件ID',
// },
// {
// component: 'Input',
// fieldName: 'fileKey',
// label: '文件Key',
// },
];
export function useColumns(
onActionClick: OnActionClickFn<LaborCostApi.LaborCost>,
): VxeTableGridOptions<LaborCostApi.LaborCost>['columns'] {
return [
{
title: '记录时间',
field: 'recordDate',
formatter: 'formatDate',
},
// {
// title: '文件ID',
// field: 'ossId',
// },
// {
// title: '文件Key',
// field: 'fileKey',
// },
{
title: '备注',
field: 'remark',
},
{
align: 'right',
cellRender: {
attrs: {
nameField: 'recordDate',
nameTitle: '人工成本档案',
onClick: onActionClick,
},
name: 'CellOperation',
options: [
{
code: 'edit',
accessCode: ['employee:laborCost:edit'],
name: '查看',
}, // 默认的编辑按钮
{
code: 'delete',
accessCode: ['employee:laborCost:remove'],
}, // 默认的删除按钮
],
},
field: 'action',
fixed: 'right',
headerAlign: 'center',
resizable: false,
showOverflow: false,
title: '操作',
width: 'auto',
},
];
}
<script lang="ts" setup>
import type { VbenFormSchema } from '#/adapter/form';
import type { LaborCostApi } from '#/api/hr/laborCost';
import { computed, ref } from 'vue';
import { useVbenDrawer } from '@vben/common-ui';
import { useVbenForm } from '#/adapter/form';
import { apiAdd, apiUpdate } from '#/api/hr/laborCost';
import { defaultFormValueGetter, useBeforeCloseDiff } from '#/utils/popup';
const emit = defineEmits<{
success: [];
}>();
const isUpdate = ref(false);
const formSchema: VbenFormSchema[] = [
{
component: 'Input',
dependencies: {
show: () => false,
triggerFields: [''],
},
fieldName: 'id',
label: 'id',
},
{
component: 'DatePicker',
fieldName: 'recordDate',
label: '记录时间',
rules: 'required',
},
{
component: 'FileUpload',
componentProps: {
maxCount: 1,
},
fieldName: 'ossId',
formItemClass: 'items-start',
label: '文件',
rules: 'required',
},
// {
// component: 'Input',
// fieldName: 'fileKey',
// label: '文件Key',
// rules: 'required',
// },
{
component: 'Textarea',
fieldName: 'remark',
label: '备注',
// rules: 'required',
},
];
const [BasicForm, formApi] = useVbenForm({
commonConfig: {
componentProps: {
class: 'w-full',
},
formItemClass: 'col-span-2',
labelWidth: 90,
},
schema: formSchema,
showDefaultActions: false,
wrapperClass: 'grid-cols-2',
});
const { onBeforeClose, markInitialized, resetInitialized } = useBeforeCloseDiff(
{
initializedGetter: defaultFormValueGetter(formApi),
currentGetter: defaultFormValueGetter(formApi),
},
);
const [Drawer, drawerApi] = useVbenDrawer({
onBeforeClose,
onClosed: handleClosed,
onConfirm: onSubmit,
async onOpenChange(isOpen) {
if (!isOpen) {
return null;
}
const data = drawerApi.getData<LaborCostApi.LaborCost>();
isUpdate.value = !!data?.id;
if (isUpdate.value) {
await formApi.setValues(data);
} else {
formApi.resetForm();
}
await markInitialized();
},
});
async function onSubmit() {
const { valid } = await formApi.validate();
if (valid) {
drawerApi.lock();
const data = await formApi.getValues<LaborCostApi.LaborCost>();
try {
await (isUpdate.value ? apiUpdate(data) : apiAdd(data));
resetInitialized();
emit('success');
drawerApi.close();
} finally {
drawerApi.unlock();
}
}
}
async function handleClosed() {
await formApi.resetForm();
resetInitialized();
}
const getDrawerTitle = computed(() =>
isUpdate.value ? '修改人工成本档案' : '新增人工成本档案',
);
</script>
<template>
<Drawer class="w-full max-w-[800px]" :title="getDrawerTitle">
<BasicForm class="mx-4" />
</Drawer>
</template>
<script lang="ts" setup>
import type { VbenFormProps } from '@vben/common-ui';
import type {
OnActionClickParams,
VxeTableGridOptions,
} from '#/adapter/vxe-table';
import type { LaborCostApi } from '#/api/hr/laborCost';
import { Page, useVbenDrawer, useVbenModal } from '@vben/common-ui';
import { Plus } from '@vben/icons';
import { Button, message, Space } from 'ant-design-vue';
import { useVbenVxeGrid } from '#/adapter/vxe-table';
import { apiDelete, apiExport, apiPage } from '#/api/hr/laborCost';
import { commonDownloadExcel } from '#/utils/file/download';
import { querySchema, useColumns } from './data';
import Form from './form.vue';
import previewModal from './modal.vue';
const formOptions: VbenFormProps = {
commonConfig: {
labelWidth: 80,
componentProps: {
allowClear: true,
},
},
schema: querySchema,
wrapperClass: 'grid-cols-1 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4',
};
const [PreviewModal, previewModalApi] = useVbenModal({
connectedComponent: previewModal,
});
const [FormDrawer, formDrawerApi] = useVbenDrawer({
connectedComponent: Form,
});
const [Grid, gridApi] = useVbenVxeGrid({
formOptions,
gridOptions: {
columns: useColumns(onActionClick),
height: 'auto',
keepSource: true,
pagerConfig: {
enabled: true,
},
proxyConfig: {
ajax: {
query: async ({ page }, formValues = {}) => {
return await apiPage({
pageNo: page.currentPage,
pageSize: page.pageSize,
...formValues,
});
},
},
},
rowConfig: {
keyField: 'id',
// 高亮当前行
isCurrent: true,
},
} as VxeTableGridOptions,
});
function onActionClick({
code,
row,
}: OnActionClickParams<LaborCostApi.LaborCost>) {
switch (code) {
case 'delete': {
onDelete(row);
break;
}
case 'edit': {
onEdit(row);
break;
}
default: {
break;
}
}
}
function onRefresh() {
gridApi.query();
}
function onEdit(row: LaborCostApi.LaborCost) {
previewModalApi.setData({ ossId: row.ossId }).open();
}
function onCreate() {
formDrawerApi.setData({}).open();
}
function onDelete(row: LaborCostApi.LaborCost) {
const hideLoading = message.loading({
content: `正在删除${row.recordDate}...`,
duration: 0,
key: 'action_process_msg',
});
apiDelete(row.id || 0)
.then(() => {
message.success({
content: `${row.recordDate}删除成功`,
key: 'action_process_msg',
});
onRefresh();
})
.catch(() => {
hideLoading();
});
}
function handleDownloadExcel() {
commonDownloadExcel(apiExport, '人工成本档案', gridApi.formApi.form.values);
}
</script>
<template>
<Page auto-content-height>
<FormDrawer @success="onRefresh" />
<Grid table-title="人工成本档案列表">
<template #toolbar-tools>
<Space>
<Button
v-access:code="['employee:laborCost:export']"
@click="handleDownloadExcel"
>
导出
</Button>
<Button
v-access:code="['employee:laborCost:add']"
type="primary"
@click="onCreate"
>
<Plus class="size-5" />
新增
</Button>
</Space>
</template>
</Grid>
<PreviewModal />
</Page>
</template>
<script lang="ts" setup>
import { ref } from 'vue';
import { useVbenModal } from '@vben/common-ui';
import { ossInfo } from '#/api/system/oss';
import { urlToBase64 } from '../../../utils/file/base64Conver';
// const emit = defineEmits<{
// success: [];
// }>();
// const formData = ref<LaborCostApi.LaborCost>();
// const formSchema: VbenFormSchema[] = [
// {
// component: 'DatePicker',
// fieldName: 'recordDate',
// label: '记录时间',
// rules: 'required',
// },
// {
// component: 'Input',
// fieldName: 'ossId',
// label: '文件ID',
// rules: 'required',
// },
// {
// component: 'Input',
// fieldName: 'fileKey',
// label: '文件Key',
// rules: 'required',
// },
// {
// component: 'Input',
// fieldName: 'remark',
// label: '备注',
// rules: 'required',
// },
// ];
// const [BasicForm, formApi] = useVbenForm({
// commonConfig: {
// componentProps: {
// class: 'w-full',
// },
// formItemClass: 'col-span-2',
// labelWidth: 90,
// },
// schema: formSchema,
// showDefaultActions: false,
// wrapperClass: 'grid-cols-2',
// });
// const { onBeforeClose, markInitialized, resetInitialized } = useBeforeCloseDiff(
// {
// initializedGetter: defaultFormValueGetter(formApi),
// currentGetter: defaultFormValueGetter(formApi),
// },
// );
const url = ref('');
const [BasicModal, modalApi] = useVbenModal({
fullscreenButton: true,
// onClosed: handleClosed,
onConfirm: onSubmit,
onOpenChange: async (isOpen) => {
if (!isOpen) {
return null;
}
modalApi.modalLoading(true);
const { ossId } = modalApi.getData() as { ossId: number };
if (ossId) {
const resp = await ossInfo(ossId);
const ossData = resp[0];
url.value = `http://172.16.200.110:8012/onlinePreview?url=${encodeURIComponent(urlToBase64(ossData.url))}`;
// console.log('[url.value]', url.value);
// formData.value = data;
// await formApi.setValues(formData.value);
}
// await markInitialized();
modalApi.modalLoading(false);
},
});
async function onSubmit() {
modalApi.close();
// const { valid } = await formApi.validate();
// if (valid) {
// modalApi.lock();
// const data = await formApi.getValues<LaborCostApi.LaborCost>();
// try {
// await (formData.value?.id
// ? apiUpdate({ id: formData.value.id, ...data })
// : apiAdd(data));
// resetInitialized();
// emit('success');
// modalApi.close();
// } finally {
// modalApi.unlock();
// }
// }
}
// async function handleClosed() {
// await formApi.resetForm();
// resetInitialized();
// }
// class="size-full"
</script>
<template>
<BasicModal class="h-[950px] w-[1100px]" title="文件预览">
<iframe :src="url" class="h-[900px] w-full rounded-[6px] border"></iframe>
</BasicModal>
</template>
......@@ -83,7 +83,7 @@ export function useColumns(): VxeTableGridOptions<PhoneBookApi.PhoneBook>['colum
// field: 'deptId',
// },
{
title: '岗位',
title: '岗位',
field: 'position',
},
{
......@@ -91,17 +91,17 @@ export function useColumns(): VxeTableGridOptions<PhoneBookApi.PhoneBook>['colum
field: 'name',
},
{
title: '手机号码',
field: 'phoneNumber',
},
{
title: '办公电话',
title: '电话',
field: 'officePhone',
},
{
title: '线',
title: '线',
field: 'shortLine',
},
{
title: '手机',
field: 'phoneNumber',
},
{
title: '备注',
field: 'remarks',
......
import type { VbenFormSchema } from '#/adapter/form';
import type { OnActionClickFn, VxeTableGridOptions } from '#/adapter/vxe-table';
import type { TrainingApi } from '#/api/hr/training';
export const querySchema: VbenFormSchema[] = [
// {
// component: 'Input',
// fieldName: 'employeeId',
// label: '员工信息ID',
// },
{
component: 'Input',
fieldName: 'name',
label: '姓名',
},
{
component: 'Input',
fieldName: 'trainingCourse',
label: '培训课程',
},
{
component: 'Input',
fieldName: 'trainingInstitution',
label: '培训机构',
},
{
component: 'Input',
fieldName: 'trainer',
label: '培训讲师',
},
{
component: 'DatePicker',
fieldName: 'trainingTime',
label: '参训时间',
},
{
component: 'DatePicker',
fieldName: 'serviceEndDate',
label: '服务期',
},
{
component: 'Input',
fieldName: 'serviceYears',
label: '服务年限',
},
{
component: 'Input',
fieldName: 'trainingAmount',
label: '培训金额',
},
];
export function useColumns(
onActionClick: OnActionClickFn<TrainingApi.Training>,
): VxeTableGridOptions<TrainingApi.Training>['columns'] {
return [
// {
// title: '员工信息ID',
// field: 'employeeId',
// },
{
title: '姓名',
field: 'name',
},
{
title: '身份证号',
field: 'idCardNumber',
},
{
title: '培训课程',
field: 'trainingCourse',
},
{
title: '培训机构',
field: 'trainingInstitution',
},
{
title: '培训讲师',
field: 'trainer',
},
{
title: '参训时间',
field: 'trainingTime',
formatter: 'formatDate',
},
{
title: '服务期',
field: 'serviceEndDate',
formatter: 'formatDate',
},
{
title: '服务年限',
field: 'serviceYears',
},
{
title: '培训金额',
field: 'trainingAmount',
},
{
title: '备注',
field: 'remark',
},
{
align: 'right',
cellRender: {
attrs: {
nameField: 'name',
nameTitle: '员工培训档案',
onClick: onActionClick,
},
name: 'CellOperation',
options: [
{
code: 'edit',
accessCode: ['employee:training:edit'],
}, // 默认的编辑按钮
{
code: 'delete',
accessCode: ['employee:training:remove'],
}, // 默认的删除按钮
],
},
field: 'action',
fixed: 'right',
headerAlign: 'center',
resizable: false,
showOverflow: false,
title: '操作',
width: 'auto',
},
];
}
<script lang="ts" setup>
import type { VbenFormSchema } from '#/adapter/form';
import type { TrainingApi } from '#/api/hr/training';
import { computed, ref } from 'vue';
import { useVbenDrawer } from '@vben/common-ui';
import { useVbenForm } from '#/adapter/form';
import { apiAdd, apiUpdate } from '#/api/hr/training';
import { defaultFormValueGetter, useBeforeCloseDiff } from '#/utils/popup';
const emit = defineEmits<{
success: [];
}>();
const isUpdate = ref(false);
const formSchema: VbenFormSchema[] = [
{
component: 'Input',
dependencies: {
show: () => false,
triggerFields: [''],
},
fieldName: 'id',
label: 'id',
},
// {
// component: 'Input',
// fieldName: 'employeeId',
// label: '员工信息ID',
// rules: 'required',
// },
{
component: 'Input',
fieldName: 'name',
label: '姓名',
rules: 'required',
},
{
component: 'Input',
fieldName: 'idCardNumber',
label: '身份证号',
rules: 'required',
},
{
component: 'Input',
fieldName: 'trainingCourse',
label: '培训课程',
rules: 'required',
},
{
component: 'Input',
fieldName: 'trainingInstitution',
label: '培训机构',
rules: 'required',
},
{
component: 'Input',
fieldName: 'trainer',
label: '培训讲师',
// rules: 'required',
},
{
component: 'DatePicker',
fieldName: 'trainingTime',
label: '参训时间',
rules: 'required',
},
{
component: 'DatePicker',
fieldName: 'serviceEndDate',
label: '服务期',
rules: 'required',
},
{
component: 'Input',
fieldName: 'serviceYears',
label: '服务年限',
rules: 'required',
},
{
component: 'Input',
fieldName: 'trainingAmount',
label: '培训金额',
rules: 'required',
},
{
component: 'Textarea',
fieldName: 'remark',
label: '备注',
// rules: 'required',
},
];
const [BasicForm, formApi] = useVbenForm({
commonConfig: {
componentProps: {
class: 'w-full',
},
formItemClass: 'col-span-2',
labelWidth: 90,
},
schema: formSchema,
showDefaultActions: false,
wrapperClass: 'grid-cols-2',
});
const { onBeforeClose, markInitialized, resetInitialized } = useBeforeCloseDiff(
{
initializedGetter: defaultFormValueGetter(formApi),
currentGetter: defaultFormValueGetter(formApi),
},
);
const [Drawer, drawerApi] = useVbenDrawer({
onBeforeClose,
onClosed: handleClosed,
onConfirm: onSubmit,
async onOpenChange(isOpen) {
if (!isOpen) {
return null;
}
const data = drawerApi.getData<TrainingApi.Training>();
isUpdate.value = !!data?.id;
if (isUpdate.value) {
await formApi.setValues(data);
} else {
formApi.resetForm();
}
await markInitialized();
},
});
async function onSubmit() {
const { valid } = await formApi.validate();
if (valid) {
drawerApi.lock();
const data = await formApi.getValues<TrainingApi.Training>();
try {
await (isUpdate.value ? apiUpdate(data) : apiAdd(data));
resetInitialized();
emit('success');
drawerApi.close();
} finally {
drawerApi.unlock();
}
}
}
async function handleClosed() {
await formApi.resetForm();
resetInitialized();
}
const getDrawerTitle = computed(() =>
isUpdate.value ? '修改员工培训档案' : '新增员工培训档案',
);
</script>
<template>
<Drawer class="w-full max-w-[800px]" :title="getDrawerTitle">
<BasicForm class="mx-4" />
</Drawer>
</template>
<script lang="ts" setup>
import type { VbenFormProps } from '@vben/common-ui';
import type {
OnActionClickParams,
VxeTableGridOptions,
} from '#/adapter/vxe-table';
import type { TrainingApi } from '#/api/hr/training';
import { Page, useVbenDrawer, useVbenModal } from '@vben/common-ui';
import { Plus } from '@vben/icons';
import { ExportOutlined, UploadOutlined } from '@ant-design/icons-vue';
import { Button, message, Space } from 'ant-design-vue';
import { useVbenVxeGrid } from '#/adapter/vxe-table';
import { apiDelete, apiExport, apiPage } from '#/api/hr/training';
import { commonDownloadExcel } from '#/utils/file/download';
import { querySchema, useColumns } from './data';
import Form from './form.vue';
import trainingImportModal from './training-import-modal.vue';
/**
* 导入
*/
const [TrainingImportModal, trainingImportModalApi] = useVbenModal({
connectedComponent: trainingImportModal,
});
function handleImport() {
trainingImportModalApi.open();
}
const formOptions: VbenFormProps = {
commonConfig: {
labelWidth: 80,
componentProps: {
allowClear: true,
},
},
schema: querySchema,
wrapperClass: 'grid-cols-1 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4',
};
const [FormDrawer, formDrawerApi] = useVbenDrawer({
connectedComponent: Form,
});
const [Grid, gridApi] = useVbenVxeGrid({
formOptions,
gridOptions: {
columns: useColumns(onActionClick),
height: 'auto',
keepSource: true,
pagerConfig: {
enabled: true,
},
proxyConfig: {
ajax: {
query: async ({ page }, formValues = {}) => {
return await apiPage({
pageNo: page.currentPage,
pageSize: page.pageSize,
...formValues,
});
},
},
},
rowConfig: {
keyField: 'id',
// 高亮当前行
isCurrent: true,
},
} as VxeTableGridOptions,
});
function onActionClick({
code,
row,
}: OnActionClickParams<TrainingApi.Training>) {
switch (code) {
case 'delete': {
onDelete(row);
break;
}
case 'edit': {
onEdit(row);
break;
}
default: {
break;
}
}
}
function onRefresh() {
gridApi.query();
}
function onEdit(row: TrainingApi.Training) {
formDrawerApi.setData(row).open();
}
function onCreate() {
formDrawerApi.setData({}).open();
}
function onDelete(row: TrainingApi.Training) {
const hideLoading = message.loading({
content: `正在删除${row.name}...`,
duration: 0,
key: 'action_process_msg',
});
apiDelete(row.id || 0)
.then(() => {
message.success({
content: `${row.name}删除成功`,
key: 'action_process_msg',
});
onRefresh();
})
.catch(() => {
hideLoading();
});
}
function handleDownloadExcel() {
commonDownloadExcel(apiExport, '员工培训档案', gridApi.formApi.form.values);
}
</script>
<template>
<Page auto-content-height>
<FormDrawer @success="onRefresh" />
<Grid table-title="员工培训档案列表">
<template #toolbar-tools>
<Space>
<Button
type="primary"
ghost
v-access:code="['employee:training:export']"
@click.stop="handleDownloadExcel"
>
<template #icon>
<ExportOutlined />
</template>
导出
</Button>
<Button
v-access:code="['employee:training:import']"
@click="handleImport"
>
<template #icon>
<UploadOutlined />
</template>
导入
</Button>
<Button
v-access:code="['employee:training:add']"
type="primary"
@click="onCreate"
>
<Plus class="size-5" />
新增
</Button>
</Space>
</template>
</Grid>
<TrainingImportModal @reload="onRefresh" />
</Page>
</template>
<script setup lang="ts">
import type { UploadFile } from 'ant-design-vue/es/upload/interface';
import { h, ref } from 'vue';
import { useVbenModal } from '@vben/common-ui';
import { ExcelIcon, InBoxIcon } from '@vben/icons';
import { Button, Modal, Upload } from 'ant-design-vue';
import { downloadImportTemplate, trainingImportData } from '#/api/hr/training';
import { commonDownloadExcel } from '#/utils/file/download';
const emit = defineEmits<{ reload: [] }>();
const UploadDragger = Upload.Dragger;
const [BasicModal, modalApi] = useVbenModal({
onCancel: handleCancel,
onConfirm: handleSubmit,
});
const fileList = ref<UploadFile[]>([]);
// const checked = ref(false);
async function handleSubmit() {
try {
modalApi.modalLoading(true);
if (fileList.value.length !== 1) {
handleCancel();
return;
}
// const data = {
// file: fileList.value[0]!.originFileObj as Blob,
// updateSupport: unref(checked),
// };
const { success, errMessage } = await trainingImportData(
fileList.value[0]!.originFileObj as Blob,
);
let modal = Modal.success;
if (success) {
emit('reload');
} else {
modal = Modal.error;
}
handleCancel();
modal({
content: h('div', {
class: 'max-h-[260px] overflow-y-auto',
innerHTML: errMessage, // 后台已经处理xss问题
}),
title: '提示',
});
} catch (error) {
console.warn(error);
modalApi.close();
} finally {
modalApi.modalLoading(false);
}
}
function handleCancel() {
modalApi.close();
fileList.value = [];
// checked.value = false;
}
</script>
<template>
<BasicModal
:close-on-click-modal="false"
:fullscreen-button="false"
title="培训信息导入"
>
<!-- z-index不设置会遮挡模板下载loading -->
<!-- 手动处理 而不是放入文件就上传 -->
<UploadDragger
v-model:file-list="fileList"
:before-upload="() => false"
:max-count="1"
:show-upload-list="true"
accept="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet, application/vnd.ms-excel"
>
<p class="ant-upload-drag-icon flex items-center justify-center">
<InBoxIcon class="text-primary size-[48px]" />
</p>
<p class="ant-upload-text">点击或者拖拽到此处上传文件</p>
</UploadDragger>
<div class="mt-2 flex flex-col gap-2">
<div class="flex items-center gap-2">
<span>允许导入xlsx, xls文件</span>
<Button
type="link"
@click="
commonDownloadExcel(downloadImportTemplate, '培训信息导入模板')
"
>
<div class="flex items-center gap-[4px]">
<ExcelIcon />
<span>下载模板</span>
</div>
</Button>
</div>
<!-- <div class="flex items-center gap-2">
<span :class="{ 'text-red-500': checked }">
是否更新/覆盖已存在的用户数据
</span>
<Switch v-model:checked="checked" />
</div> -->
</div>
</BasicModal>
</template>
......@@ -4,7 +4,9 @@ import type { EmployeeFlowApi } from '#/api/hr/employeeFlow';
import { DictEnum } from '@vben/constants';
import { getTagDicts } from '#/utils/dict';
import { getDictOptions, getTagDicts } from '#/utils/dict';
import { HrDictEnum } from '../../hr/dict-enum';
export const flowTypeOptions = [
{ label: '入职', value: '1' },
......@@ -24,7 +26,7 @@ export const querySchema: VbenFormSchema[] = [
{
component: 'Select',
componentProps: {
options: flowTypeOptions,
options: getDictOptions(HrDictEnum.HR_APPLY_TYPE),
},
fieldName: 'flowType',
label: '审批类型',
......@@ -51,12 +53,19 @@ export function useColumns(): VxeTableGridOptions<EmployeeFlowApi.EmployeeFlow>[
{
title: '审批类型',
field: 'flowType',
cellRender: { name: 'CellTag', options: flowTypeOptions },
cellRender: {
name: 'CellTag',
options: [getTagDicts(HrDictEnum.HR_APPLY_TYPE)],
},
},
{
title: '员工姓名',
field: 'name',
},
{
title: '员工部门',
field: 'deptName',
},
// {
// title: '员工信息ID',
// field: 'employeeId',
// },
// {
// title: '开始时间',
// field: 'startDate',
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment